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

2023-09-21 16:20:22

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

回顾我们在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;
            }
        }

可以通过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;
            }
            ......
    }

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;

返回的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);
                }

                ......
            }
        }
    }

这里满足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;
	}

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:
     * <ul>
     * <li>{@link WindowManager.LayoutParams#TYPE_STATUS_BAR}</li>
     * <li>{@link WindowManager.LayoutParams#TYPE_NOTIFICATION_SHADE}</li>
     * <li>{@link WindowManager.LayoutParams#TYPE_NAVIGATION_BAR}</li>
     * </ul>
     *
     * @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;
    }

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

更多推荐

竞赛 基于深度学习的人脸性别年龄识别 - 图像识别 opencv

文章目录0前言1课题描述2实现效果3算法实现原理3.1数据集3.2深度学习识别算法3.3特征提取主干网络3.4总体实现流程4具体实现4.1预训练数据格式4.2部分实现代码5最后0前言🔥优质竞赛项目系列,今天要分享的是🚩毕业设计人脸性别年龄识别系统-图像识别opencv该项目较为新颖,适合作为竞赛课题方向,学长非常推

FPGA-结合协议时序实现UART收发器(三):串口接收模块uart_rx

FPGA-结合协议时序实现UART收发器(三):串口接收模块uart_rx串口接收模块uart_rx的功能实现文章目录FPGA-结合协议时序实现UART收发器(三):串口接收模块uart_rx一、功能实现二、uart_rx代码总结一、功能实现对照代码,串口接收模块uart_rx实现功能包括:r_cnt计数信号,计数数据

DMNet复现(一)之数据准备篇:Density map guided object detection in aerial image

一、生成密度图密度图标签生成采用以下代码,生成训练集密度图gt:importcv2importglobimporth5pyimportscipyimportpickleimportnumpyasnpfromPILimportImagefromitertoolsimportislicefromtqdmimporttqdm

Git常见的面试题

在软件开发领域,Git是一个极为重要的版本控制系统,几乎每个开发者都需要掌握它。因此,在面试过程中,Git常常成为了面试官们用来考察候选人技能和经验的重要工具之一。以下是一些常见的Git面试题,希望它们能帮助你在面试中脱颖而出。什么是Git?Git是一个分布式版本控制系统,用于跟踪和管理软件项目的变化。它允许多人协作开

Kafka 源码分析——Producer

文章目录前言Producer整体流程Producer初始化Producer发送流程执行拦截器逻辑获取集群元数据序列化选择分区消息累加进缓存消息发送Producer缓冲区Producer参数调优前言在Kafka中,把产生消息的一方称为Producer即生产者,它是Kafka的核心组件之一,也是消息的来源所在。它的主要功能

千兆以太网网络层 ARP 协议的原理与 FPGA 实现

文章目录前言一、ARP帧的应用场景和存在目的二、ARP帧工作原理三、以太网ARP帧发包实例设计四、以太网CRC校验代码五、以太网ARP帧发包测试---GMII1.模拟数据发送2.仿真模块3.仿真波形六、以太网ARP帧发包测试---RGMII1.顶层文件2.仿真代码七、上板测试(RGMII)前言本节对以太网电路接口和以太

中级职称评审论文重要吗?是不是必须要论文呢?

现在评中级职称职称对论文有什么要求?没有论文可以参与职称评审吗?建筑中级职称怎么评?那自然是从多方面来考核人才是否具备了评中级工程师的能力,职称论文就是考核的标准之一。甘建二告诉你,现在评职称论文是很重要的,没有论文职称是通过不了的,所以评职称的小伙伴,首先建议您这边先考虑发表论文,湖北这边职称评审对于论文的一个要求是

多语言多平台给线程增加命名

在许多编程语言和多线程库中,可以为线程分配一个名称以便更好地识别和调试线程。以下是在一些常见编程语言中如何为线程增加命名的示例:1.Python(使用threading模块):在Python中,你可以使用threading模块来创建和管理线程。要为线程增加名称,可以在创建线程对象时指定name参数:importthre

[C++随笔录] vector使用

vector使用初始化排序算法reverse和resize通过上一篇文章string的模拟实现,其实我们就已经踏入了STL的门槛.STL容器的大致用法是差不多的⇒那我们这篇博客就讲一点跟string类不一样的新颖的东西初始化跟string一样,vector可以采用下面的形式初始化//默认空间,默认初始化vector<i

瑞芯微:基于RK3568的ocr识别

光学字符识别(OpticalCharacterRecognition,OCR)是指对文本资料的图像文件进行分析识别处理,获取文字及版面信息的过程。亦即将图像中的文字进行识别,并以文本的形式返回。OCR的应用场景卡片证件识别类:大陆、港澳台身份证、通行证、护照识别,卡类识别,车辆类驾驶证识别、行驶证识别,执照识类识别,企

浅谈GPGPU任务调度-1

文章目录前言1.Stream的概念1.文献1的工作2.Hyper-Q的改进前言转自GPUandComputing公众号在先前的文章中《近距离看GPU计算(2)》我们介绍了GPUSM单元以ThreadBlock为单位的调度方法,这些的Block属于同一个kernel任务,当然处于相同的进程上下文(CUDAContext)

热文推荐