3
头图

I. Introduction

After Google released the first version of Chrome in 2008, the entire web development field seemed to have been injected with fresh blood, and gradually broke the era of IE dominance. Chrome and Firefox are staunch supporters of the W3C Web standards. With the gradual increase in market share of these two open source browsers, the spring of developers is ushered in. This ushered in a new professional division of labor-frontend-engineer frontend-engineer, frontend engineers promote the prosperity of Web applications, powerful debugging tools are indispensable. Google launched DevTools on the basis of open source, which was widely praised by web developers, and immediately promoted the commercial success of Chrome.

This article analyzes the technical implementation of Chrome's DevTools, especially the implementation part in the browser kernel, to show the secret behind this development tool that is loved by thousands of developers. This article is suitable for reading mainly front-end developers, application engineers who are interested in developing Hybrid application debugging tools or rewriting webdriver to control Chrome or WebView.

Note: All code analysis in this article is based on the analysis of Android Chromium 87.0.4280.141 version. Since the author's team is mainly engaged in the development of the Blink kernel of the Android platform, the analysis process is mainly concentrated on the mobile terminal. Other platforms are only the difference in data channels, and the implementation principles are not very different.

2. History of web debugging tools

Before 2006, this belonged to the IE era. The debugging method when writing JavaScript code in the IE era mainly relied on window.alert() or outputting debugging information to the web page to analyze logic bugs. This hard debugging method is no less than the underlying system development. A small problem often takes a whole day, and the development efficiency is extremely low.

In January 2006, Apple's WebKit team released the first version of Web Inspector. The functions of this version are relatively simple. You can only view the inheritance relationship of DOM nodes and which CSS rules are applied to the nodes. But this version has already laid the prototype of the webpage debugging tool for many years in the future, which is of epoch-making significance.

The WebKit team's iteration speed is very fast. In June 2006, a heavyweight feature, JavaScript's breakpoint debugging function, was released. At this time, it has the embryonic form of a developer's artifact.

At the same time, a Firefox plug-in Firebug appeared in the open source camp, focusing on the debugging of Web development, laying the foundation of the Web UI layout of modern DevTools. The early version supported JavaScript debugging, the visual display of CSS Box model, and the performance analysis of HTTP Archive. Later DevTools referred to the function and product positioning of this plug-in. In 2016, Firebug was integrated into Firefox's built-in debugging tool. In 2017, Firebug stopped updating, and the first generation of artifacts came to a close.

At this time, a ruthless role in the open source industry Google team ushered in, based on WebKit to join the browser research and development, the launch of Chrome has attracted the attention of many IT geeks with its "safe, fast, and more stable". At the same time, in terms of developer tools, Google absorbed the excellent features of many debugging tools and launched DevTools, the protagonist of today.

The early version now looks a bit rudimentary in this layout, but this is a work more than ten years ago. Support DOM + CSS viewing, viewing resource loading analysis, script debugging and performance debugging. The functions of DevTools commonly used in development are basically just these functions.

The DevTools of that era basically followed the functions of Firebug, only the difference in the way of interaction. In 2007, Steve Jobs released the first generation of iPhone phones, and Google launched Android phones one after another. The development of the Internet came to the era of mobile Internet. DevTools began to surpass similar tools at this time, supporting remote real machine debugging. Chrome is a multi-process architecture, DOM and JavaScript are running in sub-processes, so the underlying implementation of DevTools is completely different from similar products. The architects of Chrome adjusted the DevTools implementation architecture to the client-server mode. This architecture makes remote real-machine debugging possible. In order to facilitate network data transmission, Chrome has designed a set of data encapsulation protocol Chrome DevTools Protocal (CDP) . In the following years, the adjustment of this architecture will shine in the open source world.

Yan Dahl designed Node.js based on Chromium's JavaScript virtual machine V8. The advent of Node.js made JavaScript, a web scripting language, out of the browser, opening up a new situation where JavaScript can be used in server-side programming and desktop programming. Relying on the client-server architecture of DevTools and the increasing number of Node.js developers, DevTools also quickly emerged from the circle. The Chrome team began to support Node.js debugging in 2016. DevTools has evolved from a web debugging tool to an important member of the JavaScript ecosystem, helping more developers develop more excellent code. Eco Node.js are inseparable DevTools, such as desktop development framework Electron , developer favorite editor Visual Studio Code , front-end architecture Vue.js , Facebook open-source Android performance analysis tool Stetho and so on.

Three, DevTools architecture

