Android 10 principle mechanism series: Activity window added to WMS process

Android 10 principle mechanism series: Activity window added to WMS process

Preface

First, let's look at the layout hierarchy of an Android interface. The most intuitive one is:

We can clearly see that this interface is divided into three parts: the top status bar (statusbar), the bottom navigation bar (navigationbar), and the application interface.

Off topic:

To view the hierarchy of the layout, the tools or approaches can be referred to below.

  • Android Studio: Tools->Layout Inspector->Select the process you want to view;
  • SDK Tools: tools/hierarchyviewer.bat. However, the latest recommendation is to use tools/monitor.bat instead of the separate hierarchyviewer.bat; hierarchyviewer.bat also exists in the project directory prebuilts/devtools/tools

This article mainly introduces the process of creating a window in Activity and adding it to WMS.

The second part is a review and conclusion, which first gives a relatively concise summary of the contents of the above two processes.

The third part is the process of adding the Activity window. Tracking the source code details the process of creating the Activity window and adding it to WMS.

Since the third part is tracing the source code, this process is relatively long, involves a lot, and is relatively boring. So the summary is put in the second part first. In this way, if you have understood the source code or this process, you can only read the second part. If you have not understood it, you can also get a general understanding of it through the second part, and then check the third part. If you encounter a part that is not clear, you can go back to the second part for comparison and understanding.

This article is also based on the source code of Android 10.

If there is anything wrong or inadequate, please feel free to point it out.

Summary

The preface has already explained why the summary is placed first. Let’s take a closer look.

The second part mainly introduces the following contents:

  • Window type: Introduction to window types
  • Several important classes: some common classes in the process of window creation and adding to WMS, and understand the relationship between them
  • Activity creation window added to WMS Overview: A brief summary of the Activity creation process and the process of adding to WMS
  • Some structural diagrams in Activity: The whole process, the relationship between some classes/structures associated with Activity, I think it is very necessary to understand this
  • Token is passed to WMS: Token is a very important parameter and is involved in the entire process. Here is a separate summary of the Token transmission process involved in this article.

Window Type

  1. //WindowManager.java
  2. public   static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
  3. public   static final int FIRST_APPLICATION_WINDOW = 1;
  4. public   static final int LAST_APPLICATION_WINDOW = 99;
  5.      
  6. public   static final int FIRST_SUB_WINDOW = 1000;
  7. public   static final int LAST_SUB_WINDOW = 1999;
  8.      
  9. public   static final int FIRST_SYSTEM_WINDOW = 2000;
  10. public   static final int LAST_SYSTEM_WINDOW = 2999;
  11. //Status bar
  12. public   static final int TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW;
  13. //Search bar
  14. public   static final int TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1;
  15. //Caller ID
  16. public   static final int TYPE_PHONE = FIRST_SYSTEM_WINDOW+2;
  17. //Warning window, common example: low battery warning
  18. public   static final int TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3;
  19. //Lock screen
  20. public   static final int TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4;
  21. //toast
  22. public   static final int TYPE_TOAST = FIRST_SYSTEM_WINDOW+5;
  23. public   static final int TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+6; //Display above all windows, covering
  24. //Incoming calls take priority even when the screen is locked
  25. public   static final int TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW+7;
  26. //Input method window
  27. public   static final int TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11;
  28. //Wallpaper
  29. public   static final int TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13;
  30. }
  • Application window (1 ~ 99): FIRST_APPLICATION_WINDOW ~ LAST_APPLICATION_WINDOW. Corresponding to an Activity, token needs to be set to the Activity's token. For example: Activity.
  • Subwindow (1000 ~ 1999): FIRST_SUB_WINDOW ~ LAST_SUB_WINDOW. There must be a parent window, and the token must be set to the parent window's token. For example: PopupWindow, attached to Activity.
  • System windows (2000 ~ 2999): FIRST_SYSTEM_WINDOW ~ LAST_SYSTEM_WINDOW. System-level windows do not need to correspond to an Activity or have a parent window. Application processes generally do not have the permission to create them, only system processes can create them. For example, some common system windows are listed above, including the status bar, incoming calls, toast, input method, etc.

Several important categories

The following classes are often seen later. Here we mainly look at their direct inheritance relationship, which will be easier to understand later.

  1. public abstract class Window {}
  2. public class PhoneWindow extends Window implements MenuBuilder.Callback {}
  3.  
  4. public interface WindowManagerPolicy extends WindowManagerPolicyConstants {}
  5. public class PhoneWindowManager implements WindowManagerPolicy {}
  6.  
  7. public interface ViewManager {
  8. public void addView( View   view , ViewGroup.LayoutParams params);
  9. public void updateViewLayout( View   view , ViewGroup.LayoutParams params);
  10. public void removeView( View   view );
  11. }
  12. public interface WindowManager extends ViewManager {}
  13. public final class WindowManagerImpl implements WindowManager {}
  14.  
  15. /** A window in the window manager. */
  16. class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState {}

Window is an abstract class. Activity, Toast, Dialog, etc. are all presented by Window.

  • PhoneWindow is the concrete implementation class of Window (almost the only implementation class).
  • WindowManager is an interface that inherits the ViewManager interface (ViewManager defines three operations: add, update, and remove).
  • WindowManagerImpl is the implementation class of WindowManager.

However, looking at the three operations of ViewManager in WindowManagerImpl, it can be seen that these three implementations are ultimately completed by WindowManagerGlobal.

WindowState maintains all the information of the window. WMS manages the window and saves the state through WindowState.

Activity creates a window and adds it to the WMS overview

