【Android 插件化】Hook 插件化框架 ( hook 插件化原理 | 插件包管理 )

举报
韩曙亮 发表于 2022/01/14 00:52:00 2022/01/14
【摘要】 Android 插件化系列文章目录 【Android 插件化】插件化简介 ( 组件化与插件化 ) 【Android 插件化】插件化原理 ( JVM 内存数据 | 类加载流程 ) 【Android 插件化...

Android 插件化系列文章目录

【Android 插件化】插件化简介 ( 组件化与插件化 )
【Android 插件化】插件化原理 ( JVM 内存数据 | 类加载流程 )
【Android 插件化】插件化原理 ( 类加载器 )

【Android 插件化】“ 插桩式 “ 插件化框架 ( 原理与实现思路 )
【Android 插件化】“ 插桩式 “ 插件化框架 ( 类加载器创建 | 资源加载 )
【Android 插件化】“ 插桩式 “ 插件化框架 ( 注入上下文的使用 )
【Android 插件化】“ 插桩式 “ 插件化框架 ( 获取插件入口 Activity 组件 | 加载插件 Resources 资源 )
【Android 插件化】“ 插桩式 “ 插件化框架 ( 运行应用 | 代码整理 )

【Android 插件化】Hook 插件化框架 ( Hook 技术 | 代理模式 | 静态代理 | 动态代理 )
【Android 插件化】Hook 插件化框架 ( Hook 实现思路 | Hook 按钮点击事件 )
【Android 插件化】Hook 插件化框架 ( Hook Activity 启动过程 | 静态代理 )
【Android 插件化】Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 一 | Activity 进程相关源码 )
【Android 插件化】Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 二 | AMS 进程相关源码 | 主进程相关源码 )

【Android 插件化】Hook 插件化框架 ( hook 插件化原理 | 插件包管理 )



前言

2 2 2 篇博客 【Android 插件化】Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 一 | Activity 进程相关源码 ) , 【Android 插件化】Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 二 | AMS 进程相关源码 | 主进程相关源码 ) 中 , 分析了从 Activity 调用 startActivity 启动另一个 Activity 的底层源码流程 , 涉及到了 2 2 2 个进程 , 一个是本应用的主线程所在的进程 , 一个是 ActivityManagerService 进程 ;

本博客中开始对 Activity 启动过程进行 Hook 操作 , 基于 Android 9 9 9 , API 28 28 28 版本 , 这里要注意 , 不同的 API 版本底层源码逻辑不同 , Hook 点以及 Hook 方式也不同 ;

目前的主流插件化框架都已经兼容到了 Android 10 10 10 版本 ;






一、hook 插件化原理



使用 Hook 实现的插件化原理如下 : 通过以下 3 3 3 个步骤实现插件化 ;


1. 加载插件包中的字节码


2. hook 技术 : 直接通过 hook 技术, 钩住系统的 Activity 启动流程实现

① Activity 对象创建之前 , 要做很多初始化操作 , 先在 ActivityRecord 中加载 Activity 信息 , 如果修改了该信息 , 将要跳转的 Activity 信息修改为插件包中的 Activity , 原来的 Activity 只用于占位 , 用于欺骗 Android 系统 ;

使用 hook 技术 , 加载插件包 apk 中的 Activity

③ 实现跳转的 Activity ( 插件包中的 )


3. 资源加载 : 主要是解决 Resources 资源冲突问题 ;

( 使用上述 hook 插件化 , 可以不用考虑 Activity 的生命周期问题 )


占位 Activity : 插件包中的 Activity 是通过正规流程 , 由 AMS 进行创建并加载的 , 但是 该 Activity 并没有在 AndroidManifest.xml 清单文件中注册 , 这里需要一个已经在清单文件注册的 Activity 欺骗系统 ;

插装式插件化 : 是通过代理 Activity , 将 插件包加载的 字节码 Class 类对应的 Activity 类作为一个普通的 Java 类 , 该普通的 Java 类有所有的 Activity 的业务逻辑 , 该 Activity 的生命周期 , 由代理 Activity 执行相关的生命周期方法

hook 插件化 : hook 插件化直接钩住系统中 Activity 启动流程的某个点





二、插件化依赖库创建



hook 插件化依赖库是 Android 依赖库 ( Android Library Module ) ;

创建插件化的核心依赖库 :

在这里插入图片描述

通过该 lib_plugin_core 依赖库 , 实现插件化相关功能 ;

在这里插入图片描述

