Android 插件化Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 一 | Activity 进程相关源码 )
Posted 韩曙亮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 插件化Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 一 | Activity 进程相关源码 )相关的知识,希望对你有一定的参考价值。
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 启动过程 | 静态代理 ) 使用了静态代理 , hook 了 Activity 的启动过程 ;
在 hook Android 的内部流程时 , 注意版本兼容 , 不同的 Android 版本底层源码实现机制可能有区别 , 需要使用不同的 hook 兼容方式 ;
hook 本身实现起来很简单 , 但是其 与底层源码耦合性太高 , 在 Android 8.0 8.0 8.0 可以 hook 住的方法 , 在 Android 10.0 10.0 10.0 可能就无法使用了 ;
Hook 插件化框架的 难点是版本兼容 , 需要逐个手动兼容 Android 低版本到最新版本 , 一旦系统更新 , 或者某厂商 ROM 更新 , 都要进行兼容测试以及改进 ;
如果 Android 高版本禁止反射 @hide 方法 , 可以在 调用链上找到一个非隐藏的方法 , 总能 hook 住 ; 极端情况下 , 使用 动态字节码技术 , 在运行时修改字节码数据 , 删除 @hide 注解 ;
插件化模块选择 : 一般的业务逻辑不建议使用插件化 ; 功能比较单一 , 业务逻辑更新比较频繁 , 并且很重要的模块 , 使用插件化实现 ;
插件化框架主要是 通过 hook 修改 Instrumentation , 以及 劫持 ActivityManagerService ;
源码分析的大忌就是死磕每一行源码的细节 , 只看自己能看懂的 , 每个方法最多看
2
2
2 层 , 不要偏离主线 ;
现在的源码参考资料很多 , 参考别人已经分析完毕的源码经验 , 可以节省很多时间 ;
一、Activity 任务栈相关源码
基于 Android 28 28 28 源码 , 分析 Activity 的启动过程 ; ( Android 27 27 27 , 28 28 28 , 29 29 29 中 Android 启动源码都进行了不同程度的改进 , 3 3 3 个版本的源码是不同的 )
1、任务栈管理者 ActivityStackSupervisor
Activity 任务栈 : ActivityStack ; Activity 启动后 , 都加入到 ActivityStack ( 任务栈 ) 中 ;
任务栈管理者 : ActivityStack 由 ActivityStackSupervisor 来管理 , ActivityStackSupervisor 中有两个数组 , 分别是
- mHomeStack : Launcher 应用使用的任务栈 ;
- mFocusedStack : 当前聚焦的任务栈 , 可以接收输入 , 或启动下一个 Activity ;
public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener,
RecentTasks.Callbacks {
/** The stack containing the launcher app. Assumed to always be attached to
* Display.DEFAULT_DISPLAY. */
ActivityStack mHomeStack;
/** The stack currently receiving input or launching the next activity. */
ActivityStack mFocusedStack;
}
源码地址 : frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
2、任务栈 ActivityStack
ActivityStack ( 任务栈 ) 中存在两个集合 :
- ArrayList<TaskRecord> mTaskHistory : 之前运行的 ( 可能仍在运行 ) 的 Activity 的历史记录 , 每个 TaskRecord 都包含了 1 1 1 个 ActivityRecord 集合 ;
- ArrayList<ActivityRecord> mLRUActivities : 当前正在运行的 Activity 列表 , 按照最近最少使用算法 LRU 机制进行排序 , 列表中第一个 Activity 是最近最少使用的 ;
ActivityRecord 就是 Activity 的信息 , 注意不是 Activity 的实例对象 , 是历史任务栈中的一个条目 , 可以代表一个 Activity ;
TaskRecord 中 维护了 1 1 1 个 ArrayList<ActivityRecord> , 用于保存 ActivityRecord ;
class ActivityStack<T extends StackWindowController> extends ConfigurationContainer
implements StackWindowListener {
/**
* The back history of all previous (and possibly still
* running) activities. It contains #TaskRecord objects.
*/
private final ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();
/**
* List of running activities, sorted by recent usage.
* The first entry in the list is the least recently used.
* It contains HistoryRecord objects.
*/
final ArrayList<ActivityRecord> mLRUActivities = new ArrayList<>();
}
3、Activity 启动涉及到的组件
ActivityThread : 应用主线程 , 每个应用都是从该主线程的 main 函数开始的 ;
Instrumentation : 每个 Activity 都持有该类对象 , 档调用 startActivity 启动其它 Activity 时 , 就会调用 Instrumentation 进行先关操作 ; ActivityThread 控制 Activity 也是通过该类进行 ; 一个应用中只有一个 Instrumentation 实例对象 ;
二、Activity 进程相关源码
1、Instrumentation 源码分析
在上一篇博客 【Android 插件化】Hook 插件化框架 ( Hook Activity 启动过程 | 静态代理 ) 一、分析 Activity 启动源码 章节中分析到 , 在 Activity 中调用 startActivity , 最终调用的是 Instrumentation 的 execStartActivity 方法 ;
在 Instrumentation 中的 newActivity(Class<?> clazz, Context context, IBinder token, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, Object lastNonConfigurationInstance)
方法 , 用于创建 Activity 实例 , 其中使用了 (Activity)clazz.newInstance()
创建 Activity 示例 ,
public Activity newActivity(Class<?> clazz, Context context,
IBinder token, Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
Object lastNonConfigurationInstance) throws InstantiationException,
IllegalAccessException {
Activity activity = (Activity)clazz.newInstance();
ActivityThread aThread = null;
// Activity.attach expects a non-null Application Object.
if (application == null) {
application = new Application();
}
activity.attach(context, aThread, this, token, 0 /* ident */, application, intent,
info, title, parent, id,
(Activity.NonConfigurationInstances)lastNonConfigurationInstance,
new Configuration(), null /* referrer */, null /* voiceInteractor */,
null /* window */, null /* activityConfigCallback */);
return activity;
}
在另外一个重载的 Activity newActivity(ClassLoader cl, String className, Intent intent)
方法中 , 通过指定 类加载器 ClassLoader , Activity 的全类名 , 也可以创建 Activity 实例对象 ;
Hook 劫持 Activity newActivity(ClassLoader cl, String className, Intent intent)
方法 , 传入插件包的类加载器 , 和插件包的类名 , 此时就可以初始化带上下文的 Activity ,
public Activity newActivity(ClassLoader cl, String className,
Intent intent)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
String pkg = intent != null && intent.getComponent() != null
? intent.getComponent().getPackageName() : null;
return getFactory(pkg).instantiateActivity(cl, className, intent);
}
public class Instrumentation {
public Activity newActivity(Class<?> clazz, Context context,
IBinder token, Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
Object lastNonConfigurationInstance) throws InstantiationException,
IllegalAccessException {
Activity activity = (Activity)clazz.newInstance();
ActivityThread aThread = null;
// Activity.attach expects a non-null Application Object.
if (application == null) {
application = new Application();
}
activity.attach(context, aThread, this, token, 0 /* ident */, application, intent,
info, title, parent, id,
(Activity.NonConfigurationInstances)lastNonConfigurationInstance,
new Configuration(), null /* referrer */, null /* voiceInteractor */,
null /* window */, null /* activityConfigCallback */);
return activity;
}
public Activity newActivity(ClassLoader cl, String className,
Intent intent)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
String pkg = intent != null && intent.getComponent() != null
? intent.getComponent().getPackageName() : null;
return getFactory(pkg).instantiateActivity(cl, className, intent);
}
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
Uri referrer = target != null ? target.onProvideReferrer() : null;
if (referrer != null) {
intent.putExtra(Intent.EXTRA_REFERRER, referrer);
}
if (mActivityMonitors != null) {
synchronized (mSync) {
final int N = mActivityMonitors.size();
for (int i=0; i<N; i++) {
final ActivityMonitor am = mActivityMonitors.get(i);
ActivityResult result = null;
if (am.ignoreMatchingSpecificIntents()) {
result = am.onStartActivity(intent);
}
if (result != null) {
am.mHits++;
return result;
} else if (am.match(who, null, intent)) {
am.mHits++;
if (am.isBlocking()) {
return requestCode >= 0 ? am.getResult() : null;
}
break;
}
}
}
}
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
int result = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
}
三、博客资源
博客资源 :
以上是关于Android 插件化Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 一 | Activity 进程相关源码 )的主要内容,如果未能解决你的问题,请参考以下文章
Android 插件化Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 二 | AMS 进程相关源码 | 主进程相关源码 )
Android 插件化Hook 插件化框架 ( Hook 实现思路 | Hook 按钮点击事件 )
Android 插件化Hook 插件化框架 ( hook 插件化原理 | 插件包管理 )
Android 插件化Hook 插件化框架 ( Hook Activity 启动流程 | Hook 点分析 )
Android 插件化Hook 插件化框架总结 ( 插件包管理 | Hook Activity 启动流程 | Hook 插件包资源加载 ) ★★★