Android5.1.1源码 - 让某个APP以解释执行模式运行
[實(shí)踐] Android5.1.1源碼 - 讓某個(gè)APP以解釋執(zhí)行模式運(yùn)行
@(Android研究)[Android5.1.1|APP解釋執(zhí)行]
前言
本文的實(shí)踐修改了Android5.1.1的源碼。
本文只簡單的講了一下原理。在“實(shí)踐”一節(jié)講了具體做法。
本文的內(nèi)容涉及Art模式下dex加載的知識(shí),想要詳細(xì)了解這部分知識(shí)可以去看老羅的文章:?Android運(yùn)行時(shí)ART簡要介紹和學(xué)習(xí)計(jì)劃?Android運(yùn)行時(shí)ART加載OAT文件的過程分析?Android運(yùn)行時(shí)ART加載類和方法的過程分析Android運(yùn)行時(shí)ART執(zhí)行類方法的過程分析
本文的內(nèi)容涉及zygote,如果不知道zygote是什么,或者好奇zygote如何啟動(dòng),可以去看老羅的文章:?Android系統(tǒng)進(jìn)程Zygote啟動(dòng)過程的源代碼分析
老羅的文章分析的是Android2.3的源碼,所以下面提到的與zygote有關(guān)的函數(shù)在老羅的文章里面可能沒有,如果想要對(duì)下面提到的與zygote有關(guān)的函數(shù)有一個(gè)簡單的了解可以看我的文章:Android5.1.1源碼 - zygote fork出的子進(jìn)程如何權(quán)限降級(jí)
原理簡介
怎么才能讓方法解釋執(zhí)行
在函數(shù)ClassLinker::LinkCode中會(huì)鏈接dex中的方法代碼,這個(gè)函數(shù)的定義在文件"art/runtime/class_linker.cc"中,下面是它的源碼(這里只列出了與本文有關(guān)的部分):
void ClassLinker::LinkCode(Handle<mirror::ArtMethod> method, const OatFile::OatClass* oat_class,const DexFile& dex_file, uint32_t dex_method_index,uint32_t method_index) {......bool enter_interpreter = NeedsInterpreter(...);......if (method->IsStatic() && !method->IsConstructor()) {......} else if (enter_interpreter) {if (!method->IsNative()) {// Set entry point from compiled code if there's no code or in interpreter only mode.method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());......} else {......}} else {......}......}在這個(gè)函數(shù)中調(diào)用了NeedsInterpreter函數(shù)判斷當(dāng)前方法是否要解釋執(zhí)行,如果返回值為true,即局部變量enter_interpreter被賦值為true,那么調(diào)用ArtMethod類中的SetEntryPointFromQuickCompiledCode函數(shù)并將GetQuickToInterpreterBridge()的返回值傳入,GetQuickToInterpreterBridge()函數(shù)返回用于解釋執(zhí)行的函數(shù)的入口地址,這個(gè)入口函數(shù)解釋執(zhí)行dex中的方法。
那么現(xiàn)在來看看NeedsInterpreter函數(shù),這個(gè)函數(shù)的定義在文件"art/runtime/class_linker.cc"中,下面是它的源碼:
// Returns true if the method must run with interpreter, false otherwise. static bool NeedsInterpreter(......// If interpreter mode is enabled, every method (except native and proxy) must// be run with interpreter.return Runtime::Current()->GetInstrumentation()->InterpretOnly() &&!method->IsNative() && !method->IsProxyMethod(); }當(dāng)"Runtime::Current()->GetInstrumentation()->InterpretOnly()"返回true且不是本地方法和代理方法,那么這個(gè)函數(shù)就會(huì)返回true,否則返回false。
InterpretOnly函數(shù)是Instrumentation類的成員函數(shù),它的函數(shù)定義在文件"art/runtime/instrumentation.h"中,下面是它的源碼:
// Called by ArtMethod::Invoke to determine dispatch mechanism. bool InterpretOnly() const {return interpret_only_; }interpret_only_是類Instrumentation的成員變量,是布爾類型。可以發(fā)現(xiàn)InterpretOnly函數(shù)僅僅是將"interpret_only_"返回,如果將interpret_only_設(shè)置為true,那么根據(jù)上文分析,所有“非本地且非代理”方法都將被解釋執(zhí)行。
那么如何將interpret_only_設(shè)置為true哪,在Instrumentation類中有一個(gè)ForceInterpretOnly函數(shù),下面是這個(gè)函數(shù)的源碼:
void ForceInterpretOnly() {interpret_only_ = true;forced_interpret_only_ = true; }這個(gè)函數(shù)是Instrumentation類的公有成員函數(shù),所以直接調(diào)用這個(gè)函數(shù)即可將interpret_only_設(shè)置為true。
這里有一個(gè)問題,將interpret_only_設(shè)置為true,那么“非本地且非代理”方法在鏈接代碼時(shí)都將被設(shè)置成解釋執(zhí)行,那么會(huì)不會(huì)影響到其他的APP進(jìn)程?不會(huì),因?yàn)镃lassLinker::LinkCode函數(shù)對(duì)方法的鏈接是在APP進(jìn)程的內(nèi)存中進(jìn)行的,所以這個(gè)操作并不會(huì)影響到其他進(jìn)程。
這里進(jìn)行一個(gè)小節(jié),當(dāng)執(zhí)行"Runtime::Current()->GetInstrumentation()->ForceInterpretOnly()"語句時(shí),會(huì)把Instrumentation對(duì)象的interpret_only_成員變量設(shè)置為true。那么當(dāng)方法是“非本地且非代理”方法時(shí),NeedsInterpreter函數(shù)將返回true,那么在ClassLinker::LinkCode函數(shù)中會(huì)將這個(gè)方法設(shè)置為解釋執(zhí)行。
如果要將APP中所有方法都設(shè)置為解釋執(zhí)行,那么就需要在鏈接APP的dex中的方法代碼之前執(zhí)行"Runtime::Current()->GetInstrumentation()->ForceInterpretOnly()"語句。
調(diào)用ForceInterpretOnly函數(shù)的時(shí)機(jī)
我的辦法是在EnableDebugFeatures函數(shù)中調(diào)用ForceInterpretOnly函數(shù),在這一節(jié)中會(huì)先說明Android如何執(zhí)行到EnableDebugFeatures函數(shù),然后會(huì)說明在EnableDebugFeatures函數(shù)中調(diào)用ForceInterpretOnly函數(shù)的好處。
所有的Android應(yīng)用進(jìn)程都是zygote fork出來的,fork APP進(jìn)程時(shí)的函數(shù)調(diào)用路徑:
|- forkAndSpecialize - java方法|- com_android_internal_os_Zygote_nativeForkAndSpecialize - native函數(shù)|- ForkAndSpecializeCommon - native函數(shù)調(diào)用完ForkAndSpecializeCommon函數(shù)后APP進(jìn)程就被fork出來了。
ForkAndSpecializeCommon函數(shù)定義在文件"frameworks/base/core/jni/com_android_internal_os_Zygote.cpp"中,下面它的源碼:
static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids, jint debug_flags, jobjectArray javaRlimits, jlong permittedCapabilities, jlong effectiveCapabilities, jint mount_external, jstring java_se_info, jstring java_se_name, bool is_system_server, jintArray fdsToClose, jstring instructionSet, jstring dataDir) {......pid_t pid = fork();if (pid == 0) {......env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,is_system_server ? NULL : instructionSet);......} else if (pid > 0) {// the parent process}return pid; }gCallPostForkChildHooks是一個(gè)全局變量,它在com_android_internal_os_Zygote.cpp文件的register_com_android_internal_os_Zygote函數(shù)中被初始化。
env->CallStaticVoidMethod(...)語句調(diào)用了Java方法"Zygote.callPostForkChildHooks"。
下面是Zygote.callPostForkChildHooks方法的源碼,這個(gè)方法在文件"frameworks/base/core/java/com/android/internal/os/Zygote.java"中:
private static void callPostForkChildHooks(int debugFlags, String instructionSet) {long startTime = SystemClock.elapsedRealtime();VM_HOOKS.postForkChild(debugFlags, instructionSet);checkTime(startTime, "Zygote.callPostForkChildHooks"); }VM_HOOKS是Zygote類的成員變量,下面是它的定義:
private static final ZygoteHooks VM_HOOKS = new ZygoteHooks();VM_HOOKS.postForkChild調(diào)用的就是ZygoteHooks類中的成員方法postForkChild,這個(gè)方法在文件"libcore/dalvik/src/main/java/dalvik/system/ZygoteHooks.java"中,下面是它的源碼:
/** * Called by the zygote in the child process after every fork. The debug * flags from {@code debugFlags} are applied to the child process. The string * {@code instructionSet} determines whether to use a native bridge. */ public void postForkChild(int debugFlags, String instructionSet) {nativePostForkChild(token, debugFlags, instructionSet); }這個(gè)方法中調(diào)用了native函數(shù)nativePostForkChild,nativePostForkChild函數(shù)的C層代碼在文件"/home/sowuy/android/system/art/runtime/native/dalvik_system_ZygoteHooks.cc"中,下面是它的源碼:
static void ZygoteHooks_nativePostForkChild(JNIEnv* env, jclass, jlong token, jint debug_flags,jstring instruction_set) {......EnableDebugFeatures(debug_flags);...... }我將在EnableDebugFeatures函數(shù)中調(diào)用ForceInterpretOnly函數(shù),原因有三點(diǎn):
實(shí)踐
修改Zygote.java中的代碼
Zygote.java文件的位置是:frameworks/base/core/java/com/android/internal/os/Zygote.java,在Zygote類中添加一個(gè)成員變量:
public static final int DEBUG_ENABLE_INTERPRET = 1 << 31;在Zygote類forkAndSpecialize方法的開始部分添加下面的代碼:
if (<APP包名>.equals(niceName)) {debugFlags |= DEBUG_ENABLE_INTERPRET; }修改dalvik_system_ZygoteHooks.cc中的代碼
dalvik_system_ZygoteHooks.cc文件的位置是:art/runtime/native/dalvik_system_ZygoteHooks.cc,修改這個(gè)文件中的EnableDebugFeatures函數(shù)的代碼。
向這個(gè)函數(shù)中添加下面的代碼:
DEBUG_ENABLE_INTERPRET = 1 << 31, if ((debug_flags & DEBUG_ENABLE_INTERPRET) != 0) {Runtime::Current()->GetInstrumentation()->ForceInterpretOnly();debug_flags &= ~DEBUG_ENABLE_INTERPRET; }下面是對(duì)這個(gè)函數(shù)修改后的完整代碼:
static void EnableDebugFeatures(uint32_t debug_flags) {// Must match values in dalvik.system.Zygote.enum {DEBUG_ENABLE_DEBUGGER = 1,DEBUG_ENABLE_CHECKJNI = 1 << 1,DEBUG_ENABLE_ASSERT = 1 << 2,DEBUG_ENABLE_SAFEMODE = 1 << 3,DEBUG_ENABLE_JNI_LOGGING = 1 << 4,DEBUG_ENABLE_INTERPRET = 1 << 31,};if ((debug_flags & DEBUG_ENABLE_CHECKJNI) != 0) {Runtime* runtime = Runtime::Current();JavaVMExt* vm = runtime->GetJavaVM();if (!vm->check_jni) {LOG(INFO) << "Late-enabling -Xcheck:jni";vm->SetCheckJniEnabled(true);// There's only one thread running at this point, so only one JNIEnv to fix up.Thread::Current()->GetJniEnv()->SetCheckJniEnabled(true);} else {LOG(INFO) << "Not late-enabling -Xcheck:jni (already on)";}debug_flags &= ~DEBUG_ENABLE_CHECKJNI;}if ((debug_flags & DEBUG_ENABLE_JNI_LOGGING) != 0) {gLogVerbosity.third_party_jni = true;debug_flags &= ~DEBUG_ENABLE_JNI_LOGGING;}Dbg::SetJdwpAllowed((debug_flags & DEBUG_ENABLE_DEBUGGER) != 0);if ((debug_flags & DEBUG_ENABLE_DEBUGGER) != 0) {EnableDebugger();}debug_flags &= ~DEBUG_ENABLE_DEBUGGER;if ((debug_flags & DEBUG_ENABLE_SAFEMODE) != 0) {// Ensure that any (secondary) oat files will be interpreted.Runtime* runtime = Runtime::Current();runtime->AddCompilerOption("--compiler-filter=interpret-only");debug_flags &= ~DEBUG_ENABLE_SAFEMODE;}// This is for backwards compatibility with Dalvik.debug_flags &= ~DEBUG_ENABLE_ASSERT;if ((debug_flags & DEBUG_ENABLE_INTERPRET) != 0) {Runtime::Current()->GetInstrumentation()->ForceInterpretOnly();debug_flags &= ~DEBUG_ENABLE_INTERPRET;}if (debug_flags != 0) {LOG(ERROR) << StringPrintf("Unknown bits set in debug_flags: %#x", debug_flags);} } 原文地址:?https://my.oschina.net/ibuwai/blog/528023 與50位技術(shù)專家面對(duì)面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的Android5.1.1源码 - 让某个APP以解释执行模式运行的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android安全开发之Provider
- 下一篇: Binder子系统之调试分析(一)