Source Code Reading Analysis-Window s Basic Principle and System Architecture

Keywords: Windows Session Android less

After doing android for a while, we began to hear some people say AMS, WMS, Windows, Windows Manager, Windows Manager Service and so on. We may understand these words, but we don't necessarily have an architecture map in mind. This time we will understand them from the perspective of source code. Before reading this article, I hope you can take some time to understand the following articles:

1. Plug-in Skin Change Framework - setContentView Source Reading
2. Communication between Android Processes - IPC (Mechanism) Binder's Principle and Source Reading
2. Android Plug-in Architecture - Activity Startup Process Analysis
3. Drawing process of source code parsing-View

How to read source code

The above articles are inextricably linked with my article today. Why can I separate them? Importantly, we need to use it to see the source code. For example, if I want to do a skin switch function, then I definitely need to understand the loading process of layout resources. You just look at the articles or lines of code written by others from the Internet and believe that you should be very difficult to do it. Of course, it's OK to use demo on github, but you don't think so. Is there anything missing? And we'd better be able to stop at that point, with questions, just know what we want to know. Many of today's source code will more or less cover the knowledge points of the above articles, but we don't need to care. Believe me, as long as you can open the source code to other people's articles, as time goes by, when we look at the source code of the system, we will be proficient in solving the problem. It's no longer a matter of trial and error (if you rely on Mongolia sometimes in the development process, you can brush a compliment at the end of the article), and if you have the source code architecture diagram of the whole android application layer in mind, it's easy to open up. It's a good idea to try and solve problems (if you can understand the source code of the native layer better).

Our doubts

We just know that the setContentView method can set up and display our layout. Plug-in Skin Change Framework - setContentView Source Reading This article just shows you the hierarchy of layout, but do you know what Windows and Windows Manager have done? Or when we touch an EditText, we pop up a system keyboard. Why does popping up a keyboard automatically adjust our activity layout? We play a Toast, but even if we quit Activity or the whole application Toast will still exist?

Phone Windows Creation Process

We can see two lines of code with Activity's setContentView as the entry:

     /**
     * Set the activity content from a layout resource.  The resource will be
     * inflated, adding all top-level views to the activity.
     *
     * @param layoutResID Resource ID to be inflated.
     *
     * @see #setContentView(android.view.View)
     * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
     */
    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }

getWindow().setContentView(layoutResID) is a line of code that just parses our layout without doing anything else. I won't analyze the source code anymore. Today's focus is not here. If you want to know, see this article. Plug-in Skin Change Framework - setContentView Source Reading getWindow() returns mWindow s, which is instantiated in the attach method:

    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) {
        // Create a Phone Window instance
        mWindow = new PhoneWindow(this, window);
        // Setting up a Controller Callback
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        // You can see what that means by looking at the method name.
        mWindow.setOnWindowDismissedCallback(this);
        // Set up a Windows Manager for Windows 
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        // Activity has a Windows Manager of its own
        mWindowManager = mWindow.getWindowManager();
    }

So when was the attach method invoked? Called in the performLaunchActivity method in ActivityThread, this involves the start-up process analysis of Activity. For more information, see this article. Android Plug-in Architecture-Activity Startup Process Analysis

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

        Activity activity = null;
        try {
            // Creating Activity Instance Objects with Reflection
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
            }
        }

        try {
            if (activity != null) {
                // Here's the way we're looking for
                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);

                // set up themes
                int theme = r.activityInfo.getThemeResource();
                if (theme != 0) {
                    activity.setTheme(theme);
                }
            }
        } catch (SuperNotCalledException e) {
            throw e;

        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to start activity " + component
                    + ": " + e.toString(), e);
            }
        }
        // Return an Activity instance
        return activity;
    }

At present, we only know that mWindow's setContentView method will be called by setContentView method. This method only parses our layout, but it has not been done at all. The instance of mWindow is actually called by the attach method of activity. This method is called by ActivityThread and then no longer exists. So how does the layout show?

Layout measurement and mapping process

stay Android Plug-in Architecture-Activity Startup Process Analysis We can find the handleResumeActivity method in ActivityThread:

final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
        // On Resume Life Cycle Approach to Executing Activity First
        // TODO Push resumeArgs into the activity for consideration
        r = performResumeActivity(token, clearHide, reason);
       
        if (r != null) {
            final Activity a = r.activity;
            if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow();
                // Getting Activity is the root layout of Phone Windows
                View decor = r.window.getDecorView();
                // Set to Display
                decor.setVisibility(View.INVISIBLE);
                // Get the Windows Manager object of Activity assigned in the attach method of Activity above
                ViewManager wm = a.getWindowManager();
                // Get Windows Manager. LayoutParams for Phone Windows 
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                // Specify type, which is an important concept. The type of the specified window will be introduced later.
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (a.mVisibleFromClient && !a.mWindowAdded) {
                    a.mWindowAdded = true;
                    // Call the addView method of ViewManager
                    wm.addView(decor, l);
                }
            }
        } else {
            // If an exception was thrown when trying to resume, then
            // just end this activity.
            try {
                ActivityManagerNative.getDefault()
                    .finishActivity(token, Activity.RESULT_CANCELED, null,
                            Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }
    }

Finally, we call the addView method of ViewManager, but we find that ViewManager is actually an interface, so we have to find the implementation method. The attach method of Activity above is obtained through context.getSystemService(Context.WINDOW_SERVICE), and the getSystemService method of ContextImpl, an instance class of ContextImpl, actually calls SystemService Registry. GetSystemService method:

    /**
    * Gets a system service from a given context.
    */
    public static Object getSystemService(ContextImpl ctx, String name) {
        ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
        return fetcher != null ? fetcher.getService(ctx) : null;
    }

SYSTEM_SERVICE_FETCHERS is a static HashMap object that is assigned through static code blocks. In fact, we can conclude that the system services acquired through Context have already been registered and added to the SYSTEM_SERVICE_FETCHERS collection, which is a typical singleton design pattern. So far we have finally found the addView method for this class of Windows Manager Impl.

    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }

Windows Manager Impl is the implementation class of ViewManager, but it handed over the work to the Windows Manager Global method. And we found that mGlobal object is a singleton entirely. Why do we design it like this? I have not explained much in this article. Let's look at mGlobal's addView method:

   public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {

        // Verification of Some Parameters
        // ......
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        if (parentWindow != null) {
            // If it's a sub-View, you need to adjust some layout parameters
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        } else {
            // If there's no parent, then hardware acceleration for this view is
            // set from the application's hardware acceleration setting.
            final Context context = view.getContext();
            if (context != null
                    && (context.getApplicationInfo().flags
                            & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
                wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
            }
        }

        ViewRootImpl root;
        View panelParentView = null;

        synchronized (mLock) {
            // Begin to view changes in system attributes.
            if (mSystemPropertyUpdater == null) {
                mSystemPropertyUpdater = new Runnable() {
                    @Override public void run() {
                        synchronized (mLock) {
                            for (int i = mRoots.size() - 1; i >= 0; --i) {
                                mRoots.get(i).loadSystemProperties();
                            }
                        }
                    }
                };
                SystemProperties.addChangeCallback(mSystemPropertyUpdater);
            }
            // Looking for locations in the collection through View, the first addition must be 0
            int index = findViewLocked(view, false);
            if (index >= 0) {
                // If it has been added, is it being destroyed?
                if (mDyingViews.contains(view)) {
                    // Don't wait for MSG_DIE to make it's way through root's queue.
                    mRoots.get(index).doDie();
                } else {
                    // If not being destroyed and added, then throw an exception to end the run
                    throw new IllegalStateException("View " + view
                            + " has already been added to the window manager.");
                }
                // The previous removeView() had not completed executing. Now it has.
            }

            // If it's a child window, let's find the View of its parent window. 
            // The types of windows are described below.
            if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                    wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                final int count = mViews.size();
                for (int i = 0; i < count; i++) {
                    if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
                        panelParentView = mViews.get(i);
                    }
                }
            }
            // Build ViewRootImpl, regardless of what ViewRootImpl is for the time being
            root = new ViewRootImpl(view.getContext(), display);
            // Set up Layout Params for View
            view.setLayoutParams(wparams);
            // Here are some saves added to the collection, one by one.
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
        }

        // The last line of code to trigger things
        // Display View on the phone. The setView method is more complex, so the most important method is here.
        try {
            root.setView(view, wparams, panelParentView);
        } catch (RuntimeException e) {
            // BadTokenException or InvalidDisplayException, clean up.
            synchronized (mLock) {
                final int index = findViewLocked(view, false);
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
            }
            throw e;
        }
    }