DevTools is a client-server architecture. The client is the user-operated Web UI interface, which is responsible for receiving user operation instructions, and then sending the operation instructions to the browser kernel or Node.js for processing, and displaying the processing result data on the Web UI. The server starts two types of services, one is HTTP service; the other is WebSocket service.

The HTTP service provides core information query capabilities. For example, get the kernel version, get the list of debug pages, start or close debugging.

The WebSocket service provides the ability to communicate with the kernel for real data, is responsible for the distribution and processing of all operating instructions passed by the Web UI, and sends the results back to the Web UI for display.

The following figure shows the overall architecture of Android DevTools. The operation commands initiated by the developer through the Web UI from the left are how to pass the operation commands step by step to the Browser Core in the phone (Browser Core runs the Chrome browser kernel Application, such as Chrome browser, Android WebView, NodeJs application, etc.).

The Android platform cleverly uses the ADB forward capability to solve the connection problem between the WebUI on the PC and the Chrome kernel in the Android phone. It is easy to realize the ability of remote debugging. Don't underestimate this realization. This is a great improvement in the efficiency of front-end developers. Because the working environment of front-end developers is basically under PC (Windows, Mac, and Linux collectively referred to as PC), through the realization of remote debugging capabilities, the development of mobile terminals realizes what you see is what you get.

It was the Chrome team based on the network communication method, as the underlying communication framework of DevTools, that laid the foundation for the subsequent Web development team to flourish. TCP/IP is the foundation of the Internet, and there is no language or platform that does not support TCP/IP. The TCP/IP method selected by DevTools directly smooths out the differences between different platforms or system frameworks.

Chrome DevTools Protocol (CDP for short) open protocol, once again the realization of DevTools is truly cross-platform. CDP is essentially a set of data encapsulation protocols in JSON format. JSON is a lightweight text exchange protocol that can be parsed by any platform or language. Because of this, there are nearly ten officially recommended language libraries that support CDP. Google officially recommended the Node.js version of Puppeteer. Through Puppeteer , the CDP protocol was fully implemented, which drew a sample of the Chrome kernel communication method, and then the open source world successively launched multiple language versions of CDP libraries. The CDP protocol will be introduced in detail in a later chapter.

Chrome's architects abstracted the underlying architecture of DevTools into two parts, TCP/IP and CDP, through a high degree of abstraction, laying the foundation for DevTools' cross-platform and cross-terminal capabilities. The implementation of WebSocket was still in the draft stage, and Chrome architects boldly adopted WebSocket to implement the main protocol part of the debugging protocol. It now appears that the real-time screenshot capability of the page that developers use daily can observe the interface displayed in the remote web page in real time. This real-time performance is provided based on WebSocket. I also admire the vision and design aura of the Chrome architects. It is their excellent ability to bring web developer tools to new heights.

Four, DevTools communication protocol

Chrome DevTools Protocol (CDP for short) This protocol consists of two parts: HTTP and WebSocket. The Web UI of DevTools sends control commands to the browser kernel. The control commands, parameters, and return values are all encapsulated by CDP. When the command is sent, it is encapsulated by the Web UI and sent to the browser kernel via WebSocket. After receiving the result from the browser kernel, it is unpacked according to the protocol and distributed to the Web UI.

In order to analyze the communication process between the Web UI and the Android browser kernel, some environment preparations are needed.

4.1 Environmental preparation

In order to be able to access the data in the kernel, the browser kernel needs to open the DevTools Server. The opening methods of PC Chrome and Android Chrome/WebView are slightly different.

When PC Chrome starts, add a startup parameter -remote-debugging-port=9222 , so that DevTools Server will listen to the local port, and you can initiate an HTTP/WebSocket request http://localhost:9222 Get the data in DevTools.

There is a slight difference between Android Chrome and WebView. Since WebView does not turn on the debugging function by default, it needs to be manually turned on on the client to start the Server.

// Android 4.4 以上 WebView 才真正使用 Blink 内核,所以需要在此版本及以上系统。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    WebView.setWebContentsDebuggingEnabled(true);
}

At this time, the Android Chrome / WebView has started the Server in the phone, but in order to be able to access it on the PC, it needs to use the port forwarding capability of the ADB tool.

ADB 端口转发
您可以使用 forward 命令设置任意端口转发,将特定主机端口上的请求转发到设备上的其他端口。以下示例设置了主机端口 6100 到设备端口 7100 的转发:

adb forward tcp:6100 tcp:7100

通过 forward 可以打通 PC 与 Android 设备之间的网络相互访问

Android Chrome / WebView uses unix domain socket to establish the Server side. The connector of this socket is:

