当前位置:   article > 正文

Android hook式插件化详解_hook插件

hook插件

引言

Android插件化是一种将应用程序的功能模块化为独立的插件,并动态加载到主应用程序中的技术。通过插件化,开发者可以将应用程序的功能分解成独立的模块,每个模块可以作为一个插件单独开发、测试和维护,然后通过动态加载的方式集成到主应用程序中,实现功能的动态扩展和更新。

Android插件化通常涉及到动态加载、组件化、插件生命周期管理、插件间通信等技术,开发者需要使用相关的框架和工具来实现插件化功能。插件化可以帮助开发者更好地管理应用程序的复杂性,提高开发效率,同时也能够实现应用程序的功能动态更新和扩展,为用户提供更好的体验。

1.startActivity源码解析

我们上篇提到,调用 startActivity 启动一个没有在 Manifest.xml 文件中注册的 Activity 会报异常,那么我们今天从 startActivity 开始分析为什么会报异常。

startActivity 的流程大概是上面所示,最后执行到 AMS.startActivity 后如果没有在 Manifest.xml 中注册,软件就会发生崩溃, 那么怎么样才能避免这样呢。其实非常简单,我们只要把我们未注册的 Activity 替换成我们已经在 Manifest.xml 注册不就行了吗。那么问题又来了,我们应该如何实现替换操作呢?说到替换,我们不得不借助动态代理的方式来实现了。

从上图可以看出,创建一个动态代理对象需要传递三个参数,下面介绍一下这些参数

ClassLoader loader: 类加载器

Class<?>[] interfaces: 需要监听的接口

InvocationHandler h: 监听的回调

说到这里,我们又延伸到另一个问题,我们应该监听哪一个接口呢?,其实从上面我们已经分析过了,我们应该要监听 AMS.startActivity 这一步,所以我们要监听的接口就是 IActivityTaskManager(9.0及以下是IActivityManager) 这个接口。接下来我们就对这个接口实现动态代理。

2.动态代理的实现

第一步:

我们可以通过 Class.forName() 得到 IActivityTaskManager 或者 IActivityManager 这个类,如下面代码所示:

  1. Class<?> mIActivityManagerClass;
  2. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
  3. mIActivityManagerClass = Class.forName("android.app.IActivityTaskManager");
  4. } else {
  5. mIActivityManagerClass = Class.forName("android.app.IActivityManager");
  6. }

有了类之后,我们可以创建动态代理对象了,但是 IActivityTaskManager 或者 IActivityManager 接口的方法那么多,我们没必要全部监听,我们只需要监听我们关注的 "startActivity" 这个方法就好了,如下代码所示:

  1. //创建动态代理
  2. Object mActivityManagerProxy = Proxy.newProxyInstance(
  3. getClassLoader(),//类加载器
  4. new Class[]{mIActivityManagerClass},//要监听的回调接口
  5. new InvocationHandler() {//回调的监听
  6. @Override
  7. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  8. if ("startActivity".equals(method.getName())) {
  9. //做自己的业务逻辑
  10. //换成可以通过AMS检测的Activity
  11. }
  12. //为了程序能够正确执行,我们需要系统的IActivityManager实例
  13. return method.invoke(需要系统的IActivityManager实例, args);
  14. }
  15. );

从上述代码中可以看出,要使动态代理生效,我们还需要一个 IActivityManager,查阅源码 ActivityTaskManager(8.0~9.0以下看 ActivityManager,8.0以下看 ActivityManagerNative) 可发现:

ActivityTaskManager.java:(Androdid10.0)

  1. /** @hide */
  2. public static IActivityTaskManager getService() {
  3. return IActivityTaskManagerSingleton.get();
  4. }

ActivityManager.java:(Android 8.0 ~ Android9.0)

  1. /**
  2. * @hide
  3. */
  4. public static IActivityManager getService() {
  5. return IActivityManagerSingleton.get();
  6. }

ActivityManagerNative.java:(Android 7.0及以下)

  1. /**
  2. * Retrieve the system's default/global activity manager.
  3. */
  4. static public IActivityManager getDefault() {
  5. return gDefault.get();
  6. }