This is the code process of tracking, which is summarized here for easy reference and understanding. The red ones are the main node methods.

  1. //attach()
  2. -performLaunchActivity()
  3. --activity.attach()//Creates PhoneWindow(mWindow). mWindowManager stores the WindowManagerImpl created by setWindowManager() obtained from mWindow.  
  4. ---mWindow.setWindowManager() //WindowManagerImpl(mWindowManager) is created inside PhoneWindow, and appToken and appName are saved.  
  5.  
  6. //onCreate()
  7. -setContentView()
  8. --installDecor()  
  9. ---generateDecor()//Created DecorView(mDecor)  
  10. ---generateLayout()//Add the activity layout as a subview (ViewGroup) to mDecor  
  11.  
  12. //onResume()
  13. -r.activity.makeVisible()//
  14. --wm.addView(mDecor, ...) //wm is mWindowManager (WindowManagerImpl object)  
  15. ---WindowManagerGlobal.addView()//Created ViewRootImpl. The view of addView is mDecor, and mWindow is created in ViewRootImpl (here is an IBinder, not created in attach())  
  16. ----ViewRootImpl.setView()//openSession() creates a Session (a proxy class of IWindowSession), and view is also mDecor. mDecor is passed to mView of ViewRootImpl  
  17. -----Session.addToDisplay()//Enter the system_server process through Session  
  18. ------mService.addWindow()//Enter WMS and execute addWindow() to add a window  

Attach stage:

  • An Activity creates a PhoneWindow object, and PhoneWindow creates a WindowManagerImpl through setWindowManager().

That is, the Activity corresponds to a PhoneWindow and gets a WindowManager (WindowManagerImpl, created by Window).

onCreate stage:

  • Create a DecorView and add the activity's layout to it.

onResume phase:

  • ViewRootImpl is created, and finally the session enters the system_server process through setView(). Finally, addWindow is executed to add the window to WMS.

Some structural diagrams in Activity

The following is a drawing based on my understanding in the learning summary, which is convenient for you to check at a glance.

(If there is anything wrong, thank you for your advice)

  1. public final class WindowManagerImpl implements WindowManager {
  2. private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
  3. }
  4.  
  5. public final class WindowManagerGlobal {
  6. private static IWindowManager sWindowManagerService; //WMS client,
  7. private static IWindowSession sWindowSession;//Session
  8. private final ArrayList< View > mViews = new ArrayList< View >();
  9. private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
  10. private final ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>();
  11. }
  • One Activity corresponds to one PhoneWindow object. That is, each Activity corresponds to one Window (the specific implementation class is PhoneWindow).
  • A PhoneWindow holds a DecorView instance. DecorView is actually a FrameLayout, which is the root (top-level View) of all Views in the Activity.
  • A PhoneWindow has a WindowManagerImpl. WindowManagerImpl holds a singleton WindowManagerGlobal.

Token is passed to WMS

When an Activity is started, AMS will create an ActivityRecord for it. For more information, see: The first startup process of an AMS application.

Let's take a look at some codes about token in ActivityRecord:

  1. final class ActivityRecord extends ConfigurationContainer {
  2. final IApplicationToken.Stub appToken; // window manager token
  3. // TODO: Remove after unification
  4. AppWindowToken mAppWindowToken;
  5.          
  6. ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller,...) {
  7. appToken = new Token(this, _intent);
  8. }
  9.      
  10. void createAppWindowToken() {
  11. mAppWindowToken = createAppWindow(mAtmService.mWindowManager, appToken,...);
  12. }
  13.      
  14. static class Token extends IApplicationToken.Stub {
  15. Token(ActivityRecord activity, Intent intent) {
  16. weakActivity = new WeakReference<>(activity);
  17. name = intent.getComponent().flattenToShortString();
  18. }
  19. }
  20. }

The member variable appToken in ActivityRecord is very important and will be involved in many places later.

There is an appToken in ActivityRecord, which is an IBinder (the internal class Token inherits the IApplicationToken interface). Token holds a weak reference to the Activity.

In ActivityRecord, the AppWindowToken object is created and saved to mAppWindowToken through createAppWindow().

mAppWindowToken: This appToken will be encapsulated in it. Path: ActivityStack.startActivityLocked()->ActivityRecord.createAppWindowToken(). AppWindowToken is a subclass of WindowToken. WindowToken can mark a window.

This appToken will be passed to the Activity as a parameter in Activity.attach().

Activity is saved to mToken.

Then pass it to Window(PhoneWindow) through Activity.attach()->mWindow.setWindowManager().

Window is saved to mAppToken.

WindowManagerGlobal.addView()->Window.adjustLayoutParamsForSubWindow() is saved to the token variable in WindowManager.LayoutParams.

Finally, WindowManager.LayoutParams (where token is the appToken in ActivityRecord) is passed as a parameter to ViewRootImpl.setView().

In ViewRootImpl, mWindowAttributes copies WindowManager.LayoutParams and passes it into WMS as a parameter through Session.addToDisplay() for subsequent operations.

This is the process in which appToken participates and passes during the entire process of adding a window (to addWindow()).

How appToken participates in adding windows can be roughly seen in the comments of "Part 3 2.8: mService.addWindow()", which is quite detailed.

Activity window adding process

This mainly introduces the creation of the Window corresponding to the Activity and the process of adding the Window to WMS.

Activity window creation

During the first launch of an AMS application, from clicking the application icon to creating the activity and executing onCreate(). The following is an excerpt from the latter part. If you are not sure, you can refer to the following article.

1.1: handleLaunchActivity()

