天天看點

[實踐] Android5.1.1源碼 - 讓某個APP以解釋執行模式運作

本文的實踐修改了android5.1.1的源碼。

本文隻簡單的講了一下原理。在“實踐”一節講了具體做法。

本文的内容涉及art模式下dex加載的知識,想要詳細了解這部分知識可以去看老羅的文章: 

<a href="http://blog.csdn.net/luoshengyang/article/details/40289405" target="_blank">android運作時art執行類方法的過程分析</a>

本文的内容涉及zygote,如果不知道zygote是什麼,或者好奇zygote如何啟動,可以去看老羅的文章: 

<a href="http://blog.csdn.net/luoshengyang/article/details/6768304" target="_blank">android系統程序zygote啟動過程的源代碼分析</a>

在函數classlinker::linkcode中會連結dex中的方法代碼,這個函數的定義在檔案”art/runtime/class_linker.cc”中,下面是它的源碼(這裡隻列出了與本文有關的部分):

[實踐] Android5.1.1源碼 - 讓某個APP以解釋執行模式運作

在這個函數中調用了needsinterpreter函數判斷目前方法是否要解釋執行,如果傳回值為true,即局部變量enter_interpreter被指派為true,那麼調用artmethod類中的setentrypointfromquickcompiledcode函數并将getquicktointerpreterbridge()的傳回值傳入,getquicktointerpreterbridge()函數傳回用于解釋執行的函數的入口位址,這個入口函數解釋執行dex中的方法。

那麼現在來看看needsinterpreter函數,這個函數的定義在檔案”art/runtime/class_linker.cc”中,下面是它的源碼:

[實踐] Android5.1.1源碼 - 讓某個APP以解釋執行模式運作

當”runtime::current()-&gt;getinstrumentation()-&gt;interpretonly()”傳回true且不是本地方法和代理方法,那麼這個函數就會傳回true,否則傳回false。

interpretonly函數是instrumentation類的成員函數,它的函數定義在檔案”art/runtime/instrumentation.h”中,下面是它的源碼:

[實踐] Android5.1.1源碼 - 讓某個APP以解釋執行模式運作

interpret_only_是類instrumentation的成員變量,是布爾類型。可以發現interpretonly函數僅僅是将”interpret_only_”傳回,如果将interpret_only_設定為true,那麼根據上文分析,所有“非本地且非代理”方法都将被解釋執行。

那麼如何将interpret_only_設定為true哪,在instrumentation類中有一個forceinterpretonly函數,下面是這個函數的源碼:

[實踐] Android5.1.1源碼 - 讓某個APP以解釋執行模式運作

這個函數是instrumentation類的公有成員函數,是以直接調用這個函數即可将interpret_only_設定為true。

這裡有一個問題,将interpret_only_設定為true,那麼“非本地且非代理”方法在連結代碼時都将被設定成解釋執行,那麼會不會影響到其他的app程序?不會,因為classlinker::linkcode函數對方法的連結是在app程序的記憶體中進行的,是以這個操作并不會影響到其他程序。

這裡進行一個小節,當執行”runtime::current()-&gt;getinstrumentation()-&gt;forceinterpretonly()”語句時,會把instrumentation對象的interpret_only_成員變量設定為true。那麼當方法是“非本地且非代理”方法時,needsinterpreter函數将傳回true,那麼在classlinker::linkcode函數中會将這個方法設定為解釋執行。 如果要将app中所有方法都設定為解釋執行,那麼就需要在連結app的dex中的方法代碼之前執行”runtime::current()-&gt;getinstrumentation()-&gt;forceinterpretonly()”語句。

我的辦法是在enabledebugfeatures函數中調用forceinterpretonly函數,在這一節中會先說明android如何執行到enabledebugfeatures函數,然後會說明在enabledebugfeatures函數中調用forceinterpretonly函數的好處。

所有的android應用程序都是zygote fork出來的,fork app程序時的函數調用路徑:

[實踐] Android5.1.1源碼 - 讓某個APP以解釋執行模式運作

調用完forkandspecializecommon函數後app程序就被fork出來了。

forkandspecializecommon函數定義在檔案”frameworks/base/core/jni/com_android_internal_os_zygote.cpp”中,下面它的源碼:

[實踐] Android5.1.1源碼 - 讓某個APP以解釋執行模式運作

gcallpostforkchildhooks是一個全局變量,它在com_android_internal_os_zygote.cpp檔案的register_com_android_internal_os_zygote函數中被初始化。

env-&gt;callstaticvoidmethod(…)語句調用了java方法”zygote.callpostforkchildhooks”。

下面是zygote.callpostforkchildhooks方法的源碼,這個方法在檔案”frameworks/base/core/java/com/android/internal/os/zygote.java”中:

[實踐] Android5.1.1源碼 - 讓某個APP以解釋執行模式運作

vm_hooks是zygote類的成員變量,下面是它的定義:

[實踐] Android5.1.1源碼 - 讓某個APP以解釋執行模式運作

vm_hooks.postforkchild調用的就是zygotehooks類中的成員方法postforkchild,這個方法在檔案”libcore/dalvik/src/main/java/dalvik/system/zygotehooks.java”中,下面是它的源碼:

[實踐] Android5.1.1源碼 - 讓某個APP以解釋執行模式運作

這個方法中調用了native函數nativepostforkchild,nativepostforkchild函數的c層代碼在檔案”/home/sowuy/android/system/art/runtime/native/dalvik_system_zygotehooks.cc”中,下面是它的源碼:

[實踐] Android5.1.1源碼 - 讓某個APP以解釋執行模式運作

我将在enabledebugfeatures函數中調用forceinterpretonly函數,原因有三點:

enabledebugfeatures函數參數接收的是一個标志,我可以設定一個新的标志位用來表示是否需要調用forceinterpretonly函數。

每次app啟動的時候都會執行enabledebugfeatures函數。

enabledebugfeatures函數被調用的時機好,它運作在fork出的app程序中,并且在連結app的dex中的方法前被調用。

zygote.java檔案的位置是:frameworks/base/core/java/com/android/internal/os/zygote.java,在zygote類中添加一個成員變量:

[實踐] Android5.1.1源碼 - 讓某個APP以解釋執行模式運作

在zygote類forkandspecialize方法的開始部分添加下面的代碼:

[實踐] Android5.1.1源碼 - 讓某個APP以解釋執行模式運作

dalvik_system_zygotehooks.cc檔案的位置是:art/runtime/native/dalvik_system_zygotehooks.cc,修改這個檔案中的enabledebugfeatures函數的代碼。

向這個函數中添加下面的代碼:

[實踐] Android5.1.1源碼 - 讓某個APP以解釋執行模式運作

下面是對這個函數修改後的完整代碼:

[實踐] Android5.1.1源碼 - 讓某個APP以解釋執行模式運作
[實踐] Android5.1.1源碼 - 讓某個APP以解釋執行模式運作

繼續閱讀