【Android】图文解密Android WindowManagerService

1、简介

WindowManagerService(WMS)是Android中很重要的一个服务,主要的职责是与ActivityManagerService(AMS)交互以管理Window,与InputManagerService(IMS)交互以派发事件。分析WMS,先从下面的类图开始吧,看看相关的类都有哪些,主要的类包括WindowManagerService、WindowManagerImpl、PhoneWindowManager、WindowManagerGlobal、ViewRootImpl等。
在这里插入图片描述

2、启动

WMS是在SystemServer中启动的,下面的时序图展示了WMS及AMS、IMS的启动过程,以及它们是如何建立联系的。

在这里插入图片描述

3、addView

addView是一个常用的方法,流程图如下。从WindowManagerImpl开始,经WindowManagerGlobal、ViewRootImpl、Session,最后到WindowManagerService结束。在WMS的addWindow中,首先要检查权限,然后通过WindowToken、WindowState完成。

在这里插入图片描述

4、Layer

Window有三种类型,Application Window、Sub Window和System Window,这些Window有不同的Type,用int表示, Application Window从1到99,Sub Window从1000到1999,System Window从2000到2999,它们在WindowManager中定义,代码如下所示。

        public static final int FIRST_APPLICATION_WINDOW = 1;
        public static final int TYPE_BASE_APPLICATION   = 1;
        public static final int TYPE_APPLICATION        = 2;
        public static final int TYPE_APPLICATION_STARTING = 3;
        public static final int TYPE_DRAWN_APPLICATION = 4;
        public static final int LAST_APPLICATION_WINDOW = 99;

        public static final int FIRST_SUB_WINDOW = 1000;
        public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;
        public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1;
        public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2;
        public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3;
        public static final int TYPE_APPLICATION_MEDIA_OVERLAY  = FIRST_SUB_WINDOW + 4;
        public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5;
        public static final int LAST_SUB_WINDOW = 1999;

        public static final int FIRST_SYSTEM_WINDOW     = 2000;
        public static final int TYPE_STATUS_BAR         = FIRST_SYSTEM_WINDOW;
        public static final int TYPE_SEARCH_BAR         = FIRST_SYSTEM_WINDOW+1;
        public static final int TYPE_PHONE              = FIRST_SYSTEM_WINDOW+2;
        public static final int TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3;
        public static final int TYPE_KEYGUARD           = FIRST_SYSTEM_WINDOW+4;
        public static final int TYPE_TOAST              = FIRST_SYSTEM_WINDOW+5;
        public static final int TYPE_SYSTEM_OVERLAY     = FIRST_SYSTEM_WINDOW+6;
        public static final int TYPE_PRIORITY_PHONE     = FIRST_SYSTEM_WINDOW+7;
        public static final int TYPE_SYSTEM_DIALOG      = FIRST_SYSTEM_WINDOW+8;
        public static final int TYPE_KEYGUARD_DIALOG    = FIRST_SYSTEM_WINDOW+9;
        public static final int TYPE_SYSTEM_ERROR       = FIRST_SYSTEM_WINDOW+10;
        public static final int TYPE_INPUT_METHOD       = FIRST_SYSTEM_WINDOW+11;
        public static final int TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12;
        public static final int TYPE_WALLPAPER          = FIRST_SYSTEM_WINDOW+13;
        public static final int TYPE_STATUS_BAR_PANEL   = FIRST_SYSTEM_WINDOW+14;
        public static final int TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15;
        public static final int TYPE_DRAG               = FIRST_SYSTEM_WINDOW+16;
        public static final int TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17;
        public static final int TYPE_POINTER = FIRST_SYSTEM_WINDOW+18;
        public static final int TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19;
        public static final int TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20;
        public static final int TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21;
        public static final int TYPE_INPUT_CONSUMER = FIRST_SYSTEM_WINDOW+22;
        public static final int TYPE_DREAM = FIRST_SYSTEM_WINDOW+23;
        public static final int TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24;
        public static final int TYPE_DISPLAY_OVERLAY = FIRST_SYSTEM_WINDOW+26;
        public static final int TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27;
        public static final int TYPE_PRIVATE_PRESENTATION = FIRST_SYSTEM_WINDOW+30;
        public static final int TYPE_VOICE_INTERACTION = FIRST_SYSTEM_WINDOW+31;
        public static final int TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32;
        public static final int TYPE_VOICE_INTERACTION_STARTING = FIRST_SYSTEM_WINDOW+33;
        public static final int TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW+34;
        public static final int TYPE_QS_DIALOG = FIRST_SYSTEM_WINDOW+35;
        public static final int TYPE_SCREENSHOT = FIRST_SYSTEM_WINDOW + 36;
        public static final int TYPE_PRESENTATION = FIRST_SYSTEM_WINDOW + 37;
        public static final int TYPE_APPLICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 38;
        public static final int LAST_SYSTEM_WINDOW      = 2999;