Start here with handleLaunchActivity().

  1. //ActivityThread.java
  2. @Override
  3. public Activity handleLaunchActivity(ActivityClientRecord r,
  4. PendingTransactionActions pendingActions, Intent customIntent) {
  5. ...
  6. WindowManagerGlobal.initialize();
  7. final Activity a = performLaunchActivity(r, customIntent);
  8. ...
  9. }
  10.  
  11. private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
  12. ...
  13. try {
  14. java.lang.ClassLoader cl = appContext.getClassLoader();
  15. activity = mInstrumentation.newActivity(
  16. cl, component.getClassName(), r.intent);
  17. }
  18. try {
  19. Application app = r.packageInfo.makeApplication( false , mInstrumentation);
  20. if (activity != null ) {
  21. Window window = null ;
  22. ...
  23. //attach(), pay attention to this r.token. Refer to 1.2
  24. activity.attach(appContext, this, getInstrumentation(), r.token,
  25. r.ident, app, r.intent, r.activityInfo, title, r.parent,
  26. r.embeddedID, r.lastNonConfigurationInstances, config,
  27. r.referrer, r.voiceInteractor, window, r.configCallback,
  28. r.assistToken);
  29. if (r.isPersistable()) {
  30. //callActivityOnCreate() The onCreate() method of the activity that is finally executed.
  31. //Refer to 1.4
  32. mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
  33. } else {
  34. mInstrumentation.callActivityOnCreate(activity, r.state);
  35. }
  36. }
  37. }
  38. ...
  39. return activity;
  40. }

WindowManagerGlobal.initialize(); is to obtain the IBinder proxy class of WMS, which is used to communicate with WMS. The code is not listed here.

Next we need to look at activity.attach(). Note that the r.token passed as a parameter to attach() is an IBinder from ActivityClientRecord, which simply identifies an Activity.

1.2: activity.attach()

  1. //Activity.java
  2. final void attach(Context context, ActivityThread aThread,
  3. Instrumentation instr, IBinder token, ...) {
  4. ...
  5. //Create PhoneWindow
  6. mWindow = new PhoneWindow(this, window, activityConfigCallback);//Create PhoneWindow
  7. //Set up the soft keyboard
  8. if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
  9. mWindow.setSoftInputMode(info.softInputMode);
  10. }
  11. //Save token to mToken.
  12. mToken = token;
  13. ...
  14. //mToken is passed to Window, refer to 1.3
  15. mWindow.setWindowManager(
  16. (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
  17. mToken, mComponent.flattenToString(),
  18. (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
  19. //mWindowManager is the WindowManagerImpl created in setWindowManager().
  20. mWindowManager = mWindow.getWindowManager();
  21. ...
  22. }

First, create the Window corresponding to Activityd, which is the implementation class of PhoneWindow-Window. Then look at mWindow.setWindowManager().

1.3: mWindow.setWindowManager()

  1. //Window.java
  2. public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
  3. boolean hardwareAccelerated) {
  4. //ActivityClientRecord.token
  5. mAppToken = appToken;
  6. mAppName = appName;
  7. mHardwareAccelerated = hardwareAccelerated;
  8. if (wm == null ) {
  9. wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
  10. }
  11. //Created WindowManagerImpl. Note that mParentWindow in WindowManagerImpl is this, not empty
  12. mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
  13. }

Here, the WindowManagerImpl object, which is the implementation class of WindowManager, is created, and appToken, appName, and mWindowManager are saved.

Through setWindowManager(), WindowManager (WindowManagerImpl) is created for Window (or PhoneWindow).

1.4: setContentView()

mInstrumentation.callActivityOnCreate() eventually calls onCreate() of Activity.

To customize the Activity and set the layout, setContentView() is executed. Let's take a look at this method directly.

  1. //Activity.java
  2. public void setContentView(@LayoutRes int layoutResID) {
  3. getWindow().setContentView(layoutResID);//
  4. initWindowDecorActionBar();
  5. }
  6.  
  7.  
  8. public Window getWindow() {
  9. return mWindow; //PhoneWindow object
  10. }
  11.  
  12. //PhoneWindow.java
  13. // This is the top - level   view   of the window, containing the window decor.
  14. private DecorView mDecor;
  15. @Override
  16. public void setContentView( int layoutResID) {
  17. // Note: FEATURE_CONTENT_TRANSITIONS may be set   in the process of installing the window
  18. // decor, when theme attributes and the like are crystalized. Do not   check the feature
  19. // before this happens.
  20. if (mContentParent == null ) {
  21. installDecor();//
  22. } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
  23. mContentParent.removeAllViews();
  24. }
  25. if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
  26. final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
  27. getContext());
  28. transitionTo(newScene);
  29. } else {
  30. mLayoutInflater.inflate(layoutResID, mContentParent);
  31. }
  32. ...
  33. }
  34.  
  35. private void installDecor() {
  36. mForceDecorInstall = false ;
  37. if (mDecor == null ) {
  38. //Generate DecorView, refer to 1.5
  39. mDecor = generateDecor(-1);
  40. ...
  41. } else {
  42. mDecor.setWindow(this);
  43. }
  44. if (mContentParent == null ) {
  45. //Add the layout to DecorView, refer to 1.5
  46. mContentParent = generateLayout(mDecor);
  47.  
  48. // Set up decor part of UI to   ignore fitsSystemWindows if appropriate.
  49. mDecor.makeOptionalFitsSystemWindows();
  50.  
  51. final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
  52. R.id.decor_content_parent);
  53. if (decorContentParent != null ) {
  54. } else {
  55. mTitleView = findViewById(R.id.title);
  56. }
  57. ...
  58. }
  59. }

Here we mainly focus on the following two methods: mDecor = generateDecor(-1); and mContentParent = generateLayout(mDecor);.

Let's take a look at their relevant code first:

