以下分析基于Android S.
简述
上文中我们知道Activity的Window被添加至WMS其实就是该Activity的ViewRootImpl中的W作为IWindow、存储该Activity窗口属性信息的LayoutParams以及InputChannel被传入WMS,然后生成WindowToken, 当然之后WindowToken自然是保存在DisplayContent.mTokenMap中,该map的key即对应Activity中的mToken(LocalActivityRecord)。
在Activity的Window被添加至WMS中,我们仅仅分析了一半,然后重点区分析了DisplayContent的构建,了解了其层次结构器的创建过程以及layer的个数和Window类型对应的layer。现在我们接着看WindowToken的创建,上文中留有一个疑问:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| DisplayArea.Tokens findAreaForToken(int windowType, boolean ownerCanManageAppTokens, boolean roundedCornerOverlay) { int windowLayerFromType = mWmService.mPolicy.getWindowLayerFromTypeLw(windowType, ownerCanManageAppTokens, roundedCornerOverlay); if (windowLayerFromType == APPLICATION_LAYER) { throw new IllegalArgumentException( "There shouldn't be WindowToken on APPLICATION_LAYER"); } return mAreaForLayer[windowLayerFromType]; }
|
因为Activity对应的windowType是TYPE_BASE_APPLICATION,所以拿到的windowLayerFromType就是APPLICATION_LAYER,那么这里必然会抛出异常!
当然按照正常理解来说,必然不会发生异常才对,所以是我们流程分析哪里有问题? 是也不是,这里就要留意到应用启动过程了,回到Activity的启动过程,我们先看ActivityRecord的创建过程。
一. ActivityRecord的创建
ActivityRecord类是WindowToken子类:
而且从名字中也可以看出,这个类应该是和Activity一一对应的,那么应该在Activity启动流程中哪个步骤创建其对象呢?不难理解,肯定是在startActivity的过程中。
Activity的启动流程这里就不展开了,直接看关键代码.
1.1 ActivityTaskManagerService.startActivity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| private int startActivityAsUser(IApplicationThread caller, String callingPackage, @Nullable String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) { ...... return getActivityStartController().obtainStarter(intent, "startActivityAsUser") .setCaller(caller) .setCallingPackage(callingPackage) .setCallingFeatureId(callingFeatureId) .setResolvedType(resolvedType) .setResultTo(resultTo) .setResultWho(resultWho) .setRequestCode(requestCode) .setStartFlags(startFlags) .setProfilerInfo(profilerInfo) .setActivityOptions(bOptions) .setUserId(userId) .execute(); }
|
将Activity的启动委托给ActivityStarter执行。
1.2 ActivityStarter.execute
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
| int execute() { try { ...... synchronized (mService.mGlobalLock) { ...... res = executeRequest(mRequest); ...... }
private int executeRequest(Request request) { ...... Task inTask = request.inTask; ...... final ActivityRecord r = new ActivityRecord.Builder(mService) .setCaller(callerApp) .setLaunchedFromPid(callingPid) .setLaunchedFromUid(callingUid) .setLaunchedFromPackage(callingPackage) .setLaunchedFromFeature(callingFeatureId) .setIntent(intent) .setResolvedType(resolvedType) .setActivityInfo(aInfo) .setConfiguration(mService.getGlobalConfiguration()) .setResultTo(resultRecord) .setResultWho(resultWho) .setRequestCode(requestCode) .setComponentSpecified(request.componentSpecified) .setRootVoiceInteraction(voiceSession != null) .setActivityOptions(checkedOptions) .setSourceRecord(sourceRecord) .build(); ...... mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession, request.voiceInteractor, startFlags, true , checkedOptions, inTask, restrictedBgActivity, intentGrants); ...... }
|
ActivityRecord的初始化是采用了Build模式.
1.2.1 ActivityRecord的初始化
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
| private ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller, int _launchedFromPid, int _launchedFromUid, String _launchedFromPackage, @Nullable String _launchedFromFeature, Intent _intent, String _resolvedType, ActivityInfo aInfo, Configuration _configuration, ActivityRecord _resultTo, String _resultWho, int _reqCode, boolean _componentSpecified, boolean _rootVoiceInteraction, ActivityTaskSupervisor supervisor, ActivityOptions options, ActivityRecord sourceRecord, PersistableBundle persistentState, TaskDescription _taskDescription, long _createTime) {
super(_service.mWindowManager, new Token(_intent).asBinder(), TYPE_APPLICATION, true, null , false );
mAtmService = _service; appToken = (Token) token; info = aInfo; ...... appToken.attach(this); ...... }
static class Token extends IApplicationToken.Stub { ...... private void attach(ActivityRecord activity) { if (weakActivity != null) { throw new IllegalStateException("Already attached..." + this); } weakActivity = new WeakReference<>(activity); } ......
|
所以ActivityRecord里的appToken其实是ActivityRecord初始化时创建的Token(为IApplicationToken.Stub的子类),里面保存了该Activity的Intent信息。
1.3 ActivityStarter.startActivityUnchecked
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 82
| private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, Task inTask, boolean restrictedBgActivity, NeededUriGrants intentGrants) { ...... result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor, startFlags, doResume, options, inTask, restrictedBgActivity, intentGrants); ...... }
int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, Task inTask, boolean restrictedBgActivity, NeededUriGrants intentGrants) { setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession, voiceInteractor, restrictedBgActivity); ...... final Task reusedTask = getReusableTask(); ...... final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask(); final boolean newTask = targetTask == null; mTargetTask = targetTask; ...... final ActivityRecord targetTaskTop = newTask ? null : targetTask.getTopNonFinishingActivity(); if (targetTaskTop != null) { startResult = recycleTask(targetTask, targetTaskTop, reusedTask, intentGrants); if (startResult != START_SUCCESS) { return startResult; } } else { mAddingToTask = true; } ...... final Task topRootTask = mPreferredTaskDisplayArea.getFocusedRootTask(); if (topRootTask != null) { startResult = deliverToCurrentTopIfNeeded(topRootTask, intentGrants); if (startResult != START_SUCCESS) { return startResult; } } if (mTargetRootTask == null) { mTargetRootTask = getLaunchRootTask(mStartActivity, mLaunchFlags, targetTask, mOptions); } if (newTask) { final Task taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null) ? mSourceRecord.getTask() : null; setNewTask(taskToAffiliate); } else if (mAddingToTask) { addOrReparentStartingActivity(targetTask, "adding to task"); } ...... mTargetRootTask.startActivityLocked(mStartActivity, topRootTask != null ? topRootTask.getTopNonFinishingActivity() : null, newTask, mKeepCurTransition, mOptions, startFromSamePackage); ...... }
private void setNewTask(Task taskToAffiliate) { final boolean toTop = !mLaunchTaskBehind && !mAvoidMoveToFront; final Task task = mTargetRootTask.reuseOrCreateTask( mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info, mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession, mVoiceInteractor, toTop, mStartActivity, mSourceRecord, mOptions); mService.getTransitionController().collectExistenceChange(task); addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask - mReuseTask");
...... }
|
这里我们假设启动的Activity是应用的首个Activity,而且也没有设置affinity,这样在启动该Activity时,会创建新的Task, 并在该Task中保存ActivityRecord!
1.3.1 ActivityStarter.setInitialState - 设置初始化状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| private void setInitialState(ActivityRecord r, ActivityOptions options, Task inTask, boolean doResume, int startFlags, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, boolean restrictedBgActivity) { reset(false );
mStartActivity = r; ...... mLaunchParams.reset(); ...... mPreferredTaskDisplayArea = mLaunchParams.hasPreferredTaskDisplayArea() ? mLaunchParams.mPreferredTaskDisplayArea : mRootWindowContainer.getDefaultTaskDisplayArea(); }
|
这里首先先清理ActivityStarter内部成员,然后依次赋值。
1.4 ActivityStarter.addOrReparentStartingActivity
1 2 3 4 5 6 7 8 9 10
| private void addOrReparentStartingActivity(Task parent, String reason) { if (mStartActivity.getTask() == null || mStartActivity.getTask() == parent) { parent.addChild(mStartActivity); } else { mStartActivity.reparent(parent, parent.getChildCount() , reason); } }
|
1.5 Task.addChild
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| void addChild(ActivityRecord r) { addChild(r, Integer.MAX_VALUE ); }
@Override void addChild(WindowContainer child, int index) { boolean hadChild = hasChild(); final int activityType = getActivityType(); index = getAdjustedChildPosition(child, index); super.addChild(child, index); ...... }
|
1.5.1 Task.getActivityType
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @Override public int getActivityType() { final int applicationType = super.getActivityType(); if (applicationType != ACTIVITY_TYPE_UNDEFINED || !hasChild()) { return applicationType; } return getTopChild().getActivityType(); }
public int getActivityType() { return mFullConfiguration.windowConfiguration.getActivityType(); }
@ActivityType public int getActivityType() { return mActivityType; }
|
ActivityType有如下取值:
名称 |
值 |
含义 |
ACTIVITY_TYPE_UNDEFINED |
0 |
Activity类型尚未定义 |
ACTIVITY_TYPE_STANDARD |
1 |
标准Activity类型 |
ACTIVITY_TYPE_HOME |
2 |
Home或Launcher的Activity类型 |
ACTIVITY_TYPE_RECENTS |
3 |
Recents或者Overview的Activity类型,系统中只有一个具有此类型的Activity |
ACTIVITY_TYPE_ASSISTANT |
4 |
Assistant Activity类型 |
ACTIVITY_TYPE_DREAM |
5 |
Dream Activity类型 |
一般情况都是ACTIVITY_TYPE_STANDARD或者ACTIVITY_TYPE_HOME类型。当前Task获取的值应该是初始化的默认值:
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
| private Configuration mFullConfiguration = new Configuration();
public final WindowConfiguration windowConfiguration = new WindowConfiguration();
public WindowConfiguration() { unset(); }
public void unset() { setToDefaults(); }
public void setToDefaults() { setAppBounds(null); setBounds(null); setMaxBounds(null); setWindowingMode(WINDOWING_MODE_UNDEFINED); setActivityType(ACTIVITY_TYPE_UNDEFINED); setAlwaysOnTop(ALWAYS_ON_TOP_UNDEFINED); setRotation(ROTATION_UNDEFINED); setDisplayWindowingMode(WINDOWING_MODE_UNDEFINED); }
|
可以看到,ActivityType是被设置成:ACTIVITY_TYPE_UNDEFINED,也即未定义类型!
1.5.2 Task.getAdjustedChildPosition
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
| private int getAdjustedChildPosition(WindowContainer wc, int suggestedPosition) { final boolean canShowChild = wc.showToCurrentUser();
final int size = mChildren.size();
int minPosition = (canShowChild) ? computeMinUserPosition(0, size) : 0; int maxPosition = (canShowChild) ? size : computeMaxUserPosition(size - 1);
if (!wc.isAlwaysOnTop()) {
while (maxPosition > minPosition) { if (!mChildren.get(maxPosition - 1).isAlwaysOnTop()) break; --maxPosition; } }
if (suggestedPosition == POSITION_BOTTOM && minPosition == 0) { return POSITION_BOTTOM; } else if (suggestedPosition == POSITION_TOP && maxPosition >= (size - 1)) { return POSITION_TOP; } return Math.min(Math.max(suggestedPosition, minPosition), maxPosition); }
|
这里是通过检查WindowContainer是否可见的属性以及是否应该永远处于最上层来调整该WC应该被插入Task的哪个位置。
当我们ActivityRecord被添加入一个新建的Task时,毫无疑问应该是处于最上层即返回POSITION_TOP。
1.5.2.1 WindowContainer.isAlwaysOnTop
1 2 3 4 5 6 7
| public boolean isAlwaysOnTop() { if (mWindowingMode == WINDOWING_MODE_PINNED) return true; if (mActivityType == ACTIVITY_TYPE_DREAM) return true; if (mAlwaysOnTop != ALWAYS_ON_TOP_ON) return false; return mWindowingMode == WINDOWING_MODE_FREEFORM || mWindowingMode == WINDOWING_MODE_MULTI_WINDOW; }
|
说明如下情况,该WindowContainer应该始终处于所在Task的最上层:
- window模式为WINDOWING_MODE_PINNED
- Activity类型是ACTIVITY_TYPE_DREAM
- 当mAlwaysOnTop为ALWAYS_ON_TOP_ON,window模式为WINDOWING_MODE_FREEFORM或WINDOWING_MODE_MULTI_WINDOW
1.6 WindowContainer.addChild
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @CallSuper void addChild(E child, int index) { ...... if (index == POSITION_TOP) { index = mChildren.size(); } else if (index == POSITION_BOTTOM) { index = 0; }
mChildren.add(index, child);
child.setParent(this); }
|
@CallSuper: 是Android中特有的注解,如果子类覆盖了同名方法而没有显示调用父类的该方法时就会报错!
这个也挺简单的,首先最后调整一下index:
- 如果传入的index为POSITION_TOP,则将index设置为当前mChildren的size值,意为将待存入的child保存在mChildren中最后一位(上面)
- 如果传入的index为POSITION_BOTTOM, 则将index设置为0,意为将待存入的child保存在mChildren中第一位(下面)
然后让child(ActivityRecord)保存该WC(即Task)。
1.7 WindowContainer.setParent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| final protected void setParent(WindowContainer<WindowContainer> parent) { final WindowContainer oldParent = mParent; mParent = parent;
if (mParent != null) { mParent.onChildAdded(this); } if (!mReparenting) { onSyncReparent(oldParent, mParent); if (mParent != null && mParent.mDisplayContent != null && mDisplayContent != mParent.mDisplayContent) { onDisplayChanged(mParent.mDisplayContent); } onParentChanged(mParent, oldParent); } }
|
设置WC(ActivityRecord)的父集(mParent, 即保存该WC的Task), 如有必要同步Task中DisplayContent至该WC中。
1.7.1 ActivityRecord.onParentChanged
1 2 3 4 5 6 7 8
| @Override void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) { final Task oldTask = oldParent != null ? (Task) oldParent : null; final Task newTask = newParent != null ? (Task) newParent : null; this.task = newTask; ...... }
|
将传入的ConfigurationContainer作为Task,存入ActivityRecord.task中,其余部分暂时先不研究。
1.8 ActivityRecord.onDisplayChanged
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
| @Override void onDisplayChanged(DisplayContent dc) { DisplayContent prevDc = mDisplayContent; super.onDisplayChanged(dc); ...... }
@Override void onDisplayChanged(DisplayContent dc) { dc.reParentWindowToken(this);
super.onDisplayChanged(dc); }
void onDisplayChanged(DisplayContent dc) { if (mDisplayContent != null && mDisplayContent.mChangingContainers.remove(this)) { mSurfaceFreezer.unfreeze(getPendingTransaction()); } mDisplayContent = dc; if (dc != null && dc != this) { dc.getPendingTransaction().merge(mPendingTransaction); } for (int i = mChildren.size() - 1; i >= 0; --i) { final WindowContainer child = mChildren.get(i); child.onDisplayChanged(dc); } for (int i = mListeners.size() - 1; i >= 0; --i) { mListeners.get(i).onDisplayChanged(dc); } }
|
这里最主要的是理清ActivityRecord、WindowToken、Task和WindowContainer之间的继承关系:
1.9 DisplayContent.reParentWindowToken
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| void reParentWindowToken(WindowToken token) { final DisplayContent prevDc = token.getDisplayContent(); if (prevDc == this) { return; } if (prevDc != null) { ...... }
addWindowToken(token.token, token); ...... }
|
由于此时还处于ActivityRecord刚被创建,正在第一次被设置DisplayContent时,所以其DisplayContent此时还是null的。那么就直接将该WindowToken(即ActivityRecord)保存在此DisplayContent中,注意token.token其实是WindowToken.token, 这个值我们之前分析过,是attrs.token,也就是从App进程传入的LocalActivityRecord.
1.10 DisplayContent.addWindowToken
1 2 3 4 5 6 7 8 9 10
| void addWindowToken(IBinder binder, WindowToken token) { final DisplayContent dc = mWmService.mRoot.getWindowTokenDisplay(token); ...... mTokenMap.put(binder, token); if (token.asActivityRecord() == null) { ...... } }
|
好了,我们终于明白了一个ActivityRecord是如何被添加进DisplayContent中了,看到这里是不是似曾相识呢?Bingo, 之前我们的windowToken创建时会抛出一个异常,就是因为这个WindowToken.asActivityRecord返回值为null, 导致DisplayContent中添加该WindowToken时找不到合适layer!
1 2 3 4 5 6 7
| int windowLayerFromType = mWmService.mPolicy.getWindowLayerFromTypeLw(windowType, ownerCanManageAppTokens, roundedCornerOverlay);
if (windowLayerFromType == APPLICATION_LAYER) { throw new IllegalArgumentException( "There shouldn't be WindowToken on APPLICATION_LAYER"); }
|
现在我们知道了,在app的Activity被resume时,早就已经有了其WindowToken(ActivityRecord)被保存在DisplayContent的mTokenMap中。所以回过头我们看WMS.addWindow方法:
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
| public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility, int displayId, int requestUserId, InsetsState requestedVisibility, InputChannel outInputChannel, InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { ...... final int type = attrs.type; synchronized (mGlobalLock) { ...... WindowToken token = displayContent.getWindowToken( hasParent ? parentWindow.mAttrs.token : attrs.token); ...... if (token == null) { ..... } ... final WindowState win = new WindowState(this, session, client, token, parentWindow, appOp[0], attrs, viewVisibility, session.mUid, userId, session.mCanAddInternalSystemWindow); ...... win.attach(); mWindowMap.put(client.asBinder(), win); ...... win.mToken.addWindow(win); ...... ...... }
|
啊哈,异常解除,因为Activity需要resume必须先start, 而start过程中就会创建其对应ActivityRecord并保存在对应DisplayContent的mTokenMap中!
最后附上一张时序图以备忘:
接下来,我们继续看WMS.addWindow的流程:WindowState的创建及其管理。