順序
どのような状況でアプリケーションによるウィンドウの追加を禁止する必要があるでしょうか?
クリックした後に透明になるアプリケーションウィンドウがある場合、またはシステムの使用に影響を与える場合は、このウィンドウを操作する必要があります。
Android T WMS ウィンドウ関連のプロセスで述べたことを振り返ると、
アプリケーションによるウィンドウの追加を禁止するには 2 つの操作があります
。 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;
}
}
ダンプ ウィンドウで表示できるウィンドウ タイプ。ここでは 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)
したがって、サーバー側でコードを変更するには 3 つのステップがあります:
1. WindowManagerGlobal に戻り値の定数を追加します。値は より小さいADD_OKAY
、つまり、より小さい必要があります。 0. 例: 2.
public static final int ADD_FORBID = -99;
ViewRootImpl の setView メソッドにswitch (res)
対応する値を追加します。例:
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
アプリケーションのパッケージ名を直接取得できます。