参考博文
http://www.tuicool.com/articles/EjEJNrJ
http://m.w2bc.com/article/126583
AMS对startActivity请求处理及返回过程
根据上一章的分析了解了调用startActivity(),终于把数据和要开启Activity的请求发送到了AMS了,接下来分析在AMS中的处理过程和重新回到app进程。
1、在AMS中处理的过程
AMS中处理startActivity的过程比较复杂,主要涉及了ActivityManagerService、ActivityStackSupervisor、ActivityStack、PackageManagerService、WindowManagerService等几个类。
在ActivityManagerService中,startActivity先是调用了startActivityAsUser(注意,第一个参数caller就是app在服务端的代理ApplicationThreadProxy,它是一个Binder对象,实现了IApplicationThread。):
public final int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
resultWho, requestCode, startFlags, profilerInfo, bOptions,
UserHandle.getCallingUserId());
}
然后在startActivityAsUser中调用了ActivityStackSupervisor的startActivityMayWait。
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
......
// TODO: Switch to user app stacks here.
return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
profilerInfo, null, null, bOptions, false, userId, null, null);
}
转到ActivityStackSupervisor中后,又在它和ActivityStack之间来回调用了许多次,主要是进行栈和Task的管理、解析Activity的信息,准备窗口的切换之类的工作,最后回到了ActivityStackSupervisor中,调用realStartActivityLocked函数。
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
......
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,
task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
}
在realStartActivityLocked函数中,app是ProcessRecord类型,app.thread是IApplicationThread类型,也就是从客户端的代理ApplicationThreadProxy,在这儿调用了它的scheduleLaunchActivity方法,接下来就是回到app的进程空间里的过程。
2、AMS回到app进程
再回顾一下AMS和app之间交互原理图:
ActivityThread的类图结构:
ApplicationThreadProxy中scheduleLaunchActivity方法:
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) throws RemoteException {
......
mRemote.transact(SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
}
在该方法中调用IBinder的transact发出命令,然后由ApplicationThread的代理ApplicationThreadNative的onTransact来处理:
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
......
case SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION:
{
......
scheduleLaunchActivity(intent, b, ident, info, curConfig, overrideConfig, compatInfo,
referrer, voiceInteractor, procState, state, persistentState, ri, pi,
notResumed, isForward, profilerInfo);
return true;
}
}
ApplicationThreadNative的onTransact函数会调用scheduleLaunchActivity,其具体实现在ApplicationThread中:
private class ApplicationThread extends ApplicationThreadNative {
......
@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.referrer = referrer;
r.voiceInteractor = voiceInteractor;
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
r.persistentState = persistentState;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
r.startsNotResumed = notResumed;
r.isForward = isForward;
r.profilerInfo = profilerInfo;
r.overrideConfig = overrideConfig;
updatePendingConfiguration(curConfig);
sendMessage(H.LAUNCH_ACTIVITY, r);
}
}
ApplicationThread是ActivityThread里的一个内部类,它的scheduleLaunchActivity的实现就是发一个LAUNCH_ACTIVITY类型的message到ActivityThread中的一个handler上。
private class H extends Handler {
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
......
}
}
H类继承自Handler也是Activity Thread的内部类,重写了handleMessage(Message msg)方法。根据标识LAUNCH_ACTIVITY调用了handleLaunchActivity()方法,handleLaunchActivity里调用了performLaunchActivity:
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
......
Activity a = performLaunchActivity(r, customIntent);
}
performLaunchActivity中又用到了Instrumentation类,调它的newActivity函数构造出activity对象。newActivity函数很简单,直接用classLoader加载了Activity类,然后用反射调它的构造函数newInstance出activity实例:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
}
public Activity newActivity(ClassLoader cl, String className,
Intent intent)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return (Activity)cl.loadClass(className).newInstance();
}
然后再回到performLaunchActivity中,在通过newActivity得到activity的实例后,接下来就该调用它的生命周期函数onCreate了,照旧还是通过Instrumentation来完成,调用它的callActivityOnCreate函数。
activity.mCalled = false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
在callActivityOnCreate里会调用Activity的performCreate函数,它里面调用的就是我们熟悉的onCreate了。
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
restoreHasCurrentPermissionRequest(icicle);
onCreate(icicle, persistentState);
mActivityTransitionState.readState(icicle);
performCreateCommon();
}
app到AMS过程时序图:
总结:到此为止,startActivity的整个流程就结束了,从整个完整流程可以看出,Instrumentation这个类是startActivity整个过程中的必经之路,无论是从app到AMS,还是从AMS回到app都会经过它,所以它就是Hook对象。并且它是ActivityThread里的一个成员mInstrumentation,所以我们在客户端进程中可以通过反射拿到ActivityThread对象,也可以拿到mInstrumentation。
在早期版本中,作者hook的是newActivity,最新版本将其改为对handler.callback进行hook。为什么?
通过请教作者,他给我的答复是:“提前hook时机,可以减少“善后”工作,handler是跑到App进程最开始的地方,到了newActivity实际上有很多事已经被做掉了,需要再通过反射来重置一些参数,比如Resources,这意味着一件事你实际上做了两次。所以越早处理越好。”
Small中对StartActivity的返回处理解析
根据以上原理分析我们知道ActivityThread中的内部类H继承自handler处理主线程消息对列(MessageQueue)中的Message。因为Android的UI操作是由handler机制进行的,所以在Activity的创建需要通过H类处理。Small框架在对AMS到app的过程进行Hook的就是H类。具体在ApkBundleLauncher实现如下:
public void setUp(Context context) {
......
// 反射获取ActivityThread类中mH成员变量
field = activityThreadClass.getDeclaredField("mH");
field.setAccessible(true);
//获得activityThread对象中mH成员变量的属性值
Handler ah = (Handler) field.get(thread);
//反射获取Handler类中mCallback成员变量
field = Handler.class.getDeclaredField("mCallback");
field.setAccessible(true);
//向ah对象中赋值为ActivityThreadHandlerCallback()
//此刻的field是mCallback成员变量,下面就将ActivityThreadHandlerCallback的实例赋给mCallback变量
field.set(ah, new ActivityThreadHandlerCallback());
}
由以上可知Small主要改变了H类中mCallback成员变量的值。
为什么要这样做呢?
根据handler源码解析可知,Handler内部是通过执行dispatchMessage方法以实现对Message的处理的,Handler的dispatchMessage的源码如下:
public void dispatchMessage(Message msg) {
//注意下面这行代码
if (msg.callback != null) {
handleCallback(msg);
} else {
//注意下面这行代码
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//注意下面这行代码
handleMessage(msg);
}
}
我们来分析下这段代码:
1.首先会判断msg.callback存不存在,如果msg.callback存在,这种情况下会执行handleCallback(msg), handleCallback源码如下:
private static void handleCallback(Message message) {
message.callback.run();
}
2.如果msg.callback就是null,代码继续往下执行,接着我们会判断Handler的成员字段mCallback存不存在。mCallback是Hanlder.Callback类型的,我们在上面提到过,在Handler的构造函数中我们可以传递Hanlder.Callback类型的对象,该对象需要实现handleMessage方法,如果我们在构造函数中传递了该Callback对象,那么我们就会让Callback的handleMessage方法来处理Message。
3.如果我们在构造函数中没有传入Callback类型的对象,那么mCallback就为null,那么我们会调用Handler自身的hanldeMessage方法,该方法默认是个空方法,我们需要自己是重写实现该方法。
综上,我们可以看到Handler提供了三种途径处理Message,而且处理有前后优先级之分:首先尝试让postXXX中传递的Runnable执行,其次尝试让Handler构造函数中传入的Callback的handleMessage方法处理,最后才是让Handler自身的handleMessage方法处理Message。
因此Small对mCallback进行hook实现的就是第二种处理方式,ActivityThreadHandlerCallback中具体代码如下:
private static class ActivityThreadHandlerCallback implements Handler.Callback {
private static final int LAUNCH_ACTIVITY = 100;
@Override
public boolean handleMessage(Message msg) {
if (msg.what != LAUNCH_ACTIVITY) return false;
Object/*ActivityClientRecord*/ r = msg.obj;
//获取到r中的Intent对象
Intent intent = ReflectAccelerator.getIntent(r);
//使用unwrapIntent方法将插件的类名赋给targetClass
String targetClass = unwrapIntent(intent);
if (targetClass == null) return false;
// 替换上插件类对应的activityInfo
ActivityInfo targetInfo = sLoadedActivities.get(targetClass);
ReflectAccelerator.setActivityInfo(r, targetInfo);
return false;
}
}
代码分析可知,handleMessage方法中主要
是将msg.obj中存根的activityInfo中变成插件类对应的activityInfo,以供后续实例Activity和调用onCreate时使用。
重点:
重写的mCallback.handleMessage(msg)返回的是false,为什么要这样做呢?
这样做的目的是为了实现在handler里dispatchMessage方法中对Message的处理除了执行了第二种方式,还接着执行第三种方式。这样做为了实现对源码的轻度hook来达到将存根Activity替换为插件Activity的过程。
unwrapIntent()方法解析:
private static String unwrapIntent(Intent intent) {
//得到该intent对象中的所有category
Set<String> categories = intent.getCategories();
if (categories == null) return null;
//通过查找categories其中名为REDIRECT_FLAG的category来找到原来插件activity类名
Iterator<String> it = categories.iterator();
while (it.hasNext()) {
String category = it.next();
if (category.charAt(0) == REDIRECT_FLAG) {
//返回对应插件activity类名
return category.substring(1);
}
}
return null;
}
app的生命周期调用最后都是由Instrumentation来执行,所以Small框架中定义的InstrumentationWrapper也对其中的callActivityOnCreate,callActivityOnStop,callActivityOnDestroy等方法进行了重写,具体如下:
callActivityOnCreate()方法解析:
@Override
/**为插件准备资源*/
public void callActivityOnCreate(Activity activity, android.os.Bundle icicle) {
do {
if (sLoadedActivities == null) break;
ActivityInfo ai = sLoadedActivities.get(activity.getClass().getName());
if (ai == null) break;
//同步插件activity对应的窗口信息
applyActivityInfo(activity, ai);
} while (false);
//调用原Instrumentation的callActivityOnCreate方法
sHostInstrumentation.callActivityOnCreate(activity, icicle);
//如果它被其他的应用程序修改了一些,复位原先的activity instrumentation
if (sBundleInstrumentation != null) {
try {
Field f = Activity.class.getDeclaredField("mInstrumentation");
f.setAccessible(true);
Object instrumentation = f.get(activity);
if (instrumentation != sBundleInstrumentation) {
f.set(activity, sBundleInstrumentation);
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
applyActivityInfo()方法解析:
/**
* 申请的插件Activity信息是与插件的AndroidManifest.xml里面一样
* @param activity
* @param ai
*/
private static void applyActivityInfo(Activity activity, ActivityInfo ai) {
// Apply window attributes
Window window = activity.getWindow();
window.setSoftInputMode(ai.softInputMode);
activity.setRequestedOrientation(ai.screenOrientation);
}
callActivityOnStop方法解析:
@Override
public void callActivityOnStop(Activity activity) {
sHostInstrumentation.callActivityOnStop(activity);
if (!Small.isUpgrading()) return;
// If is upgrading, we are going to kill self while application turn into background,
// and while we are back to foreground, all the things(code & layout) will be reload.
// Don't worry about the data missing in current activity, you can do all the backups
// with your activity's `onSaveInstanceState' and `onRestoreInstanceState'.
// Get all the processes of device (1)
ActivityManager am = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> processes = am.getRunningAppProcesses();
if (processes == null) return;
// Gather all the processes of current application (2)
// Above 5.1.1, this may be equals to (1), on the safe side, we also
// filter the processes with current package name.
String pkg = activity.getApplicationContext().getPackageName();
final List<RunningAppProcessInfo> currentAppProcesses = new ArrayList<>(processes.size());
for (RunningAppProcessInfo p : processes) {
if (p.pkgList == null) continue;
boolean match = false;
int N = p.pkgList.length;
for (int i = 0; i < N; i++) {
if (p.pkgList[i].equals(pkg)) {
match = true;
break;
}
}
if (!match) continue;
currentAppProcesses.add(p);
}
if (currentAppProcesses.isEmpty()) return;
// The top process of current application processes.
RunningAppProcessInfo currentProcess = currentAppProcesses.get(0);
if (currentProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) return;
// Seems should delay some time to ensure the activity can be successfully
// restarted after the application restart.
// FIXME: remove following thread if you find the better place to `killProcess'
new Thread() {
@Override
public void run() {
try {
sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (RunningAppProcessInfo p : currentAppProcesses) {
android.os.Process.killProcess(p.pid);
}
}
}.start();
}
callActivityOnDestroy()方法解析:
@Override
public void callActivityOnDestroy(Activity activity) {
do {
if (sLoadedActivities == null) break;
String realClazz = activity.getClass().getName();
ActivityInfo ai = sLoadedActivities.get(realClazz);
if (ai == null) break;
//存根activity与真实activity解绑
inqueueStubActivity(ai, realClazz);
} while (false);
//调用原Instrumentation的callActivityOnDestroy方法
sHostInstrumentation.callActivityOnDestroy(activity);
}
在调用到callActivityOnDestroy时,需要将存根activity与真实activity解绑,主要通过inqueueStubActivity方法实现:
private void inqueueStubActivity(ActivityInfo ai, String realActivityClazz) {
if (ai.launchMode == ActivityInfo.LAUNCH_MULTIPLE) return;
if (mStubQueue == null) return;
int countForMode = STUB_ACTIVITIES_COUNT;
int offset = (ai.launchMode - 1) * countForMode;
for (int i = 0; i < countForMode; i++) {
String stubClazz = mStubQueue[i + offset];
if (stubClazz != null && stubClazz.equals(realActivityClazz)) {
mStubQueue[i + offset] = null;
break;
}
}
}
从ActivityInfo获取launchMode,通过启动模式和插件Activity类名找到对存根Activity对应的mStubQueue数组位置并将其赋值为null,这样就实现了解绑。
**
1、由于我们欺骗了 AMS , AMS 应该只知道 StubActivity 的存在,它压根儿就不知道TargetActivity是什么,为什么它能正确完成对TargetActivity生命周期的回调呢?
一切的秘密在 token 里面。 AMS 与 ActivityThread 之间对于Activity的生命周期的交互,并没有直接使用Activity对象进行交互,而是使用一个token来标识,这个token是binder对象,因此可以方便地跨进程传递。Activity里面有一个成员变量 mToken 代表的就是它,token可以唯一地标识一个Activity对象,它在Activity的 attach 方法里面初始化;
在 AMS 处理Activity的任务栈的时候,使用这个token标记Activity,因此在Small里面, AMS 进程里面的token对应的是StubActivity,也就是 AMS 还在傻乎乎地操作StubActivity(关于这一点,你可以dump出任务栈的信息,可以观察到dump出的确实是StubActivity)。但是在我们App进程里面,token对应的却是TargetActivity!因此,在ActivityThread执行回调的时候,能正确地回调到TargetActivity相应的方法。
2、为什么App进程里面,token对应的是TargetActivity呢?
回到代码,ActivityClientRecord是在 mActivities 里面取出来的,确实是根据token取;那么这个token是什么时候添加进去的呢?我们看performLaunchActivity就完成明白了:它通过classloader加载了TargetActivity,然后完成一切操作之后把这个activity添加进了 mActivities !另外,在这个方法里面我们还能看到对Ativity attact 方法的调用,它传递给了新创建的Activity一个token对象,而这个token是在ActivityClientRecord构造函数里面初始化的。
至此我们已经可以确认,通过这种方式启动的Activity有它自己完整而独立的生命周期!
最后总结:至此,我们对Small框架中解决“Activity注册和生命周期问题”,从原理和代码两方面做了一个全面的分析。这个过程中,我弄懂了Android的activity启动流程,领会了Small框架怎么通过轻度hook实现对Android插件化的。