android插件开发-就是你了!启动吧!插件的activity(二)
这篇博客是上篇的延续,在阅读之前先阅读第一部分:第一部分
我们在启动插件的activity时,通过替换component成功欺骗AMS获得了启动一个activity所必须的一些资源。不过,我们还没有把获取的那些资源都转移到插件的activity之下。这一节就是解决这个问题。
所有的答案都是分析源码之后得到的,所以我们还和之前一样继续分析源码,看下AMS是怎么把资源关联到一个activity上的,这样我们才有可能转移这些资源到插件的activity之下。
在上一篇博文中我们分析到了startActivityLocked函数。在这个函数里面,我们在获得启动一个activity的信息,和要启动的activity信息之后,我们转到了startActivityUncheckedLocked函数:
final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
boolean doResume, Bundle options, TaskRecord inTask) {
...
//用来判断是否需要重新创建一个新的任务栈来启动这个activity
//在我们这里例子里面 我们newTask会一直是false
boolean newTask = false;
boolean keepCurTransition = false;
...
// Should this be considered a new task?
if (r.resultTo == null && inTask == null && !addingToTask
&& (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
...
} else if (sourceRecord != null) {
} else ....
....
//调用ActivityStack的成员函数
targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
...
return ActivityManager.START_SUCCESS;
}
之后调用的是startActivityLocked方法:
final void startActivityLocked(ActivityRecord r, boolean newTask,
boolean doResume, boolean keepCurTransition, Bundle options) {
...
if (!newTask) {
// If starting in an existing task, find where that is...
boolean startIt = true;
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
task = mTaskHistory.get(taskNdx);
if (task.getTopActivity() == null) {
// All activities in task are finishing.
continue;
}
if (task == r.task) {
// Here it is! Now, if this is not yet visible to the
// user, then just add it without starting; it will
// get started when the user navigates back to it.
if (!startIt) {
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task "
+ task, new RuntimeException("here").fillInStackTrace());
task.addActivityToTop(r);
r.putInHistory();
mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0,
r.userId, r.info.configChanges, task.voiceSession != null,
r.mLaunchTaskBehind);
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
ActivityOptions.abort(options);
return;
}
break;
} else if (task.numFullscreen > 0) {
startIt = false;
}
}
}
...
//把要启动的activity压入活动栈中
task.addActivityToTop(r);
task.setFrontOfTask();
...
//我们显然是要让activity显示 所以这里一定会执行
if (doResume) {
mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
}
}
这个函数做的事情很简单,就是把要启动的activity压到活动栈的栈顶,这里又证实了我们之前的猜想:
AMS解析Intent,获得ActivityRecord,而ActivityRecord用来表示一个activity,至于如何解析Intent获得ActivityRecord,内容和网上一些intent解析过程一样intent解析过程 ,而我们在代码中是显示启动一个activity,所以我们替换ComponeneName就可以
接下来我们继续转到StackSupervisor中去查看resumeTopActivitiesLocked
看下是否是最前面的一个任务活动栈(很好理解,因为你不可能一次只开一个应用,你可能在使用手机时打开QQ,微信,微博,他们都各自对应很多个活动栈),是的话就准备响应他
stack.resumeTopActivityLocked:
最后都转发到了resumeTopActivityInnerLocked
查看下:
final boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
...
// We need to start pausing the current activity so the top one
// can be resumed...
boolean dontWaitForPause = (next.info.flags&ActivityInfo.FLAG_RESUME_WHILE_PAUSING) != 0;
boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);
if (mResumedActivity != null) {
if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Pausing " + mResumedActivity);
//调用start[
pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
}
...
return true;
}
在确认一切无误之后调用startPausingLocked方法
final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,
boolean dontWait) {
...
if (prev.app != null && prev.app.thread != null) {
if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending pause: " + prev);
try {
...
//prev.app.thread返回一个IApplicationThread
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
userLeaving, prev.configChangeFlags, dontWait);
} catch (Exception e) {
...
}
} else {
...
}
...
}
prev.app.thread返回一个IApplicationThread,它通知Ui线程可以终止当前正在响应的activity了,我要开启新的activity了!
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
userLeaving, prev.configChangeFlags, dontWait);
在本例中就是:
这里prev.appToken是一个IBinder对象,其他的都是Boolean还有Configuration类型,我们不难得出,AMS区分activity是谁就是通过这个IBinder对象(Token是IBinder的实现类)!!!
为了验证我们的猜想,还是继续阅读源码:
Handler中的处理代码:
IBinder被保存在Message的obj中,之后调用handlePauseActivity函数:
//mActiv