Window都有自己的Layer,即z-order,表示在屏幕上显示的层级顺序。Application Window都属于Application Layer,值为2,其它的则不同,它们在WindowManagerPolicy可以找到,代码如下。

    int APPLICATION_LAYER = 2;
    int APPLICATION_MEDIA_SUBLAYER = -2;
    int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
    int APPLICATION_PANEL_SUBLAYER = 1;
    int APPLICATION_SUB_PANEL_SUBLAYER = 2;
    int APPLICATION_ABOVE_SUB_PANEL_SUBLAYER = 3;

    default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow) {
        if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
            return APPLICATION_LAYER;
        }

        switch (type) {
            case TYPE_WALLPAPER:
                // wallpaper is at the bottom, though the window manager may move it.
                return  1;
            case TYPE_PRESENTATION:
            case TYPE_PRIVATE_PRESENTATION:
                return  APPLICATION_LAYER;
            case TYPE_DOCK_DIVIDER:
                return  APPLICATION_LAYER;
            case TYPE_QS_DIALOG:
                return  APPLICATION_LAYER;
            case TYPE_PHONE:
                return  3;
            case TYPE_SEARCH_BAR:
            case TYPE_VOICE_INTERACTION_STARTING:
                return  4;
            case TYPE_VOICE_INTERACTION:
                // voice interaction layer is almost immediately above apps.
                return  5;
            case TYPE_INPUT_CONSUMER:
                return  6;
            case TYPE_SYSTEM_DIALOG:
                return  7;
            case TYPE_TOAST:
                // toasts and the plugged-in battery thing
                return  8;
            case TYPE_PRIORITY_PHONE:
                // SIM errors and unlock.  Not sure if this really should be in a high layer.
                return  9;
            case TYPE_SYSTEM_ALERT:
                // like the ANR / app crashed dialogs
                return  canAddInternalSystemWindow ? 11 : 10;
            case TYPE_APPLICATION_OVERLAY:
                return  12;
            case TYPE_DREAM:
                // used for Dreams (screensavers with TYPE_DREAM windows)
                return  13;
            case TYPE_INPUT_METHOD:
                // on-screen keyboards and other such input method user interfaces go here.
                return  14;
            case TYPE_INPUT_METHOD_DIALOG:
                // on-screen keyboards and other such input method user interfaces go here.
                return  15;
            case TYPE_STATUS_BAR_SUB_PANEL:
                return  17;
            case TYPE_STATUS_BAR:
                return  18;
            case TYPE_STATUS_BAR_PANEL:
                return  19;
            case TYPE_KEYGUARD_DIALOG:
                return  20;
            case TYPE_VOLUME_OVERLAY:
                // the on-screen volume indicator and controller shown when the user
                // changes the device volume
                return  21;
            case TYPE_SYSTEM_OVERLAY:
                // the on-screen volume indicator and controller shown when the user
                // changes the device volume
                return  canAddInternalSystemWindow ? 22 : 11;
            case TYPE_NAVIGATION_BAR:
                // the navigation bar, if available, shows atop most things
                return  23;
            case TYPE_NAVIGATION_BAR_PANEL:
                // some panels (e.g. search) need to show on top of the navigation bar
                return  24;
            case TYPE_SCREENSHOT:
                // screenshot selection layer shouldn't go above system error, but it should cover
                // navigation bars at the very least.
                return  25;
            case TYPE_SYSTEM_ERROR:
                // system-level error dialogs
                return  canAddInternalSystemWindow ? 26 : 10;
            case TYPE_MAGNIFICATION_OVERLAY:
                // used to highlight the magnified portion of a display
                return  27;
            case TYPE_DISPLAY_OVERLAY:
                // used to simulate secondary display devices
                return  28;
            case TYPE_DRAG:
                // the drag layer: input for drag-and-drop is associated with this window,
                // which sits above all other focusable windows
                return  29;
            case TYPE_ACCESSIBILITY_OVERLAY:
                // overlay put by accessibility services to intercept user interaction
                return  30;
            case TYPE_SECURE_SYSTEM_OVERLAY:
                return  31;
            case TYPE_BOOT_PROGRESS:
                return  32;
            case TYPE_POINTER:
                // the (mouse) pointer layer
                return  33;
            default:
                Slog.e("WindowManager", "Unknown window type: " + type);
                return APPLICATION_LAYER;
        }
    }

    default int getSubWindowLayerFromTypeLw(int type) {
        switch (type) {
            case TYPE_APPLICATION_PANEL:
            case TYPE_APPLICATION_ATTACHED_DIALOG:
                return APPLICATION_PANEL_SUBLAYER;
            case TYPE_APPLICATION_MEDIA:
                return APPLICATION_MEDIA_SUBLAYER;
            case TYPE_APPLICATION_MEDIA_OVERLAY:
                return APPLICATION_MEDIA_OVERLAY_SUBLAYER;
            case TYPE_APPLICATION_SUB_PANEL:
                return APPLICATION_SUB_PANEL_SUBLAYER;
            case TYPE_APPLICATION_ABOVE_SUB_PANEL:
                return APPLICATION_ABOVE_SUB_PANEL_SUBLAYER;
        }
        Slog.e("WindowManager", "Unknown sub-window type: " + type);
        return 0;
    }