在其中创建插件化的核心管理类 PluginManager , 用于管理插件相关内容 ;

在这里插入图片描述





三、插件包管理



插件包目录 : 将插件包放在 /data/data/< package name >/files/ 目录中 ;

// 插件包的绝对路径 ,  /data/data/< package name >/files/
String apkPath = mBase.getFilesDir().getAbsolutePath() + "plugin.apk";

  
 
  • 1
  • 2

插件包缓存目录 : 同时设置 , 加载插件包中产生的缓存文件路径是 /data/data/< package name >/app_plugin_cache/ 目录 ;

// 加载插件包后产生的缓存文件路径
// /data/data/< package name >/app_plugin_cache/
String cachePath =
        mBase.getDir("plugin_cache", Context.MODE_PRIVATE).getAbsolutePath();

  
 
  • 1
  • 2
  • 3
  • 4

创建插件包的类加载器 :

// 创建类加载器
DexClassLoader plugin_dexClassLoader =
        new DexClassLoader(
                apkPath,                // 插件包路径
                cachePath,              // 插件包加载时产生的缓存路径
                null,   				// 库的搜索路径, 可以设置为空
                mBase.getClassLoader()  // 父加载器, PathClassLoader
        );

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8




四、插件包管理完整代码示例



package kim.hsl.plugin;

import android.content.Context;

import java.lang.reflect.Field;

import dalvik.system.DexClassLoader;

/**
 * 使用 Hook 实现的插件使用入口
 *  1. 加载插件包中的字节码
 *  2. 直接通过 hook 技术, 钩住系统的 Activity 启动流程实现
 *      ① Activity 对象创建之前 , 要做很多初始化操作 , 先在 ActivityRecord 中加载 Activity 信息
 *          如果修改了该信息 , 将要跳转的 Activity 信息修改为插件包中的 Activity
 *          原来的 Activity 只用于占位 , 用于欺骗 Android 系统
 *      ② 使用 hook 技术 , 加载插件包 apk 中的 Activity
 *      ③ 实现跳转的 Activity ( 插件包中的 )
 *  3. 解决 Resources 资源冲突问题
 *  ( 使用上述 hook 插件化 , 可以不用考虑 Activity 的声明周期问题 )
 *
 *  插件包中的 Activity 是通过正规流程 , 由 AMS 进行创建并加载的
 *      但是该 Activity 并没有在 AndroidManifest.xml 清单文件中注册
 *      这里需要一个已经在清单文件注册的 Activity 欺骗系统
 *
 *  插装式插件化 是通过代理 Activity , 将插件包加载的字节码 Class 作为一个普通的 Java 类
 *      该普通的 Java 类有所有的 Activity 的业务逻辑
 *      该 Activity 的声明周期 , 由代理 Activity 执行相关的生命周期方法
 *  hook 插件化 : hook 插件化直接钩住系统中 Activity 启动流程的某个点
 *      使用插件包中的 Activity 替换占位的 Activity
 */
public class PluginManager {

    /**
     * 上下文
     */
    private Context mBase;

    /**
     * 单例
     */
    private static PluginManager instance;

    public static PluginManager getInstance(Context context) {
        if (instance == null) {
            instance = new PluginManager(context);
        }
        return instance;
    }

    private PluginManager(Context context) {
        this.mBase = context;
    }

    /**
     * Application 启动后 , 调用该方法初始化插件化环境
     *  加载插件包中的字节码
     */
    private void init() {
        // 加载 apk 文件
        loadApk();
    }

    private void loadApk() {
        // 插件包的绝对路径 ,  /data/data/< package name >/files/
        String apkPath = mBase.getFilesDir().getAbsolutePath() + "plugin.apk";
        // 加载插件包后产生的缓存文件路径
        // /data/data/< package name >/app_plugin_cache/
        String cachePath =
                mBase.getDir("plugin_cache", Context.MODE_PRIVATE).getAbsolutePath();
        // 创建类加载器
        DexClassLoader plugin_dexClassLoader =
                new DexClassLoader(
                        apkPath,                // 插件包路径
                        cachePath,              // 插件包加载时产生的缓存路径
                        null,   // 库的搜索路径, 可以设置为空
                        mBase.getClassLoader()  // 父加载器, PathClassLoader
                );
    }

}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81




五、博客资源



博客资源 :

文章来源: hanshuliang.blog.csdn.net,作者:韩曙亮,版权归原作者所有,如需转载,请联系作者。

原文链接:hanshuliang.blog.csdn.net/article/details/118035052

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。