Android 9.0 system source code_window management (3) WindowManagerService's process of window management

foreword

In the previous article, we specifically analyzed the process of adding windows by the addView method of WindowManager. We know that WindowManager will eventually call the addWindow method of WindowManagerService. In this article, on this basis, we will specifically analyze the process of adding windows by the addWindow method of WindowManagerService. The code logic of this method is very long, so be mentally prepared in advance.

1. The addWindow method of WindowManagerService is as follows.

frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

public class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
    
    
        
    //窗口管理策略的接口类,用来定义一个窗口策略所要遵循的通用规范,具体实现类为PhoneWindowManager。
    final WindowManagerPolicy mPolicy;
    public int addWindow(Session session, IWindow client, int seq,
            LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
    
    
                    int[] appOp = new int[1];
			        int res = mPolicy.checkAddPermission(attrs, appOp);
			        if (res != WindowManagerGlobal.ADD_OKAY) {
    
    
			            return res;
			        }
			        ...代码省略...
            }
}

The addWindow method will first call the checkAddPermission method of WindowManagerPolicy to judge the permission. WindowManagerPolicy is an interface, and the specific implementer is PhoneWindowManager.

2. The checkAddPermission method of PhoneWindowManager is as follows.

frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

public class PhoneWindowManager implements WindowManagerPolicy {
    
    

