AMS启动流程图
首先来看一下这张流程图,时常看看这个图有助于我们理解Android AMS的启动流程,脑中形成一个大概的启动流程体系,里面包含如下内容:
- SystemServer启动流程
- AMS具体方法启动逻辑
- APP进程的启动流程
- startActivity的启动流程
startBootstrapServices中mActivityManagerService.setSystemProcess设置SystemServer,这里也设置各种服务设置到ServiceManager,为了以后服务通过Binder进行通信。
与Activity管理有关的数据结构
ActivityRecord(An entry in the history stack,representing an activity)
ActivityRecord中存在着大量的成员变量,包含了一个Activity的所有信息。ActivityRecord中的成员变量task表示其所在的TaskRecord,由此可以看出:ActivityRecord与TaskRecord建立了联系
TaskRecord
TaskRecord,内部维护一个ArrayList<ActivityRecord>用来保存ActivityRecord,TaskRecord中的mStack表示其所在的ActivityStack,startActivity()时也会创建一个TaskRecord
ActivityStackSupervisor
ActivityStack mHomeStack; //管理的是launcher相关的任务
ActivityStack mFocusedStack; //管理非Launcher相关的任务
Android系统的一些服务
Android系统通过SystemServiceManager管理Java层的各种服务启动,大概有80多种服务,放入一个ArrayList中
可以看一下Android系统的一些服务,这里参考的是深入理解Android的书中的内容,并非官方标准的区分。
· 位于第一大类的是Android的核心服务,如ActivityManagerService、WindowManagerService等。
· 位于第二大类的是和通信相关的服务,如Wifi相关服务、Telephone相关服务。
· 位于第三大类的是和系统功能相关的服务,如AudioService、MountService、UsbService等。
· 位于第四大类的是BatteryService、VibratorService等服务。
· 位于第五大类的是EntropyService,DiskStatsService、Watchdog等相对独立的服务。
· 位于第六大类的是蓝牙服务。
· 位于第七大类的是UI方面的服务,如状态栏服务,通知管理服务等。
Activity启动流程相关
ApplicationThread是一个Binder,通过Handler进行跨线程通信,走到ActivityThread
应用没有启动时,点击app,一定会调用startProcessLocked()函数,通过zogyte去fork一个app进程,接下来就是应用进程和AMS两者的事情了,应用进程去调用AMS的方法,比如startActivity,很容易调用,因为AMS是一个有名称的Binder服务,在任意的地方都可以通过在ServiceManager(SM)里面查询拿到代理类,应用进程fork完第一件事情就是进行attach,attach过程就是为了把我的代理类交给AMS,应用进程有AMS的代理类对象,AMS也有应用进程的代理类对象,接下来这两者就可以进行交流了,这个就是startActivity的启动流程了。
SM的获取Acitivity的Binder服务
代理的设置过程
Activity Manager的组成主要分为以下几个部分:
1.服务代理:由ActivityManagerProxy实现,用于与Server端提供的系统服务进行进程间通信
2.服务中枢:ActivityManagerNative继承自Binder并实现IActivityManager,它提供了服务接口和 Binder接口的相互转化功能,并在内部存储服务代理对像,并提供了getDefault方法返回服务代理
3.Client:由ActivityManager封装一部分服务接口供Client调用。ActivityManager内部通过调用 ActivityManagerNative的getDefault方法,可以得到一个ActivityManagerProxy对像的引用,进而通过 该代理对像调用远程服务的方法
4.Server:由ActivityManagerService实现,提供Server端的系统服务
时序图
Activity在AMS中是一个ActivityRecord对象存在的,一个Activity对应一个ActivityRecord,ActivityRecord中存在着大量的成员变量,包含了一个Activity的所有信息。 ActivityRecord中的成员变量task表示其所在的TaskRecord。ActivityRecord是在startActivity的时候创建的。
相关的知识点:
- 微信双开,选择哪一个微信,或者pdf文件打开的时候,有多个选择,是在这里进行收集的,根据intent的action
- Instrumentation理解
Android instrumentation是Android系统里面的一套控制方法或者“钩子”,这些钩子可以在正常的生命周期(正常是有操作系统控制的)之外控制Android控件的运行,其实指的就是Instrumentation类提供的各种流程控制方法。
app->instrumentation->ams->app ,自动化测试是可以通过操作Instrumentation来操作Activity等,这个Instrumentation相当于设计了一个统一的入口。
3. ActivityThread不是线程类(Thread),只不过它会跑在UI主线程中,ActivityThead.main方法中,UI主线程中会有一个looper
Binder通信相关
天然的带有调用者的身份信息uid,验证调用者是不是有这个权限
id需要恢复,所以需要有这么一个流程。
Hook Activity启动流程
首先需要了解上面的Activity的启动流程,简单介绍如下:
-
AMS(验证Activity是否注册),不能传targetActivity
传一个假的StubActivity,return success,然后StubActivity替换回targetActivity
-
回到app进程后(Instrumentation 创建Activity)
-
AMS控制 Instrumentation执行Activity生命周期
我们需要欺骗AMS,然后启动真正的TargetActivity,Hook有起始点和终点。这里需要寻找两个地方的hook点,一个是对Intent中Activity的替换(hookIActivityTaskManager方法),一个是对Intent中Activity的还原(hookHandler)。
import android.app.Activity;
import android.app.Instrumentation;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import com.jackie.activityhookdemo.StubActivity;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;
public class HookHelper {
private static final String TAG = "Jackie";
public static final String EXTRA_TARGET_INTENT = "extra_target_intent";
public static void hookAMSAidl(){
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.P){
hookIActivityTaskManager();
}else{
hookIActivityManager();
}
}
public static void hookIActivityTaskManager(){
try{
Field singletonField = null;
Class<?> actvityManager = Class.forName("android.app.ActivityTaskManager");
singletonField = actvityManager.getDeclaredField("IActivityTaskManagerSingleton");
singletonField.setAccessible(true);
Object singleton = singletonField.get(null);
//拿IActivityManager对象
Class<?> singletonClass = Class.forName("android.util.Singleton");
Field mInstanceField = singletonClass.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
//原始的IActivityTaskManager
final Object IActivityTaskManager = mInstanceField.get(singleton);
Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader()
, new Class[]{Class.forName("android.app.IActivityTaskManager")}
, new InvocationHandler() {
@Override
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
// Log.i(TAG, "invoke: " + method.getName());
//偷梁换柱
//真正要启动的activity目标
Intent raw = null;
int index = -1;
if ("startActivity".equals(method.getName())) {
Log.i(TAG, "invoke: startActivity 启动准备");
for (int i = 0; i < args.length; i++) {
if(args[i] instanceof Intent){
raw = (Intent)args[i];
index = i;
}
}
Log.i(TAG, "invoke: raw: " + raw);
//代替的Intent
Intent newIntent = new Intent();
newIntent.setComponent(new ComponentName("com.jackie.activityhookdemo", StubActivity.class.getName()));
newIntent.putExtra(EXTRA_TARGET_INTENT,raw);
args[index] = newIntent;
}
return method.invoke(IActivityTaskManager, args);
}
});
// 7. IActivityManagerProxy 融入到framework
mInstanceField.set(singleton, proxy);
}catch (Exception e){
e.printStackTrace();
}
}
public static void hookIActivityManager() {
try{
Field singletonField = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Class<?> actvityManager = Class.forName("android.app.ActivityManager");
singletonField = actvityManager.getDeclaredField("IActivityManagerSingleton");
} else {
Class<?> actvityManager = Class.forName("android.app.ActivityManagerNative");
singletonField = actvityManager.getDeclaredField("gDefault");
}
singletonField.setAccessible(true);
Object singleton = singletonField.get(null);
//拿IActivityManager对象
Class<?> actvityManager = Class.forName("android.util.Singleton");
Field mInstanceField = actvityManager.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
//原始的IActivityManager
final Object rawIActivityManager = mInstanceField.get(singleton);
//创建一个IActivityManager代理对象
Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader()
, new Class[]{Class.forName("android.app.IActivityManager")}
, new InvocationHandler() {
@Override
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
// Log.i(TAG, "invoke: " + method.getName());
//偷梁换柱
//真正要启动的activity目标
Intent raw = null;
int index = -1;
if ("startActivity".equals(method.getName())) {
Log.i(TAG, "invoke: startActivity 启动准备");
for (int i = 0; i < args.length; i++) {
if(args[i] instanceof Intent){
raw = (Intent)args[i];
index = i;
}
}
Log.i(TAG, "invoke: raw: " + raw);
//代替的Intent
Intent newIntent = new Intent();
newIntent.setComponent(new ComponentName("com.jackie.activityhookdemo", StubActivity.class.getName()));
newIntent.putExtra(EXTRA_TARGET_INTENT,raw);
args[index] = newIntent;
}
return method.invoke(rawIActivityManager, args);
}
});
// 7. IActivityManagerProxy 融入到framework
mInstanceField.set(singleton, proxy);
}catch (Exception e){
e.printStackTrace();
}
}
public static void hookHandler() {
try {
Class<?> atClass = Class.forName("android.app.ActivityThread");
Field sCurrentActivityThreadField = atClass.getDeclaredField("sCurrentActivityThread");
sCurrentActivityThreadField.setAccessible(true);
Object sCurrentActivityThread = sCurrentActivityThreadField.get(null);
//ActivityThread 一个app进程 只有一个,获取它的mH
Field mHField = atClass.getDeclaredField("mH");
mHField.setAccessible(true);
final Handler mH = (Handler) mHField.get(sCurrentActivityThread);
//获取mCallback
Field mCallbackField = Handler.class.getDeclaredField("mCallback");
mCallbackField.setAccessible(true);
mCallbackField.set(mH, new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Log.i(TAG, "handleMessage: " + msg.what);
switch (msg.what) {
case 100: {
}
break;
case 159: {
Object obj = msg.obj;
Log.i(TAG, "handleMessage: obj=" + obj);
try {
Field mActivityCallbacksField = obj.getClass().getDeclaredField("mActivityCallbacks");
mActivityCallbacksField.setAccessible(true);
List mActivityCallbacks = (List) mActivityCallbacksField.get(obj);
Log.i(TAG, "handleMessage: mActivityCallbacks= " + mActivityCallbacks);
//注意了 这里如果有同学debug调试会发现第一次size=0 原因如下
//在Android O之前
//public static final int LAUNCH_ACTIVITY = 100;
//public static final int PAUSE_ACTIVITY = 101;
//public static final int PAUSE_ACTIVITY_FINISHING= 102;
//public static final int STOP_ACTIVITY_SHOW = 103;
//public static final int STOP_ACTIVITY_HIDE = 104;
//public static final int SHOW_WINDOW = 105;
//public static final int HIDE_WINDOW = 106;
//public static final int RESUME_ACTIVITY = 107;
//public static final int SEND_RESULT = 108;
//public static final int DESTROY_ACTIVITY = 109;
//end
//从AndroidP开始重构了状态模式
//public static final int EXECUTE_TRANSACTION = 159;
// 首先一个app 只有一个ActivityThread 然后就只有一个mH
//我们app所有的activity的生命周期的处理都在mH的handleMessage里面处理
//在Android 8.0之前,不同的生命周期对应不同的msg.what处理
//在Android 8.0 改成了全部由EXECUTE_TRANSACTION来处理
//所以这里第一次mActivityCallbacks是MainActivity的生命周期回调的
// handleMessage: 159
// handleMessage: obj=android.app.servertransaction.ClientTransaction@efd342
// handleMessage: mActivityCallbacks= []
// invoke: method activityPaused
// handleMessage: 159
// handleMessage: obj=android.app.servertransaction.ClientTransaction@4962
// handleMessage: mActivityCallbacks= [WindowVisibilityItem{showWindow=true}]
// handleMessage: size= 1
// handleMessage: 159
// handleMessage: obj=android.app.servertransaction.ClientTransaction@9e98c6b
// handleMessage: mActivityCallbacks= [LaunchActivityItem{intent=Intent { cmp=com.zero.activityhookdemo/.StubActivity (has extras) },ident=168243404,info=ActivityInfo{5b8d769 com.zero.activityhookdemo.StubActivity},curConfig={1.0 310mcc260mnc [en_US] ldltr sw411dp w411dp h659dp 420dpi nrml port finger qwerty/v/v -nav/h winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=Rect(0, 0 - 1080, 1794) mWindowingMode=fullscreen mActivityType=undefined} s.6},overrideConfig={1.0 310mcc260mnc [en_US] ldltr sw411dp w411dp h659dp 420dpi nrml port finger qwerty/v/v -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 1794) mAppBounds=Rect(0, 0 - 1080, 1794) mWindowingMode=fullscreen mActivityType=standard} s.6},referrer=com.zero.activityhookdemo,procState=2,state=null,persistentState=null,pendingResults=null,pendingNewIntents=null,profilerInfo=null}]
// handleMessage: size= 1
if (mActivityCallbacks.size() > 0) {
Log.i(TAG, "handleMessage: size= " + mActivityCallbacks.size());
String className = "android.app.servertransaction.LaunchActivityItem";
if (mActivityCallbacks.get(0).getClass().getCanonicalName().equals(className)) {
Object object = mActivityCallbacks.get(0);
Field intentField = object.getClass().getDeclaredField("mIntent");
intentField.setAccessible(true);
Intent intent = (Intent) intentField.get(object);
Intent targetIntent = intent.getParcelableExtra(EXTRA_TARGET_INTENT);
intent.setComponent(targetIntent.getComponent());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
break;
}
mH.handleMessage(msg);
return true;
}
});
} catch (Exception e) {
Log.e(TAG, "hookHandler: " + e.getMessage());
e.printStackTrace();
}
}
public static void hookInstrumentation(Activity activity) {
//TODO:
Class<?> activityClass = Activity.class;
//通过Activity.class 拿到 mInstrumentation字段
Field field = null;
try {
field = activityClass.getDeclaredField("mInstrumentation");
field.setAccessible(true);
//根据activity内mInstrumentation字段 获取Instrumentation对象
Instrumentation instrumentation = (Instrumentation) field.get(activity);
//创建代理对象,注意了因为Instrumentation是类,不是接口 所以我们只能用静态代理,
Instrumentation instrumentationProxy = new ProxyInstrumentation(instrumentation);
//进行替换
field.set(activity, instrumentationProxy);
} catch (Exception e) {
e.printStackTrace();
}
}
static class ProxyInstrumentation extends Instrumentation {
private static final String TAG = "Zero";
// ActivityThread中原始的对象, 保存起来
Instrumentation mBase;
public ProxyInstrumentation(Instrumentation base) {
mBase = base;
}
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
Log.d(TAG, "执行了startActivity, 参数如下: " + "who = [" + who + "], " +
"contextThread = [" + contextThread + "], token = [" + token + "], " +
"target = [" + target + "], intent = [" + intent +
"], requestCode = [" + requestCode + "], options = [" + options + "]");
// 由于这个方法是隐藏的,因此需要使用反射调用;首先找到这个方法
//execStartActivity有重载,别找错了
try {
Method execStartActivity = Instrumentation.class.getDeclaredMethod(
"execStartActivity",
Context.class, IBinder.class, IBinder.class, Activity.class,
Intent.class, int.class, Bundle.class);
execStartActivity.setAccessible(true);
return (ActivityResult) execStartActivity.invoke(mBase, who,
contextThread, token, target, intent, requestCode, options);
} catch (Exception e) {
throw new RuntimeException("do not support!!! pls adapt it");
}
}
/**
* 重写newActivity 因为newActivity 方法有变
* 原来是:(Activity)cl.loadClass(className).newInstance();
*
* @param cl
* @param className
* @param intent
* @return
* @throws InstantiationException
* @throws IllegalAccessException
* @throws ClassNotFoundException
*/
@Override
public Activity newActivity(ClassLoader cl, String className,
Intent intent)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return mBase.newActivity(cl, className, intent);
}
}
public static void hookActivityThreadInstrumentation() {
//TODO:
try {
// 先获取到当前的ActivityThread对象
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");
currentActivityThreadMethod.setAccessible(true);
//currentActivityThread是一个static函数所以可以直接invoke,不需要带实例参数
Object currentActivityThread = currentActivityThreadMethod.invoke(null);
// 拿到原始的 mInstrumentation字段
Field mInstrumentationField = activityThreadClass.getDeclaredField("mInstrumentation");
mInstrumentationField.setAccessible(true);
Instrumentation mInstrumentation = (Instrumentation) mInstrumentationField.get(currentActivityThread);
// 创建代理对象
Instrumentation proxyInstrumentation = new ProxyInstrumentation(mInstrumentation);
// 偷梁换柱
mInstrumentationField.set(currentActivityThread, proxyInstrumentation);
} catch (Exception e) {
e.printStackTrace();
}
}
}