1.5: generateDecor() and generateLayout()

  1. protected DecorView generateDecor( int featureId) {
  2. // System process doesn't have application context and   in that case we need to directly use
  3. // the context we have. Otherwise we want the application context, so we don't cling to the
  4. // activity.
  5. Context context;
  6. ...
  7. return new DecorView(context, featureId, this, getAttributes());//
  8. }
  9.  
  10. public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
  11. }
  12.  
  13. protected ViewGroup generateLayout(DecorView decor) {
  14. ...
  15. mDecor.startChanging();
  16. mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
  17. ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
  18. ...
  19. mDecor.finishChanging();
  20. return contentParent;
  21. }
  22.  
  23. //DecorView.java
  24. void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
  25. ...
  26. mDecorCaptionView = createDecorCaptionView(inflater);
  27. final View root = inflater.inflate(layoutResource, null );
  28. if (mDecorCaptionView != null ) {
  29. if (mDecorCaptionView.getParent() == null ) {
  30. addView(mDecorCaptionView,
  31. new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
  32. }
  33. mDecorCaptionView.addView(root,
  34. new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
  35. } else {
  36.  
  37. // Put it below the color views.
  38. addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
  39. }
  40. mContentRoot = (ViewGroup) root;
  41. initializeElevation();
  42. }

A DecorView is created through generateDecor(). DecorView is actually a FrameLayout.

Then, through generateLayout(), the activity's layout is finally added to DecorView as a subview (ViewGroup).

As can be seen above, from the activity generation to the execution of onCreate(), during this process, the activity generates the associated PhoneWindow, and then creates WindowManagerImpl and DecorView.

Let's look at the process of adding a Window to WMS and see how these created objects are connected to form the structural diagram introduced at the beginning.

Window added to the WMS process

In the first startup process of the AMS application, onCreate is mainly discussed. In fact, onResume is also included. I will not explain it in detail here. I will list the relevant code again:

  1. //ActivityStackSupervisor.java:
  2. boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
  3. boolean andResume, boolean checkConfig) throws RemoteException {
  4. ...
  5. try {
  6. ...
  7. try {
  8. // Create activity launch transaction .
  9. final ClientTransaction clientTransaction = ClientTransaction.obtain(
  10. proc.getThread(), r.appToken);
  11.  
  12. final DisplayContent dc = r.getDisplay().mDisplayContent;
  13. clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
  14. ...
  15. // Set desired final state.
  16. final ActivityLifecycleItem lifecycleItem;
  17. if (andResume) {
  18. lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward());
  19. } else {
  20. lifecycleItem = PauseActivityItem.obtain();
  21. }
  22. clientTransaction.setLifecycleStateRequest(lifecycleItem);
  23.  
  24. // Schedule transaction .
  25. mService.getLifecycleManager().scheduleTransaction(clientTransaction);
  26. ...
  27. }
  28. }
  29. ...
  30. return   true ;
  31. }

The final result of the association with LaunchActivityItem is to create the application's Activity and execute attach() and onCreate(). andResume is true (the parameter passed in is true, you can refer to that code section to see it forward), and the final execution result of the association with ResumeActivityItem is ActivityThread.handleResumeActivity().

Here we look at ActivityThread.handleResumeActivity().

2.1: ActivityThread.handleResumeActivity()

  1. //ActivityThread.java
  2. @Override
  3. public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
  4. String reason) {
  5. ...
  6. // TODO Push resumeArgs into the activity for consideration
  7. //Execute onStart()->onResume(). Refer to 2.2
  8. final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
  9. final Activity a = r.activity;
  10. if (r.window == null && !a.mFinished && willBeVisible) {
  11. r.window = r.activity.getWindow();
  12. View decor = r.window.getDecorView();
  13. decor.setVisibility( View .INVISIBLE);
  14. ViewManager wm = a.getWindowManager();
  15. WindowManager.LayoutParams l = r.window.getAttributes();
  16. a.mDecor = decor;
  17. l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
  18. ...
  19. }
  20. ...
  21. // The window is now visible if it has been added, we are not  
  22. // simply finishing, and we are not starting another activity.
  23. if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
  24. ...
  25. r.activity.mVisibleFromServer = true ;
  26. mNumVisibleActivities++;
  27. if (r.activity.mVisibleFromClient) {
  28. //Refer to 2.3
  29. r.activity.makeVisible();
  30. }
  31. }
  32. ...
  33. }

Note that View decor = r.window.getDecorView(); gets the DecorView object, and finally assigns DecorView to the Activity through a.mDecor = decor;.

Here are two of them:

  1. performResumeActivity()  
  2. r.activity.makeVisible();

2.2: performResumeActivity()

  1. //ActivityThread.java
  2. @VisibleForTesting
  3. public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest,
  4. String reason) {
  5. final ActivityClientRecord r = mActivities.get(token);
  6. ...
  7. try {
  8. r.activity.onStateNotSaved();
  9. r.activity.mFragments.noteStateNotSaved();
  10. ...
  11. r.activity.performResume(r.startsNotResumed, reason);
  12.  
  13. r.state = null ;
  14. r.persistentState = null ;
  15. r.setState(ON_RESUME);
  16.  
  17. reportTopResumedActivityChanged(r, r.isTopResumedActivity, "topWhenResuming" );
  18. }
  19. return r;
  20. }
  21.  
  22. //Activity.java
  23. final void performResume(boolean followedByPause, String reason) {
  24. performRestart( true /* start */, reason);
  25. mInstrumentation.callActivityOnResume(this);
  26. }
  27.  
  28. final void performRestart(boolean start, String reason) {
  29. mInstrumentation.callActivityOnRestart(this);
  30. }
  31.  
  32. //Instrumentation.java
  33. public void callActivityOnRestart(Activity activity) {
  34. activity.onRestart();
  35. }
  36.  
  37. public void callActivityOnResume(Activity activity) {
  38. activity.mResumed = true ;
  39. activity.onResume();
  40. ...
  41. }

r.activity.performResume() in performResumeActivity() calls back the performResume() method of Activity. Finally, the onResume() method of Activity is executed.