The most important way to go for so long is actually root. setView (view, wparams, panel ParentView); this line of code is very complex, but this method is the most important, I hope I can not go too deep and easy to understand. Before we analyze this, let's talk about the recurring type attribute above.

Three Types of Window s

Windows are typed, and as we can see above, different types can be processed differently. Windows can be divided into three types: System Windows, Application Windows, and Sub-Windows.

  • Common system Windows, such as when the power of mobile phones is low, there will be a Window indicating low power. When we input text, we will pop up the input method Windows, as well as the search bar Windows, caller display Windows, Toast corresponding Windows. It can be concluded that the system Windows is independent of our application program. For the application program, we can not create the system in theory. Windows, because there is no permission, this permission is only available to the system process. The corresponding level interval is more than 2000.

  • Application Windows, such as Activity, is an application Windows. From the source code above, you can see that TYPE_BASE_APPLICATION is given by type. The corresponding level interval is 1 - 99

  • Sub-Windows, so-called sub-Windows, means that this Windows must have a parent form, such as PopWindow,Dialog, etc. The corresponding level interval is 1000 - 1999

So what's specific at each level? See the type value in Windows Manager. LayoutParams. Here I post it but don't translate it, because my English is not good:

        /**
         * Start of window types that represent normal application windows.
         */
        public static final int FIRST_APPLICATION_WINDOW = 1;

        /**
         * Window type: an application window that serves as the "base" window
         * of the overall application; all other application windows will
         * appear on top of it.
         * In multiuser systems shows only on the owning user's window.
         */
        public static final int TYPE_BASE_APPLICATION   = 1;

        /**
         * Window type: a normal application window.  The {@link #token} must be
         * an Activity token identifying who the window belongs to.
         * In multiuser systems shows only on the owning user's window.
         */
        public static final int TYPE_APPLICATION        = 2;

        /**
         * Window type: special application window that is displayed while the
         * application is starting.  Not for use by applications themselves;
         * this is used by the system to display something until the
         * application can show its own windows.
         * In multiuser systems shows on all users' windows.
         */
        public static final int TYPE_APPLICATION_STARTING = 3;

        /**
         * Window type: a variation on TYPE_APPLICATION that ensures the window
         * manager will wait for this window to be drawn before the app is shown.
         * In multiuser systems shows only on the owning user's window.
         */
        public static final int TYPE_DRAWN_APPLICATION = 4;

        /**
         * End of types of application windows.
         */
        public static final int LAST_APPLICATION_WINDOW = 99;

        /**
         * Start of types of sub-windows.  The {@link #token} of these windows
         * must be set to the window they are attached to.  These types of
         * windows are kept next to their attached window in Z-order, and their
         * coordinate space is relative to their attached window.
         */
        public static final int FIRST_SUB_WINDOW = 1000;

        /**
         * Window type: a panel on top of an application window.  These windows
         * appear on top of their attached window.
         */
        public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;

        /**
         * Window type: window for showing media (such as video).  These windows
         * are displayed behind their attached window.
         */
        public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1;

        /**
         * Window type: a sub-panel on top of an application window.  These
         * windows are displayed on top their attached window and any
         * {@link #TYPE_APPLICATION_PANEL} panels.
         */
        public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2;

        /** Window type: like {@link #TYPE_APPLICATION_PANEL}, but layout
         * of the window happens as that of a top-level window, <em>not</em>
         * as a child of its container.
         */
        public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3;

        /**
         * Window type: window for showing overlays on top of media windows.
         * These windows are displayed between TYPE_APPLICATION_MEDIA and the
         * application window.  They should be translucent to be useful.  This
         * is a big ugly hack so:
         * @hide
         */
        public static final int TYPE_APPLICATION_MEDIA_OVERLAY  = FIRST_SUB_WINDOW + 4;

        /**
         * Window type: a above sub-panel on top of an application window and it's
         * sub-panel windows. These windows are displayed on top of their attached window
         * and any {@link #TYPE_APPLICATION_SUB_PANEL} panels.
         * @hide
         */
        public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5;

        /**
         * End of types of sub-windows.
         */
        public static final int LAST_SUB_WINDOW = 1999;

        /**
         * Start of system-specific window types.  These are not normally
         * created by applications.
         */
        public static final int FIRST_SYSTEM_WINDOW     = 2000;

        /**
         * Window type: the status bar.  There can be only one status bar
         * window; it is placed at the top of the screen, and all other
         * windows are shifted down so they are below it.
         * In multiuser systems shows on all users' windows.
         */
        public static final int TYPE_STATUS_BAR         = FIRST_SYSTEM_WINDOW;

        /**
         * Window type: the search bar.  There can be only one search bar
         * window; it is placed at the top of the screen.
         * In multiuser systems shows on all users' windows.
         */
        public static final int TYPE_SEARCH_BAR         = FIRST_SYSTEM_WINDOW+1;

        /**
         * Window type: phone.  These are non-application windows providing
         * user interaction with the phone (in particular incoming calls).
         * These windows are normally placed above all applications, but behind
         * the status bar.
         * In multiuser systems shows on all users' windows.
         */
        public static final int TYPE_PHONE              = FIRST_SYSTEM_WINDOW+2;

        /**
         * Window type: system window, such as low power alert. These windows
         * are always on top of application windows.
         * In multiuser systems shows only on the owning user's window.
         */
        public static final int TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3;

        /**
         * Window type: keyguard window.
         * In multiuser systems shows on all users' windows.
         * @removed
         */
        public static final int TYPE_KEYGUARD           = FIRST_SYSTEM_WINDOW+4;

        /**
         * Window type: transient notifications.
         * In multiuser systems shows only on the owning user's window.
         */
        public static final int TYPE_TOAST              = FIRST_SYSTEM_WINDOW+5;

        /**
         * Window type: system overlay windows, which need to be displayed
         * on top of everything else.  These windows must not take input
         * focus, or they will interfere with the keyguard.
         * In multiuser systems shows only on the owning user's window.
         */
        public static final int TYPE_SYSTEM_OVERLAY     = FIRST_SYSTEM_WINDOW+6;

        /**
         * Window type: priority phone UI, which needs to be displayed even if
         * the keyguard is active.  These windows must not take input
         * focus, or they will interfere with the keyguard.
         * In multiuser systems shows on all users' windows.
         */
        public static final int TYPE_PRIORITY_PHONE     = FIRST_SYSTEM_WINDOW+7;

        /**
         * Window type: panel that slides out from the status bar
         * In multiuser systems shows on all users' windows.
         */
        public static final int TYPE_SYSTEM_DIALOG      = FIRST_SYSTEM_WINDOW+8;

        /**
         * Window type: dialogs that the keyguard shows
         * In multiuser systems shows on all users' windows.
         */
        public static final int TYPE_KEYGUARD_DIALOG    = FIRST_SYSTEM_WINDOW+9;

        /**
         * Window type: internal system error windows, appear on top of
         * everything they can.
         * In multiuser systems shows only on the owning user's window.
         */
        public static final int TYPE_SYSTEM_ERROR       = FIRST_SYSTEM_WINDOW+10;

        /**
         * Window type: internal input methods windows, which appear above
         * the normal UI.  Application windows may be resized or panned to keep
         * the input focus visible while this window is displayed.
         * In multiuser systems shows only on the owning user's window.
         */
        public static final int TYPE_INPUT_METHOD       = FIRST_SYSTEM_WINDOW+11;

        /**
         * Window type: internal input methods dialog windows, which appear above
         * the current input method window.
         * In multiuser systems shows only on the owning user's window.
         */
        public static final int TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12;

        /**
         * Window type: wallpaper window, placed behind any window that wants
         * to sit on top of the wallpaper.
         * In multiuser systems shows only on the owning user's window.
         */
        public static final int TYPE_WALLPAPER          = FIRST_SYSTEM_WINDOW+13;

        /**
         * Window type: panel that slides out from over the status bar
         * In multiuser systems shows on all users' windows.
         */
        public static final int TYPE_STATUS_BAR_PANEL   = FIRST_SYSTEM_WINDOW+14;

        /**
         * Window type: secure system overlay windows, which need to be displayed
         * on top of everything else.  These windows must not take input
         * focus, or they will interfere with the keyguard.
         *
         * This is exactly like {@link #TYPE_SYSTEM_OVERLAY} except that only the
         * system itself is allowed to create these overlays.  Applications cannot
         * obtain permission to create secure system overlays.
         *
         * In multiuser systems shows only on the owning user's window.
         * @hide
         */
        public static final int TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15;

        /**
         * Window type: the drag-and-drop pseudowindow.  There is only one
         * drag layer (at most), and it is placed on top of all other windows.
         * In multiuser systems shows only on the owning user's window.
         * @hide
         */
        public static final int TYPE_DRAG               = FIRST_SYSTEM_WINDOW+16;

        /**
         * Window type: panel that slides out from under the status bar
         * In multiuser systems shows on all users' windows.
         * @hide
         */
        public static final int TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17;

        /**
         * Window type: (mouse) pointer
         * In multiuser systems shows on all users' windows.
         * @hide
         */
        public static final int TYPE_POINTER = FIRST_SYSTEM_WINDOW+18;

        /**
         * Window type: Navigation bar (when distinct from status bar)
         * In multiuser systems shows on all users' windows.
         * @hide
         */
        public static final int TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19;

        /**
         * Window type: The volume level overlay/dialog shown when the user
         * changes the system volume.
         * In multiuser systems shows on all users' windows.
         * @hide
         */
        public static final int TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20;

        /**
         * Window type: The boot progress dialog, goes on top of everything
         * in the world.
         * In multiuser systems shows on all users' windows.
         * @hide
         */
        public static final int TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21;

        /**
         * Window type to consume input events when the systemUI bars are hidden.
         * In multiuser systems shows on all users' windows.
         * @hide
         */
        public static final int TYPE_INPUT_CONSUMER = FIRST_SYSTEM_WINDOW+22;

        /**
         * Window type: Dreams (screen saver) window, just above keyguard.
         * In multiuser systems shows only on the owning user's window.
         * @hide
         */
        public static final int TYPE_DREAM = FIRST_SYSTEM_WINDOW+23;

        /**
         * Window type: Navigation bar panel (when navigation bar is distinct from status bar)
         * In multiuser systems shows on all users' windows.
         * @hide
         */
        public static final int TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24;

        /**
         * Window type: Display overlay window.  Used to simulate secondary display devices.
         * In multiuser systems shows on all users' windows.
         * @hide
         */
        public static final int TYPE_DISPLAY_OVERLAY = FIRST_SYSTEM_WINDOW+26;

        /**
         * Window type: Magnification overlay window. Used to highlight the magnified
         * portion of a display when accessibility magnification is enabled.
         * In multiuser systems shows on all users' windows.
         * @hide
         */
        public static final int TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27;

        /**
         * Window type: keyguard scrim window. Shows if keyguard needs to be restarted.
         * In multiuser systems shows on all users' windows.
         * @hide
         */
        public static final int TYPE_KEYGUARD_SCRIM           = FIRST_SYSTEM_WINDOW+29;

        /**
         * Window type: Window for Presentation on top of private
         * virtual display.
         */
        public static final int TYPE_PRIVATE_PRESENTATION = FIRST_SYSTEM_WINDOW+30;

        /**
         * Window type: Windows in the voice interaction layer.
         * @hide
         */
        public static final int TYPE_VOICE_INTERACTION = FIRST_SYSTEM_WINDOW+31;

        /**
         * Window type: Windows that are overlaid <em>only</em> by a connected {@link
         * android.accessibilityservice.AccessibilityService} for interception of
         * user interactions without changing the windows an accessibility service
         * can introspect. In particular, an accessibility service can introspect
         * only windows that a sighted user can interact with which is they can touch
         * these windows or can type into these windows. For example, if there
         * is a full screen accessibility overlay that is touchable, the windows
         * below it will be introspectable by an accessibility service even though
         * they are covered by a touchable window.
         */
        public static final int TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32;

        /**
         * Window type: Starting window for voice interaction layer.
         * @hide
         */
        public static final int TYPE_VOICE_INTERACTION_STARTING = FIRST_SYSTEM_WINDOW+33;

        /**
         * Window for displaying a handle used for resizing docked stacks. This window is owned
         * by the system process.
         * @hide
         */
        public static final int TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW+34;

        /**
         * Window type: like {@link #TYPE_APPLICATION_ATTACHED_DIALOG}, but used
         * by Quick Settings Tiles.
         * @hide
         */
        public static final int TYPE_QS_DIALOG = FIRST_SYSTEM_WINDOW+35;

        /**
         * Window type: shares similar characteristics with {@link #TYPE_DREAM}. The layer is
         * reserved for screenshot region selection. These windows must not take input focus.
         * @hide
         */
        public static final int TYPE_SCREENSHOT = FIRST_SYSTEM_WINDOW + 36;

        /**
         * End of types of system windows.
         */
        public static final int LAST_SYSTEM_WINDOW      = 2999;