通过 getService() 或者 getDefault() 可以返回一个我们需要的对象实例,我们接下来可以反射来执行该方法来获取 IActivityTaskManager 或者 IActivityManager 实例对象。代码如下:

  1. //获取 ActivityManager 或 ActivityManagerNative 或 ActivityTaskManager
  2. Class<?> mActivityManagerClass;
  3. Method getActivityManagerMethod;
  4. if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1) {
  5. mActivityManagerClass = Class.forName("android.app.ActivityManagerNative");
  6. getActivityManagerMethod = mActivityManagerClass.getDeclaredMethod("getDefault");
  7. } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1 && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q){
  8. mActivityManagerClass = Class.forName("android.app.ActivityManager");
  9. getActivityManagerMethod = mActivityManagerClass.getDeclaredMethod("getService");
  10. } else {
  11. mActivityManagerClass = Class.forName("android.app.ActivityTaskManager");
  12. getActivityManagerMethod = mActivityManagerClass.getDeclaredMethod("getService");
  13. }
  14. getActivityManagerMethod.setAccessible(true);
  15. //这个实例本质是 IActivityManager或者IActivityTaskManager
  16. final Object IActivityManager = getActivityManagerMethod.invoke(null);

现在有了 IActivityTaskManager 或者 IActivityManager 实例对象我们就可以让程序继续能够执行下去了。

第二步: 既然我们自己创建了 IActivityTaskManager 或者 IActivityManager 的动态代理,我们就要把原来系统的 IActivityTaskManager 或者 IActivityManager 实例对象给替换掉。还是通过上面的 getService() 或者 getDefault() 方法入手,我们继续跟踪代码发现: ActivityManager 或 ActivityManagerNative 或 ActivityTaskManager 都有一个 Singleton 共同的属性,我们查看一下这个类的源码:

  1. public abstract class Singleton<T> {
  2. private T mInstance;
  3. protected abstract T create();
  4. public final T get() {
  5. synchronized (this) {
  6. if (mInstance == null) {
  7. mInstance = create();
  8. }
  9. return mInstance;
  10. }
  11. }
  12. }

里面的 mInstance 属性正好是 IActivityTaskManager 或者 IActivityManager 实例,所以我们直接替换掉 mInstance 值就可以了。代码如下:

  1. //获取 IActivityTaskManagerSingleton 或者 IActivityManagerSingleton 或者 gDefault 属性
  2. Field mSingletonField;
  3. if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1) {
  4. mSingletonField = mActivityManagerClass.getDeclaredField("gDefault");
  5. } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1 && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q){
  6. mSingletonField = mActivityManagerClass.getDeclaredField("IActivityManagerSingleton");
  7. } else {
  8. mSingletonField = mActivityManagerClass.getDeclaredField("IActivityTaskManagerSingleton");
  9. }
  10. mSingletonField.setAccessible(true);
  11. Object mSingleton = mSingletonField.get(null);
  12. //替换点
  13. Class<?> mSingletonClass = Class.forName("android.util.Singleton");
  14. Field mInstanceField = mSingletonClass.getDeclaredField("mInstance");
  15. mInstanceField.setAccessible(true);
  16. //将我们创建的动态代理设置到 mInstance 属性当中
  17. mInstanceField.set(mSingleton, mActivityManagerProxy);

到这里我们的动态代理算是实现好了,完整的代码如下:

  1. private void hookAMSAction() throws Exception {
  2. //动态代理
  3. Class<?> mIActivityManagerClass;
  4. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
  5. mIActivityManagerClass = Class.forName("android.app.IActivityTaskManager");
  6. } else {
  7. mIActivityManagerClass = Class.forName("android.app.IActivityManager");
  8. }
  9. //获取 ActivityManager 或 ActivityManagerNative 或 ActivityTaskManager
  10. Class<?> mActivityManagerClass;
  11. Method getActivityManagerMethod;
  12. if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1) {
  13. mActivityManagerClass = Class.forName("android.app.ActivityManagerNative");
  14. getActivityManagerMethod = mActivityManagerClass.getDeclaredMethod("getDefault");
  15. } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1 && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q){
  16. mActivityManagerClass = Class.forName("android.app.ActivityManager");
  17. getActivityManagerMethod = mActivityManagerClass.getDeclaredMethod("getService");
  18. } else {
  19. mActivityManagerClass = Class.forName("android.app.ActivityTaskManager");
  20. getActivityManagerMethod = mActivityMa
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/861132
推荐阅读
相关标签
  

闽ICP备14008679号