    public int checkAddPermission(WindowManager.LayoutParams attrs, int[] outAppOp) {
    
    
        final int type = attrs.type;
        final boolean isRoundedCornerOverlay =
                (attrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0;

        if (isRoundedCornerOverlay && mContext.checkCallingOrSelfPermission(INTERNAL_SYSTEM_WINDOW)
                != PERMISSION_GRANTED) {
    
    
            return ADD_PERMISSION_DENIED;
        }

        outAppOp[0] = AppOpsManager.OP_NONE;
		//判断是不是一个合法的窗口类型,必须是应用窗口、子窗口、系统窗口三种类型中的一种。
        if (!((type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW)
                || (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW)
                || (type >= FIRST_SYSTEM_WINDOW && type <= LAST_SYSTEM_WINDOW))) {
    
    
            return WindowManagerGlobal.ADD_INVALID_TYPE;
        }

        if (type < FIRST_SYSTEM_WINDOW || type > LAST_SYSTEM_WINDOW) {
    
    
            // Window manager will make sure these are okay.
            return ADD_OKAY;
        }
        
		//如果不是系统弹窗
        if (!isSystemAlertWindowType(type)) {
    
    
            switch (type) {
    
    
                case TYPE_TOAST:
                    // Only apps that target older than O SDK can add window without a token, after
                    // that we require a token so apps cannot add toasts directly as the token is
                    // added by the notification system.
                    // Window manager does the checking for this.
                    outAppOp[0] = OP_TOAST_WINDOW;
                    return ADD_OKAY;
                case TYPE_DREAM:
                case TYPE_INPUT_METHOD:
                case TYPE_WALLPAPER:
                case TYPE_PRESENTATION:
                case TYPE_PRIVATE_PRESENTATION:
                case TYPE_VOICE_INTERACTION:
                case TYPE_ACCESSIBILITY_OVERLAY:
                case TYPE_QS_DIALOG:
                    // The window manager will check these.
                    return ADD_OKAY;
            }
            return mContext.checkCallingOrSelfPermission(INTERNAL_SYSTEM_WINDOW)
                    == PERMISSION_GRANTED ? ADD_OKAY : ADD_PERMISSION_DENIED;
        }

        // Things get a little more interesting for alert windows...
        outAppOp[0] = OP_SYSTEM_ALERT_WINDOW;

        final int callingUid = Binder.getCallingUid();
        // system processes will be automatically granted privilege to draw
        if (UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
    
    
            return ADD_OKAY;
        }

		//获取弹窗对应的应用信息
        ApplicationInfo appInfo;
        try {
    
    
            appInfo = mContext.getPackageManager().getApplicationInfoAsUser(
                            attrs.packageName,
                            0 /* flags */,
                            UserHandle.getUserId(callingUid));
        } catch (PackageManager.NameNotFoundException e) {
    
    
            appInfo = null;
        }

        if (appInfo == null || (type != TYPE_APPLICATION_OVERLAY && appInfo.targetSdkVersion >= O)) {
    
    
            /**
             * Apps targeting >= {@link Build.VERSION_CODES#O} are required to hold
             * {@link android.Manifest.permission#INTERNAL_SYSTEM_WINDOW} (system signature apps)
             * permission to add alert windows that aren't
             * {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY}.
             */
            return (mContext.checkCallingOrSelfPermission(INTERNAL_SYSTEM_WINDOW)
                    == PERMISSION_GRANTED) ? ADD_OKAY : ADD_PERMISSION_DENIED;
        }

        // check if user has enabled this operation. SecurityException will be thrown if this app
        // has not been allowed by the user
        final int mode = mAppOpsManager.noteOpNoThrow(outAppOp[0], callingUid, attrs.packageName);
        switch (mode) {
    
    
            case AppOpsManager.MODE_ALLOWED:
            case AppOpsManager.MODE_IGNORED:
                // although we return ADD_OKAY for MODE_IGNORED, the added window will
                // actually be hidden in WindowManagerService
                return ADD_OKAY;
            case AppOpsManager.MODE_ERRORED:
                // Don't crash legacy apps
                if (appInfo.targetSdkVersion < M) {
    
    
                    return ADD_OKAY;
                }
                return ADD_PERMISSION_DENIED;
            default:
                // in the default mode, we will make a decision here based on
                // checkCallingPermission()
                return (mContext.checkCallingOrSelfPermission(SYSTEM_ALERT_WINDOW)
                        == PERMISSION_GRANTED) ? ADD_OKAY : ADD_PERMISSION_DENIED;
        }
    }
        
     //是不是系统弹窗
     public static boolean isSystemAlertWindowType(int type) {
    
    
            switch (type) {
    
    
                case TYPE_PHONE:
                case TYPE_PRIORITY_PHONE:
                case TYPE_SYSTEM_ALERT:
                case TYPE_SYSTEM_ERROR:
                case TYPE_SYSTEM_OVERLAY:
                case TYPE_APPLICATION_OVERLAY:
                    return true;
            }
            return false;
        }
}

checkAddPermission will make some window type and security-related permission judgments, and return the result to res. If res is not equal to WindowManagerGlobal.ADD_OKAY, addWindow of WindowManagerService will return directly, and combined with the previous article, we know that the return result will be received by ViewRootImpl.

3. The related operations after the setView method of ViewRootImpl receives the return value are as follows.

public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
    
    

  public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    
    