Connection process between window and Windows Manager Service service

Back to the setView method in ViewRootImpl:

    /**
    * We have one child
    */
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                mView = view;
                // ......
                // Schedule the first layout -before- adding to the window
                // manager, to make sure we do the relayout before receiving
                // any other events from the system.
                // Layout mapping begins with this method.
                requestLayout();
                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) {
                    mAdded = false;
                    mView = null;
                    mAttachInfo.mRootView = null;
                    mInputChannel = null;
                    mFallbackEventHandler.setView(null);
                    unscheduleTraversals();
                    setAccessibilityFocus(null, null);
                    throw new RuntimeException("Adding window failed", e);
                } finally {
                    if (restore) {
                        attrs.restore();
                    }
                }
                // ......
        }
    }

RequLayout () is a very valuable method, if you want to read this article Drawing process of source code parsing-View We mainly analyze the mWindows Session. addToDisplay method. What is mWindows Session? Seeing Session actually still knows what it means. Is it really similar to Session on the Internet? MWindows Session is obtained through Windows Manager Global. get Windows Session (); let's go and see:

    public static IWindowSession getWindowSession() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowSession == null) {
                try {
                    InputMethodManager imm = InputMethodManager.getInstance();
                    IWindowManager windowManager = getWindowManagerService();
                    sWindowSession = windowManager.openSession(
                            new IWindowSessionCallback.Stub() {
                                @Override
                                public void onAnimatorScaleChanged(float scale) {
                                    ValueAnimator.setDurationScale(scale);
                                }
                            },
                            imm.getClient(), imm.getInputContext());
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowSession;
        }
    }

    public static IWindowManager getWindowManagerService() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowManagerService == null) {
                sWindowManagerService = IWindowManager.Stub.asInterface(
                        ServiceManager.getService("window"));
                try {
                    sWindowManagerService = getWindowManagerService();
                    ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowManagerService;
        }
    }

