Window 与 WindowManager

Related categories:

  • Window : It is an abstract class, but a concept that does not actually exist. The only implementation class is PhoneWindow, which manages View
  • WindowManager : An interface class, inherited from ViewManager, literally means to manage Window, in fact it is to add, delete and update View. The implementation class is WindowManagerImpl
/**
  * code 1
  */
public interface ViewManager
{
    
    
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}
  • WindowManagerService (WMS): The class that actually processes the View and communicates with WindowManager through IPC

Activity completes the entire startup process through the performLaunchActivity() method in ActivityThread, and creates an instance of Activity through the ClassLoader class loader, and calls the attach method to associate a series of context environment variables that its running process depends on:
frameworks/base/core/java/ android/app/ActivityThread.java

/**
  * code 2
  */
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    
    
	ContextImpl appContext = createBaseContextForActivity(r);
    Activity activity = null;
    java.lang.ClassLoader cl = appContext.getClassLoader();
    activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
    if (activity != null) {
    
    
    	Window window = null;
    	//如果保存Activity信息的ActivityClientRecord实例中mPendingRemoveWindow不为空,则使用使用已保存的window对象
	    if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
    
    
	        window = r.mPendingRemoveWindow;
	        r.mPendingRemoveWindow = null;
	        r.mPendingRemoveWindowManager = null;
	    }
	    appContext.setOuterContext(activity);
	    activity.attach(appContext, this, getInstrumentation(), r.token,
	                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
	                        r.embeddedID, r.lastNonConfigurationInstances, config,
	                        r.referrer, r.voiceInteractor, window, r.configCallback);
    }
}
  • The mPendingRemoveWindow in ActivityClientRecord only has the assignment code in the handleDestroyActivity method, and the mPreserveWindow (whether to retain the window) used for judgment appears in the handleRelaunchActivity method.Relaunch is to destroy and then start, change mPreserveWindow to true, and then call handleDestroyActivity. The delayed window and wms objects are saved, then the Activity is destroyed, and finally the handleLaunchActivity is called, and the performLaunchActivity method is used to re-pull the Activity. At this time, the above code is reached, and the window object in the attach method is saved after the Activity was destroyed just now. The window object assignment.
/**
 *  code 3
 *  此处ActivityThread会回调Activitiy的onDestroy方法
 */
private void handleDestroyActivity(IBinder token, boolean finishing,
            int configChanges, boolean getNonConfigInstance) {
    
    
            ...
            if (r.activity.mWindowAdded) {
    
    
                    if (r.mPreserveWindow) {
    
    
                        // 延迟移除window和wms对象,直到新Activity中的window被添加
                        r.mPendingRemoveWindow = r.window;
                        r.mPendingRemoveWindowManager = wm;
                        // We can only keep the part of the view hierarchy that we control,
                        // everything else must be removed, because it might not be able to
                        // behave properly when activity is relaunching.
                        r.window.clearContentView();
                    } else {
    
    
                        wm.removeViewImmediate(v);
                    }
            ...
	}
  • So what if the activity is started normally? In the attach method, the parameter window will be empty. Now when you walk into the attach method, you can see that the specific implementation class of Window is PhoneWindow. PhoneWindow directly creates an instance in the attach method and sets the callback interface. In the Callback interface, there are methods such as dispatchTouchEvent, onAttachToWindow, etc.
/**
  * code 4
  */
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) {
    
    
    attachBaseContext(context);

    mFragments.attachHost(null /*parent*/);
        
	mWindow = new PhoneWindow(this, window, activityConfigCallback);
	mWindow.setWindowControllerCallback(this);
	mWindow.setCallback(this);
	mWindow.setOnWindowDismissedCallback(this);
	...
	mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
	...

PhoneWindow is directly instantiated in the attach method, and WindowManager is set for Window in the setWindowManager method below. This method is in the PhoneWindow parent class Window:
frameworks/base/core/java/android/view/Window.java

	/**
	  * code 5
	  */
    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) {
    
    
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }

If the incoming WindowManager is empty, it is obtained by mContext.getSystemService(Context.WINDOW_SERVICE), where the Context implementation class is ContextImpl, why? Here we must first find the place where Activity is instantiated, which is the performLaunchActivity method of ActivityThread, that is The first code code1 of the article, the first line of code:

ContextImpl appContext = createBaseContextForActivity(r);
/**
  * code 6
  */
private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
    
    
        final int displayId;
        try {
    
    
            displayId = ActivityManager.getService().getActivityDisplayId(r.token);
        } catch (RemoteException e) {
    
    
            throw e.rethrowFromSystemServer();
        }
		//annotation 1
        ContextImpl appContext = ContextImpl.createActivityContext(
                this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);

        final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
        // For debugging purposes, if the activity's package name contains the value of
        // the "debug.use-second-display" system property as a substring, then show
        // its content on a secondary display if there is one.
        String pkgName = SystemProperties.get("debug.second-display.pkg");
        if (pkgName != null && !pkgName.isEmpty()
                && r.packageInfo.mPackageName.contains(pkgName)) {
    
    
            for (int id : dm.getDisplayIds()) {
    
    
                if (id != Display.DEFAULT_DISPLAY) {
    
    
                    Display display =
                            dm.getCompatibleDisplay(id, appContext.getResources());
                    appContext = (ContextImpl) appContext.createDisplayContext(display);
                    break;
                }
            }
        }
        return appContext;
    }

