Android 12系统源码_窗口管理(四)窗口令牌WindowToken和窗口状态WindowState

RootWindowContainer是Android12系统中WindowManagerService的重要组成部分,负责管理所有窗口的层级、布局和生命周期。它在WindowManagerService创建时初始化,并处理多屏幕显示设备的情况。RootWindowContainer还涉及窗口的焦点变化、睡眠令牌和用户活动超时等关键功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

在 Android 系统中,WindowToken(窗口令牌) 和 WindowState(窗口状态)是两个重要的类,用于管理窗口视图的显示和布局。
WindowToken用于标识窗口中的视图层级,而WindowState用于管理窗口的状态和属性。这两个类在 Android 系统中起着重要的作用,帮助确保应用程序界面正确地显示和布局,只有认识了这两个类我们才能更好的理解WindowManagerService这个服务。

WindowContainer

类介绍

/**
 * Defines common functionality for classes that can hold windows directly or through their
 * children in a hierarchy form.
 * The test class is {@link WindowContainerTests} which must be kept up-to-date and ran anytime
 * changes are made to this class.
 */
class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
        implements Comparable<WindowContainer>, Animatable, SurfaceFreezer.Freezable {
}

WindowContainer为哪些可以在层级树表格中可以直接持有窗口或者通过子类进行持有的类定义了一些通用的方法和属性。

继承关系

代码中常见的RootWindowContainer、DisplayContent、DisplayArea、DisplayArea.Tokens、TaskDisplayArea、Task、ActivityRecord、WindowToken、WindowState都是直接或间接的继承该类,具体继承关系可以参看下图。继承关系

  • RootWindowContainer:根窗口容器,树的根是它。通过它遍历寻找,可以找到窗口树上的窗口。它的孩子是DisplayContent。
  • DisplayContent:该类是对应着显示屏幕的,Android是支持多屏幕的,所以可能存在多个DisplayContent对象。上图只画了一个对象的结构,其他对象的结构也是和画的对象的结构是相似的。
  • DisplayArea:该类是对应着显示屏幕下面的,代表一组窗口合集,具有多个子类,如Tokens,TaskDisplayArea等
  • TaskDisplayArea:它为DisplayContent的孩子,对应着窗口层次的第2层。第2层作为应用层,看它的定义:int APPLICATION_LAYER = 2,应用层的窗口是处于第2层。TaskDisplayArea的孩子是Task类,其实它的孩子类型也可以是TaskDisplayArea。而Task的孩子则可以是ActivityRecord,也可以是Task。
  • Tokens:代表专门包含WindowTokens的容器,它的孩子是WindowToken,而WindowToken的孩子则为WindowState对象。WindowState是对应着一个窗口的。
  • ImeContainer:它是输入法窗口的容器,它的孩子是WindowToken类型。WindowToken的孩子为WindowState类型,而WindowState类型则对应着输入法窗口。
  • Task:任务,它的孩子可以是Task,也可以是ActivityRecord类型。
  • ActivityRecord:是对应着应用进程中的Activity的。ActivityRecord是继承WindowToken的,它的孩子类型为WindowState。
  • WindowState:WindowState是对应着一个窗口的。

重要成员变量

class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
        implements Comparable<WindowContainer>, Animatable, SurfaceFreezer.Freezable {
    //窗口层级的父节点
    private WindowContainer<WindowContainer> mParent = null;

    //子节点,而且子节点的list顺序代表就是z轴的层级显示顺序,尾部的节点比头部的节点的z轴层级要高。
    protected final WindowList<E> mChildren = new WindowList<E>();
}

窗口层级结构树

如果我们一上来就结合系统源码去学习WMS关于窗口的层级结构,那么总会有一种盲人摸象的感觉,比较好的方法是我们先对实际运行种的系统的窗口层级数有个整体认识,然后再结合源码进行分析。

层级结构树堆栈信息

通过adb shell dumpsys activity containers可以打印出当前系统中的窗口层级数信息。