chrome\_devtools\_remote and webview\_devtools\_remote_ are the connectors of chrome and WebView respectively. The connection of WebView may use WebView in different applications, so the process ID (PID) is used as the suffix to distinguish.

adb shell cat /proc/net/unix | grep "devtools_remote"
0000000000000000: 00000002 00000000 00010000 0001 01 528176 @chrome_devtools_remote
0000000000000000: 00000002 00000000 00010000 0001 01 276394 @webview_devtools_remote_23119

Through ADB forward, connect PC and Android device access, execute the following command:

# 在 PC 上侦听 9222 端口,对 localhost:9222 的请求将会转发到 android 设备上的 webview_devtools_remote_23119 上
adb forward tcp:9222 localabstract:webview_devtools_remote_23119

At this point, you can access the debug page in the Android device through 9222 on the PC.

4.2 HTTP protocol analysis

4.2.1 Get kernel version information

# 使用 curl 工具,GET http://localhost:9222/json/version
curl http://localhost:9222/json/version                       
{
   "Android-Package": "com.vivo.browser",
   "Browser": "Chrome/87.0.4280.141",
   "Protocol-Version": "1.3",
   "User-Agent": "Mozilla/5.0 (Linux; Android 8.1.0; vivo X20Plus A Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/87.0.4280.141 Mobile Safari/537.36",
   "V8-Version": "8.7.220.31",
   "WebKit-Version": "537.36 (@9f05d1d9ee7483a73e9fe91ddcb8274ebcec9d7f)",
   "webSocketDebuggerUrl": "ws://localhost:9222/devtools/browser"
}

From the above return value, you can get the following information:

  • Android-Package, use the package name of the WebView application.
  • Browser, the version number of the kernel.
  • Protocol-Version, is the CDP protocol version, the current version is 1.3, starting from 1.0, there are 1.1, 1.2, etc.
  • User-Agent, the UA information of the browser.
  • V8-Version, the version number of the JavaScript engine used.
  • WebKit-Version, since the Blink kernel is developed based on WebKit version 537.36, there will be this version information.
  • webSocketDebuggerUrl, this is the debugging URL of the WebSocket.

4.2.2 Get the list of debuggable pages

# 使用 curl 工具,GET http://localhost:9222/json/list
curl http://localhost:9222/json/list  
[ {
   "description": "{\"attached\":true,\"empty\":false,\"height\":1812,\"never_attached\":false,\"screenX\":0,\"screenY\":72,\"visible\":true,\"width\":1080}",
   "devtoolsFrontendUrl": "https://chrome-devtools-frontend.appspot.com/serve_rev/@9f05d1d9ee7483a73e9fe91ddcb8274ebcec9d7f/inspector.html?ws=localhost:9222/devtools/page/B86E67DEA526D5EEE83A170B1F62A72C",
   "faviconUrl": "https://mat1.gtimg.com/www/mobi/2017/image/logo/v0/192.png",
   "id": "B86E67DEA526D5EEE83A170B1F62A72C",
   "title": "腾讯网-QQ.COM",
   "type": "page",
   "url": "https://xw.qq.com/#news",
   "webSocketDebuggerUrl": "ws://localhost:9222/devtools/page/B86E67DEA526D5EEE83A170B1F62A72C"
}, {
   "description": "{\"attached\":false,\"empty\":true,\"never_attached\":true,\"screenX\":0,\"screenY\":0,\"visible\":true}",
   "devtoolsFrontendUrl": "https://chrome-devtools-frontend.appspot.com/serve_rev/@9f05d1d9ee7483a73e9fe91ddcb8274ebcec9d7f/inspector.html?ws=localhost:9222/devtools/page/3F9E05905F1919D563DF01BAEC64D2E4",
   "id": "3F9E05905F1919D563DF01BAEC64D2E4",
   "title": "about:blank",
   "type": "page",
   "url": "about:blank",
   "webSocketDebuggerUrl": "ws://localhost:9222/devtools/page/3F9E05905F1919D563DF01BAEC64D2E4"
} ]

A JSON array is returned. Each debug page occupies one data element. The return value above shows that the vivo browser in the author's environment has opened two pages, one is https://xw.qq.com/#news and about:blank.

  • description is a JSON object that displays the status information of the current page. For example, the page width, height, offset on the screen, whether the WebView has been attached to the view, only the attached page will be displayed and whether it can be debugged.
  • devtoolsFrontendUrl, this value is a URL, which is the WebUI control panel address of DevTools that is used daily. This is a Web APP. After one visit, it will cache a copy in the browser. This page is hosted in an address that cannot be accessed normally in the country, so it often appears that the panel cannot be opened and a white screen is displayed. When the Chrome browser is packaged, it will have a built-in version of WebUI that matches the current kernel, so Chrome can directly debug its own pages.
  • id, which is a GUID value randomly generated for each open page, used to generate WebSocket links to distinguish different pages.
  • title, open the title of the webpage, corresponding to the content of the title tag in the head of the webpage.
  • type, the type of the page, there are mainly the following types of page, iframe, worker, service_worker, etc.
  • URL, the URL of the currently opened page.
  • webSocketDebuggerUrl, this parameter is the URL of the WebSocket connection.

