之前在分析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);