ACTIVITY MANAGER CONTAINERS (dumpsys activity containers)
ROOT type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
  #0 Display 0 name="内置屏幕" type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][1080,2400] bounds=[0,0][1080,2400]
   #4 Leaf:100:100 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
   #3 HideDisplayCutout:58:99 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
    #2 OneHanded:67:99 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
     #0 FullscreenMagnification:67:99 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
      #0 Leaf:67:99 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
    #1 FullscreenMagnification:66:66 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
     #0 Leaf:66:66 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
      #0 WindowToken{bd56012 type=2015 android.view.OplusViewRootImplHooks$ColorW@fd9139d} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
       #0 98f51e0 PointerLocation - display 0 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
    #0 OneHanded:58:65 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
     #2 FullscreenMagnification:61:65 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
      #0 Leaf:61:65 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
       #1 WindowToken{61c5371 type=2026 android.os.BinderProxy@e64d18} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
        #0 8445e51 OplusPrivacyIconTopRight type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
       #0 WindowToken{376c16c type=2026 android.os.BinderProxy@c65d140} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
        #0 ca5537a OplusPrivacyIconTopLeft type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
     #1 Leaf:60:60 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
     #0 FullscreenMagnification:58:59 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
      #0 Leaf:58:59 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
   #2 Leaf:56:57 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
    #3 WindowToken{cf318e2 type=2024 android.os.BinderProxy@789edad} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
     #0 38d3f30 ColorSideGestureRight type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
    #2 WindowToken{624f0b type=2024 android.os.BinderProxy@ac2eeda} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
     #0 664d0e7 ColorSideGestureLeft type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
    #1 WindowToken{4b77211 type=2024 android.os.BinderProxy@ad64238} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
     #0 102ef76 pip-dismiss-overlay type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
    #0 WindowToken{fec29ba type=2019 android.os.BinderProxy@22239dc} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
     #0 c20a06b NavigationBar0 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
   #1 HideDisplayCutout:32:55 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
    #0 OneHanded:32:55 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
     #1 FullscreenMagnification:33:55 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
      #0 Leaf:33:55 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
     #0 Leaf:32:32 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
   #0 WindowedMagnification:0:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
    #4 HideDisplayCutout:18:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
     #0 OneHanded:18:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
      #0 FullscreenMagnification:18:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
       #0 Leaf:18:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
    #3 OneHanded:17:17 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
     #0 FullscreenMagnification:17:17 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
      #0 Leaf:17:17 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
       #0 WindowToken{ea3abd8 type=2040 android.os.BinderProxy@712fb4a} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
        #0 b1c2b31 NotificationShade type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
    #2 HideDisplayCutout:16:16 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
     #0 OneHanded:16:16 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
      #0 FullscreenMagnification:16:16 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
       #0 Leaf:16:16 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
    #1 OneHanded:15:15 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
     #0 FullscreenMagnification:15:15 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
      #0 Leaf:15:15 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
       #0 WindowToken{44ec633 type=2000 android.os.BinderProxy@dd7496d} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
        #0 4601df0 StatusBar type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
    #0 HideDisplayCutout:0:14 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
     #0 OneHanded:0:14 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
      #1 ImePlaceholder:13:14 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
       #0 ImeContainer type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
        #0 WindowToken{e664e78 type=2011 android.os.Binder@994c3db} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
         #0 bcd1b0e InputMethod type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
      #0 FullscreenMagnification:0:12 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
       #2 Leaf:3:12 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
        #0 WindowToken{4065228 type=2038 android.os.BinderProxy@a616862} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
         #0 c3e851a ShellDropTarget type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
       #1 DefaultTaskDisplayArea type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
        #3 Task=51 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
         #0 ActivityRecord{eb42d1c u0 com.example.empty/.InputActivity} t51} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
          #0 5c35675 com.example.empty/com.example.empty.InputActivity type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
        #2 Task=1 type=home mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
         #0 Task=2 type=home mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
          #0 ActivityRecord{bc97017 u0 com.android.launcher/.Launcher} t2} type=home mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
           #1 353c57c com.coloros.assistantscreen type=home mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
           #0 11637b5 com.android.launcher/com.android.launcher.Launcher type=home mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
        #1 Task=3 type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
        #0 Task=4 type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
         #1 Task=6 type=undefined mode=multi-window override-mode=multi-window requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
         #0 Task=5 type=undefined mode=multi-window override-mode=multi-window requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
       #0 Leaf:0:1 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
        #0 WallpaperWindowToken{c7090c2 token=android.os.Binder@1f4d90d} type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]
         #0 7f48c51 com.android.systemui.ImageWallpaper type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2400]