Before performing onResume(), performRestart() is called, which ultimately calls the activity's onStart(). It can be seen here that onStart() is executed before onResume().

2.3: r.activity.makeVisible()

  1. //Activity.java
  2. void makeVisible() {
  3. if (!mWindowAdded) {
  4. ViewManager wm = getWindowManager();
  5. wm.addView(mDecor, getWindow().getAttributes());
  6. mWindowAdded = true ;
  7. }
  8. mDecor.setVisibility( View .VISIBLE);
  9. }
  10.  
  11. //WindowManagerImpl.java
  12. public final class WindowManagerImpl implements WindowManager {
  13. @UnsupportedAppUsage
  14. private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
  15. @Override
  16. public void addView(@NonNull View   view , @NonNull ViewGroup.LayoutParams params) {
  17. applyDefaultToken(params);
  18. //mParentWindow is the window manager that creates WindowManagerImpl. Refer to 2.4
  19. mGlobal.addView( view , params, mContext.getDisplay(), mParentWindow);
  20. }
  21. }

The getWindowManager() here gets the WindowManagerImpl object created by setWindowManager() during attach() mentioned earlier.

As mentioned earlier, the three operations such as addView() are defined and implemented in WindowManagerGlobal, which can be seen here.

2.4: WindowManagerGlobal.addView()

  1. //WindowManagerGlobal
  2. @UnsupportedAppUsage
  3. private final ArrayList< View > mViews = new ArrayList< View >();
  4. @UnsupportedAppUsage
  5. private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
  6. public void addView( View   view , ViewGroup.LayoutParams params,
  7. Display display, Window parentWindow) {
  8. ...
  9. final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
  10. if (parentWindow != null ) {
  11. //Adjust the Window parameters. This process sets the token.
  12. //Refer to 2.4.1
  13. parentWindow.adjustLayoutParamsForSubWindow(wparams);
  14. }
  15. ...
  16. ViewRootImpl root;
  17. View panelParentView = null ;
  18. synchronized (mLock) {
  19. ...
  20. root = new ViewRootImpl( view .getContext(), display);
  21. view .setLayoutParams(wparams);
  22. mViews.add ( view );
  23. mRoots.add (root);
  24. mParams.add (wparams);
  25. try {
  26. //Set the view and related parameters to ViewRootImpl. ViewRootImpl will add a new window to WMS, apply for Surface and do drawing work, etc.
  27. //Refer to 2.6
  28. root.setView( view , wparams, panelParentView);
  29. }
  30. ...
  31. }
  32. }
  33.  
  34. //ViewRootImpl.java
  35. @UnsupportedAppUsage
  36. final IWindowSession mWindowSession;
  37. public ViewRootImpl(Context context, Display display) {
  38. mContext = context;
  39. // Created Session(), refer to 2.5
  40. mWindowSession = WindowManagerGlobal.getWindowSession();
  41. mDisplay = display;
  42. mBasePackageName = context.getBasePackageName();
  43. mThread = Thread.currentThread();
  44. mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
  45. //The mWindow here is not the PhoneWindow in the previous Activity, it is W extends IWindow.Stub
  46. mWindow = new W(this);
  47. mViewVisibility = View .GONE;
  48. //Create AttachInfo
  49. mAttachInfo = new View .AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
  50. context);
  51. ...
  52. }
  53.  
  54. static class W extends IWindow.Stub {...}
  55.  
  56. //ViewRootImpl.java
  57. public final class ViewRootImpl implements ViewParent,
  58.  
  59. // View .java
  60. final static class AttachInfo {
  61. AttachInfo(IWindowSession session, IWindow window, Display display,
  62. ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer,
  63. Context context) {
  64. mSession = session;
  65. mWindow = window;
  66. mWindowToken = window.asBinder();
  67. mDisplay = display;
  68. mViewRootImpl = viewRootImpl;
  69. mHandler = handler;
  70. mRootCallbacks = effectPlayer;
  71. mTreeObserver = new ViewTreeObserver(context);
  72. }
  73. }

Here we can see that the ViewRootImpl object is created. This class implements the necessary protocol between View and WindowManager.

Note that mWindow = new W(this); in the creation, this W inherits IWindow.Stub.

When creating a ViewRootImpl object, a mAttachInfo = View.AttachInfo() is created. AttachInfo is a series of binding information. mWindowSession and mWindow are passed in as parameters. When creating AttachInfo, note that mWindowToken = window.asBinder();

  • mWindowSession is described in subsequent 2.5/2.6/2.7. It is a Session object, a proxy class of IWindowSession, through which the binder interface can communicate with WMS.
  • mWindow is the W object, which is IWindow.Stub, created by new. You can see that it will be passed to WMS later. It is the binder interface for WMS to call back the application (communicate with the application).
  • mWindowToken, which is the IBinder object of W, is also the interface for WMS to communicate with applications.

After creating the ViewRootImpl object, WindowManagerGlobal saves View, ViewRootImpl, and LayoutParams into the corresponding ArrayList. As mentioned earlier, WindowManagerGlobal is a singleton, and there is only one in the application process. Finally, View (here is DecorView) is passed to ViewRootImpl through root.setView().

2.4.1: adjustLayoutParamsForSubWindow()

As we saw earlier, mAppToken is passed in from Activity.

Here mAppToken is set to WindowManager.LayoutParams, and later we can see that it is finally passed to WMS for processing.

  1. //Window.java
  2. void adjustLayoutParamsForSubWindow(WindowManager.LayoutParams wp) {
  3. CharSequence curTitle = wp.getTitle();
  4. //Subwindow, this article is the application window, so I won’t go through this, but I’ll also learn about it.
  5. if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
  6. wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
  7. if (wp.token == null ) {
  8. View decor = peekDecorView();
  9. if (decor != null ) {
  10. wp.token = decor.getWindowToken();
  11. }
  12. }
  13. ...
  14. //System window, don't go this way either
  15. } else if (wp.type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW &&
  16. wp.type <= WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
  17. ...
  18. //Application window, this article goes here
  19. } else {
  20. if (wp.token == null ) {
  21. //Set to WindowManager.LayoutParams
  22. wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
  23. }
  24. ...
  25. }
  26. ...
  27. }