This is another typical IPC communication mechanism. It's very similar to AMS. Android Interprocess Communication - IPC (Mechanism) Binder's Principle and Source Reading Now let's go to the openSession method of the server-side Windows Manager Service:

    @Override
    public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,
            IInputContext inputContext) {
        if (client == null) throw new IllegalArgumentException("null client");
        if (inputContext == null) throw new IllegalArgumentException("null inputContext");
        Session session = new Session(this, callback, client, inputContext);
        return session;
    }

Session we finally got, the server-side Windows Manager Service created a Session object and returned. Then we found that Session's addToDisplay method came to Windows Manager's addWindow method. I believe it should be almost finished. This is not a human thing.

    public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            InputChannel outInputChannel) {
        ......  
  
        WindowState attachedWindow = null;  
        final int type = attrs.type;
  
        synchronized(mWindowMap) {  
            ......  
  
            if (mWindowMap.containsKey(client.asBinder())) {  
                ......  
                return WindowManagerImpl.ADD_DUPLICATE_ADD;  
            } 

This code first checks whether there is a Windows State object corresponding to the parameter client in a HashMap described by the member variable mWindows Manager Service class. If it already exists, it indicates that the Windows Manager Service service has created a Windows State object for it. Therefore, instead of proceeding further, it returns a Windows State object directly. Error code Windows Manager Impl. ADD_DUPLICATE_ADD. Let's move on to the code:

if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) {  
    attachedWindow = windowForClientLocked(null, attrs.token, false);  
    if (attachedWindow == null) {  
        ......  
        return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;  
    }  
    if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW  
            && attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) {  
        ......  
        return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;  
    }  
}  