可以将以上dumpsys的输入信息转化为图表,看起来会更加直观。

一、WindowToken(窗口令牌)

1、介绍

  • WindowToken主要用于标识Android系统中窗口中的特定视图层级,它代表了窗口中的一个视图层级的令牌。
  • 在 Android 中,窗口是视图层级的容器,用于组织和管理应用程序界面中的不同元素。每个窗口都有一个关联的 WindowToken,用于标识该窗口中的视图层级。
  • WindowToken 通常与窗口管理器一起使用,用于跟踪窗口的属性和状态,并确保正确地显示和管理窗口。
  • 例如,当应用程序中有多个窗口(例如活动、对话框、弹出窗口等)时,每个窗口都有自己的 WindowToken,用于标识其包含的视图层级。

2、WindowToken这个类如下所示。

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

class WindowToken extends WindowContainer<WindowState> {

    final IBinder token;
    final int windowType;
    final Bundle mOptions;
    private final boolean mFromClientToken;
    private boolean mClientVisible;
    
    protected WindowToken(WindowManagerService service, IBinder _token, int type,
            boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens) {
        this(service, _token, type, persistOnEmpty, dc, ownerCanManageAppTokens,
                false /* roundedCornerOverlay */, false /* fromClientToken */, null /* options */);
    }

    protected WindowToken(WindowManagerService service, IBinder _token, int type,
            boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens,
            boolean roundedCornerOverlay, boolean fromClientToken, @Nullable Bundle options) {
        super(service);
        token = _token;
        windowType = type;
        mOptions = options;
        mPersistOnEmpty = persistOnEmpty;
        mOwnerCanManageAppTokens = ownerCanManageAppTokens;
        mRoundedCornerOverlay = roundedCornerOverlay;
        mFromClientToken = fromClientToken;
        if (dc != null) {
            dc.addWindowToken(token, this);
        }
    }

    static class Builder {
        private final WindowManagerService mService;
        private final IBinder mToken;
        @WindowType
        private final int mType;

        private boolean mPersistOnEmpty;
        private DisplayContent mDisplayContent;
        private boolean mOwnerCanManageAppTokens;
        private boolean mRoundedCornerOverlay;
        private boolean mFromClientToken;
        @Nullable
        private Bundle mOptions;

        Builder(WindowManagerService service, IBinder token, int type) {
            mService = service;
            mToken = token;
            mType = type;
        }

        /** @see WindowToken#mPersistOnEmpty */
        Builder setPersistOnEmpty(boolean persistOnEmpty) {
            mPersistOnEmpty = persistOnEmpty;
            return this;
        }

        /** Sets the {@link DisplayContent} to be associated. */
        Builder setDisplayContent(DisplayContent dc) {
            mDisplayContent = dc;
            return this;
        }

        /** @see WindowToken#mOwnerCanManageAppTokens */
        Builder setOwnerCanManageAppTokens(boolean ownerCanManageAppTokens) {
            mOwnerCanManageAppTokens = ownerCanManageAppTokens;
            return this;
        }

        /** @see WindowToken#mRoundedCornerOverlay */
        Builder setRoundedCornerOverlay(boolean roundedCornerOverlay) {
            mRoundedCornerOverlay = roundedCornerOverlay;
            return this;
        }

        /** @see WindowToken#mFromClientToken */
        Builder setFromClientToken(boolean fromClientToken) {
            mFromClientToken = fromClientToken;
            return this;
        }

        /** @see WindowToken#mOptions */
        Builder setOptions(Bundle options) {
            mOptions = options;
            return this;
        }