There are several other sub-commands of the HTTP protocol, such as protocol, new, activate, etc., which are mainly for page control, so I won't introduce them one by one.

4.2.3 WebSocket protocol analysis

The WebSocket protocol consists of four parts: Domain, Method, Event and Type.

1) Domain, namespace, similar to namespace or package name in C++/Java, used to separate different commands. It is used to divide many subcommands into categories to facilitate the user to call and prevent method conflicts with the same name. With the 1.3 version of the CDP protocol, a total of 15 domains are divided.

  • Browser : Used to manage browser objects.
  • Debugger : Categories used to debug JavaScript, such as breakpoints, call stacks, etc.
  • DOM : All DOM node operations are under this Domain, DOM node modification, traversal, etc.
  • DOMDebugger : Manages the domain of DOM node debugging. The node modification breakpoint in DevTools is completed by the Method provided in this group of Domains.
  • Emulation : This is a set of environment simulators. The modification of device size and UserAgent in DevTools are implemented by this Domain.
  • Input : A collection of event distribution methods.
  • IO : I/O stream operation collection.
  • Log : Log controls the Method collection.
  • Network : Browser network communication data, which may be captured through this Domain.
  • Page : Based on the Page operation Method set in Blink, such as refresh and open URL.
  • Performance : Integrated performance analysis Method.
  • Profiler : The Method of the sampling analyzer is integrated under this Domain.
  • Runtime : The Method that communicates with JavaScript is integrated under this Domain, such as executing JavaScript code.
  • Security : Security operations, such as certificate errors.
  • Target : Some control methods connected by DevTools are under this Domain.

2) Method, method name, there will be a group of Method under each Domain, which indicates the function of operating the browser kernel. It consists of three parts: name, parameter and return value. It is consistent with the method description in C++/Java.

  • name : Debugger.setBreakpointByUrl;
  • parameter : lineNumber integer [, url string, urlRegex string, scriptHash string, columnNumber integer, condition string];
  • return value : breakpointId BreakpointId, actualLocation Location.
// Debugger.setBreakpointByUrl 到内核,带上如下参数
{
   "lineNumber":1,
   "url":"snippet:///Script%20snippet%20%231",
   "columnNumber":0,
   "condition":""
}
 
// 将会收到内核的返回值,返回断点成功信息
{
   "breakpointId":"1:1:0:snippet:///Script%20snippet%20%231",
   "locations":[]
}

3) Event, notification event , there will be many status notifications on the web page, which need to be synchronized to WebUI or other control terminals. Event is used to notify these events. For example, when the DOM attribute changes, it will receive the Dom.attributeModified event; when the JavaScript is passed to the kernel for execution, it will receive the Debugger.scriptParsed event and parameters sent back by the kernel. The parameters are as follows:

{
   "scriptId":"238",
   "url":"",
   "startLine":0,
   "startColumn":0,
   "endLine":0,
   "embedderName":"",
   "endColumn":7,
   "endLine":0,
   "executionContextAuxData":{
      "isDefault":true,
      "type":"default",
      "frameId":"2059AA1A2C1A535CF4C480DC01E7FDEC"
   },
   "frameId":"2059AA1A2C1A535CF4C480DC01E7FDEC",
   "isDefault":true,
   "type":"default",
   "executionContextId":5,
   "hasSourceURL":false,
   "hash":"035a9e1738252e22523ed8f1c52d9dbf81abe278",
   "isLiveEdit":false,
   "isModule":false,
   "length":7,
   "scriptId":"238",
   "scriptLanguage":"JavaScript",
   "sourceMapURL":"",
   "startColumn":0,
   "startLine":0,
   "url":""
}

