preface
Why is this article about Windows Manager in the first place rather than looking directly at Windows ManagerService? What is the relationship between them? This is because in order to understand WMS, you need to understand WindowManager first, and WindowManager is the class most closely associated with WMS, so it kind of lays the groundwork for WMS. This article will cover Windows Manager in more detail. To recap, we’ve looked at SystemServer, the four major components, and AMS startup analysis. After an Activity starts, you need to parse XML into a View and add a View to the Window. How does Windows relate to Windows Manager? Let’s take a look at why. If you haven’t read this series, you are advised to read it first. Otherwise, it will not be easy to understand the process of adding or binding WMS to Windows directly.
Android 8.0 source code analysis (a) SystemServer process started
Android 8.0 source code analysis (ii) Launcher
Android 8.0 source code analysis (three) application process creation to the application startup process
Android 8.0 source code analysis (four) Activity start
Android 8.0 source code analysis (5) Service startup
Android 8.0 source code analysis (6) BroadcastReceiver launch
Android 8.0 source code analysis (seven) ContentProvider start
ActivityManagerService
Android 8.0 source code analysis (nine) WindowManager
Android 8.0 source code analysis (ten) WindowManagerService window management
The relationship between Windows, WindowManager, and WMS
-
Window: Window is an abstract class that implements PhoneWindow and manages views.
//Window.java public abstract class Window {... }//PhoneWindow.java public class PhoneWindow extends Window implements MenuBuilder.Callback {... }Copy the code
-
WindowManager is an interface class, inherited from the interface ViewManager, from its name know that it is used to manage Windows, its implementation class is WindowManagerImpl.
//ViewManager.java public interface ViewManager { / / add the View public void addView(View view, ViewGroup.LayoutParams params); / / update public void updateViewLayout(View view, ViewGroup.LayoutParams params); / / delete public void removeView(View view); } //WindowManager.java public interface WindowManager extends ViewManager {... }//WindowManagerImpl public final class WindowManagerImpl implements WindowManager {... }Copy the code
If you want to add, update, or delete Windows, you can use the WindowManager class. WindowManager hands over the work to WMS, which communicates with its Binder. This is the same with ActivityManager and AMS.
Let’s use a diagram of their relationship to illustrate their connection
Windows contains the View and manages the View, WindowManager manages the Window, and the functionality provided by WindowManager is ultimately handled by WMS.
WindowManager’s associated class
Next, we will analyze the WindowManager associated classes from the source point of view, from which we can better understand the relationship between Windows and WindowManager.
As we learned in the previous section, WindowManager is an interface that inherits from ViewManager, which defines three abstract methods for adding, updating, and deleting views. WindowManager inherits the method of the parent class, indicating that it also has the ability of the parent class. From the first parameter in the parent class method, we know that all the parameters passed in are View type parameters, so we can indicate that the Window is in View mode. In addition to inheriting the features of the parent class, WindowManager has added many features, such as Window types and hierarchical constants, inner classes, and methods, two of which were added according to the features of Window. As follows:
//interface-->WindowManager.java
public interface WindowManager extends ViewManager {.../** * The Window has been added to the screen@return* /
public Display getDefaultDisplay(a);
/ * * * rules to be executed immediately before this method returns the onDetachedFromWindow () to complete the incoming View relevant logic destruction of *@param view
*/
public void removeViewImmediate(View view); . }Copy the code
PhoneWindow is an abstract class, and its only subclass is PhoneWindow. When was PhoneWindow created? The handleLaunchActivity -> performLaunchActivity method of class H is used to start an Activity The Attach method, where the PhoneWindow is created, lets just look at the code:
//Activity.java
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback) {.../** * 1. Instantiate the unique subclass of Window PhoneWindow */
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this); ./** * 2. Bind WindowManager */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();
mCurrentConfig = config;
mWindow.setColorMode(info.colorMode);
}
Copy the code
The code above mainly two meanings, one Window abstract class instantiation of subclasses PhonWindow, secondly is PhoneWindow associated with WindowManager want to, we see setWindowManager method, the code is as follows:
//Window.java
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated
|| SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
if (wm == null) {
/ / 1.
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
/ / 2.
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
Copy the code
If the WindowManager of wm type is null, the method McOntext. getSystemService is used to retrieve the WindowManager object, where mContext is of Context type. Its implementation class is the ContentImp object, also instantiated in the performLaunchActivity method. ContentImp getSystemService (ContentImp getSystemService)
//ContextImpl.java
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
Copy the code
We see the static method getSystemService in the SystemServiceRegistry class as follows:
//SystemServiceRegistry.java
final class SystemServiceRegistry {.../ / 1.
private static finalHashMap<String, ServiceFetcher<? >> SYSTEM_SERVICE_FETCHERS =newHashMap<String, ServiceFetcher<? > > (); .static{.../ / 2.
registerService(Context.WINDOW_SERVICE, WindowManager.class,
new CachedServiceFetcher<WindowManager>() {
@Override
public WindowManager createService(ContextImpl ctx) {
return newWindowManagerImpl(ctx); }}); . }private static <T> void registerService(String serviceName, Class
serviceClass, ServiceFetcher
serviceFetcher)
{
SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
}
public static Object getSystemService(ContextImpl ctx, String name) { ServiceFetcher<? > fetcher = SYSTEM_SERVICE_FETCHERS.get(name);returnfetcher ! =null ? fetcher.getService(ctx) : null;
}
Copy the code
SYSTEM_SERVICE_FETCHERS is a container singleton class that registers services of type context. XXX in a static block of SystemServiceRegistry. Finally, the register success is stored in the singleton container.
Then look at note 2 and call createLocalWindowManager to create the WindowManager implementation class as follows:
//WindowManagerImpl.java
public final class WindowManagerImpl implements WindowManager {...public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
// Instantiate the WindowManager implementation class object
return new WindowManagerImpl(mContext, parentWindow);
}
private WindowManagerImpl(Context context, Window parentWindow) { mContext = context; mParentWindow = parentWindow; }... }Copy the code
Both comment 1 and comment 2 create a WindowManagerImpl. The difference is that comment 2 also passes in the instance that created Window, so that WindowManagerImpl has a reference to PhoneWindow, You can then do something to the Window, such as call WindowManagerImp addView, as follows:
//WindowManagerImpl.java
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
/** * delegate to Windows ManagerGlobal to handle addView */
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
Copy the code
As you can see from the above code, the addView method is called in the WindowManagerImp class, but the internal method is not implemented. Instead, the addView logic is delegated to the WindowManagerGlobal. Windows ManagerGlobal will be covered in a later section. Let’s first look at how it is created in Windows Manager IMP. The code is as follows:
//WindowManagerImp.java
public final class WindowManagerImpl implements WindowManager {
//1. Get Windows ManagerGlobal objects via thread-safe singletons
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
/ * * 2. * /
private final Window mParentWindow;
private WindowManagerImpl(Context context, Window parentWindow) {
mContext = context;
/ / 3mParentWindow = parentWindow; }}//WindowManagerGlobal.java
public static WindowManagerGlobal getInstance(a) {
synchronized (WindowManagerGlobal.class) {
if (sDefaultWindowManager == null) {
sDefaultWindowManager = new WindowManagerGlobal();
}
returnsDefaultWindowManager; }}Copy the code
You can see in the code in comment 1 that we get the address of WindowManagerGlobal through a thread-safe singleton, and then comments 2 and 3 are passed along when the Activity creates the PhoneWindow, This represents which Window instance WindowManagerImpl will be used as a child Window. Using the source code described in this section, I have drawn a WindowManager association diagram, as shown in the following figure.
As can be seen from the figure, PhoneWindow inherits from Window, and PhoneWindow is associated with WindowManager through setWindowManager. WindowManager inherits from the ViewManager interface. WindowManagerImpl is the implementation class of the WindowManager interface, but the internal functions are delegated to WindowManagerGlobal.
The attribute of the Window
In the previous section, we explained the relationship between Windows, WindowManager and WMS, and we also know that WMS is the executor who finally deals with Windows. Window is like an employee, and WMS is like a boss. In order to facilitate the boss to manage employees, a set of “rules and regulations” should be defined. These rules are equivalent to the properties of Window, which are defined in the WindowManager inner class LayoutParams. Understanding the properties of Window will help you better understand the inner workings of WMS. There are many kinds of Window attributes, and the three most closely related to application development are Type(Window Type), Flag(Window Flag) and SoftInputMode(soft keyboard related mode). The following three attributes are introduced respectively.
The type of the Window
There are many types of Windows, such as application Window, system error Window, input method Window, PopWindow, Toast, Dialog, etc. Generally speaking, Windows can be divided into three types, namely Application Window, Sub Window and System Window. Each large type contains many types. They are all defined in the Static inner class LayoutParams of WindowManager, and we’ll look at each of the three types.
-
Application window
An Activity is a typical application window. Application Windows contain the following types:
//WindowManager.java /** * indicates the application window type initial value */ public static final int FIRST_APPLICATION_WINDOW = 1; /** * window base value, other window values are greater than this value */ public static final int TYPE_BASE_APPLICATION = 1; /** * Normal application window ** / public static final int TYPE_APPLICATION = 2; /** * The type of application launch window that the system displays before the application window starts */ public static final int TYPE_APPLICATION_STARTING = 3; public static final int TYPE_DRAWN_APPLICATION = 4; /** * indicates the end value of the application window type. The value ranges from 1 to 99 */ public static final int LAST_APPLICATION_WINDOW = 99; Copy the code
From the above constants, we know that the Type value of the application window ranges from 1 to 99. This value is related to the window hierarchy, which we will learn more about later.
-
Child window
Child window, as its name implies, is a fragment that must be attached to other Windows. The subwindow types are defined as follows:
//WindowManager.java /** * Subclass window initializes the value */ public static final int FIRST_SUB_WINDOW = 1000; public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW; public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1; public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2; public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3; public static final int TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW + 4; public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5; /** * Subclass window type end value */ public static final int LAST_SUB_WINDOW = 1999; Copy the code
It can be seen that the Type value of the sub-window ranges from 1000 to 1999
-
The system window
For example, Toast, input method Window, system volume bar Window and system error Window in Android are all system-level Windows. System-level window types are defined as follows:
//WindowManager.java /** * System type window type initial value */ public static final int FIRST_SYSTEM_WINDOW = 2000; /** * System status bar window */ public static final int TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW; /** * Search bar window */ public static final int TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1; /** * Call window */ @Deprecated public static final int TYPE_PHONE = FIRST_SYSTEM_WINDOW+2; /** * system aleat window */ @Deprecated public static final int TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3; /** * System lock window */ public static final int TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4; /** * Toast window */ @Deprecated public static final int TYPE_TOAST = FIRST_SYSTEM_WINDOW+5; ./** * End value of system window type */ public static final int LAST_SYSTEM_WINDOW = 2999; Copy the code
There are nearly more than 40 system window Type values, only part of which are listed here. The system window Type values range from 2000 to 2999.
A sign of the Window
Window Flag, also known as Flag, is used to control the reality of Window. It is also defined in the inner class LayoutParams of WindowManager. There are more than 20 of them.
Window Flag | instructions |
---|---|
FLAG_ALLOW_LOCK_WHILE_SCREEN_ON | Lock the screen on the open screen as long as the window is visible |
FLAG_NOT_FOCUSABLE | Windows do not get input focus. FLAG_NOT_TOUCH_MODAL is also set when this flag is set |
FLAG_NOT_TOUCHABLE | The window does not receive any touch events |
FLAG_NOT_TOUCH_MODAL | Passes touch events outside the Window area to other Windows, and only handles touch events inside the Window area itself |
FLAG_KEEP_SCREEN_NO | The screen is always on as long as the window is visible |
FLAG_LAYOUT_NO_LIMITS | Allows Windows to go beyond the screen |
FLAG_FULISCREEN | Hide all screen decoration Windows, such as full-screen displays in games and players |
FLAG_SHOW_WHEN_LOCKED | Windows can be displayed on top of Windows on the lock screen |
FLAG_IGNORE_CHEEK_PRESSES | When the user’s face is close to the screen (for example, making a phone call), it does not respond to events |
FLAG_TURN_SCREEN_NO | Light up the screen when the window is displayed |
There are three ways to set the Flag of a Window
-
The Window addFlag method is used
Window mWindow = getWindow(); mWindow.addFlay(WindowManager.LayoutParams.FLAG_FULLSCREEN); Copy the code
-
Through the Window setFlags method
Window mWindow = getWindow(); mWindow.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN) Copy the code
-
Set flags for LayoutParams and add them through the addView method of Windows Manager
WindowManager.LayoutParams mWindowLayoutParams = new WindowManager.LayoutParams(); mWindowLayoutParams.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN; WindowManager mWindowManager = (WindowManager)getSystemService(Context.WINDOW_SERVICE); Text mText = new Text(this); mWindowManager.addView(mTextView,mWindowLayoutParams); Copy the code
Software disk related mode
The overlay of Windows is a very common scenario, but if the window is the window of the software disk, there may be some problems, for example, a typical user login page, the default pop-up window of the software disk may block the button below the input box, so that the user experience is very bad. In order to make the soft keyboard window display as expected, Windows Manager static inner class LayoutParams defines the software disk related mode, here are some commonly used:
SoftInputMode | describe |
---|---|
SOFT_INPUT_STATE_UNSPECIFIED | If no state is set, the system selects an appropriate state or subject-dependent setting |
SOFT_INPUT_STATE_UNCHANGED | Does not change the soft keyboard state |
SOFT_INPUT_STATE_ALWAYS_HIDDEN | The soft keyboard is always hidden when the window gets focus |
SOFT_INPUT_ADJUST_RESIZE | When the soft keyboard pops up, the window resizes |
SOFT_INPUT_ADJUST_PAN | The window does not need to be resized when the soft keyboard pops up, making sure the input focus is visible |
SOFT_INPUT_STATE_HIDDEN | The soft keyboard is hidden by default when the user enters the window |
From SoftInputMode given above, can be found, they and AndroidManifest. Activity in the XML attribute android: windowsoftInputMode is corresponding. Therefore, in addition to configuring an Activity in androidmanifest.xml, you can also configure it dynamically with code, as shown below:
geWindow().setSoftInputMode(MindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
Copy the code
The operation of the Window
WindowManager manages Windows. When it comes to managing Windows, it cannot do without a series of operations such as Add, Update and remove. For these operations, WMS is the last one to handle them. Windows can be divided into three categories: ApplicationWindow, SubWindow and SystemWindow. The process of adding Windows varies according to different types. But it is the same for WMS processing. Here is a schematic diagram to help you understand:
The process of adding system Windows
According to the introduction of the above article, we know that Window is divided into three types, and the adding process of different Window types is different. This section will analyze the process of adding system Windows. Here Toast is used to analyze the process of adding the SystemWindow. Instead of introducing the four major components to start the analysis, we will mainly focus on the main point. After all, the main character is still the process of adding the SystemWindow. Toast makeText: Toast makeText: Toast makeText: Toast makeText: Toast makeText
//Toast
public static Toast makeText(@NonNull Context context, @Nullable Looper looper,
@NonNull CharSequence text, @Duration int duration) {
//1. Instantiate Toast objects
Toast result = new Toast(context, looper);
LayoutInflater inflate = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//2. Internal parsing of XML as a View
View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null);
TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message);
tv.setText(text);
//3. Remember mNextView which is the object we will add later
result.mNextView = v;
result.mDuration = duration;
return result;
}
final TN mTN;
int mDuration;
View mNextView;
public Toast(@NonNull Context context, @Nullable Looper looper) {
mContext = context;
mTN = new TN(context.getPackageName(), looper);
mTN.mY = context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.toast_y_offset);
mTN.mGravity = context.getResources().getInteger(
com.android.internal.R.integer.config_toastDefaultGravity);
}
Copy the code
From makeText, we know that Toast mainly creates a View with a default layout, and then assigns the View to the mNextView variable of Toast. Let’s look at the Toast show method, with the code as follows:
//Toast.java
public void show(a) {
if (mNextView == null) {
throw new RuntimeException("setView must have been called");
}
//1. Get the NMS agent class
INotificationManager service = getService();
String pkg = mContext.getOpPackageName();
2. TN receives the NMS message
TN tn = mTN;
tn.mNextView = mNextView;
try {
//3. Notify NMS to call the enqueueToast method
service.enqueueToast(pkg, tn, mDuration);
} catch (RemoteException e) {
// Empty}}private static class TN extends ITransientNotification.Stub {... }Copy the code
By the above code we know get INotificationManager first, and then will create good mTN assigned to TN object, it inherits from ITransientNotification. The Stub Binder object that has the function of receiving interprocess communication, Last call INotificationManager enqueueToast method to notify NotificationManagerService, let’s take a look at below NMS enqueueToast concrete implementation, the code is as follows:
//NotificationManagerService.java
public class NotificationManagerService extends SystemService {...private final IBinder mService = new INotificationManager.Stub() {
@Override
public void enqueueToast(String pkg, ITransientNotification callback, int duration)
{...synchronized (mToastQueue) {
int callingPid = Binder.getCallingPid();
long callingId = Binder.clearCallingIdentity();
try{ ToastRecord record; ./ / 1.
record = new ToastRecord(callingPid, pkg, callback, duration, token);
if (index == 0) {
/ / 2.showNextToastLocked(); }}finally {
Binder.restoreCallingIdentity(callingId);
}
}
}
}
....
}
void showNextToastLocked(a) {
ToastRecord record = mToastQueue.get(0);
while(record ! =null) {
try {
/ / 3.
record.callback.show(record.token);
scheduleTimeoutLocked(record);
return;
} catch(RemoteException e) { .... }}Copy the code
Call ToastRecord (PKG, callback, etc.); call record.callback.show (); The callback is defined to receive the NMS message in Toast. Let’s go back to the Toast show(Binder Binder) method, with the following code:
//Toast.java
@Override
public void show(IBinder windowToken) {
/ / 1.
mHandler.obtainMessage(SHOW, windowToken).sendToTarget();
}
mHandler = new Handler(looper, null) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case SHOW: {
IBinder token = (IBinder) msg.obj;
/ / 2.
handleShow(token);
break; }... }}}};Copy the code
The above is a simple inter-thread communication operation, we directly look at the concrete implementation of note 2, the code is as follows:
//Toast.java
public void handleShow(IBinder windowToken) {...if(mView ! = mNextView) { .../** * 1. The added object */
mView = mNextView;
Context context = mView.getContext().getApplicationContext();
String packageName = mView.getContext().getOpPackageName();
if (context == null) {
context = mView.getContext();
}
/** * 1. Get WindowManager */mWM = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); .try {
/** * 3. Call WindowManager addView to add */
mWM.addView(mView, mParams);
trySendAccessibilityEvent();
} catch (WindowManager.BadTokenException e) {
/* ignore */}}}Copy the code
We directly look at the above most important code note 3, call WindowManager addView method, through the above introduction, we know that the implementation of WindowManager is in WindowManagerImpl, the specific implementation code is as follows:
//WindowManagerImpl.java
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
/** * delegate to Windows ManagerGlobal to handle addView */
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
Copy the code
The first parameter of addView is of type View, indicating that Windows exist in the form of View. AddView calls the addView method of WindowManagerGlobal. The code is as follows:
//
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) {...final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if(parentWindow ! =null) {
/ * * * 1. According to the WindowManager. LayoutParams parameters to adjust to add the child window * /
parentWindow.adjustLayoutParamsForSubWindow(wparams);
} else{... } ViewRootImpl root; View panelParentView =null;
synchronized (mLock) {
...
/** * 2. Instantiate the ViewRootImpl object and assign it to root */
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
/** * 3. Add view to mViews list */
mViews.add(view);
/** * 4. Store root in ViewRootImp */
mRoots.add(root);
/** * 5. Save the window parameters to the layout parameter list. * /
mParams.add(wparams);
try {
/**
* 6. 将窗口和窗口的参数通过 setView 方法设置到 ViewRootImpl 中
*/
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throwe; }}}Copy the code
From the above code, we can know that six things are done as follows:
- According to the WindowManager. LayoutParams parameters to adjust to add the child window.
- Instantiate the ViewRootImpl object and assign it to the root variable
- Add view to mViews list
- Store root in the ViewRootImp list
- Save the window’s parameters to the layout parameter list
- Set the window and its parameters to the View wrootimpl using the setView method
Finally, after a series of steps to step 6, you can see that we added the window using the View wrootimpl. ViewRootImpl has many responsibilities, mainly the following:
- View tree root and manage the View tree
- Trigger View measurement, layout, and drawing
- A relay station for input events
- Management of surface
- Responsible for inter-system communication with WMS
Now that we know what the ViewRootImpl does, let’s look at the ViewRootImpl setView method:
//ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {...try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
} catch(RemoteException e) { ... }... }}Copy the code
There’s a lot of logic in the setView method, and I’m just going to grab the important code, which is basically the addToDisplay method that calls WindowSession of type mWindowSession, which is a Binder object, and its server implementation is the Session class, Let’s take a look at the diagram to see the relationship between view wrotimpl, IWindowSession, WMS and Session, as follows:
Let’s look at its implementation in detail, the code is as follows:
//Session.java
public class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
finalWindowManagerService mService; .@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
Rect outOutsets, InputChannel outInputChannel) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outContentInsets, outStableInsets, outOutsets, outInputChannel); }... }Copy the code
We know from the above code that the local process viewrotimpl needs to go through a Session to communicate with the WMS, so why is the Session included in the WMS? If we look at the code above, the addToDisplay method inside the Session is actually calling the addWindow method of WMS. Each application process will have a Session, and WMS will call ArrayList to hold those sessions. This is why WMS wraps sessions. WMS assigns the Surface to the added Window, so the Surface is responsible for displaying the interface, not the Window. WMS assigns the Surface it manages to SurfaceFlinger. SurfaceFlinger mixes and draws these surfaces onto the screen.
The WMS Window addition section will be examined separately in the next article. The process of adding system Windows Toast will be examined here. Let’s look at the process of adding Windows to the application.
The process of adding an Activity
No matter what kind of window it is, the process of adding it is basically similar in the WMS processing part, but it is different in the WindowManager processing part. Here is a typical example of an Activity. If the Activity is in a process that doesn’t already exist, a new process is created. After the new process is created, an instance of ActivityThread, representing the main thread, runs. ActivityThread manages the threads of the current application process. This is evident during the Activity startup process, when the interface interacts with the user, the ActivityThread’s handleResumeActivity method is called, as shown below:
//ActivityThread.java
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {.../** * 1. The Activity onResume lifecycle function is eventually called */
r = performResumeActivity(token, clearHide, reason);
if(r ! =null) {...if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
/** * 2. Get the ViewManager object */
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (r.mPreserveWindow) {
a.mWindowAdded = true;
r.mPreserveWindow = false;
ViewRootImpl impl = decor.getViewRootImpl();
if(impl ! =null) { impl.notifyChildRebuilt(); }}if (a.mVisibleFromClient) {
if(! a.mWindowAdded) { a.mWindowAdded =true;
/** * 3. Call the addView method of ViewManager */
wm.addView(decor, l);
} else{ a.onWindowAttributesChanged(l); }}... }}Copy the code
We get three important pieces of information from the code above, one, through the comment one, the Activity’s onResume lifecycle function is executed, and two, we get the ViewManager object, which we introduced earlier, It is an interface inherited by WindowManager and finally implemented in WindowManagerImpl, so three, comment three is the addView method that calls WindowManagerImpl, and the rest of the call is the same as Toast’s execution flow, I won’t repeat it here. Let’s examine the Window update process
Windows update process
Updating a Window is similar to adding a Window. You call the ViewManager updateViewlayout method, which is implemented in WindowmanagerImpl. WindowManagerImpl’s updateViewLayout method calls WindowManagerGlobal’s updateViewLayout method as follows:
//WindowManagerGlobal.java
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
if(! (paramsinstanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
/**
* 1. 将更新的参数设置到 View 中
*/
view.setLayoutParams(wparams);
synchronized (mLock) {
/** * 2. Get the index of the window to be updated in the View list */
int index = findViewLocked(view, true);
/** * 3. Get the window's ViewRootImpl */ according to the index
ViewRootImpl root = mRoots.get(index);
/** * 4. Delete the old parameter */
mParams.remove(index);
/** * 5. Add a new parameter */
mParams.add(index, wparams);
/** * 6. Set the updated parameters to ViewRootImpl */
root.setLayoutParams(wparams, false); }}Copy the code
Get the ViewRootImpl that needs to be updated and call its setLayoutParams to pass in the parameters. Let’s look at the code implementation of comment 6:
//ViewRootImpl.java
void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {... scheduleTraversals(); }Copy the code
//ViewRootImpl.java
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
final class TraversalRunnable implements Runnable {... }void scheduleTraversals(a) {
if(! mTraversalScheduled) { mTraversalScheduled =true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
/** * mChoreographer: For receiving VSync signals from the display system, for controlling the execution of operations on the next frame of render, * for issuing add callbacks within the Run of mTraversalRunnable */
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
Copy the code
TraversalRunnable TraversalRunnable TraversalRunnable TraversalRunnable
//ViewRootImpl.java
final class TraversalRunnable implements Runnable {
@Override
public void run(a) {
// Call the internal doTraversal methoddoTraversal(); }}Copy the code
//ViewRootImpl.java
void doTraversal(a) {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false; }}}Copy the code
In doTraversal the performTraversals method is called again, and so on:
//ViewRootImpl.java
private void performTraversals(a) {
/** * 1. The relayout method of IWindowSession is called internally to update the Window view */relayoutResult = relayoutWindow(params, viewVisibility, insetsPending); ./** * 2. Call the View measure method */performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); ./** * 3. The View layout is called internally */performLayout(lp, mWidth, mHeight); ./** * 4. Draw the View by calling the View draw method. * /performDraw(); . }Copy the code
Through the above performTraversals function, internal View measure, layout and draw are performed to complete the View drawing process. The Window is updated by updating the Window view in the performTraversals method.
conclusion
The article learned WindowManager related knowledge points, including WindowManager associated classes, Window properties and Window operations, the next article will bring home WindowManagerService source code analysis, please look forward to!
Thank you for reading, I hope to help you!
reference
- Android Advanced Decryption