        synchronized (this) {
    
    
              ...代码省略...
               res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                       getHostVisibility(), mDisplay.getDisplayId(),
                       mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                       mAttachInfo.mOutsets, mInputChannel);
              ...代码省略...
              //会根据WindowManagerService返回的判断窗口是否添加成功,以便抛出各种异常
             if (res < WindowManagerGlobal.ADD_OKAY) {
    
    
                  mAttachInfo.mRootView = null;
                  mAdded = false;
                  mFallbackEventHandler.setView(null);
                  unscheduleTraversals();
                  setAccessibilityFocus(null, null);
                  switch (res) {
    
    
                      case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
                      case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
                          throw new WindowManager.BadTokenException(
                                  "Unable to add window -- token " + attrs.token
                                  + " is not valid; is your activity running?");
                      case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
                          throw new WindowManager.BadTokenException(
                                  "Unable to add window -- token " + attrs.token
                                  + " is not for an application");
                      case WindowManagerGlobal.ADD_APP_EXITING:
                          throw new WindowManager.BadTokenException(
                                  "Unable to add window -- app for token " + attrs.token
                                  + " is exiting");
                      case WindowManagerGlobal.ADD_DUPLICATE_ADD:
                          throw new WindowManager.BadTokenException(
                                  "Unable to add window -- window " + mWindow
                                  + " has already been added");
                      case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
                          // Silently ignore -- we would have just removed it
                          // right away, anyway.
                          return;
                      case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
                          throw new WindowManager.BadTokenException("Unable to add window "
                                  + mWindow + " -- another window of type "
                                  + mWindowAttributes.type + " already exists");
                      case WindowManagerGlobal.ADD_PERMISSION_DENIED:
                          throw new WindowManager.BadTokenException("Unable to add window "
                                  + mWindow + " -- permission denied for window type "
                                  + mWindowAttributes.type);
                      case WindowManagerGlobal.ADD_INVALID_DISPLAY:
                          throw new WindowManager.InvalidDisplayException("Unable to add window "
                                  + mWindow + " -- the specified display can not be found");
                      case WindowManagerGlobal.ADD_INVALID_TYPE:
                          throw new WindowManager.InvalidDisplayException("Unable to add window "
                                  + mWindow + " -- the specified window type "
                                  + mWindowAttributes.type + " is not valid");
                  }
                  throw new RuntimeException(
                          "Unable to add window -- unknown error code " + res);
            }
    }
}

ViewRootImpl will judge whether the window is added successfully according to the return value of WindowManagerService, so as to decide whether to throw various exception information.

4. Continue to look down at the addWindow method of WindowManagerService.

public class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
    
    

    public int addWindow(Session session, IWindow client, int seq,
            LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
    
    
			        ...代码省略...
			boolean reportNewConfig = false;
	        WindowState parentWindow = null;//父窗口
	        long origId;
	        final int callingUid = Binder.getCallingUid();//调用者id
	        final int type = attrs.type;//窗口类型
	
	        synchronized(mWindowMap) {
    
    
	            if (!mDisplayReady) {
    
    
	                throw new IllegalStateException("Display has not been initialialized");
	            }
	            
	            //获取窗口需要添加的屏幕设备是否为空
	            final DisplayContent displayContent = getDisplayContentOrCreate(displayId);
	            if (displayContent == null) {
    
    
	                Slog.w(TAG_WM, "Attempted to add window to a display that does not exist: "
	                        + displayId + ".  Aborting.");
	                return WindowManagerGlobal.ADD_INVALID_DISPLAY;
	            }
	            if (!displayContent.hasAccess(session.mUid)
	                    && !mDisplayManagerInternal.isUidPresentOnDisplay(session.mUid, displayId)) {
    
    
	                Slog.w(TAG_WM, "Attempted to add window to a display for which the application "
	                        + "does not have access: " + displayId + ".  Aborting.");
	                return WindowManagerGlobal.ADD_INVALID_DISPLAY;
	            }
	
	            if (mWindowMap.containsKey(client.asBinder())) {
    
    
	                Slog.w(TAG_WM, "Window " + client + " is already added");
	                return WindowManagerGlobal.ADD_DUPLICATE_ADD;
	            }
				//判断窗口是否是子窗口类型
	            if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
    
    
	                parentWindow = windowForClientLocked(null, attrs.token, false);
	                //判断父类窗口是否为空
	                if (parentWindow == null) {
    
    
	                    Slog.w(TAG_WM, "Attempted to add window with token that is not a window: "
	                          + attrs.token + ".  Aborting.");
	                    return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
	                }
	                //判断父类窗口是否为子窗口类型
	                if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
	                        && parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {
    
    
	                    Slog.w(TAG_WM, "Attempted to add window with token that is a sub-window: "
	                            + attrs.token + ".  Aborting.");
	                    return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
	                }
	            }
	           ...代码省略...
            }
}