4) Type is a complex data type for Method or Event to pass parameters. These types correspond to objects in the kernel. For example, the DOM.Node type corresponds to the DOM node in Blink. The main attributes are as follows:

  • nodeId: NodeId is also Type, node id, according to this value, the corresponding node can be found in the kernel.
  • parentId: NodeId is also Type, the id of the parent node.
  • nodeType: integer, node type.
  • nodeName: string, the name of the node.
  • nodeValue: string, node content.
  • children: array, an array of child nodes.
  • attributes: array, node attribute array Through these attributes on Node, the memory usage of the nodes of the DOM tree can be described. The Element panel in the Web UI of DevTools displays a DOM tree through the DOM.getDocument Method.

Through this data organization of CDP, it is possible to pass control commands to operate the kernel, and also to receive kernel status notifications (Event). Through CDP, you can let the browser do anything, and get far more information than using the Chrome graphical interface. Therefore, Google launched the Chrome Headless version, which is widely used in fields such as web automated testing, web crawlers, and web sandboxes.

When debugging the mobile browser, you can see the screen viewed on the mobile device in real time. How is this done?

In fact, it is just a screenshot that sends the base64 pictures back to the Web UI for display through the Page.screencastFrame event.

The picture and description information (Meta data) are brought back from the Page.screencastFrame notification event:

{
   "data":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBw...",
   "metadata":{
      "deviceHeight":604,
      "deviceWidth":360,
      "offsetTop":60,
      "pageScaleFactor":1,
      "scrollOffsetX":0,
      "scrollOffsetY":832.6666870117188,
      "timestamp":1631018056.565802
   },
   "sessionId":2
}

Through the description information, the information of this picture can be displayed on the WebUI. A screenshot is nearly 1M in size. Because DevTools takes advantage of the two-way long link feature of WebSocket, the display is extremely smooth and clear.

4.3 DevTools kernel implementation

The above chapters introduced the overall process of transferring operation commands to the Browser Core of the mobile terminal from the perspective of a Web developer, as well as the related content of the CDP communication protocol. This section focuses on the implementation process in Browser Core, first introduces the implementation of DevTools in the browser core, and later the author will select how JavaScript is passed from the string to the execution process in V8, and expand to introduce in detail, the implementation of this behavior .

4.3.1 Introduction to the kernel architecture

DevTools starts with starting a Web Server, and then sends the calling command to the corresponding processing module. The overall architecture diagram is as follows:

DevTools is roughly divided into four layers in the kernel:

  • The Server layer is used to receive operation requests from external networks.
  • The Agent layer disassembles the requests sent by the Server layer, and distributes them to different Agents for processing according to different types of operations.
  • Session layer, Session is an abstraction of different business modules. After passing the Session layer, you will enter different business modules, which can reach V8, Blink, etc.
  • The business layer is the specific functional module, such as the V8 module, which is mainly responsible for the support of JavaScript debugging related capabilities.

The Server layer is managed by the singleton object DevToolsManager. Because it is a singleton, there will only be one Manger object in a process, which prevents multiple creations from being repeated and leads to disordered state.

4.3.2 Web Server data receiving entrance

The requests received by the Server will be distributed to the DevToolsHttpHandler class. This class is responsible for the data request response sent by the network Client and sending the processing results back to the network Client. This class has two important methods, OnJsonRequest and OnWebSocketMessage, which are used to process the HTTP protocol and WebSocket respectively. protocol.

