FrameWork源码解析(8)-插件化框架VirtualApk之初始化

主目录见:Android高级进阶知识(这是总目录索引)
框架地址:VirtualApk
在线源码查看:AndroidXRef

 今天我们就从滴滴的插件化VirtualApk来结合我们之前说的一些知识讲讲插件化,如果之前未涉及的知识点,在这里也会讲到,希望我们的插件化之旅能圆满愉快。同时今天这是我们的第一篇,我们在这里先从初始化开始。

初始化

这里我们就不讲怎么使用了,想必怎么使用大家看下文档就知道了,可以参照这里https://github.com/didi/VirtualAPK/wiki

我们都知道,插件化框架一般会分出宿主程序和插件程序部分,今天我们会先从Host(宿主工程)开始讲,在使用这个插件化框架的时候,我们除了要添加依赖之外,最开始的就是要初始化:

//Initialize PluginManager in YourApplication::attachBaseContext().
@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    PluginManager.getInstance(base).init();
}

我们从这个使用入手,我们来看看PluginManager#getInstance(base)方法做了什么:

 public static PluginManager getInstance(Context base) {
        if (sInstance == null) {
            synchronized (PluginManager.class) {
                if (sInstance == null)
                    sInstance = new PluginManager(base);
            }
        }

        return sInstance;
    }

我们看到这里是通过单例模式获取PluginManager对象,那么我们这里直接看到构造函数:

 private PluginManager(Context context) {
        Context app = context.getApplicationContext();
        if (app == null) {
            this.mContext = context;
        } else {
            this.mContext = ((Application)app).getBaseContext();
        }
        prepare();
    }

前面很容易,获取宿主程序的上下文对象,然后调用prepare方法:

   private void prepare() {
        Systems.sHostContext = getHostContext();
        this.hookInstrumentationAndHandler();
        if (Build.VERSION.SDK_INT >= 26) {
            this.hookAMSForO();
        } else {
            this.hookSystemServices();
        }
    }

