之前在分析Activity的时候有很多和WMS相关的,我们这里再简单总结下和WMS相关的那部分。
一、appToken在WMS中创建
在博客http://blog.csdn.net/kc58236582/article/details/52413871中在APPWindowToken创建过程这节中,我们分析到在AMS调用startActivityLocked的时候,会调用WMS的addAppToken来创建一个APPWindowToken。
-
final void startActivityLocked(ActivityRecord r, boolean newTask,
-
boolean doResume, boolean keepCurTransition, Bundle options) {
-
TaskRecord rTask = r.task;
-
final
int taskId = rTask.taskId;
-
// mLaunchTaskBehind tasks get placed at the back of the task stack.
-
if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
-
// Last activity in task had been removed or ActivityManagerService is reusing task.
-
// Insert or replace.
-
// Might not even be in.
-
insertTaskAtTop(rTask, r);
-
mWindowManager.moveTaskToTop(taskId);
-
}
-
TaskRecord task = null;
-
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_FOR_ALL_USERS) !=
0,
-
r.userId, r.info.configChanges, task.voiceSession != null,
-
r.mLaunchTaskBehind);
我们再来看看WMS的addAppToken函数,在WMS中创建了APPWindowToken然后保存在mTokenMap中。
-
public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
-
int requestedOrientation, boolean fullscreen, boolean showForAllUsers,
int userId,
-
int configChanges, boolean voiceInteraction, boolean launchTaskBehind) {
-
......
-
synchronized(mWindowMap) {
-
AppWindowToken atoken = findAppWindowToken(token.asBinder());
//如果已经有了直接退出
-
if (atoken != null) {
-
Slog.w(TAG,
"Attempted to add existing app token: " + token);
-
return;
-
}
-
atoken =
new AppWindowToken(
this, token, voiceInteraction);
//新建一个APPWindowToken
-
atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
-
atoken.appFullscreen = fullscreen;
-
atoken.showForAllUsers = showForAllUsers;
-
atoken.requestedOrientation = requestedOrientation;
-
atoken.layoutConfigChanges = (configChanges &
-
(ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) !=
0;
-
atoken.mLaunchTaskBehind = launchTaskBehind;
-
if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
"addAppToken: " + atoken
-
+
" to stack=" + stackId +
" task=" + taskId +
" at " + addPos);
-
-
Task task = mTaskIdToTask.get(taskId);
-
if (task == null) {
-
task = createTaskLocked(taskId, stackId, userId, atoken);
-
}
-
task.addAppToken(addPos, atoken);
-
-
mTokenMap.put(token.asBinder(), atoken);
//保存在mTokenMap中 token为key(Activity的binder对象)
-
-
// Application tokens start out hidden.
-
atoken.hidden =
true;
-
atoken.hiddenRequested =
true;
-
}
-
}
再来看看AppWindowToken的构造函数,它是WindowToken的子类,再调用父类构造函数的时候说明了自己是TYPE_APPLICATION类型的。参数_token指向的是一个ActivityRecord对象的IBinder接口,因此,AppWindowToken类的成员变量appToken描述的就是一个ActivityRecord对象。
-
AppWindowToken(WindowManagerService _service, IApplicationToken _token,
-
boolean _voiceInteraction) {
-
super(_service, _token.asBinder(),
-
WindowManager.LayoutParams.TYPE_APPLICATION,
true);
-
appWindowToken =
this;
-
appToken = _token;
-
voiceInteraction = _voiceInteraction;
-
mInputApplicationHandle =
new InputApplicationHandle(
this);
-
mAnimator = service.mAnimator;
-
mAppAnimator =
new AppWindowAnimator(
this);
-
}
二、Activity的attach函数
首先在博客http://blog.csdn.net/kc58236582/article/details/52397657中主要分析了Activity的创建 初始化。
handleLaunchActivity函数先调用performLaunchActivity函数,再调用handleResumeActivity函数。
在performLaunchActivity函数先新建Activity,然后调用其attach函数,最后调用了Activity的onCreate函数。
在Activity的attach函数中,主要代码如下:
-
......
-
mWindow =
new PhoneWindow(
this);
//新建PhoneWindow对象
-
mWindow.setCallback(
this);
//这window中设置回调,在按键事件分发的时候中用到。如果有这个回调,就调用Activity的dispatchKeyEvent
-
mWindow.setOnWindowDismissedCallback(
this);
-
......
-
mWindow.setWindowManager(
-
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
-
mToken, mComponent.flattenToString(),
-
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) !=
0);
-
if (mParent != null) {
-
mWindow.setContainer(mParent.getWindow());
-
}
-
mWindowManager = mWindow.getWindowManager();
三、创建ViewRootImpl、DecorView
我们继续分析,在http://blog.csdn.net/kc58236582/article/details/52411791博客,我们分析到了ViewRootImpl和DecorView的创建。
一般在Activity的onCreate函数中会调用setContentView。而在setContentView会创建DecorView对象。
下面我们再从ActivityThread的handleResumeActivity函数看,先调用了performResumeActivity函数来查找这个Activity,后面主要调用了WindowManager的addView函数。
-
final void handleResumeActivity(IBinder token,
-
boolean clearHide, boolean isForward, boolean reallyResume) {
-
// If we are getting ready to gc after going to the background, well
-
// we are back active so skip it.
-
unscheduleGcIdler();
-
mSomeActivitiesChanged =
true;
-
-
// TODO Push resumeArgs into the activity for consideration
-
ActivityClientRecord r = performResumeActivity(token, clearHide);
-
-
if (r != null) {
-
final Activity a = r.activity;
-
-
if (localLOGV) Slog.v(
-
TAG,
"Resume " + r +
" started activity: " +
-
a.mStartedActivity +
", hideForNow: " + r.hideForNow
-
+
", finished: " + a.mFinished);
-
-
final
int forwardBit = isForward ?
-
WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION :
0;
-
-
// If the window hasn't yet been added to the window manager,
-
// and this guy didn't finish itself or start another activity,
-
// then go ahead and add the window.
-
boolean willBeVisible = !a.mStartedActivity;
-
if (!willBeVisible) {
-
try {
-
willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(
-
a.getActivityToken());
-
}
catch (RemoteException e) {
-
}
-
}
-
if (r.window == null && !a.mFinished && willBeVisible) {
-
r.window = r.activity.getWindow();
-
View decor = r.window.getDecorView();
-
decor.setVisibility(View.INVISIBLE);
-
ViewManager wm = a.getWindowManager();
-
WindowManager.LayoutParams l = r.window.getAttributes();
-
a.mDecor = decor;
-
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-
l.softInputMode |= forwardBit;
-
if (a.mVisibleFromClient) {
-
a.mWindowAdded =
true;
-
wm.addView(decor, l);
-
}
我们来看WindowManagerImpl的addView函数,其实就是调用了WindowManagerGlobal的addView函数
-
@
Override
-
public
void
addView
(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
-
applyDefaultToken(params);
-
mGlobal.addView(view, params, mDisplay, mParentWindow);
-
}
之前也分析过WindowManagerGlobal,它有3个重要的成员变量:
-
private final ArrayList<View> mViews =
new ArrayList<View>();
//所有的DecorView对象
-
private final ArrayList<ViewRootImpl> mRoots =
new ArrayList<ViewRootImpl>();
//所有的ViewRootImpl对象
-
private final ArrayList<WindowManager.LayoutParams> mParams =
//所有顶层View的layout参数
-
new ArrayList<WindowManager.LayoutParams>();
们再来看WindowManagerGlobal的addView函数,这个函数先是查找是否已经在WindowManagerGlobal中已经有这个view,如果有的话就调用其ViewRootImpl的doDie函数中主要是调用WindowManagerGlobal函数去除这个ViewRootImpl对象,在这个主要是创建了ViewRootImpl,并且把DecorView,RootViewRootImpl,layout参数都保存起来了。然后调用了ViewRootImpl的setView函数。
-
public void addView(View view, ViewGroup.LayoutParams params,
-
Display display, Window parentWindow) {
-
......
-
int index = findViewLocked(view,
false);
//查找是否有该view,获取其index
-
if (index >=
0) {
-
if (mDyingViews.contains(view)) {
-
// Don't wait for MSG_DIE to make it's way through root's queue.
-
mRoots.get(index).doDie();
//调用ViewRootImpl的doDie函数
-
}
else {
-
throw
new IllegalStateException(
"View " + view
-
+
" has already been added to the window manager.");
-
}
-
// The previous removeView() had not completed executing. Now it has.
-
}
-
......
-
-
root =
new ViewRootImpl(view.getContext(), display);
//新建ViewRootImpl对象
-
-
view.setLayoutParams(wparams);
-
-
mViews.add(view);
//成员变量增加
-
mRoots.add(root);
-
mParams.add(wparams);
-
}
-
-
// do this last because it fires off messages to start doing things
-
try {
-
root.setView(view, wparams, panelParentView);
//调用ViewRootImpl的setView函数
-
}
catch (RuntimeException e) {
-
// BadTokenException or InvalidDisplayException, clean up.
-
synchronized (mLock) {
-
final
int index = findViewLocked(view,
false);
-
if (index >=
0) {
-
removeViewLocked(index,
true);
-
}
-
}
-
throw e;
-
}
-
}
四、ViewRootImpl的setView函数
上面在创建完ViewRootImpl之后会调用其setView函数,setView函数主要可以分成两个部分。
4.1 requestLayout函数
在setView中先会调用requestLayout函数,这个函数在http://blog.csdn.net/kc58236582/article/details/52421683博客中有详细分析,主要调用了WMS的relayoutWindow函数,然后通过SurfaceFlinger来创建一个Surface
4.2 addToDisplay
另一部分就是如下代码,最终会调用WMS的addWindow函数,增加窗口。在http://blog.csdn.net/kc58236582/article/details/52413871博客中WindowState的创建过程那节中有详细分析。
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mInputChannel);