The above code mainly makes two key judgments.
1) Obtain whether the specific screen device to be added is empty through the window to determine whether an exception needs to be returned.
2) If the window type is a child window, judge whether the parent window of the child window is empty and whether the type of the parent window is a child window to determine whether to return an exception.

5. Continue to look down at the addWindow method of WindowManagerService.

public class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
    
    

    public int addWindow(Session session, IWindow client, int seq,
            LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
    
     
			...代码省略...
            AppWindowToken atoken = null;
            //是否有父窗口
            final boolean hasParent = parentWindow != null;
            // 获取当前Window的令牌
            WindowToken token = displayContent.getWindowToken(
                    hasParent ? parentWindow.mAttrs.token : attrs.token);
            // 获取当前Window的跟类型
            final int rootType = hasParent ? parentWindow.mAttrs.type : type;

            boolean addToastWindowRequiresToken = false;

            if (token == null) {
    
    //如果Window的令牌为空
                if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
    
    //应用程序窗口
                    Slog.w(TAG_WM, "Attempted to add application window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                if (rootType == TYPE_INPUT_METHOD) {
    
    //输入法
                    Slog.w(TAG_WM, "Attempted to add input method window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                if (rootType == TYPE_VOICE_INTERACTION) {
    
    
                    Slog.w(TAG_WM, "Attempted to add voice interaction window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                if (rootType == TYPE_WALLPAPER) {
    
    //壁纸
                    Slog.w(TAG_WM, "Attempted to add wallpaper window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                if (rootType == TYPE_DREAM) {
    
    
                    Slog.w(TAG_WM, "Attempted to add Dream window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                if (rootType == TYPE_QS_DIALOG) {
    
    
                    Slog.w(TAG_WM, "Attempted to add QS dialog window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                if (rootType == TYPE_ACCESSIBILITY_OVERLAY) {
    
    
                    Slog.w(TAG_WM, "Attempted to add Accessibility overlay window with unknown token "
                            + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                if (type == TYPE_TOAST) {
    
    
                    // Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
                    if (doesAddToastWindowRequireToken(attrs.packageName, callingUid,
                            parentWindow)) {
    
    
                        Slog.w(TAG_WM, "Attempted to add a toast window with unknown token "
                                + attrs.token + ".  Aborting.");
                        return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                    }
                }
                final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
                final boolean isRoundedCornerOverlay =
                        (attrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0;
                //为窗口创建隐式令牌
                token = new WindowToken(this, binder, type, false, displayContent,
                        session.mCanAddInternalSystemWindow, isRoundedCornerOverlay);
            } else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
    
    //令牌不为空,且属于应用程序窗口
                atoken = token.asAppWindowToken();
                if (atoken == null) {
    
    
                    Slog.w(TAG_WM, "Attempted to add window with non-application token "
                          + token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_NOT_APP_TOKEN;
                } else if (atoken.removed) {
    
    
                    Slog.w(TAG_WM, "Attempted to add window with exiting application token "
                          + token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_APP_EXITING;
                } else if (type == TYPE_APPLICATION_STARTING && atoken.startingWindow != null) {
    
    
                    Slog.w(TAG_WM, "Attempted to add starting window to token with already existing"
                            + " starting window");
                    return WindowManagerGlobal.ADD_DUPLICATE_ADD;
                }
            } else if (rootType == TYPE_INPUT_METHOD) {
    
    //令牌不为空,且属于输入法窗口
                if (token.windowType != TYPE_INPUT_METHOD) {
    
    //判断令牌类型是否为输入法
                    Slog.w(TAG_WM, "Attempted to add input method window with bad token "
                            + attrs.token + ".  Aborting.");
                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
            } else if (rootType == TYPE_VOICE_INTERACTION) {
    
    
                if (token.windowType != TYPE_VOICE_INTERACTION) {
    
    
                    Slog.w(TAG_WM, "Attempted to add voice interaction window with bad token "
                            + attrs.token + ".  Aborting.");
                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
            } else if (rootType == TYPE_WALLPAPER) {
    
    //令牌不为空,且属于壁纸
                if (token.windowType != TYPE_WALLPAPER) {
    
    //判断令牌类型是否为壁纸
                    Slog.w(TAG_WM, "Attempted to add wallpaper window with bad token "
                            + attrs.token + ".  Aborting.");
                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
            } else if (rootType == TYPE_DREAM) {
    
    
                if (token.windowType != TYPE_DREAM) {
    
    
                    Slog.w(TAG_WM, "Attempted to add Dream window with bad token "
                            + attrs.token + ".  Aborting.");
                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
            } else if (rootType == TYPE_ACCESSIBILITY_OVERLAY) {
    
    
                if (token.windowType != TYPE_ACCESSIBILITY_OVERLAY) {
    
    
                    Slog.w(TAG_WM, "Attempted to add Accessibility overlay window with bad token "
                            + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
            } else if (type == TYPE_TOAST) {
    
    //令牌不为空,且属于吐司
                // Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
                addToastWindowRequiresToken = doesAddToastWindowRequireToken(attrs.packageName,
                        callingUid, parentWindow);
                if (addToastWindowRequiresToken && token.windowType != TYPE_TOAST) {
    
    
                    Slog.w(TAG_WM, "Attempted to add a toast window with bad token "
                            + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
            } else if (type == TYPE_QS_DIALOG) {
    
    
                if (token.windowType != TYPE_QS_DIALOG) {
    
    
                    Slog.w(TAG_WM, "Attempted to add QS dialog window with bad token "
                            + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
            } else if (token.asAppWindowToken() != null) {
    
    
                Slog.w(TAG_WM, "Non-null appWindowToken for system window of rootType=" + rootType);
                // It is not valid to use an app token with other system types; we will
                // instead make a new token for it (as if null had been passed in for the token).
                attrs.token = null;
                token = new WindowToken(this, client.asBinder(), type, false, displayContent,
                        session.mCanAddInternalSystemWindow);
            }
            ...代码省略...
      }
}            

The above code mainly makes judgments in two directions.
1) The window token is empty, combined with the window root type to determine whether an exception needs to be returned, if not, an implicit token will be created for the window at the end.
2) If the window token is not empty, it will further combine the type of the window token to determine whether an exception needs to be returned.

6. Continue to look down at the addWindow method of WindowManagerService.

public class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
    
    

    public int addWindow(Session session, IWindow client, int seq,
            LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
    
     
			...代码省略...
            final WindowState win = new WindowState(this, session, client, token, parentWindow,
                    appOp[0], seq, attrs, viewVisibility, session.mUid,
                    session.mCanAddInternalSystemWindow);
            if (win.mDeathRecipient == null) {
    
    
                // Client has apparently died, so there is no reason to
                // continue.
                Slog.w(TAG_WM, "Adding window client " + client.asBinder()
                        + " that is dead, aborting.");
                return WindowManagerGlobal.ADD_APP_EXITING;
            }

            if (win.getDisplayContent() == null) {
    
    
                Slog.w(TAG_WM, "Adding window to Display that has been removed.");
                return WindowManagerGlobal.ADD_INVALID_DISPLAY;
            }

            final boolean hasStatusBarServicePermission =
                    mContext.checkCallingOrSelfPermission(permission.STATUS_BAR_SERVICE)
                            == PackageManager.PERMISSION_GRANTED;
            mPolicy.adjustWindowParamsLw(win, win.mAttrs, hasStatusBarServicePermission);
            win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
            //在将弹窗添加到WindowManagerService前,做一些准备工作,具体实现类为PhoneWindowManager
            res = mPolicy.prepareAddWindowLw(win, attrs);
            if (res != WindowManagerGlobal.ADD_OKAY) {
    
    
                return res;
            }
           ...代码省略...
         }
   }

7. Continue to look down at the addWindow method of WindowManagerService.

public class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
    
    

    public int addWindow(Session session, IWindow client, int seq,
            LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
    
     
			...代码省略...
            final boolean openInputChannels = (outInputChannel != null
                    && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
            if  (openInputChannels) {
    
    
                win.openInputChannel(outInputChannel);
            }

            // If adding a toast requires a token for this app we always schedule hiding
            // toast windows to make sure they don't stick around longer then necessary.
            // We hide instead of remove such windows as apps aren't prepared to handle
            // windows being removed under them.
            //
            // If the app is older it can add toasts without a token and hence overlay
            // other apps. To be maximally compatible with these apps we will hide the
            // window after the toast timeout only if the focused window is from another
            // UID, otherwise we allow unlimited duration. When a UID looses focus we
            // schedule hiding all of its toast windows.
            if (type == TYPE_TOAST) {
    
    
                if (!getDefaultDisplayContentLocked().canAddToastWindowForUid(callingUid)) {
    
    
                    Slog.w(TAG_WM, "Adding more than one toast window for UID at a time.");
                    return WindowManagerGlobal.ADD_DUPLICATE_ADD;
                }
                // Make sure this happens before we moved focus as one can make the
                // toast focusable to force it not being hidden after the timeout.
                // Focusable toasts are always timed out to prevent a focused app to
                // show a focusable toasts while it has focus which will be kept on
                // the screen after the activity goes away.
                if (addToastWindowRequiresToken
                        || (attrs.flags & LayoutParams.FLAG_NOT_FOCUSABLE) == 0
                        || mCurrentFocus == null
                        || mCurrentFocus.mOwnerUid != callingUid) {
    
    
                    mH.sendMessageDelayed(
                            mH.obtainMessage(H.WINDOW_HIDE_TIMEOUT, win),
                            win.mAttrs.hideTimeoutMilliseconds);
                }
            }

            // From now on, no exceptions or errors allowed!

            res = WindowManagerGlobal.ADD_OKAY;
            if (mCurrentFocus == null) {
    
    
                mWinAddedSinceNullFocus.add(win);
            }

            if (excludeWindowTypeFromTapOutTask(type)) {
    
    
                displayContent.mTapExcludedWindows.add(win);
            }

            origId = Binder.clearCallingIdentity();

            win.attach();
            mWindowMap.put(client.asBinder(), win);

            win.initAppOpsState();

            final boolean suspended = mPmInternal.isPackageSuspended(win.getOwningPackage(),
                    UserHandle.getUserId(win.getOwningUid()));
            win.setHiddenWhileSuspended(suspended);

            final boolean hideSystemAlertWindows = !mHidingNonSystemOverlayWindows.isEmpty();
            win.setForceHideNonSystemOverlayWindowIfNeeded(hideSystemAlertWindows);

            final AppWindowToken aToken = token.asAppWindowToken();
            if (type == TYPE_APPLICATION_STARTING && aToken != null) {
    
    
                aToken.startingWindow = win;
                if (DEBUG_STARTING_WINDOW) Slog.v (TAG_WM, "addWindow: " + aToken
                        + " startingWindow=" + win);
            }

            boolean imMayMove = true;

            win.mToken.addWindow(win);
            if (type == TYPE_INPUT_METHOD) {
    
    
                win.mGivenInsetsPending = true;
                setInputMethodWindowLocked(win);
                imMayMove = false;
            } else if (type == TYPE_INPUT_METHOD_DIALOG) {
    
    
                displayContent.computeImeTarget(true /* updateImeTarget */);
                imMayMove = false;
            } else {
    
    
                if (type == TYPE_WALLPAPER) {
    
    
                    displayContent.mWallpaperController.clearLastWallpaperTimeoutTime();
                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                } else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
    
    
                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                } else if (displayContent.mWallpaperController.isBelowWallpaperTarget(win)) {
    
    
                    // If there is currently a wallpaper being shown, and
                    // the base layer of the new window is below the current
                    // layer of the target window, then adjust the wallpaper.
                    // This is to avoid a new window being placed between the
                    // wallpaper and its target.
                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                }
            }
           ...代码省略...
         }
   }            

8. Continue to look down

public class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
    
    

    public int addWindow(Session session, IWindow client, int seq,
            LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
    
     
				...代码省略...
	    	 	// If the window is being added to a stack that's currently adjusted for IME,
	            // make sure to apply the same adjust to this new window.
	            win.applyAdjustForImeIfNeeded();
	
	            if (type == TYPE_DOCK_DIVIDER) {
    
    
	                mRoot.getDisplayContent(displayId).getDockedDividerController().setWindow(win);
	            }
	
	            final WindowStateAnimator winAnimator = win.mWinAnimator;
	            winAnimator.mEnterAnimationPending = true;
	            winAnimator.mEnteringAnimation = true;
	            // Check if we need to prepare a transition for replacing window first.
	            if (atoken != null && atoken.isVisible()
	                    && !prepareWindowReplacementTransition(atoken)) {
    
    
	                // If not, check if need to set up a dummy transition during display freeze
	                // so that the unfreeze wait for the apps to draw. This might be needed if
	                // the app is relaunching.
	                prepareNoneTransitionForRelaunching(atoken);
	            }
	
	            final DisplayFrames displayFrames = displayContent.mDisplayFrames;
	            // TODO: Not sure if onDisplayInfoUpdated() call is needed.
	            final DisplayInfo displayInfo = displayContent.getDisplayInfo();
	            displayFrames.onDisplayInfoUpdated(displayInfo,
	                    displayContent.calculateDisplayCutoutForRotation(displayInfo.rotation));
	            final Rect taskBounds;
	            if (atoken != null && atoken.getTask() != null) {
    
    
	                taskBounds = mTmpRect;
	                atoken.getTask().getBounds(mTmpRect);
	            } else {
    
    
	                taskBounds = null;
	            }
	            if (mPolicy.getLayoutHintLw(win.mAttrs, taskBounds, displayFrames, outFrame,
	                    outContentInsets, outStableInsets, outOutsets, outDisplayCutout)) {
    
    
	                res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR;
	            }
	
	            if (mInTouchMode) {
    
    
	                res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE;
	            }
	            if (win.mAppToken == null || !win.mAppToken.isClientHidden()) {
    
    
	                res |= WindowManagerGlobal.ADD_FLAG_APP_VISIBLE;
	            }
	
	            mInputMonitor.setUpdateInputWindowsNeededLw();
	
	            boolean focusChanged = false;
	            if (win.canReceiveKeys()) {
    
    
	                focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
	                        false /*updateInputWindows*/);
	                if (focusChanged) {
    
    
	                    imMayMove = false;
	                }
	            }
	
	            if (imMayMove) {
    
    
	                displayContent.computeImeTarget(true /* updateImeTarget */);
	            }
	
	            // Don't do layout here, the window must call
	            // relayout to be displayed, so we'll do it there.
	            win.getParent().assignChildLayers();
	
	            if (focusChanged) {
    
    
	                mInputMonitor.setInputFocusLw(mCurrentFocus, false /*updateInputWindows*/);
	            }
	            mInputMonitor.updateInputWindowsLw(false /*force*/);
	
	            if (localLOGV || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addWindow: New client "
	                    + client.asBinder() + ": window=" + win + " Callers=" + Debug.getCallers(5));
	
	            if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(displayId)) {
    
    
	                reportNewConfig = true;
	            }
	        }
	
	        if (reportNewConfig) {
    
    
	            sendNewConfiguration(displayId);
	        }
	
	        Binder.restoreCallingIdentity(origId);
	
	        return res;
         }
   }

おすすめ

転載: blog.csdn.net/abc6368765/article/details/129821270