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;
            }
        }

덤프 창을 통해 볼 수 있는 창 유형 여기서는 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)창 TYPE, FLAG 및 기타 측면을 판단하는 DisplayPolicy.java의 verifyAddingWindowLw() 메서드를 호출합니다. 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. 예: 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의 verifyAddingWindowLw() 메서드에서 필터 창 작업을 수행합니다.

코드 경로: 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애플리케이션 패키지 이름을 직접 얻을 수 있습니다.

추천

출처blog.csdn.net/yimelancholy/article/details/133134621