void DevToolsHttpHandler::OnJsonRequest(
    int connection_id,
    const net::HttpServerRequestInfo& info) {
  // 查询内核版本信息
  if (command == "version") {
    base::DictionaryValue version;
    version.SetString("Protocol-Version",
                      DevToolsAgentHost::GetProtocolVersion());
    // ...
    SendJson(connection_id, net::HTTP_OK, &version, std::string());
    return;
  }
  // 获取内核所支持的协议
  if (command == "protocol") {
    DecompressAndSendJsonProtocol(connection_id);
    return;
  }
  // 获取可调试页
  if (command == "list") {
    DevToolsManager* manager = DevToolsManager::GetInstance();
    DevToolsAgentHost::List list =
        manager->delegate() ? manager->delegate()->RemoteDebuggingTargets()
                            : DevToolsAgentHost::GetOrCreateAll();
    RespondToJsonList(connection_id, info.GetHeaderValue("host"),
                      std::move(list));
    return;
  }
  // 启动一个新调试
  if (command == "new") {
    // ...
    std::string host = info.GetHeaderValue("host");
    std::unique_ptr<base::DictionaryValue> dictionary(
        SerializeDescriptor(agent_host, host));
    SendJson(connection_id, net::HTTP_OK, dictionary.get(), std::string());
    return;
  }
  // 激活或关闭一个调试
  if (command == "activate" || command == "close") {
   // ...
  SendJson(connection_id, net::HTTP_NOT_FOUND, nullptr,
           "Unknown command: " + command);
}
 
void DevToolsHttpHandler::OnWebSocketRequest(
    int connection_id,
    const net::HttpServerRequestInfo& request) {
  // 创建调试的 Agent
  if (base::StartsWith(request.path, browser_guid_,
                       base::CompareCase::SENSITIVE)) {
    scoped_refptr<DevToolsAgentHost> browser_agent =
        DevToolsAgentHost::CreateForBrowser(
            thread_->task_runner(),
            base::BindRepeating(&DevToolsSocketFactory::CreateForTethering,
                                base::Unretained(socket_factory_.get())));
    connection_to_client_[connection_id] =
        std::make_unique<DevToolsAgentHostClientImpl>(
            thread_->task_runner(), server_wrapper_.get(), connection_id,
            browser_agent);
    AcceptWebSocket(connection_id, request);
    return;
  }
 
  connection_to_client_[connection_id] =
      std::make_unique<DevToolsAgentHostClientImpl>(
          thread_->task_runner(), server_wrapper_.get(), connection_id, agent);
    // Accept websocket
  AcceptWebSocket(connection_id, request);
}
 
// WebSocket 数据接收接口,所有 WebUI 的请求都通过此接口分发
void DevToolsHttpHandler::OnWebSocketMessage(int connection_id,
                                             std::string data) {
  auto it = connection_to_client_.find(connection_id);
  if (it != connection_to_client_.end()) {
    it->second->OnMessage(base::as_bytes(base::make_span(data)));
  }
}
  • DevToolsHttpHandler::OnJsonRequest is used to respond to HTTP requests and to query the kernel status, such as the kernel version and the current supported protocol. The complete protocol content will be returned to facilitate developers to adapt to the corresponding support.
  • DevToolsHttpHandler::OnWebSocketRequest is used to receive WebSocket connections, and different Agent objects are created according to this method.
  • DevToolsHttpHandler::OnWebSocketMessage all debugging request data is distributed to different Agents through this interface through Client.

The server layer data response through the above three interfaces to achieve the ability to receive and distribute data.

4.3.3 JavaScript execution process

The V8 JavaScript engine is used to interpret and execute JavaScript scripts in webpages. At the same time, it can also receive externally passed scripts through DevTools. The scripts are executed under the context of the current webpage, so JavaScript can be used to manipulate webpage behaviors, such as modifying DOM node attributes. The JavaScript interface Runtime.evaluate is designed in CDP, and the parameters of the cited method are as follows:

{
    allowUnsafeEvalBlockedByCSP: false,
    awaitPromise: false,
    contextId: 14,
    expression: "alert('hi');",
    generatePreview: true,
    includeCommandLineAPI: true,
    objectGroup: "console",
    replMode: true,
    returnByValue: false,
    silent: false
}

Among them, the most important parameter is expression, which is a string type parameter used to store the content of the script that needs to be executed. The above example will pop up an alert confirmation box with the content hi on the web page.

There is a special module in V8. V8RuntimeAgentImpl is used to support the Domain of Runtime in CDP. Of course, V8DebuggerAgentImpl is used to support the specific implementation of Debug. The evaluate method in V8RuntimeAgentImpl is used to receive execution requests from DevTools.

void V8RuntimeAgentImpl::evaluate(
    const String16& expression, Maybe<String16> objectGroup,
    Maybe<bool> includeCommandLineAPI, Maybe<bool> silent,
    Maybe<int> executionContextId, Maybe<bool> returnByValue,
    Maybe<bool> generatePreview, Maybe<bool> userGesture,
    Maybe<bool> maybeAwaitPromise, Maybe<bool> throwOnSideEffect,
    Maybe<double> timeout, Maybe<bool> disableBreaks, Maybe<bool> maybeReplMode,
    Maybe<bool> allowUnsafeEvalBlockedByCSP,
    std::unique_ptr<EvaluateCallback> callback);

V8RuntimeAgentImpl::evaluate will start a microtasks to execute the script, and will eventually go to v8::internal::Execution::Call. The Execution module will be responsible for parsing and compiling the script into bytecode, and finally dispatching it to the virtual machine run.

The execution process is shown in the figure above. The Web UI sends out a string to execute the script, and the OnWebSocketMessage of WebSocket will receive this command, and then distribute it to V8 layer by layer through DevToolsSession. Since Chrome is a multi-process architecture, it is divided into Browser process and Render process, and the communication is carried out through IPC. The left side of the figure above is the execution process on the Browser side, and the right side is the execution process on the Render side.

The DevToolsSession::DispatchProtocolCommand on the Render side is an important distribution interface, so control commands sent to V8 or Blink will pass through this interface. Then the control command will be sent to V8RuntimeAgentImpl, and according to the different function of the command, it will be dispatched to different functional modules for processing.

4.4 Web page performance tuning

4.4.1 Introduction to Performance Analysis Panel

DevTools provides a set of powerful performance analysis tools, network, JavaScript debugging, rendering, memory and standard support detection, etc. The following introduces some functions during performance analysis in the Performance panel. The main interface is divided into these sections:

1) Frame rate (FPS): Linearly shows the frame rate of web page rendering during Performance.