The parameter attrs refers to a Windows Manager.LayoutParams object that describes the UI layout of the Activity component being started. When its member variable type is greater than or equal to FIRST_SUB_WINDOW and less than or equal to LAST_SUB_WINDOW, it means that a sub-window is to be added now. In this case, you have to specify a parent window, which is specified by the member variable token of a Windows Manager. LayoutParams object pointed to by the number attrs, so this code calls another member function of the Windows Manager Service class, windows ForClientLocked, to get a Windows State object that describes the parent window, and And save it in the variable attachedWindow.

If the value of the variable attachedWindow is equal to null, it means that the parent window does not exist, which is not allowed. Therefore, the function will not continue to execute forward, but directly return an error code of Windows ManagerImpl. ADD_BAD_SUBWINDOW_TOKEN. On the other hand, if the value of the variable attachedWindow is not equal to null, but the value of the member variable type of a Windows Manager. LayoutParams object pointed to by its member variable mAttrs is also greater than or equal to FIRST_SUB_WINDOW and less than or equal to LAST_SUB_WINDOW, then the parent window found is also a child window, which is also not allowed, so the function is not allowed. Instead of proceeding forward, an error code Windows Manager Impl. ADD_BAD_SUBWINDOW_TOKEN is returned directly.

Keep looking at the code:

// Some check legitimate code

win = new WindowState(session, client, token,  
        attachedWindow, attrs, viewVisibility);  
......  
mPolicy.adjustWindowParamsLw(win.mAttrs);  
  
res = mPolicy.prepareAddWindowLw(win, attrs);  
if (res != WindowManagerImpl.ADD_OKAY) {  
    return res;  
} 

After checking the validity above, you can create a Windows State object for the window you are adding. The member variable mPolicy of the Windows Manager Service class points to a window management policy that implements the Windows Manager Policy interface. In Phone platform, this window management strategy is implemented by com. android. internal. policy. impl. Phone Windows Manager, which is responsible for making some rules for window implementation in the system. This is mainly to call the member function adjustWindows ParamsLw of the window management policy to adjust the layout parameters of the window currently being added, and call the member function prepareAddWindows Lw to check whether the window requested by the current application process is legitimate. If it is not legal, that is, the value of the variable res is not equal to Windows Manager Impl. ADD_OKAY, then the function will not continue to execute forward and return the error code res directly.

We'll see here first, and you can even go to see what the member variables of Windows State do, or what the legitimate checking code does, and so on. Finally, I'll draw a sketch.


Connection model between Activity component and Windows Manager Service service.png

It took me about half a month to barely understand some of the source code, including all the source links in this article. If you don't understand it well, it will take more time. If you can't stand the text, you can watch my live video. This is the last article in the custom View section.

All sharing outlines: Android Advanced Journey - Custom View Paper

Video Address: 8 p.m. Saturday

Posted by TheDeadPool on Mon, 03 Jun 2019 17:54:41 -0700