Here appContext is the source obtained by the ClassLoader, and the Activity is generated by the class loader, that is to say, the context in the Activity is derived from the
createActivityContext method of ContextImpl , that is, note 1, seeing here also understands the source of getSystemService, let us continue Follow ContextImpl and look down at
frameworks/base/core/java/android/app/ContextImpl.java

/**
  * code 7
  */
@Override
public Object getSystemService(String name) {
    
    
        return SystemServiceRegistry.getSystemService(this, name);
    }

Here will call SystemServiceRegistry.getSystemService(this, name), click into this class and you will find that this class manages all system services that can be returned, that is, can be called
frameworks/base/core/java/android/app/SystemServiceRegistry.java

private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
            new HashMap<String, ServiceFetcher<?>>();
/**
  * code 8
  */
public static Object getSystemService(ContextImpl ctx, String name) {
    
    
        ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
        return fetcher != null ? fetcher.getService(ctx) : null;
    }

Looking at the code, it is found that the name passed in by getSystemService is equivalent to the key. Remember what is passed in?
Context.WINDOW_SERVICE

public static final String WINDOW_SERVICE = "window";

That is to say, when we pass in the corresponding context and key, it will return to us the object returned by the fetcher.getService method. What is returned by the "window"? It is known that the systemservice comes from the HashMap named SYSTEM_SERVICE_FETCHERS, so look for it globally The put method of map is positioned as follows:

/**
  * code 9
  */
private static <T> void registerService(String serviceName, Class<T> serviceClass,
            ServiceFetcher<T> serviceFetcher) {
    
    
        SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
        SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
    }

Looking for the call to the registerService method, it is found that there is a static code block in the SystemServiceRegistry, which registers all system services through the registerService method, and the WINDOW_SERVICE we are looking for is in it:

/**
  * code 10
  */
static {
    
    
	registerService(Context.WINDOW_SERVICE, WindowManager.class,
	                new CachedServiceFetcher<WindowManager>() {
    
    
	            @Override
	            public WindowManager createService(ContextImpl ctx) {
    
    
	                return new WindowManagerImpl(ctx);
	            }});
}

CachedServiceFetcher is an abstract class, what really returns is WindowManagerImpl, that is to say, getSystemService(Context.WINDOW_SERVICE) finally returns WindowManagerImpl object, so we end the view of ContextImpl and SystemServiceRegistry source code, and return to the setWindowManager method of the Window abstract class, also It is code 5 , after obtaining the WindowManagerImpl object, continue to go down, you will find that the createLocalWindowManager method is called, click in and take a look

frameworks/base/core/java/android/view/WindowManagerImpl.java

/**
  * code 11
  */
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
    
    
        return new WindowManagerImpl(mContext, parentWindow);
}

private WindowManagerImpl(Context context, Window parentWindow) {
    
    
        mContext = context;
        mParentWindow = parentWindow;
}

A WindowManagerImpl is still instantiated here. The difference from the previous one is that the WindowManagerImpl constructor instantiated in the SystemServiceRegistry static code block only has the context, and this time the constructor is passed in, that is to say, WindowManagerImpl holds the reference to the Window, so Then you can add and delete views in the window. Next, let's look at the addView method:

/**
  * code 12
  */
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();

@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    
    
	applyDefaultToken(params);
	mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
  • I thought that WindowManagerImpl was the end point, but I didn't expect it to actually operate on the View, but WindowManagerGlobal. Here we obtain its instance through the singleton mode and perform actual operations on the view.

So far, we can roughly sort out the relationship between Window and WindowManager:

  1. PhoneWindow inherits from the Window abstract class and is essentially View. It is internally associated with WindowManager through the setWindowManager method (instantiating WindowManagerImpl)
  2. There are methods for adding, deleting and updating views inside the ViewManager interface. WindowManager inherits ViewManager, and WindowManagerImpl inherits WindowManager.
  3. Window is associated with WindowManager, and finally the implementation class PhoneWindow of the two is bound to WindowManagerImpl
  4. What actually handles the view inside WindowManagerImpl is actually WindowManagerGlobal (bridge mode)

Insert picture description here

reference:

  1. http://liuwangshu.cn/framework/wm/1-windowmanager.html
  2. https://blog.csdn.net/weixin_41101173/article/details/79685305
  3. https://blog.csdn.net/tonyandroid1984/article/details/71046368
  4. Android development art exploration

Guess you like

Origin blog.csdn.net/Rockphoenix/article/details/113994964