2) CPU usage: CPU usage trend chart

3) Screen capture during loading: the performance of webpage screenshots is collected regularly

4) Network loading sequence: display network resource loading sequence and time-consuming situation

5) Frame time (Frames): Shows the time it takes to render each frame. Red indicates that there are frames that take a long time.

6) Web Vitals indicators: Google recommends a set of performance experience indicators, which will be described in detail below.

7) The main thread in the kernel: There are multiple threads in the browser kernel, each with its own division of labor. When a long time-consuming frame occurs, it is necessary to check in these threads, which thread is consuming time. Mainly divided into these several:

  • Main, this is the main thread of Blink, responsible for web page layout, analysis, JavaScript execution, etc.
  • Raster, the rasterization thread, is used to convert the rendered object into a Bitmap.
  • GPU, hardware-accelerated rendering thread, draws Texture to the screen.
  • Chrome_ChildIOThread is responsible for network resources and file operations.
  • Compositor, the compositing thread, is responsible for compositing each layer during rendering and then rasterizing.
  • ThreadPoolForegoundWorker, Worker's worker thread pool.

8) Information panel: used to display the detailed information of the selected module, the meaning of several indicators:

  • Loading: Time-consuming network requests and HTML parsing.
  • Scripting: JavaSript analysis, compilation, execution in a virtual machine, and time consuming GC.
  • Rendering: Blink typesetting and rendering are time-consuming.
  • Painting: Time-consuming painting, including painting, synthesis, picture decoding, and screen display.
  • System and Idle: system scheduling and idle time-consuming.

4.4.2 Conventional Ideas for Performance Analysis

The basic idea of performance analysis starts with the problem, the common performance problems of webpages, the author encountered mainly these kinds of situations.

  • The required resources were not requested in time. Troubleshoot server issues, the resource request was initiated too late? Too much resources?
  • There are too many layers of web pages, which leads to too long Rendering and Painting time.
  • Too much memory is occupied, pages are too complex, resources are too large and large, and the life cycle of large JavaScript resources is too long.
  • There are many animations and they are not removed after disappearing. JavaScript carousel animation, CSS animation, image resources with animation, such as GIF, SVG, WebP, etc.
  • Event listening is unreasonable. The event listens to too much and may be touched by high frequency, such as node changes, Move events, etc.

In general, whether it is web page performance optimization or Native program optimization, as long as the two resource occupations are coordinated: CPU + memory. As long as the problem is discovered, the performance problem will be solved. In addition to the source-level review of the problem, DevTools can help.

For the conventional scenarios summarized above, use the performance analysis capabilities of DevTools to first examine the Profile diagram as a whole.

Whether the order and duration of network requests are reasonable;

Is the long task of Main Thread reasonable?

Observe the order in which resource requests are initiated from the Network section. Whether there is a long time-consuming task blocking the loading of resources displayed on the first screen. If the required timely loading is not guaranteed, the screen will be blank for a long time.

After the resource problem is ready, it is necessary to troubleshoot which long time-consuming tasks are executed. First look at the Long task in the Main Thread. For example, the Long task in the picture above is the scripting that takes a long time. Check the specific time-consuming points through Bottom-Up / CallTree, and optimize accordingly.

There is a little trick when investigating specific optimization points. Usually the development environment is simulated on the PC, and problems can be exposed only after the version is released. Due to the fragmentation of mobile devices, the performance of many users' devices may not be good. So how to optimize the performance on such low-configuration machines in the development environment? DevTools provides a simulation of current limiting, which can limit the network standard to 2G/3G and CPU speed reduction.

There is a "Settings" in the upper right corner, expand the configuration items, you can see the current limiting options of Network and CPU, select and re-record the Profile.

