序
什么情况下会出现我们需要禁止应用添加窗口的情况呢?
假如有一个应用的窗口,我们点开后是透明的或者会影响到系统的使用,那么我们就有必要对这个窗口操作一下
回顾我们在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
获取应用包名即可。