2.4.2: Learn more about AttachInfo

ViewRootImpl and each View. Through the following process, the AttachInfo binding information is set to each View, that is, each View can obtain various related information.

2.6 After executing ViewRootImpl.setView(), refer to the process: setView()->requestLayout()->scheduleTraversals()->mTraversalRunnable->doTraversal()->performTraversals()->host.dispatchAttachedToWindow(mAttachInfo, 0)->View.dispatchAttachedToWindow()->ViewGroup.dispatchAttachedToWindow().

The AttachInfo belonging to the same ViewGroup is the same.

  1. //ViewGroup.java
  2. @Override
  3. @UnsupportedAppUsage
  4. void dispatchAttachedToWindow(AttachInfo info, int visibility) {
  5. mGroupFlags |= FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
  6. super.dispatchAttachedToWindow(info, visibility);
  7. mGroupFlags &= ~FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
  8.  
  9. final int   count = mChildrenCount;
  10. final View [] children = mChildren;
  11. for ( int i = 0; i < count ; i++) {
  12. final View child = children[i];
  13. child.dispatchAttachedToWindow(info,
  14. combineVisibility(visibility, child.getVisibility()));
  15. }
  16. final int transientCount = mTransientIndices == null ? 0 : mTransientIndices. size ();
  17. for ( int i = 0; i < transientCount; ++i) {
  18. View   view = mTransientViews.get(i);
  19. view .dispatchAttachedToWindow(info,
  20. combineVisibility(visibility, view .getVisibility()));
  21. }
  22. }
  23. }

The above process performTraversals() has a general understanding: traverse the view tree from top to bottom, each View draws itself, and ViewGroup notifies the child View to draw. Measure performMeasure() Perform layout performLayout() Draw performDraw().

The important part of Android drawing is here. If you need to understand it, you can study this method (performTraversals()) carefully. I will not pay attention to it here.

2.5: WindowManagerGlobal.getWindowSession()

  1. // WindowManagerGlobal.java
  2. @UnsupportedAppUsage
  3. public   static IWindowSession getWindowSession() {
  4. synchronized (WindowManagerGlobal.class) {
  5. if (sWindowSession == null ) {
  6. try {
  7. InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
  8. IWindowManager windowManager = getWindowManagerService();
  9. //Create a Session object
  10. sWindowSession = windowManager.openSession(
  11. new IWindowSessionCallback.Stub() {
  12. @Override
  13. public void onAnimatorScaleChanged( float scale) {
  14. ValueAnimator.setDurationScale(scale);
  15. }
  16. });
  17. } catch (RemoteException e) {
  18. throw e.rethrowFromSystemServer();
  19. }
  20. }
  21. return sWindowSession;
  22. }
  23. }
  24.  
  25. //WindowManagerService.java
  26. @Override
  27. public IWindowSession openSession(IWindowSessionCallback callback) {
  28. return new Session(this, callback);
  29. }

Get the Sessiond object, if not, create it through windowManager.openSession(). Session is the proxy class of IWindowSession, and then return it to mWindowSession in ViewRootImpl.

2.6: ViewRootImpl.setView()

  1. //ViewRootImpl.java
  2. public void setView( View   view , WindowManager.LayoutParams attrs, View panelParentView) {
  3. synchronized (this) {
  4. if (mView == null ) {
  5. mView = view ;
  6. mWindowAttributes.copyFrom(attrs);
  7. ...
  8. // Schedule the first layout -before- adding to the window
  9. // manager, to make sure we do the relayout before receiving
  10. // any other events from the system.
  11. requestLayout();//TODO
  12. try {
  13. mOrigWindowType = mWindowAttributes.type;
  14. mAttachInfo.mRecomputeGlobalAttributes = true ;
  15. collectViewAttributes();
  16. //Refer to 2.7, enter the system_server process
  17. res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
  18. getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
  19. mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
  20. mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
  21. mTempInsets);
  22. setFrame(mTmpFrame);
  23. }
  24. ...
  25. }
  26. }
  27. }

res = mWindowSession.addToDisplay(): mWindowSession is the created Session returned above, mWindowSession.addToDisplay() enters the system_server process through binder and executes Session.addToDisplay().

mView is DecorView.

The mWindow here is mentioned in 2.4, which is W inherited from IWindow.Stub. This is an IBinder object, which is created when the application process creates ViewRootImpl.

Here mWindowSession.addToDisplay() can be seen being passed to WMS.

2.7: Session.addToDisplay()

  1. //Session.java
  2. class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
  3. final WindowManagerService mService;
  4. public Session(WindowManagerService service, IWindowSessionCallback callback) {
  5. mService = service;
  6. ...
  7. }
  8.  
  9. @Override
  10. public   int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
  11. int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
  12. Rect outStableInsets, Rect outOutsets,
  13. DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
  14. InsetsState outInsetsState) {
  15. //Refer to 2.8
  16. return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
  17. outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel,
  18. outInsetsState);
  19. }
  20. }

Enter WMS and add Window.

2.8: mService.addWindow()