首先将宿主的上下文对象保存在Systems类中的静态变量sHostContext中。然后后面会hook几个Android系统的类,我们先来看第一个hookInstrumentationAndHandler()方法:

 private void hookInstrumentationAndHandler() {
        try {
            Instrumentation baseInstrumentation = ReflectUtil.getInstrumentation(this.mContext);
            if (baseInstrumentation.getClass().getName().contains("lbe")) {
                // reject executing in paralell space, for example, lbe.
                System.exit(0);
            }

            final VAInstrumentation instrumentation = new VAInstrumentation(this, baseInstrumentation);
            Object activityThread = ReflectUtil.getActivityThread(this.mContext);
            ReflectUtil.setInstrumentation(activityThread, instrumentation);
            ReflectUtil.setHandlerCallback(this.mContext, instrumentation);
            this.mInstrumentation = instrumentation;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

我们一步一步来看,首先来看ReflectUtil#getInstrumentation()做了啥:

    public static Instrumentation getInstrumentation(Context base) {
        if (getActivityThread(base) != null) {
            try {
                sInstrumentation = (Instrumentation) ReflectUtil.invoke(
                        sActivityThread.getClass(), sActivityThread, "getInstrumentation");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return sInstrumentation;
    }

这个方法主要是通过反射来获取Instrumentation对象(为什么要反射得到这个对象呢?其实在启动activity的时候会进行用占坑的Activity来欺骗过系统检查),我们知道在ActivityThread中可以获取到Instrumentation实例 ,所以同样的,程序先要通过调用getActivityThread()方法来获取ActivityThread对象:

  @UiThread
    public static Object getActivityThread(Context base) {
        if (sActivityThread == null) {
            try {
                Class<?> activityThreadClazz = Class.forName("android.app.ActivityThread");
                Object activityThread = null;
                try {
                    activityThread = ReflectUtil.getField(activityThreadClazz, null, "sCurrentActivityThread");
                } catch (Exception e) {
                    // ignored
                }
                if (activityThread == null) {
                    activityThread = ((ThreadLocal<?>) ReflectUtil.getField(activityThreadClazz, null, "sThreadLocal")).get();
                }
                sActivityThread = activityThread;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return sActivityThread;
    }

我们看到这里反射了ActivityThread类,然后通过获取sCurrentActivityThread实例来得到ActivityThread实例,如果没有获取到则通过获取sThreadLocal来得到ActivityThread实例,为什么这样呢?这是因为早期的版本中ActivityThread是放在ThreadLocal中的(static final ThreadLocal<ActivityThread> sThreadLocal = new ThreadLocal()),到这里,我们的ActivityTthread实例已经获取成功,我们继续通过反射调用这个实例中的getInstrumentation()来获取Instrumentation实例,即上面ReflectUtil#getInstrumentation()做的事情。然后我们继续看hookInstrumentationAndHandler()方法,这个方法里面会实例化VAInstrumentation对象,并将我们获取到的系统的Instrumentation当做参数传进构造函数,然后将我们实例化出来的VAInstrumentation实例替换ActivityThread实例中的Instrumentation,并将Handler的回调设置为VAInstrumentation类,因为这个类实现了Handler.Callback接口。接着我们看prepare()方法中:

    if (Build.VERSION.SDK_INT >= 26) {
            this.hookAMSForO();
        } else {
            this.hookSystemServices();
        }

这两个方法都是使用了动态代理来代理系统的AMS(也就是hook AMS在客户端的代理ActivityManagerProxy),这样在以后所有执行该代理的方法,都是默认先走到我们自己定义的ActivityManagerProxy(继承自InvocationHanlder)的invoke方法中(这是动态代理的机制)。这里有个版本判断,是为了兼容8.0系统的,因为8.0系统把AMS客户端代理获取放在IActivityManagerSingleton属性中,如下所示,如果熟悉FrameWork的应该知道:

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;
   } 
};

我们先来看8.0系统下的hookAMSForO()方法是怎么做的:

 private void hookAMSForO() {
        try {
            Singleton<IActivityManager> defaultSingleton = (Singleton<IActivityManager>) ReflectUtil.getField(ActivityManager.class, null, "IActivityManagerSingleton");
            IActivityManager activityManagerProxy = ActivityManagerProxy.newInstance(this, defaultSingleton.get());
            ReflectUtil.setField(defaultSingleton.getClass().getSuperclass(), defaultSingleton, "mInstance", activityManagerProxy);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

一样的,我们这里通过反射取到ActivityManager类中IActivityManagerSingleton属性,然后我们通过调用ActivityManagerProxy#newInstance()方法来实例化新的ActivityManagerProxy,我们跟进去看看:

  public static IActivityManager newInstance(PluginManager pluginManager, IActivityManager activityManager) {
        return (IActivityManager) Proxy.newProxyInstance(activityManager.getClass().getClassLoader(), new Class[] { IActivityManager.class }, new ActivityManagerProxy(pluginManager, activityManager));
    }

这个地方使用了动态代理来代理系统中的AMS客户端代理ActivityManagerProxy,所以之后调用通过这个代理调用远程AMS的服务都会先到我们创建的ActivityManagerProxy中的invoke方法里,因为这个类实现了InvocationHandler接口。为什么要hook掉这个类呢?其实主要是要拦截Service启动,停止,绑定等等的方法。接着我们看8.0版本之前的hook AMS服务的方法hookSystemServices()

 private void hookSystemServices() {
        try {
            Singleton<IActivityManager> defaultSingleton = (Singleton<IActivityManager>) ReflectUtil.getField(ActivityManagerNative.class, null, "gDefault");
            IActivityManager activityManagerProxy = ActivityManagerProxy.newInstance(this, defaultSingleton.get());

            // Hook IActivityManager from ActivityManagerNative
            ReflectUtil.setField(defaultSingleton.getClass().getSuperclass(), defaultSingleton, "mInstance", activityManagerProxy);

            if (defaultSingleton.get() == activityManagerProxy) {
                this.mActivityManager = activityManagerProxy;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

我们看到这里面主要是通过获取ActivityManagerNative类中的gDefault属性来获取AMS客户端代理,我们可以看到这个gDefault属性如下:

   private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        protected IActivityManager create() {
            IBinder b = ServiceManager.getService("activity");
            if (false) {
                Log.v("ActivityManager", "default service binder = " + b);
            }
            IActivityManager am = asInterface(b);
            if (false) {
                Log.v("ActivityManager", "default service = " + am);
            }
            return am;
        }
    };

这个也主要是获取远程的AMS的客户端代理,因为服务启动完会注册在ServiceManager中,所以我们只要从这里查找即可。然后下面的步骤其实跟hookAMSForO()一样了。到这里我们PluginManager的构造函数里面的初始化已经完成,然后我们会调用PluginManager#getInstance(base)#init()方法:

   public void init() {
        mComponentsHandler = new ComponentsHandler(this);
        RunUtil.getThreadPool().execute(new Runnable() {
            @Override
            public void run() {
                doInWorkThread();
            }
        });
    }

这个方法很简单,实例化ComponentsHandler类,然后在子线程中调用doInWorkThread()方法,doInWorkThread()方法暂时为空实现。到这里我们的初始化工作已经完成了。

总结:我们看到我们这里初始化主要是hook了两个中的类,一个是Instrumentation,另一个是系统服务AMS的客户端代理ActivityManagerProxy,在后面都会用到,系统大家有个印象,好啦,祝大家插件化之路愉快。

    原文作者:ZJ_Rocky
    原文地址: https://www.jianshu.com/p/56e8465677d7
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