zoukankan      html  css  js  c++  java
  • Xposed学习三:基石

        在上一篇我们留下问题:handleLoadPackage如何生效即在何时被执行。

     先看XposedBridge.class的main(该函数是在appruntime.start函数中替换原先zygoteinit,故结尾处会调用zygoteinit):

     1 private static void main(String[] args) {
     2         String startClassName = getStartClassName();
     3             ......
     4             if(initNative()) {
     5                 if(startClassName == null) {
     6                     initXbridgeZygote();
     7                 }
     8                 // 读取/data/data/de.robv.android.xposed.installer/conf/modules.list内容,存储着模块apk的地址,
     9                 // 内容:/data/app/com.jason.learnxposed-2.apk
    10                 // 加载模块loadModule(APK,startClassName)
    11                 loadModules(startClassName);
    12             } 
    13             ......
    14         if(startClassName == null) {
    15             ZygoteInit.main(args);
    16         } else {
    17             RuntimeInit.main(args);
    18         }
    20     }

      main中分三步:initXbridgeZygote、initloadModules、ZygoteInit.main。

     先来看initXbridgeZygote:

     private static void initXbridgeZygote() throws Throwable {
            final HashSet loadedPackagesInProcess = new HashSet(1);
            XposedHelpers.findAndHookMethod(ActivityThread.class, "handleBindApplication", new Object[]{"android.app.ActivityThread.AppBindData", new XC_MethodHook() {
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                 }});
            XposedHelpers.findAndHookMethod("com.android.server.ServerThread", (ClassLoader)null, VERSION.SDK_INT < 19?"run":"initAndLoop", new Object[]{new XC_MethodHook() {
                 protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
            }});
            hookAllConstructors(LoadedApk.class, new XC_MethodHook() {
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
            });    
            XposedHelpers.findAndHookMethod("android.app.ApplicationPackageManager", (ClassLoader)null, "getResourcesForApplication", new Object[]{ApplicationInfo.class, new XC_MethodHook() {
                 protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
            }});
            if(!(new File("/data/data/de.robv.android.xposed.installer/conf/disable_resources")).exists()) {
                hookResources();
            } else {
                disableResources = true;
            }
        }

      上面粉红色的诱惑很熟悉对吧,就是前面上篇分析的findAndHookMethod函数。来看下它hooked了什么函数,"handleBindApplication","initAndLoop"

    "getResourcesForApplication",不要小看这几个hooked哦,这是xposed的基石。我们先不去看起before回调函数做了什么,等分析完loadModules后再回来有彩蛋。看红色警戒的hookAllConstructors,之前没见过这小子,看看他是干什么吃的。
      public static Set<Unhook> hookAllConstructors(Class<?> hookClass, XC_MethodHook callback) {
            ......
            for(int var4 = 0; var4 < var5; ++var4) {
                Constructor constructor = var6[var4];
                unhooks.add(hookMethod(constructor, callback));
            }
            ......
        }
     原来他也是要调用hookMethod,与findAndHookMethod区别是少了findMethodExact这步。前面分析过findMethodExact是把参数+返回值+函数名组成method,这样相同的函数如果带不同的参数也可以hook(xposed会根据method来判别是否已hooked),而hookAllConstructors直接来是什么用意呢?因为在hookAllConstructors中会hook所有的构造函数故没有必要去findMethodExact。ok,上面就是几个hooked,看下面if里是hookResources道理不言而喻咯,我们先不分析这个,有空再来^_^。
     

      再来看loadModules

     private static void loadModule(String apk, String startClassName) {
          ......
                PathClassLoader mcl = new PathClassLoader(apk, BOOTCLASSLOADER);
                InputStream is = mcl.getResourceAsStream("assets/xposed_init");
                // 读取apk的assets/xposed_init内容,Xposed学习一中的第五步
                if(is == null) {
                    log("assets/xposed_init not found in the APK");
                } else {
                    BufferedReader moduleClassesReader = new BufferedReader(new InputStreamReader(is));
                        ......
                        if(startClassName == null) {
                            if(moduleInstance instanceof IXposedHookZygoteInit) {
                                StartupParam param = new StartupParam();
                                param.modulePath = apk;
                                ((IXposedHookZygoteInit)moduleInstance).initZygote(param);
                            }
    
                            if(moduleInstance instanceof IXposedHookLoadPackage) {
                                hookLoadPackage(new Wrapper((IXposedHookLoadPackage)moduleInstance));
                            }
    
                            if(moduleInstance instanceof IXposedHookInitPackageResources) {
                           hookInitPackageResources(new de.robv.android.xposed.IXposedHookInitPackageResources.Wrapper((IXposedHookInitPackageResources)moduleInstance));
                            }
                        } else if(moduleInstance instanceof IXposedHookCmdInit) {
                            de.robv.android.xposed.IXposedHookCmdInit.StartupParam param1 = new de.robv.android.xposed.IXposedHookCmdInit.StartupParam();
                            param1.modulePath = apk;
                            param1.startClassName = startClassName;
                            ((IXposedHookCmdInit)moduleInstance).initCmdApp(param1);
                        }
                         ......
                }
            }
        }

      简单说下loadModule中步骤,

      1. 读取Xposed_init文本里的内容,里面是我们的类名。我们可以在一个模块中写好几个功能的类,但请注意一定要将类全名字符串写到Xposed_init里且每个类字符串为一行。到此,我们就得到类名可以加载类啦;

      2. 根据startClassName是否为空又可分为执行普通的xposed模块和IXposedHookCmdInit。startClassName值我们后面再深究,先继续往下看;

      3. 根据功能类实现的接口又可执行多步操作(当然功能类能实现多个接口)

       3.1 IXposedHookZygoteInit:

           话不多说,直接执行类的initZygote(IXposedHookCmdInit类同)。这个最干脆,不像下面2个还慢慢来^—^

       3.2 IXposedHookLoadPackage:——>redClock示例中使用这个接口  貌似在XC_loadPackage的call中被执行,待分析

          代码就不贴了,反正在java层就是各种封装和存储。一句话总结:把类添加到

                XposedBridge.CopyOnWriteSortedSet<XC_LoadPackage>  sLoadedPackageCallbacks

       3.3 IXposedHookInitPackageResources:

          把类添加到XposedBridge.CopyOnWriteSortedSet<XC_InitPackageResources> sInitPackageResourcesCallbacks

        ok,loadMoudle就算结束了。但我们得到2个list,肯定要执行的嘛。记得之前的蛋蛋吗,重新回到initXbridgeZygote分析其before回调:

      代码我就不贴了,老是贴代码搞得我很水一样(* ̄rǒ ̄)。先看sLoadedPackageCallbacks,其出现在"handleBindApplication","initAndLoop","loadedAPK"的before回调函数里。那这三个是干什么的呢

      handleBindApplication函数:mInstrumentation.callApplicationOnCreate(app);  

      initAndLoop函数:在serverThread的initAndLoop启动系统服务(在system_server的main函数中)

      loadedAPK类:

      不用多说,很明显其都和package有关。但是最终要的是在各自的before函数都包含代码:XC_LoadPackage.callAll(lpparam);lpparam包含sLoadedPackageCallbacks,上面的代码回去执行sLoadedPackageCallbacks中所有callbakc也就是我们在hookLoadPackage函数中添加的callback。即在此刻会调用所有实现IXposedHookLoadPackage接口的类中的handleLoadPackage()。有点绕哦,举例子就是redClock中的handleLoadPackage会在此刻被调用,如果package=com.android.systemui则会执行findAndHookMethod函数去hooked "updateClock"函数。现在理清了吧

      同理来看sInitPackageResourcesCallbacks,还记得上面initXbridgeZygote中的hookResources不。在hookResources会hooked"getTopLevelResources",而其after回调函数会执行XCallback.callAll(resparam1);当然  resparam1 = new InitPackageResourcesParam(XposedBridge.sInitPackageResourcesCallbacks);

      第一步initXbridgeZygote和loadMoudle到此为此了啦。

      来看init之前我们还是先看下startClassName这个字符串,它涉及到刚刚分析的loadModule和下面的init。

    Android是基于Linux内核构建的,它最早存在的肯定是Native世界,那么Java世界是什么时候创建的呢?      ---by 深入理解android

     答案就是Zygote,而Zygote是通过init读取init.rc文本中配置来创建。在init.rc(在android5.0中移到/system/core/rootdir/init_zygotexx.rc)中,关于Zygote的配置

      service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server

      执行/system/bin/app_process ,参数arg是-Xzygote  /system/bin  --zygote  --start-system-server。在Xposed的app_main的main函数中会判断器参数是否为先前定义的字符串(自行看代码),若不是会赋值为className,而这就是我们上面的startClassName(这里如果表述有错误,往指出)。看完startClassName,我们看这里是是干什么的,执行ZygoteInit.main正式进入java世界。其实对比android原本的app_main执行流程,我们发现在XposedBridge.main中除了这个ZygoteInit.main代码(xposed结合Zygote分析)其他都是xposed自己添加的,而这也正是xposed基石,基石,基石。

      疑问:类实现多个接口,但像上转接口时,每个接口时如何协调的。比如class 实现inface1 inface2,(inface1 )class和(inface2)class如何操作??? 

     

  • 相关阅读:
    (树链剖分+线段树)POJ
    (树上莫队)HDU
    (LCA+树上主席树)FZU 2237
    (预处理+莫队算法)HDU
    (莫队算法)两题莫队算法统计数量的入门题
    (莫队算法)CodeForces
    sublime配置C++14
    (dfs序+莫队算法/启发式合并/树分治)Codeforces 375D
    (线段树两个lazy标记需要设定优先级)UVA 11992
    (线段树区间合并)UVA 11235
  • 原文地址:https://www.cnblogs.com/vendanner/p/4789906.html
Copyright © 2011-2022 走看看