Finally, we come to WMS.addWindow(), where we complete the window addition. You can carefully look at the source code and comments below. Even though this method has been shortened a lot, it is still quite long and requires patience.

  1. //WindowManagerService.java
  2. public   int addWindow(Session session, IWindow client, int seq,
  3. LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
  4. Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
  5. DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
  6. InsetsState outInsetsState) {
  7. int [] appOp = new int [1];
  8. // Check permissions, no permission can not add window
  9. int res = mPolicy.checkAddPermission(attrs, appOp);
  10. if (res != WindowManagerGlobal.ADD_OKAY) {
  11. return res;
  12. }
  13.  
  14. boolean reportNewConfig = false ;
  15. WindowState parentWindow = null ;
  16. ...
  17. final int type = attrs.type;
  18. synchronized (mGlobalLock) {
  19. ...
  20. //Get the DisplayContent to which the window is to be added. That is, on which screen it is displayed
  21. final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token);
  22.          
  23. if (displayContent == null ) {
  24. Slog.w(TAG_WM, "Attempted to add window to a display that does not exist: "  
  25. + displayId + ". Aborting." );
  26. return WindowManagerGlobal.ADD_INVALID_DISPLAY;
  27. }
  28. if (!displayContent.hasAccess(session.mUid)) {
  29. Slog.w(TAG_WM, "Attempted to add window to a display for which the application "  
  30. + "does not have access: " + displayId + ". Aborting." );
  31. return WindowManagerGlobal.ADD_INVALID_DISPLAY;
  32. }
  33.  
  34. if (mWindowMap.containsKey(client.asBinder())) {
  35. Slog.w(TAG_WM, "Window " + client + " is already added" );
  36. return WindowManagerGlobal.ADD_DUPLICATE_ADD;
  37. }
  38. //To add a child window, the parent window must exist.
  39. if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
  40. parentWindow = windowForClientLocked( null , attrs.token, false );
  41. if (parentWindow == null ) {
  42. Slog.w(TAG_WM, "Attempted to add window with token that is not a window: "  
  43. + attrs.token + ". Aborting." );
  44. return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
  45. }
  46. //Here we can see that WMS requires the window level to be at most two layers
  47. if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
  48. && parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {
  49. Slog.w(TAG_WM, "Attempted to add window with token that is a sub-window: "  
  50. + attrs.token + ". Aborting." );
  51. return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
  52. }
  53. }
  54. if (type == TYPE_PRIVATE_PRESENTATION && !displayContent.isPrivate()) {
  55. Slog.w(TAG_WM, "Attempted to add private presentation window to a non-private display. Aborting." );
  56. return WindowManagerGlobal.ADD_PERMISSION_DENIED;
  57. }
  58.  
  59. AppWindowToken atoken = null ;
  60. final boolean hasParent = parentWindow != null ;
  61. //Get WindowToken and use the parent window's token for the child window.
  62. //Take it out from mTokenMap through attrs.token: private final HashMap<IBinder, WindowToken> mTokenMap = new HashMap();
  63. //About Activity window: WindowToken. As mentioned earlier, AppWindowToken is created when ActivityRecord is created. During this process, appToken and AppWindowToken are saved in mTokenMap.
  64. WindowToken token = displayContent.getWindowToken(
  65. hasParent ? parentWindow.mAttrs.token : attrs.token);
  66.  
  67. // If this is a child window, we want to apply the same type checking rules as the
  68. // parent window type.
  69. final int rootType = hasParent ? parentWindow.mAttrs.type : type;
  70. boolean addToastWindowRequiresToken = false ;
  71. //The following is the relationship between WindowToken and window
  72. if (token == null ) {
  73. //For the following window types, WindowToken cannot be empty
  74. if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
  75. Slog.w(TAG_WM, "Attempted to add application window with unknown token "  
  76. + attrs.token + ". Aborting." );
  77. return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
  78. }
  79. if (rootType == TYPE_INPUT_METHOD) {
  80. Slog.w(TAG_WM, "Attempted to add input method window with unknown token "  
  81. + attrs.token + ". Aborting." );
  82. return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
  83. }
  84. if (rootType == TYPE_VOICE_INTERACTION) {
  85. Slog.w(TAG_WM, "Attempted to add voice interaction window with unknown token "  
  86. + attrs.token + ". Aborting." );
  87. return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
  88. }
  89. if (rootType == TYPE_WALLPAPER) {
  90. Slog.w(TAG_WM, "Attempted to add wallpaper window with unknown token "  
  91. + attrs.token + ". Aborting." );
  92. return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
  93. }
  94. if (rootType == TYPE_DREAM) {
  95. Slog.w(TAG_WM, "Attempted to add Dream window with unknown token "  
  96. + attrs.token + ". Aborting." );
  97. return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
  98. }
  99. if (rootType == TYPE_QS_DIALOG) {
  100. Slog.w(TAG_WM, "Attempted to add QS dialog window with unknown token "  
  101. + attrs.token + ". Aborting." );
  102. return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
  103. }
  104. if (rootType == TYPE_ACCESSIBILITY_OVERLAY) {
  105. Slog.w(TAG_WM, "Attempted to add Accessibility overlay window with unknown token "  
  106. + attrs.token + ". Aborting." );
  107. return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
  108. }
  109. if (type == TYPE_TOAST) {
  110. // Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
  111. if (doesAddToastWindowRequireToken(attrs.packageName, callingUid,
  112. parentWindow)) {
  113. Slog.w(TAG_WM, "Attempted to add a toast window with unknown token "  
  114. + attrs.token + ". Aborting." );
  115. return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
  116. }
  117. }
  118. final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
  119. final boolean isRoundedCornerOverlay =
  120. (attrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0;
  121. //Token is empty, except for the above window type, the others are allowed. Create a new WindowToken at this time
  122. token = new WindowToken(this, binder, type, false , displayContent,
  123. session.mCanAddInternalSystemWindow, isRoundedCornerOverlay);
  124. //Token is not empty, and it is the application window type. AppWindowToken type is when token is needed.
  125. } else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
  126. //Judge whether token is AppWindowToken type
  127. //I know earlier that Activity creates AppWindowToken, that is, the obtained atoken is not empty
  128. atoken = token.asAppWindowToken();
  129. if (atoken == null ) {
  130. Slog.w(TAG_WM, "Attempted to add window with non-application token "  
  131. + token + ". Aborting." );
  132. return WindowManagerGlobal.ADD_NOT_APP_TOKEN;
  133. } else if (atoken.removed) {
  134. Slog.w(TAG_WM, "Attempted to add window with exiting application token "  
  135. + token + ". Aborting." );
  136. return WindowManagerGlobal.ADD_APP_EXITING;
  137. } else if (type == TYPE_APPLICATION_STARTING && atoken.startingWindow != null ) {
  138. Slog.w(TAG_WM, "Attempted to add starting window to token with already existing"  
  139. + " starting window" );
  140. return WindowManagerGlobal.ADD_DUPLICATE_ADD;
  141. }
  142. //All other window types handle
  143. } else if (rootType == TYPE_INPUT_METHOD) {
  144. ...
  145. }...
  146. //WindowState maintains the information of all windows, it is the "window" actually managed by WMS
  147. //It is closely related to Z- Order (multiple Window Cascading Layout). The larger the mLayer, the higher the window.
  148. final WindowState win = new WindowState(this, session, client, token, parentWindow,
  149. appOp[0], seq, attrs, viewVisibility, session.mUid,
  150. session.mCanAddInternalSystemWindow);
  151. if (win.mDeathRecipient == null ) {
  152. // Client has apparently died, so there is   no reason to  
  153. // continue .
  154. Slog.w(TAG_WM, "Adding window client " + client.asBinder()
  155. + " that is dead, aborting." );
  156. return WindowManagerGlobal.ADD_APP_EXITING;
  157. }
  158. ...
  159. origId = Binder.clearCallingIdentity();
  160. //Create a SurfaceSession to communicate with SurfaceFlinger. Refer to 2.9 for a brief description
  161. win.attach();
  162. //Add WindowState object to mWindowMap
  163. mWindowMap.put(client.asBinder(), win);
  164. win.initAppOpsState();
  165. ...
  166. final AppWindowToken aToken = token.asAppWindowToken();
  167. win.mToken.addWindow(win);
  168. win.applyAdjustForImeIfNeeded();
  169. ...
  170. }
  171. ...
  172. return res;
  173. }