        WindowToken build() {
            return new WindowToken(mService, mToken, mType, mPersistOnEmpty, mDisplayContent,
                    mOwnerCanManageAppTokens, mRoundedCornerOverlay, mFromClientToken, mOptions);
        }
    }
 }
  • WindowToken将属于同一个应用的组件窗口组织在一起。

所谓的应用组件可以是 Activity、InputMethod、Wallpaper以及Dream。在WMS对窗口的管理过程中,用 WindowToken指代一个应用组件。例如在进行窗口ZOrder排序时,属于同一个 WindowToken的窗口会被安排在一起,而且在其中定义的一些属性将会影响所有属于此WindowToken的窗口。这些都表明了属于同一个WindowToken的窗口之间的紧密联系。

  • WindowToken具有令牌的作用,是对应用组件的行为进行规范管理的一个手段。

WindowToken由应用组件或其管理者负责向WMS声明并持有。结合Android 12系统源码_窗口管理(三)WindowManagerService对窗口的管理过程我们可以知道,应用组件在需要新的窗口时,必须提供WindowToken以表明自己的身份,并且窗口的类型必须与所持有的WindowToken类型一致。

3、既然应用组件在创建一个窗口时必须指定一个有效的WindowToken才行,那么 WindowToken究竟该如何声明呢?来看一下WMS的addWindowToken方法。

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

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

    @Override
    public void addWindowToken(@NonNull IBinder binder, int type, int displayId,
                               @Nullable Bundle options) {
        //需要声明Token的调用者拥有MANAGE_APP_TOKENS的权限,否则直接抛出异常
        if (!checkCallingPermission(MANAGE_APP_TOKENS, "addWindowToken()")) {
            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
        }
        synchronized (mGlobalLock) {
            final DisplayContent dc = getDisplayContentOrCreate(displayId, null /* token */);
            if (dc == null) {
                ProtoLog.w(WM_ERROR, "addWindowToken: Attempted to add token: %s"
                        + " for non-exiting displayId=%d", binder, displayId);
                return;
            }
            WindowToken token = dc.getWindowToken(binder);
            if (token != null) {
                ProtoLog.w(WM_ERROR, "addWindowToken: Attempted to add binder token: %s"
                        + " for already created window token: %s"
                        + " displayId=%d", binder, token, displayId);
                return;
            }
            if (type == TYPE_WALLPAPER) {//如果是壁纸类型,则创建壁纸窗口令牌
                new WallpaperWindowToken(this, binder, true, dc,
                        true /* ownerCanManageAppTokens */, options);
            } else {
                //创建通用的窗口令牌
                new WindowToken.Builder(this, binder, type)
                        .setDisplayContent(dc)
                        .setPersistOnEmpty(true)
                        .setOwnerCanManageAppTokens(true)
                        .setOptions(options)
                        .build();
            }
        }
    }

}

二、WindowState(窗口状态)

1、介绍

  • WindowState 是一个表示窗口状态的类。它用于跟踪窗口的属性和状态,以确保窗口正确地显示和布局。
  • WindowState 包含了窗口的各种属性,如位置、大小、可见性等。通过管理这些属性,系统可以管理窗口的显示和布局。
  • WindowState 还可以包含其他与窗口相关的信息,如焦点状态、输入事件处理等。
  • 与 WindowToken 不同,WindowState 更专注于管理窗口的状态和属性,而不是标识窗口中的特定视图层级。

💡 技术无价,赞赏随心

写文不易,如果本文帮你避开了“八小时踩坑”,或者让你直呼“学到了!”
欢迎扫码赞赏,让我知道这篇内容值得!

