• Android T 禁止应用添加窗口的操作


    什么情况下会出现我们需要禁止应用添加窗口的情况呢?
    假如有一个应用的窗口,我们点开后是透明的或者会影响到系统的使用,那么我们就有必要对这个窗口操作一下

    回顾我们在Android T WMS窗口相关流程中所讲的内容
    在这里插入图片描述
    禁止应用添加窗口的操作有两种
    1.直接在客户端对应用禁止添加窗口
    2.在服务端禁止应用添加窗口

    客户端对应用禁止添加窗口

    一般来说,应用添加窗口的方式是通过addView()方法直接添加,我们也只需在这个里面修改即可,参考修改如下:
    代码路径:frameworks/base/core/java/android/view/WindowManagerGlobal.java

        public void addView(View view, ViewGroup.LayoutParams params,
                Display display, Window parentWindow, int userId) {
            if (view == null) {
                throw new IllegalArgumentException("view must not be null");
            }
            if (display == null) {
                throw new IllegalArgumentException("display must not be null");
            }
            if (!(params instanceof WindowManager.LayoutParams)) {
                throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
            }
            
            /* modify TAG START */
            if (((WindowManager.LayoutParams) params).type == WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
            && "问题窗口包名".equals(ActivityThread.currentPackageName())) {
                android.util.Log.e("TEST","问题窗口包名    有毛病,我不想添加它");
                return;
            }
            /* modify TAG END */
    
            final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
            if (parentWindow != null) {
                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;
                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    可以通过dump window来查看的窗口类型,这里我们以TYPE_APPLICATION_OVERLAY为例,其表示系统覆盖窗口在所有应用窗口上方,但在状态栏和输入法窗口下方。
    此时的windowState是还没创建的,无法通过windowState的mAttrs属性获取包名,因此使用ActivityThread.currentPackageName()获取当前执行的进程的包名

    在服务端禁止应用添加窗口

    我们知道服务端添加窗口的方法就是WindowManagerService中的addWindow()方法,这个方法里面会对需要添加的窗口先进行验证
    代码路径:frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

        public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
                int displayId, int requestUserId, InsetsVisibilities requestedVisibilities,
                InputChannel outInputChannel, InsetsState outInsetsState,
                InsetsSourceControl[] outActiveControls) {
                ......
                res = displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid);
                if (res != ADD_OKAY) {
                    return res;
                }
                ......
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid)调用DisplayPolicy.java的validateAddingWindowLw()方法,该方法会对窗口TYPE,FLAG等多方面判断。只有返回ADD_OKAY时表示允许当前窗口的添加,反之则不允许添加该窗口。
    在WindowManagerGlobal.java中有定义这些返回值

        public static final int ADD_OKAY = 0;
        public static final int ADD_BAD_APP_TOKEN = -1;
        public static final int ADD_BAD_SUBWINDOW_TOKEN = -2;
        public static final int ADD_NOT_APP_TOKEN = -3;
        public static final int ADD_APP_EXITING = -4;
        public static final int ADD_DUPLICATE_ADD = -5;
        public static final int ADD_STARTING_NOT_NEEDED = -6;
        public static final int ADD_MULTIPLE_SINGLETON = -7;
        public static final int ADD_PERMISSION_DENIED = -8;
        public static final int ADD_INVALID_DISPLAY = -9;
        public static final int ADD_INVALID_TYPE = -10;
        public static final int ADD_INVALID_USER = -11;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    返回的res最终会走到ViewRootImpl的setView方法中
    代码路径:frameworks/base/core/java/android/view/ViewRootImpl.java

        public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
                int userId) {
            synchronized (this) {
                if (mView == null) {
                    ......
                    if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
                    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");
                            case WindowManagerGlobal.ADD_INVALID_USER:
                                throw new WindowManager.BadTokenException("Unable to add Window "
                                        + mWindow + " -- requested userId is not valid");
                        }
                        throw new RuntimeException(
                                "Unable to add window -- unknown error code " + res);
                    }
    
                    ......
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    这里满足if (res < WindowManagerGlobal.ADD_OKAY) 才会进入后面的switch (res)
    因此我们在服务端修改代码有三步:
    1.在WindowManagerGlobal中添加返回值常量,该值小于ADD_OKAY,也就是小于0即可,例如:
    public static final int ADD_FORBID = -99;
    2.在ViewRootImpl的setView方法中switch (res)添加相应的 case,例如:

    switch (res) {
    	......
    	case WindowManagerGlobal.ADD_FORBID:
    		android.util.Log.e("ViewRootImpl.setView","问题窗口包名    有毛病,我不想添加它");
    		return;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.DisplayPolicy.java的validateAddingWindowLw()方法中进行过滤窗口操作,例如

    代码路径:frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java

        /**
         * Check if a window can be added to the system.
         *
         * Currently enforces that two window types are singletons per display:
         * 
      *
    • {@link WindowManager.LayoutParams#TYPE_STATUS_BAR}
    • *
    • {@link WindowManager.LayoutParams#TYPE_NOTIFICATION_SHADE}
    • *
    • {@link WindowManager.LayoutParams#TYPE_NAVIGATION_BAR}
    • *
    * * @param attrs Information about the window to be added. * * @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons, * WindowManagerImpl.ADD_MULTIPLE_SINGLETON */
    int validateAddingWindowLw(WindowManager.LayoutParams attrs, int callingPid, int callingUid) { ...... /* modify TAG START */ if (attrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY && "问题窗口包名".equals(attrs.packageName) { android.util.Log.e("DisplayPolicy.validateAddingWindowLw","问题窗口包名 有毛病,我不想添加它"); return ADD_FORBID; } /* modify TAG END */ return ADD_OKAY; }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    此时的windowState已经创建了,所有我们直接通过attrs.packageName获取应用包名即可。

  • 相关阅读:
    SpringMVC学习|JSON讲解、Controller返回JSON数据、Jackson、JSON乱码处理、FastJson
    Python跨语言调用Java服务Rpc接口
    Java设计模式之装饰器模式
    一些场景题
    [NewStarCTF 2023 公开赛道] week1 Crypto
    UE4\UE5 蓝图节点Delay与Retriggerable Delay的使用与区别
    【书籍篇】Git 学习指南(一)基础概念及入门
    不再受害:如何预防和应对.mallab勒索病毒攻击
    计算物理专题----蒙特卡洛积分实战
    java计算机毕业设计网络精品课程网站(附源码、数据库)
  • 原文地址:https://blog.csdn.net/yimelancholy/article/details/133134621