WMS manages windows, saves status, etc. through WindowState.

When adding windows, you need to specify its WindowToken; at the same time, the windows need to specify its DisplayContent to determine which screen device to be displayed to.

For details, please see the comments above, which are more detailed.

After reading it, you can roughly understand the window type and the role of WindowToken in window addition. Understand the role of token.

For example: If a child window is added, it must have a parent window, and the window level is at most two layers. WindowToken is null, so it can be clearly seen that those situations are not allowed to be added. When applying windows when adding windows, if the WindowToken is AppWindowToken. etc.

addWindow() will talk about this for the time being.

The result after this addition was finally returned to 2.6 through res: ViewRootImpl.setView() and continues to be processed according to the result.

2.9: win.attach()

Why does win.attach() create communication with SurfaceFlinger? Let's take a brief look.

Tracking continues to create a SurfaceSession object, which enters native, and ultimately creates a SurfaceComposerClient that communicates with the SurfaceFlinger. Therefore, it is possible to communicate with the SurfaceFlinger.

The mSurface created when ViewRootImpl is created. mSurface is a member variable of ViewRootImpl. The Surface created at this time has nothing. Finally, enter WMS through relayoutWindow() and send a request to SurfaceFlinger step by step.

Several related codes are available at this time.

  1. //WindowState.java
  2. void attach() {
  3. if (localLOGV) Slog.v(TAG, "Attaching " + this + " token=" + mToken);
  4. mSession.windowAddedLocked(mAttrs.packageName);
  5. }
  6.  
  7. //Session.java
  8. void windowAddedLocked(String packageName) {
  9. mPackageName = packageName;
  10. mRelayoutTag = "relayoutWindow: " + mPackageName;
  11. if (mSurfaceSession == null ) {
  12. mSurfaceSession = new SurfaceSession();
  13. ...
  14. }
  15. mNumWindow++;
  16. }
  17.  
  18. //ViewRootImpl.java
  19. // These can be accessed by   any thread, must be protected with a lock.
  20. // Surface can never be reassigned or cleared (use Surface.clear()).
  21. @UnsupportedAppUsage
  22. public final Surface mSurface = new Surface();
  23. private final SurfaceControl mSurfaceControl = new SurfaceControl();

Here we will only talk about adding windows to WMS, and we will summarize them later on the processing after window addition, the calculation and display update of interfaces, etc.

<<:  Huawei AppGallery enters Chengdu, fully empowering game developers from the dimensions of development, operation, and overseas expansion

>>:  It’s been 10 years! This is the first code of WeChat

Recommend

Fish bone stuck in throat, swallow rice and drink vinegar?

Popular saying: Many people have experienced fish...

Information flow of Internet promotion channels!

Our marketing channels are located where there ar...

How much does it cost to customize a sports mini program in Yichang?

According to industry insiders, mini programs wil...

Big model drives service upgrade, the exploration and practice of Jetour Auto

On May 15, the 2024 Spring Volcano Engine FORCE P...

Alibaba and the Treasure Map of the Forty Thieves

Introduction to the treasure map of Alibaba and t...

32-bit is dead. What does this mean for Android and Apple?

[[405514]] This article is reproduced from Leipho...

Google adds new call status bar indicator to Android 12

Google recently pushed the Android 12 Beta 2 upda...

3 Steps to User Growth Strategy

John has written about some methods of fission be...