As mentioned above, there are too many web pages, which greatly affects web page rendering performance. What does "page number of layers" mean? Currently, in order to improve the rendering performance of web pages, browser rendering engines layer web pages when rendering. The advantage of this is that only the modified layer is redrawn. If the contents of other layers remain unchanged, there is no need to redraw, and the last drawing result is directly taken, thereby improving the drawing efficiency. Different WEB engines have different layering strategies. Normal web pages, CSS animations, Canvas, WebGL, Fix tags, etc. are usually divided into one layer. Layering will increase rendering efficiency, but it will also bring memory overhead, which will affect performance. Can DevTools analyze the number of page layers? Yes, there is an option "Enable advanced paint instrumentation(slow)" in the above "Settings" to enable it, and perform performance recording again.

There is an additional "Layers" tab in the "Information Panel". After selecting it, you will see the web page layering status. If there is unreasonable stratification, you can try to adjust the way to merge the stratification to improve performance.

4.4.3 Web Vitals

Web Vitals is a set of web performance and experience measurement standards launched by Google. The original measurement strategy is basically based on the "first word" and "first screen" to measure, but from the perspective of users and technical optimization, these two indicators have problems of this kind. Therefore, Google introduced the Web Vitals standard and cooperated with DevTools to facilitate developers to identify Web performance problems during the development phase. Since the standard has been changing with the development of the times, developers have been chasing the changes in the indicators are a bit overwhelming. Fortunately, Google has made it clear that the three indicators currently launched will not change in a short period of time. The author is not clear about this short period of time. How long is it.

The first indicator: Largest Contentful Paint (LCP), a large area filled with time points, within 2.5 seconds is considered excellent. It mainly means that a large area of text and pictures are displayed, even if it has reached the LCP.

The second indicator: First Input Delay (FID), the time point when it can respond to an external input event for the first time, within 100 ms is considered excellent. This indicator is based on the user's point of view. The time point when the FID is reached means that the user can operate the webpage.

The third indicator: Cumulative Layout Shift (CLS), a typographic jump indicator, 0.1 is excellent. During the web page loading process, if there are arranged elements and large areas of movement are found, this indicator will be very high. For example, the width and height of the img tag in the web page are not set. After the image is loaded, the version is sorted according to the actual size of the image. This will trigger a re-typesetting of the web page. From the user's point of view, the web page is pushed down by a picture height as a whole. Google thinks this experience is not good.

The three indicators, LCP / FID / CLS, are essentially the performance measurement indicators for web pages from the user's perspective. Developers can see what level of their work these three indicators belong to.

5. The importance of tools in ecological construction

(Data from statcounter.com)

With its excellent product features, security, speed, and stability, Chrome has won the favor of a large number of users. From the StatCounter statistics in the above figure, it can be seen that Chrome has become an absolute elder brother in the browser industry, and of course it has achieved commercial success. However, in the establishment of open source and ecology of Chrome, DevTools can be described as the first achievement. Google has attracted a large number of front-end developers through DevTools' features beyond competing products, turning to Chrome to develop their own products. The early ecological products were Chrome plug-ins, and the number of plug-ins in the Chrome Store can show its success.

When Node.js came out, DevTools was the first debugging tool to support Node.js, which promoted the popularity of Node.js. Then DevTools relied on Node.js to quickly get out of the circle. On the other hand, the open source world has also begun to feed back the DevTools project. At present, there are more than 10 open source solutions that support the CDP protocol, and the commonly used languages are basically supported. This field is still developing rapidly, and we look forward to better development in this field.

The DevTools Web UI has been separated from the Chromium warehouse and can be cloned separately for secondary development. The Web UI is limited in space this time, and there is no implementation principle analysis. In fact, Web UI is also a very good Web APP, which is very suitable for front-end developers to study in depth.

What we learn from excellent open source projects is not only code implementation and architecture, but also higher-dimensional things, such as product thinking and tool thinking, and implement them in our own projects. Looking back at the development process in the field of web debugging, how did it evolve from a JavaScript plug-in into today's front-end development ecosystem, there are many points worth learning.

Six, concluding remarks

The author’s team has long been committed to the research and learning of the Chromium kernel. Based on its derived products, it serves our ecological users and provides them with a high-quality online experience. At the same time, the web browsing service we incubated also provides powerful, fast and stable web service capabilities for applications within the ecosystem. If you are interested in the research of the underlying technology of the Web, welcome to join us and grow together with a group of like-minded friends, while also serving hundreds of millions of users.

Seven, references

[1] Google Chrome

[2] 10 Years of Web Inspector

[3] 10 years of Speed in Chrome

[4] Chrome DevTools

[5] Chrome DevTools Protocol protocol

[6] Web Vitals

Author: vivo Internet browser kernel team-Li Qingmei

vivo互联网技术
3.3k 声望10.2k 粉丝