<think>好的,我现在需要回答用户关于在WindowManagerService中如何调用getWindow()方法的问题。首先,我得理解用户的需求。他们可能是在进行Android系统开发或者定制ROM时遇到了相关问题,想要在WindowManagerService这个系统服务中获取某个窗口的实例。不过,用户可能对Android框架的层次结构不太清楚,特别是系统服务普通应用开发的区别。 首先,我应该回忆一下WindowManagerService(WMS)的作用。WMS是Android系统中的一个核心服务,负责管理所有窗口的布局、层级动画等。它运行在系统进程中,与应用进程中的WindowManager不同。应用开发中常用的getWindow()方法属于Activity类,用于获取当前Activity的窗口实例,但这在WMS中并不直接可用。 接下来,用户提到在WMS中调用getWindow(),这可能存在误解。我需要确认getWindow()是否存在于WMS中。根据我的知识,WMS本身并没有提供这样的方法,因为它的职责是管理所有窗口,而不是直接操作单个窗口对象。应用层的getWindow()返回的是PhoneWindow实例,而WMS处理的是WindowTokenWindowState等内部结构。 然后,我应该考虑用户可能的实际需求。他们可能想通过WMS获取某个特定窗口的引用,或者修改窗口属性。这时候需要解释WMS内部如何追踪窗口,比如通过WindowTokenWindowState。例如,WMS通过Session与客户端交互,每个窗口都有一个对应的WindowState对象,管理状态属性。 此外,需要强调系统服务的限制。普通应用无法直接访问WMS的内部方法,因为这些是@hide的或者需要系统权限。修改WMS的代码通常需要定制ROM或拥有系统级权限,比如系统签名或root权限。 可能的解决方案包括使用反射访问隐藏的API,或者通过Binder调用系统服务的方法。但需要警告用户这样做可能导致兼容性问题,并且在高版本Android中可能被限制。 最后,总结用户的误区,说明WMS应用层WindowManager的不同,并提供替代方案,如正确使用应用层的API或进行系统级开发时的注意事项。</think>--- ### 核心概念澄清 1. **WindowManagerService 与 getWindow() 的关系** - `WindowManagerService`(WMS)是系统级服务,运行在`system_server`进程中,**不直接暴露`getWindow()`方法** - 应用层`Activity.getWindow()`获取的是`PhoneWindow`对象(客户端窗口),与WMS中的窗口管理逻辑完全隔离 2. **窗口操作层级差异** | 层级 | 操作对象 | 典型接口 | 权限要求 | |---|---|---|---| | 应用层 | `PhoneWindow` | `Activity.getWindow()` | 无 | | 系统层 | `WindowState` | `WMS`内部接口 | 系统签名/root | --- ### 实现窗口操作的两种场景 #### 场景1:应用层窗口控制(常规开发) ```java // 在Activity中操作窗口属性 Window window = getWindow(); window.setLayout(width, height); // 设置窗口尺寸 window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); // 修改背景 ``` #### 场景2:系统窗口管理(需定制ROM) 1. **获取WindowState对象** WMS通过以下方式追踪窗口: ```java // 在WMS内部代码中 WindowState win = mWindowMap.get(IBinder token); // 通过Binder令牌获取窗口 ``` 2. **修改窗口属性的内部方法** ```java // 系统层操作示例(需系统权限) void adjustWindowSize(WindowState win, int newWidth, int newHeight) { win.mRequestedWidth = newWidth; win.mRequestedHeight = newHeight; win.computeFrameLw(); // 重新计算窗口框架 } ``` --- ### 关键限制与替代方案 1. **系统API保护机制** - `WindowManagerService`的关键方法被`@hide`标记,普通应用无法直接调用 - 需要添加系统签名(如`platform.pk8``platform.x509.pem`) 2. **反射访问风险示例(不推荐)** ```java try { Class<?> wmsClass = Class.forName("android.view.WindowManagerGlobal"); Method getWmService = wmsClass.getDeclaredMethod("getWindowManagerService"); IWindowManager wms = (IWindowManager) getWmService.invoke(null); } catch (Exception e) { // 高版本Android会抛出SecurityException } ``` 3. **合法替代方案** ```xml <!-- 声明系统权限(需内置到系统镜像) --> <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/> ``` --- ### 最佳实践建议 1. 常规应用开发应使用`Window``WindowManager.LayoutParams`的公开API 2. 系统级开发需: - 使用AOSP源码环境编译 - 通过`IWindowManager.aidl`接口通信 - 处理多用户场景下的窗口隔离(`DisplayContent``WindowContainer`) 若需调试窗口系统状态,可通过以下命令观察窗口层级: ```bash adb shell dumpsys window windows # 查看所有窗口状态 adb shell dumpsys activity top # 获取前台窗口信息 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值