美文网首页
Android-Framework-Plugin插件话框架-Ho

Android-Framework-Plugin插件话框架-Ho

作者: AntCoding | 来源:发表于2019-03-11 21:48 被阅读0次

    概括

    在插件话的世界中Hook技术随处可见,而本次要讲解的内容Hook Activity的过程,主要分为两大块
    • Hook IActivityManger

    • Hook Instrumentation

    知识铺垫

    在讲解这篇文章之前我们需要Hook是什么,为什么在插件化框架中随处可见,我们首先做一下系统讲解

    Hook的概念

    Hook中文名"钩子",它使用的是一种面向切面的编程思想(业内专称 AOP编程思想),主要作用是在事件传递过程中对事件进行拦截、修改、监听,将自身的代码动态性替换进去,当这些方法被调用时,保证执行的是我们代码,已达到我们预期的效果

    Hook所需知识

    • 反射技术
    • 动态代理技术

    案例分解

    1.在PluginApplication类的attachBaseContext函数中执行初始化操作
    @Override
    protected void attachBaseContext(Context base) {
       super.attachBaseContext(base);
       //这个地方之所以这样写,是因为如果是插件进程,initloader必须在applicaiotn启动时执行
       //而如果是宿主进程,initloader可以在这里执行,也可以在需要时再在宿主的其他组件中执行,
       // 例如点击宿主的某个Activity中的button后再执行这个方法来启动插件框架。
       //总体原则有3点:
       //1、插件进程和宿主进程都必须有机会执行initloader
       //2、在插件进程和宿主进程的initloader方法都执行完毕之前,不可和插件交互
       //3、在插件进程和宿主进程的initlaoder方法都执行完毕之前启动的组件,即使在initloader都执行完毕之后,也不可和插件交互
       //如果initloader都在进程启动时就执行,自然很轻松满足上述条件。
       if (ProcessUtil.isPluginProcess(this)) {
          //插件进程,必须在这里执行initLoader
          PluginLoader.initLoader(this);
       } else {
          //宿主进程,可以在这里执行,也可以选择在宿主的其他地方在需要时再启动插件框架
          PluginLoader.initLoader(this);
       }
    }
    
    2.调用PluginLoader的静态方法initLoader()执行初始化
    /*** 初始化loader, 只可调用一次* * @param app*/
    public static synchronized void initLoader(Application app) {
        ...
        //安装ActivityManagerProxy
        AndroidAppIActivityManager.installProxy();
        // 安装NotificationManagerProxy
         ​AndroidAppINotificationManager.installProxy();
        //安装PackageManagerProxy​
        AndroidAppIPackageManager.installProxy(FairyGlobal.getHostApplication().getPackageManager());
        if (isPluginProcess) {
            HackLayoutInflater.installPluginCustomViewConstructorCache();
            CompatForSupportv7ViewInflater.installPluginCustomViewConstructorCache();
            CompatForFragmentClassCache.installFragmentClassCache();
            CompatForFragmentClassCache.installSupportV4FragmentClassCache();//不可在主进程中同步安装,因为此时ActivityThread还没有准备好, 会导致空指针。
            new Handler().post(new Runnable() {
                @Overridepublic
                void run() {
                    AndroidWebkitWebViewFactoryProvider.installProxy();
                }
            });
        }//本来宿主进程是不需要注入handlecallback的,这里加上是为了对抗360安全卫士等软件,提高Instrumentation的成功率​
        PluginInjector.injectHandlerCallback();//注入Instrumentation​
        PluginInjector.injectInstrumentation();
        PluginInjector.injectBaseContext(FairyGlobal.getHostApplication());
        ...
    }
    
    3. 上面叙述的Hook的位置,接下来我们讲解的重点就来了Hook IActivityManager 和 Hook Insrtumentation
    3.1 AndroidAppIActivityManager.installProxy(); Hook IActvityManger原理
    1> 这个方法是用于安装ActivityManagerProxy,我们看看方法中的实现:
    public static void installProxy() {
        Object androidAppActivityManagerProxy = HackActivityManagerNative.getDefault();   //7.0
        Object androidAppIActivityManagerStubProxyProxy = ProxyUtil.createProxy(androidAppActivityManagerProxy, new AndroidAppIActivityManager());
        //O Preview版本暂时不能通过SDK_INT来区分 2017-5-18
        if (Build.VERSION.SDK_INT <= 25) { //SDK版本判断
            Object singleton = HackActivityManagerNative.getGDefault();
            //如果是androidAppIActivityManagerStubProxyProxy实例对应的类是否被singleton实例对应的类包装过
            if (singleton.getClass().isAssignableFrom(androidAppIActivityManagerStubProxyProxy.getClass())) {
                HackActivityManagerNative.setGDefault(androidAppIActivityManagerStubProxyProxy);
            } else {//否则是New一个被包装过的单例
                new HackSingleton(singleton).setInstance(androidAppIActivityManagerStubProxyProxy);
            }
        } else {
            //Android O 没有gDefault这个成员了, 变量被移到了ActivityManager这个类中
            Object singleton = HackActivityManager.getIActivityManagerSingleton();
            if (singleton != null) {
                new HackSingleton(singleton).setInstance(androidAppIActivityManagerStubProxyProxy); //2 new出一个HookSingleton
            } else {
                LogUtil.e("WTF!!");
            }
        }
        LogUtil.d("安装完成");
    }
    
    2>我们这里主要讲解25版本以上的,所以我么继续观察HackActivityManager类的静态函数方法getIActivityManagerSingleton()的实现
    public class HackActivityManager {
        private static final String ClassName = "android.app.ActivityManager";
        private static final String Field_IActivityManagerSingleton = "IActivityManagerSingleton";
        public static Object getIActivityManagerSingleton() {
            return RefInvoker.getField(null, ClassName, Field_IActivityManagerSingleton);
        }
        public static Object setIActivityManagerSingleton(Object activityManagerSingleton) {
           return RefInvoker.getField(null, ClassName, Field_IActivityManagerSingleton);
        }
    }
    
    3>这里通过反射ActivityManager类获取IActivityManagerSingleton静态私有成员变量的值,此处我们进入源码看一下:
    private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };
    
    4>ServiceManager通过调用getService函数方法获取AMS的代理实例,进而调用AMS的startActivity方法函数。IActivityManager借助了Singleton类实现单例的创建,再来看Singleton是如何创建单例对象
    public abstract class Singleton<T> {
        private T mInstance;
        protected abstract T create();
        public final T get() {
            synchronized (this) {
                if (mInstance == null) {
                    mInstance = create();
                }
                return mInstance;
            }
        }
    }​
    
    5>回到1>中的方法体我们接着解析标记//2的函数方法
    public class HackSingleton {
        private static final String ClassName = "android.util.Singleton";
        private static final String Field_mInstance = "mInstance";
        private Object instance;
        public HackSingleton(Object instance) {
            this.instance = instance;
        }
        public void setInstance(Object object) {
            RefInvoker.setField(instance, ClassName, Field_mInstance, object);
        }
    }
    
    6>创建一个HookSingleton的实例,为Singleton的实例赋值,从前面Singleton类的代码可以得知mInstance字段的类型为T,此处T的类型为IActivityManager,所以我们通过 AndroidAppIActivityManager创建出了androidAppIActivityManagerStubProxyProxy实例,用用AndroidAppIActivityManager来替换IActivityManager,然后经Application中attachBaseContext()函数调用Hook IActivityManager(即最顶层方法)
    3.2 PluginInjector.injectInstrumentation(); Hook Instrumentation 原理
    1>注入Instrumentation主要是为了支持Activity
    static void injectInstrumentation() {
       // 给Instrumentation添加一层代理,用来实现隐藏api的调用
       LogUtil.d("替换宿主程序Intstrumentation");
       HackActivityThread.wrapInstrumentation();
    }
    
    2>调用HackActivityThread类中静态方法 wrapInstrumentation()设置Hook Instrumentation
    private Object instance;
    private static final String ClassName = "android.app.ActivityThread";
    private static final String Field_mInstrumentation = "mInstrumentation";
    ​
    ​public static void wrapInstrumentation() {
        //此处get()函数是从ThreadLocal中获取到当前线程​
        HackActivityThread hackActivityThread = get();
        if (hackActivityThread != null) {
            //通过反射获取Instrumentation的实例​
            Instrumentation originalInstrumentation = hackActivityThread.getInstrumentation();
            //此处PluginInstrumentationWrapper继承于Instrumentation,插件Activity免注册的主要实现原理
            if (!(originalInstrumentation instanceof PluginInstrumentionWrapper)) {
                hackActivityThread.setInstrumentation(new PluginInstrumentionWrapper(originalInstrumentation));
            }
        } else {
            LogUtil.e("wrapInstrumentation fail!!");
        }
    }
    //这个方法必须在主线程调用,因为它是从ThreadLocal中取出来的,在其他线程中取出来一定是null
    public static synchronized HackActivityThread get() {
        if (hackActivityThread == null) {
            Object instance = currentActivityThread();
            if (instance != null) {
                hackActivityThread = new HackActivityThread(instance);
            }
        }
        return hackActivityThread;
    }​​
    public Instrumentation getInstrumentation() {
        return (Instrumentation) RefInvoker.getField(instance,
                ClassName, Field_mInstrumentation);
    }​
    public void setInstrumentation(Instrumentation instrumentation) {
        RefInvoker.setField(instance, ClassName,
                Field_mInstrumentation,
                instrumentation);
    }​​
    
    3>通过上面那一步我们已经成功的将我们 PluginInstrumentionWrapper设置进了Instrumentation,通过上篇Activity启动过程可知,关于Activity的生命周期状态的设置最终都是由Instrumentation相关函数调入到Activity中对应的方法实现的状态的设置;这里的PluginInstrumentationWrapper继承于Instrumentation,在super.父类方法之前执行了自己方法实现了函数覆盖重写.

    This ALL! Thanks EveryBody!

    相关文章

      网友评论

          本文标题:Android-Framework-Plugin插件话框架-Ho

          本文链接:https://www.haomeiwen.com/subject/fsyipqtx.html