Window的Layer,上面只是从1开始逐个递增1,在转换为z-order时,还要进行转换,首先乘10000,然后偏移1000,同类的Window逐个递增5,这些值在WindowManagerService中定义,代码如下所示。

    /** How much to multiply the policy's type layer, to reserve room
     * for multiple windows of the same type and Z-ordering adjustment
     * with TYPE_LAYER_OFFSET. */
    static final int TYPE_LAYER_MULTIPLIER = 10000;

    /** Offset from TYPE_LAYER_MULTIPLIER for moving a group of windows above
     * or below others in the same layer. */
    static final int TYPE_LAYER_OFFSET = 1000;

    /** How much to increment the layer for each window, to reserve room
     * for effect surfaces between them.
     */
    static final int WINDOW_LAYER_MULTIPLIER = 5;

Java层与Native层的Layer设置是通过SurfaceControl的setLayer完成的,在Native层由SurfaceComposer进行合成。

5、WindowState

WindowState是Android中的事实Window,WindowManager真正管理的是WindowState而不是Window。WindowState在WindowManagerService中创建,从上面的addView的时序图中可以看出。创建WindowState之后,还需要设置上文提到的Window Layer,通过InputChannel与IMS取得联系,将Session中维护的Window个数加1,最后通过WindowToken将这个WindowState添加到WindowContainer中。

6、WindowToken

WindowToken是个容器,将相关的WindowState收集到一起,同样是在WindowManagerService中创建。真正的token是IBinder类型的成员变量token,用于IPC。WindowToken有个子类AppWindowToken,用于Application和Activity。

7、Session

Session是个客户端对象,每个进程只有一个,与WindowManagerService进行交互。Session对应的interface为IWindowSession,在WindowManagerGlobal中实例化。

8、Surface

View或Window真正地是在一个Surface上进行描画的,Surface即一个Buffer,由辅助类SurfaceControl进行控制,上文提到的Window Layer的设置就是由SurfaceControl与Native层进行交互的。

<think>好的,用户想了解如何通过WindowManagerService修改Android应用的分辨率。首先,我需要回忆一下WindowManagerService的相关功能。根据引用[1]和[2],WindowManagerService负责管理窗口的尺寸和显示设置,而Display类提供屏幕信息。 用户的问题涉及到修改分辨率,可能需要调整Display的尺寸。引用[1]提到使用setForcedDisplaySize方法,这可能是一个关键点。但需要确认这个方法是否真的可以改变分辨率,并且是否需要特定权限,比如系统权限或root权限,因为普通应用通常无法调用这类系统级API。 接下来,我需要考虑实际的操作步骤。可能需要通过反射或者ADB命令来调用WindowManagerService的方法。例如,使用adb shell命令调用wm命令,如wm size WxH。这可能更实际,因为直接编程调用系统服务对普通开发者来说可能不可行。 还要注意,修改分辨率可能会影响所有应用,而不仅仅是某个特定的应用。用户可能误解了分辨率修改的范围,需要澄清这一点。此外,不同Android版本可能有不同的实现方式,需要检查兼容性。 最后,应该提醒用户需要系统权限,并建议谨慎操作,因为不当修改可能导致系统不稳定。同时,提供替代方案,如应用内调整布局或使用兼容模式,可能对用户更有帮助。</think>要修改Android应用分辨率,需通过WindowManagerService的显示控制接口实现。这里提供两种实现方式: ### 一、通过ADB命令修改(需系统权限) ```bash adb shell wm size 1080x1920 ``` 这会修改全局显示分辨率[^1][^2]。恢复默认分辨率使用: ```bash adb shell wm size reset ``` ### 二、通过Java反射调用(需系统级权限) ```java try { IWindowManager wm = IWindowManager.Stub.asInterface( ServiceManager.getService("window")); wm.setForcedDisplaySize(Display.DEFAULT_DISPLAY, 1080, 1920); } catch (RemoteException e) { e.printStackTrace(); } ``` 注意: 1. 需要`android.permission.WRITE_SECURE_SETTINGS`权限 2. 仅适用于系统应用或拥有root权限的设备 3. 影响范围为全局显示设置[^1] ### 三、应用级适配建议 对于普通开发者,建议采用响应式布局: ```xml <androidx.constraintlayout.widget.ConstraintLayout tools:context=".MainActivity"> <TextView android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintDimensionRatio="H,16:9"/> </androidx.constraintlayout.widget.ConstraintLayout> ``` ### 四、原理说明 WindowManagerService通过`setForcedDisplaySize()`方法强制修改显示参数,Display对象会更新屏幕尺寸信息。应用进程通过Binder与WindowManagerService通信获取最新显示参数,触发ViewRootImpl重新布局[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值