1. 程式人生 > >Android WebView載入Chromium動態庫的過程分析

Android WebView載入Chromium動態庫的過程分析



       Chromium動態庫的體積比較大,有27M左右,其中程式段和資料段分別佔據25.65M和1.35M。如果按照通常方式載入Chromium動態庫,那麼當有N個正在執行的App使用WebView時,系統需要為Chromium動態庫分配的記憶體為(25.65 + N x 1.35)M。這是非常可觀的。為此,Android使用了特殊的方式載入Chromium動態庫。本文接下來就詳細分析這種特殊的載入方式。

《Android系統原始碼情景分析》一書正在進擊的程式設計師網(http://0xcc0xcd.com)中連載,點選進入!

       為什麼當有N個正在執行的App使用WebView時,系統需要為Chromium動態庫分配的記憶體為(25.65 + N x 1.35)M呢?這是由於動態庫的程式段是隻讀的,可以在多個程序之間進行共享,但是資料段一般是可讀可寫的,不能共享。在1.35M的資料段中,有1.28M在Chromium動態庫載入完成後就是隻讀的。這1.28M資料包含有C++虛擬函式表,以及指標型別的常量等,它們在編譯的時候會放在一個稱為GNU_RELRO的Section中,如圖1所示:


圖1 App程序間不共享GNU_RELRO Section

       如果我們將該GNU_RELRO Section看作是一般的資料段,那麼系統就需要為每一個使用了WebView的App程序都分配一段1.28M大小的記憶體空間。前面說到,這1.28M資料在Chromium動態庫載入完成後就是隻讀的,那麼有沒有辦法讓它像程式段一樣,在多個App程序之間共享呢?

       只要能滿足一個條件,那麼答案就是肯定的。這個條件就是所有的App程序都在相同的虛擬地址空間載入Chromium動態庫。在這種情況下,就可以在系統啟動的過程中,建立一個臨時程序,並且在這個程序中載入Chromium動態庫。假設Chromium動態庫的載入地址為Base Address。載入完成後,將Chromium動態庫的GNU_RELRO Section的內容Dump出來,並且寫入到一個檔案中去。

       以後App程序載入Chromium動態庫時,都將Chromium動態庫載入地址Base Address上,並且使用記憶體對映的方式將前面Dump出來的GNU_RELRO檔案代替Chromium動態庫的GNU_RELRO Section。這樣就可以實現在多個App程序之間共享Chromium動態庫的GNU_RELRO Section了,如圖2所示:


圖2 App程序間共享GNU_RELRO Section

       從前面Android應用程式程序啟動過程的原始碼分析一文可以知道,所有的App程序都是由Zygote程序fork出來的,因此,要讓所有的App程序都在相同的虛擬地址空間載入Chromium動態庫的最佳方法就是在Zygote程序的地址空間中預留一塊地址。

       還有兩個問題需要解決。第一個問題是要將載入後的Chromium動態庫的GNU_RELRO Section的內容Dump出來,並且寫入到一個檔案中去。第二個問題是要讓所有的App程序將Chromium動態載入在指定位置,並且可以使用指定的檔案來代替它的GNU_RELRO Section。這兩個問題都可以通過Android在5.0版本提供的一個動態庫載入函式android_dlopen_ext解決。

       接下來,我們就結合原始碼,分析Zygote程序是如何為App程序預留地址載入Chromium動態庫的,以及App程序如何使用新的動態庫載入函式android_dlopen_ext載入Chromium動態庫的。

       從前面Android系統程序Zygote啟動過程的原始碼分析一文可以知道,Zygote程序在Java層的入口函式為ZygoteInit類的靜態成員函式main,它的實現如下所示:

  1. publicclass ZygoteInit {  
  2.     ......  
  3.     publicstaticvoid main(String argv[]) {  
  4.         try {  
  5.             .......  
  6.             preload();  
  7.             .......  
  8.             if (startSystemServer) {  
  9.                 startSystemServer(abiList, socketName);  
  10.             }  
  11.             ......  
  12.             runSelectLoop(abiList);  
  13.             ......  
  14.         } catch (MethodAndArgsCaller caller) {  
  15.             ......  
  16.         } catch (RuntimeException ex) {  
  17.             ......  
  18.         }  
  19.     }  
  20.     ......  
  21. }  

       這個函式定義在檔案frameworks/base/core/java/com/android/internal/os/ZygoteInit.java中。

       ZygoteInit類的靜態成員函式main在啟動System程序以及使得Zygote程序進入執行狀態之前,首先會呼叫另外一個靜態成員函式preload預載入資源。這些預載入的資源以後就可以在App程序之間進行共享。

       ZygoteInit類的靜態成員函式preload在預載入資源的過程中,就會為Chromium動態庫預保留載入地址,如下所示:

  1. publicclass ZygoteInit {  
  2.     ......  
  3.     staticvoid preload() {  
  4.         ......  
  5.         // Ask the WebViewFactory to do any initialization that must run in the zygote process,
  6.         // for memory sharing purposes.
  7.         WebViewFactory.prepareWebViewInZygote();  
  8.         ......  
  9.     }  
  10.     ......  
  11. }  

       這個函式定義在檔案frameworks/base/core/java/com/android/internal/os/ZygoteInit.java中。

       ZygoteInit類的靜態成員函式preload是通過呼叫WebViewFactory類的靜態成員函式prepareWebViewInZygote為Chromium動態庫預保留載入地址的,後者的實現如下所示:

  1. publicfinalclass WebViewFactory {  
  2.     ......  
  3.     publicstaticvoid prepareWebViewInZygote() {  
  4.         try {  
  5.             System.loadLibrary("webviewchromium_loader");  
  6.             long addressSpaceToReserve =  
  7.                     SystemProperties.getLong(CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,  
  8.                     CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);  
  9.             sAddressSpaceReserved = nativeReserveAddressSpace(addressSpaceToReserve);  
  10.             ......  
  11.         } catch (Throwable t) {  
  12.             ......  
  13.         }  
  14.     }  
  15.     ......  
  16. }  

       這個函式定義在檔案frameworks/base/core/java/android/webkit/WebViewFactory.java中。

       WebViewFactory類的靜態成員函式prepareWebViewInZygote首先會載入一個名稱為“webviewchromium_loader”的動態庫,接下來又會獲得需要為Chromium動態庫預留的地址空間大小addressSpaceToReserve。知道了要預留的地址空間的大小之後,WebViewFactory類的靜態成員函式prepareWebViewInZygote就會呼叫另外一個靜態成員函式nativeReserveAddressSpace為Chromium動態庫預留地址空間。

       WebViewFactory類的靜態成員函式nativeReserveAddressSpace是一個JNI方法,它在C++層對應的函式為ReserveAddressSpace。這個函式實現在上述名稱為“webviewchromium_loader”的動態庫中,如下所示:

  1. jboolean ReserveAddressSpace(JNIEnv*, jclass, jlong size) {  
  2.   return DoReserveAddressSpace(size);  
  3. }  

       這個函式定義在檔案frameworks/webview/chromium/loader/loader.cpp中。

       函式ReserveAddressSpace呼叫另外一個函式DoReserveAddressSpace預留大小為size的地址空間,如下所示:

  1. void* gReservedAddress = NULL;  
  2. size_t gReservedSize = 0;  
  3. jboolean DoReserveAddressSpace(jlong size) {  
  4.   size_t vsize = static_cast<size_t>(size);  
  5.   void* addr = mmap(NULL, vsize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);  
  6.   ......  
  7.   gReservedAddress = addr;  
  8.   gReservedSize = vsize;  
  9.   ......  
  10.   return JNI_TRUE;  
  11. }  

       這個函式定義在檔案frameworks/webview/chromium/loader/loader.cpp中。

       函式DoReserveAddressSpace是通過系統介面mmap預留指定大小的地址空間的。同時,預留出來的地址空間的起始地址和大小分別記錄在全域性變數gReservedAddress和gReservedSize中。以後Chromium動態庫就可以載入在該地址空間中。

       為Chromium動態庫預留好載入地址之後,Android系統接下來要做的一件事情就是請求Zygote程序啟動一個臨時程序。這個臨時程序將會在上述預留的地址空間中載入Chromium動態庫。這個Chromium動態庫在載入的過程中,它的GNU_RELRO Section會被重定位。重定位完成之後,就可以將它的內容Dump到一個檔案中去。這個檔案以後就會以記憶體對映的方式代替在App程序中載入的Chromium動態庫的GNU_RELRO Section。

       請求Zygote程序啟動臨時程序的操作是由System程序完成的。從前面Android系統程序Zygote啟動過程的原始碼分析一文可以知道,System程序是由Zygote程序啟動的,它在Java層的入口函式為SystemServer的靜態成員函式main,它的實現如下所示:

  1. publicfinalclass SystemServer {  
  2.     ......  
  3.     publicstaticvoid main(String[] args) {  
  4.         new SystemServer().run();  
  5.     }  
  6.     ......  
  7. }  

      這個函式定義在檔案frameworks/base/services/java/com/android/server/SystemServer.java中。

      SystemServer的靜態成員函式main首先是建立一個SystemServer物件,然後呼叫這個SystemServer物件的成員函式run在System程序中啟動各種系統服務,如下所示:

  1. publicfinalclass SystemServer {  
  2.     ......  
  3.     privatevoid run() {  
  4.         ......  
  5.         // Start services.
  6.         try {  
  7.             startBootstrapServices();  
  8. 相關推薦

    Android WebView載入Chromium動態過程分析

            Chromium動態庫的體積比較大,有27M左右,其中程式段和資料段分別佔據25.65M和1.35M。如果按照通常方式載入Chromium動態庫,那麼當有N個正在執行的App使用WebView時,系統需要為Chromium動態庫分配的記憶體為

    Android WebView啟動Chromium渲染引擎的過程分析

           Android WebView載入了Chromium動態庫之後,就可以啟動Chromium渲染引擎了。Chromium渲染引擎由Browser、Render和GPU三端組成。其中,Browser端負責將網頁UI合成在螢幕上,Render端負責載入網頁的URL和渲

    Android執行時ART載入OAT檔案的過程分析

                            在前面一文中,我們介紹了Android執行時ART,它的核心是OAT檔案。OAT檔案是一種Android私有ELF檔案格式,它不僅包含有從DEX檔案翻譯而來的本地機器指令,還包含有原來的DEX檔案內容。這使得我們無需重新編譯原有的APK就可以讓它正常地在ART裡

    關於Linux靜態動態分析

    所在 mis color 先後 main 技術 哪些 共享 協議 關於Linux靜態庫和動態庫的分析 關於Linux靜態庫和動態庫的分析 1.什麽是庫 在windows平臺和linux平臺下都大量存在著庫。 本質上來說庫是一種可運行代碼的二進制形式。能夠被操作系

    配置環境的時候,PHP無法載入MySQL動態,麻煩大家幫忙看看!nocsl

    不出 沒有 都沒有 小狗狗 ocs 想象 無法 配置環境 配置 黑暗降臨 夜空再一次降臨在人們的視線中 繁星點點 是那麽的美麗 當一顆流星夜空又添了一道美麗的景色 不過它消失的是那麽快 它匆匆的來又匆匆地走 沒留下一絲痕跡 但它確實來過 我常常在想 人生不就如此嗎?雖然現在

    android ndk 減小jni動態的大小

    http://blog.csdn.net/hhh901119/article/details/71175609 用readelf -SW libxxx.so可以看到動態庫裡的資訊; 發現有需要.debug資訊段。 用命令arm-linux-androideabi-strip --s

    Android WebView載入HTML表單並通過javascript提交

    分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

    轉老羅 Android應用程式資源的查詢過程分析

    原文地址  http://blog.csdn.net/luoshengyang/article/details/8806798   轉載請說明     我們知道,在Android系統中,每一個應用程式一般都會配置很多資源,用來適配不同密

    Android Activity應用視窗的建立過程分析

    前言 所謂的視窗(Window)就是一個顯示在手機螢幕上視覺化檢視的一片區域。在Android中視窗是一個抽象的概念,每一個Activity就對應著一個視窗,而所有的視窗都是由檢視(View)來呈現,而我們知道View構成的一個樹形結構的檢視就組成了一個Activity的介面了。在Android

    Android webView載入html程式碼 不執行js方法的情況

    頁面中有一個webView顯示後臺返回的富文字資料,富文字資料是一串html程式碼,但是並沒有<html><body>這些標籤,webView不做任何處理,使用 webView.loadData(html, "text/html; charset=U

    Android webview載入頁面

    private WebView webView; public void init() { webView = (WebView) findViewById(R.id.webview); //支援js webV

    android WebView載入URL不顯示圖片

    WebSettings settings = mWebView.getSettings(); settings.setJavaScriptEnabled(true);//

    Android webview 載入https:// 網站時不展示 圖片資源

    可能原因是:該圖片資源不是https的; 解決辦法: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { webSettings.setMixedContentMode(WebSetti

    android WebView載入html 處理的圖片過寬的工具類 (過寬的控制到100%,正常尺寸的不放大)

    參考 部落格: 小曾同志的專欄: https://blog.csdn.net/u010023795/article/details/53509495 工具類 import org.jsoup.Jsoup; import org.jsoup.nodes.Document; impor

    基於NDK編譯Android平臺的FFmpeg動態

    需求 FFmpeg在Linux平臺(如Ubuntu)上的支援已經比較完善了,如前述文章介紹 http://blog.csdn.net/ericbar/article/details/73702061,我們很容易就可以基於FFmpeg+SDL實現一個播放器,比

    Android: WebView載入網頁的幾種方式及網路異常處理

    1.載入本地assert目錄下檔案(error.html) webcontent.loadUrl(" file:///android_asset/error.html "); 2.載入網路url(http://www.csdn.com) webcontent.loadUrl(" http://www.csd

    android:webview載入網頁速度很慢的的究極解決方案

     Android客戶端中混搭HTML頁面,會出現雖然HTML內容載入完成,標題也正常顯示,但是整個網頁需要等到近5秒(甚至更多)時間才會顯示出來。研究了很久,搜遍了國外很多網站,也看過PhoneGap的程式碼,一直無解。        一般人堆WebView的加速,都是建

    Android WebView載入空白

    原創不易,轉載請註明轉載,並附上原文地址http://blog.csdn.net/z736232402/article/details/51646577 今天看自己寫的WebView的時候,發現,部分

    Android webview載入html程式碼 上下左右有白邊問題

    直接開始後臺返回一串html程式碼字串 然候客戶端用webview做展示  別的都正常  只是四周會有白邊 網上找的各種方法都不好使 如下圖後來給webview添加了兩個setting表框變窄了 但是還

    Android WebView載入url網路視訊

    前言 webview 的 功能日益強大,不僅可以用來載入圖片,網站連結, 今天聊一聊 webview 載入視訊的那些混淆點。 載入 視訊 一般會設定 硬體加速。其實 兩者一毛錢 關係都沒有 ,webview 不設定 硬體加速,依然能夠加載出來 ,不受其影