Android6.0 WMS(一) WMS和應用進程的關係

之前在分析Activity的時候有很多和WMS相關的,我們這裏再簡單總結下和WMS相關的那部分。


一、appToken在WMS中創建

在博客http://blog.csdn.net/kc58236582/article/details/52413871中在APPWindowToken創建過程這節中,我們分析到在AMS調用startActivityLocked的時候,會調用WMS的addAppToken來創建一個APPWindowToken。

  1. final void startActivityLocked(ActivityRecord r, boolean newTask,
  2. boolean doResume, boolean keepCurTransition, Bundle options) {
  3. TaskRecord rTask = r.task;
  4. final int taskId = rTask.taskId;
  5. // mLaunchTaskBehind tasks get placed at the back of the task stack.
  6. if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
  7. // Last activity in task had been removed or ActivityManagerService is reusing task.
  8. // Insert or replace.
  9. // Might not even be in.
  10. insertTaskAtTop(rTask, r);
  11. mWindowManager.moveTaskToTop(taskId);
  12. }
  13. TaskRecord task = null;
  14. if (!newTask) {
  15. // If starting in an existing task, find where that is...
  16. boolean startIt = true;
  17. for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
  18. task = mTaskHistory.get(taskNdx);
  19. if (task.getTopActivity() == null) {
  20. // All activities in task are finishing.
  21. continue;
  22. }
  23. if (task == r.task) {
  24. // Here it is! Now, if this is not yet visible to the
  25. // user, then just add it without starting; it will
  26. // get started when the user navigates back to it.
  27. if (!startIt) {
  28. if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task "
  29. + task, new RuntimeException("here").fillInStackTrace());
  30. task.addActivityToTop(r);
  31. r.putInHistory();
  32. mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
  33. r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
  34. (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0,
  35. r.userId, r.info.configChanges, task.voiceSession != null,
  36. r.mLaunchTaskBehind);
我們再來看看WMS的addAppToken函數,在WMS中創建了APPWindowToken然後保存在mTokenMap中。

  1. public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
  2. int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int userId,
  3. int configChanges, boolean voiceInteraction, boolean launchTaskBehind) {
  4. ......
  5. synchronized(mWindowMap) {
  6. AppWindowToken atoken = findAppWindowToken(token.asBinder());//如果已經有了直接退出
  7. if (atoken != null) {
  8. Slog.w(TAG, "Attempted to add existing app token: " + token);
  9. return;
  10. }
  11. atoken = new AppWindowToken(this, token, voiceInteraction);//新建一個APPWindowToken
  12. atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
  13. atoken.appFullscreen = fullscreen;
  14. atoken.showForAllUsers = showForAllUsers;
  15. atoken.requestedOrientation = requestedOrientation;
  16. atoken.layoutConfigChanges = (configChanges &
  17. (ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) != 0;
  18. atoken.mLaunchTaskBehind = launchTaskBehind;
  19. if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken
  20. + " to stack=" + stackId + " task=" + taskId + " at " + addPos);
  21. Task task = mTaskIdToTask.get(taskId);
  22. if (task == null) {
  23. task = createTaskLocked(taskId, stackId, userId, atoken);
  24. }
  25. task.addAppToken(addPos, atoken);
  26. mTokenMap.put(token.asBinder(), atoken);//保存在mTokenMap中 token爲key(Activity的binder對象)
  27. // Application tokens start out hidden.
  28. atoken.hidden = true;
  29. atoken.hiddenRequested = true;
  30. }
  31. }

再來看看AppWindowToken的構造函數,它是WindowToken的子類,再調用父類構造函數的時候說明了自己是TYPE_APPLICATION類型的。參數_token指向的是一個ActivityRecord對象的IBinder接口,因此,AppWindowToken類的成員變量appToken描述的就是一個ActivityRecord對象。

  1. AppWindowToken(WindowManagerService _service, IApplicationToken _token,
  2. boolean _voiceInteraction) {
  3. super(_service, _token.asBinder(),
  4. WindowManager.LayoutParams.TYPE_APPLICATION, true);
  5. appWindowToken = this;
  6. appToken = _token;
  7. voiceInteraction = _voiceInteraction;
  8. mInputApplicationHandle = new InputApplicationHandle(this);
  9. mAnimator = service.mAnimator;
  10. mAppAnimator = new AppWindowAnimator(this);
  11. }

二、Activity的attach函數

首先在博客http://blog.csdn.net/kc58236582/article/details/52397657中主要分析了Activity的創建 初始化。

handleLaunchActivity函數先調用performLaunchActivity函數,再調用handleResumeActivity函數。

在performLaunchActivity函數先新建Activity,然後調用其attach函數,最後調用了Activity的onCreate函數。

在Activity的attach函數中,主要代碼如下:

  1. ......
  2. mWindow = new PhoneWindow(this);//新建PhoneWindow對象
  3. mWindow.setCallback(this);//這window中設置回調,在按鍵事件分發的時候中用到。如果有這個回調,就調用Activity的dispatchKeyEvent
  4. mWindow.setOnWindowDismissedCallback(this);
  5. ......
  6. mWindow.setWindowManager(
  7. (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
  8. mToken, mComponent.flattenToString(),
  9. (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
  10. if (mParent != null) {
  11. mWindow.setContainer(mParent.getWindow());
  12. }
  13. 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函數。

  1. final void handleResumeActivity(IBinder token,
  2. boolean clearHide, boolean isForward, boolean reallyResume) {
  3. // If we are getting ready to gc after going to the background, well
  4. // we are back active so skip it.
  5. unscheduleGcIdler();
  6. mSomeActivitiesChanged = true;
  7. // TODO Push resumeArgs into the activity for consideration
  8. ActivityClientRecord r = performResumeActivity(token, clearHide);
  9. if (r != null) {
  10. final Activity a = r.activity;
  11. if (localLOGV) Slog.v(
  12. TAG, "Resume " + r + " started activity: " +
  13. a.mStartedActivity + ", hideForNow: " + r.hideForNow
  14. + ", finished: " + a.mFinished);
  15. final int forwardBit = isForward ?
  16. WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
  17. // If the window hasn't yet been added to the window manager,
  18. // and this guy didn't finish itself or start another activity,
  19. // then go ahead and add the window.
  20. boolean willBeVisible = !a.mStartedActivity;
  21. if (!willBeVisible) {
  22. try {
  23. willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(
  24. a.getActivityToken());
  25. } catch (RemoteException e) {
  26. }
  27. }
  28. if (r.window == null && !a.mFinished && willBeVisible) {
  29. r.window = r.activity.getWindow();
  30. View decor = r.window.getDecorView();
  31. decor.setVisibility(View.INVISIBLE);
  32. ViewManager wm = a.getWindowManager();
  33. WindowManager.LayoutParams l = r.window.getAttributes();
  34. a.mDecor = decor;
  35. l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
  36. l.softInputMode |= forwardBit;
  37. if (a.mVisibleFromClient) {
  38. a.mWindowAdded = true;
  39. wm.addView(decor, l);
  40. }

我們來看WindowManagerImpl的addView函數,其實就是調用了WindowManagerGlobal的addView函數

  1. @Override
  2. public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
  3. applyDefaultToken(params);
  4. mGlobal.addView(view, params, mDisplay, mParentWindow);
  5. }

之前也分析過WindowManagerGlobal,它有3個重要的成員變量:

  1. private final ArrayList<View> mViews = new ArrayList<View>();//所有的DecorView對象
  2. private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();//所有的ViewRootImpl對象
  3. private final ArrayList<WindowManager.LayoutParams> mParams =//所有頂層View的layout參數
  4. new ArrayList<WindowManager.LayoutParams>();

們再來看WindowManagerGlobal的addView函數,這個函數先是查找是否已經在WindowManagerGlobal中已經有這個view,如果有的話就調用其ViewRootImpl的doDie函數中主要是調用WindowManagerGlobal函數去除這個ViewRootImpl對象,在這個主要是創建了ViewRootImpl,並且把DecorView,RootViewRootImpl,layout參數都保存起來了。然後調用了ViewRootImpl的setView函數。

  1. public void addView(View view, ViewGroup.LayoutParams params,
  2. Display display, Window parentWindow) {
  3. ......
  4. int index = findViewLocked(view, false);//查找是否有該view,獲取其index
  5. if (index >= 0) {
  6. if (mDyingViews.contains(view)) {
  7. // Don't wait for MSG_DIE to make it's way through root's queue.
  8. mRoots.get(index).doDie();//調用ViewRootImpl的doDie函數
  9. } else {
  10. throw new IllegalStateException("View " + view
  11. + " has already been added to the window manager.");
  12. }
  13. // The previous removeView() had not completed executing. Now it has.
  14. }
  15. ......
  16. root = new ViewRootImpl(view.getContext(), display);//新建ViewRootImpl對象
  17. view.setLayoutParams(wparams);
  18. mViews.add(view);//成員變量增加
  19. mRoots.add(root);
  20. mParams.add(wparams);
  21. }
  22. // do this last because it fires off messages to start doing things
  23. try {
  24. root.setView(view, wparams, panelParentView);//調用ViewRootImpl的setView函數
  25. } catch (RuntimeException e) {
  26. // BadTokenException or InvalidDisplayException, clean up.
  27. synchronized (mLock) {
  28. final int index = findViewLocked(view, false);
  29. if (index >= 0) {
  30. removeViewLocked(index, true);
  31. }
  32. }
  33. throw e;
  34. }
  35. }


四、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的創建過程那節中有詳細分析。

  1. res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
  2. getHostVisibility(), mDisplay.getDisplayId(),
  3. mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
  4. mAttachInfo.mOutsets, mInputChannel);



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章