diff options
8 files changed, 87 insertions, 32 deletions
diff --git a/core/java/android/companion/virtual/flags/flags.aconfig b/core/java/android/companion/virtual/flags/flags.aconfig index 22a9ccf425c2..297fe8a9e691 100644 --- a/core/java/android/companion/virtual/flags/flags.aconfig +++ b/core/java/android/companion/virtual/flags/flags.aconfig @@ -111,3 +111,10 @@ flag { description: "Device awareness in power and display APIs" bug: "285020111" } + +flag { + name: "status_bar_and_insets" + namespace: "virtual_devices" + description: "Allow for status bar and insets on virtual devices" + bug: "350007866" +} diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 424429e11748..749025b0cf40 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -16,6 +16,7 @@ package com.android.server.policy; +import static android.Manifest.permission.CREATE_VIRTUAL_DEVICE; import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; import static android.Manifest.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW; import static android.Manifest.permission.SYSTEM_ALERT_WINDOW; @@ -59,13 +60,18 @@ import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; +import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE; import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION; import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION; import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG; +import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; +import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL; +import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION; +import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType; import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_KEY_CHORD; @@ -3058,7 +3064,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ @Override public int checkAddPermission(int type, boolean isRoundedCornerOverlay, String packageName, - int[] outAppOp) { + int[] outAppOp, int displayId) { if (isRoundedCornerOverlay && mContext.checkCallingOrSelfPermission(INTERNAL_SYSTEM_WINDOW) != PERMISSION_GRANTED) { return ADD_PERMISSION_DENIED; @@ -3098,6 +3104,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { case TYPE_VOICE_INTERACTION: case TYPE_QS_DIALOG: case TYPE_NAVIGATION_BAR_PANEL: + case TYPE_STATUS_BAR: + case TYPE_NOTIFICATION_SHADE: + case TYPE_NAVIGATION_BAR: + case TYPE_STATUS_BAR_ADDITIONAL: + case TYPE_STATUS_BAR_SUB_PANEL: + case TYPE_VOICE_INTERACTION_STARTING: // The window manager will check these. return ADD_OKAY; } @@ -3141,6 +3153,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { return ADD_OKAY; } + // Allow virtual device owners to add overlays on the displays they own. + if (mWindowManagerFuncs.isCallerVirtualDeviceOwner(displayId, callingUid) + && mContext.checkCallingOrSelfPermission(CREATE_VIRTUAL_DEVICE) + == PERMISSION_GRANTED) { + return ADD_OKAY; + } + // check if user has enabled this operation. SecurityException will be thrown if this app // has not been allowed by the user. The reason to use "noteOp" (instead of checkOp) is to // make sure the usage is logged. diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index 989c8a802b36..892af6bec534 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -362,6 +362,12 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { * Invoked when a screenshot is taken of the given display to notify registered listeners. */ List<ComponentName> notifyScreenshotListeners(int displayId); + + /** + * Returns whether the given UID is the owner of a virtual device, which the given display + * belongs to. + */ + boolean isCallerVirtualDeviceOwner(int displayId, int callingUid); } /** @@ -421,6 +427,7 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { * @param packageName package name * @param outAppOp First element will be filled with the app op corresponding to * this window, or OP_NONE. + * @param displayId The display on which this window is being added. * * @return {@link WindowManagerGlobal#ADD_OKAY} if the add can proceed; * else an error code, usually @@ -429,7 +436,7 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { * @see WindowManager.LayoutParams#PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY */ int checkAddPermission(int type, boolean isRoundedCornerOverlay, String packageName, - int[] outAppOp); + int[] outAppOp, int displayId); /** * After the window manager has computed the current configuration based diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index e90a2c90bfab..9a3ad2d85de6 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -107,7 +107,6 @@ import android.app.servertransaction.LaunchActivityItem; import android.app.servertransaction.PauseActivityItem; import android.app.servertransaction.ResumeActivityItem; import android.app.servertransaction.StopActivityItem; -import android.companion.virtual.VirtualDeviceManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -158,6 +157,7 @@ import com.android.server.LocalServices; import com.android.server.am.ActivityManagerService; import com.android.server.am.HostingRecord; import com.android.server.am.UserState; +import com.android.server.companion.virtual.VirtualDeviceManagerInternal; import com.android.server.pm.SaferIntentUtils; import com.android.server.utils.Slogf; import com.android.server.wm.ActivityMetricsLogger.LaunchingState; @@ -285,7 +285,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { private WindowManagerService mWindowManager; private AppOpsManager mAppOpsManager; - private VirtualDeviceManager mVirtualDeviceManager; + private VirtualDeviceManagerInternal mVirtualDeviceManagerInternal; /** Common synchronization logic used to save things to disks. */ PersisterQueue mPersisterQueue; @@ -1298,16 +1298,24 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { if (displayId == DEFAULT_DISPLAY || displayId == INVALID_DISPLAY) { return Context.DEVICE_ID_DEFAULT; } - if (mVirtualDeviceManager == null) { + if (mVirtualDeviceManagerInternal == null) { if (mService.mHasCompanionDeviceSetupFeature) { - mVirtualDeviceManager = - mService.mContext.getSystemService(VirtualDeviceManager.class); + mVirtualDeviceManagerInternal = + LocalServices.getService(VirtualDeviceManagerInternal.class); } - if (mVirtualDeviceManager == null) { + if (mVirtualDeviceManagerInternal == null) { return Context.DEVICE_ID_DEFAULT; } } - return mVirtualDeviceManager.getDeviceIdForDisplayId(displayId); + return mVirtualDeviceManagerInternal.getDeviceIdForDisplayId(displayId); + } + + boolean isDeviceOwnerUid(int displayId, int callingUid) { + final int deviceId = getDeviceIdForDisplayId(displayId); + if (deviceId == Context.DEVICE_ID_DEFAULT || deviceId == Context.DEVICE_ID_INVALID) { + return false; + } + return mVirtualDeviceManagerInternal.getDeviceOwnerUid(deviceId) == callingUid; } private AppOpsManager getAppOpsManager() { diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 745b79209546..5c621208c4db 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -1036,7 +1036,7 @@ public class DisplayPolicy { /** * Check if a window can be added to the system. * - * Currently enforces that two window types are singletons per display: + * Currently enforces that these window types are singletons per display: * <ul> * <li>{@link WindowManager.LayoutParams#TYPE_STATUS_BAR}</li> * <li>{@link WindowManager.LayoutParams#TYPE_NOTIFICATION_SHADE}</li> @@ -1058,41 +1058,39 @@ public class DisplayPolicy { ActivityTaskManagerService.enforceTaskPermission("DisplayPolicy"); } + final String systemUiPermission = + mService.isCallerVirtualDeviceOwner(mDisplayContent.getDisplayId(), callingUid) + // Allow virtual device owners to add system windows on their displays. + ? android.Manifest.permission.CREATE_VIRTUAL_DEVICE + : android.Manifest.permission.STATUS_BAR_SERVICE; + switch (attrs.type) { case TYPE_STATUS_BAR: - mContext.enforcePermission( - android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid, + mContext.enforcePermission(systemUiPermission, callingPid, callingUid, "DisplayPolicy"); if (mStatusBar != null && mStatusBar.isAlive()) { return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; } break; case TYPE_NOTIFICATION_SHADE: - mContext.enforcePermission( - android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid, + mContext.enforcePermission(systemUiPermission, callingPid, callingUid, "DisplayPolicy"); - if (mNotificationShade != null) { - if (mNotificationShade.isAlive()) { - return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; - } + if (mNotificationShade != null && mNotificationShade.isAlive()) { + return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; } break; case TYPE_NAVIGATION_BAR: - mContext.enforcePermission(android.Manifest.permission.STATUS_BAR_SERVICE, - callingPid, callingUid, "DisplayPolicy"); + mContext.enforcePermission(systemUiPermission, callingPid, callingUid, + "DisplayPolicy"); if (mNavigationBar != null && mNavigationBar.isAlive()) { return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; } break; case TYPE_NAVIGATION_BAR_PANEL: - mContext.enforcePermission(android.Manifest.permission.STATUS_BAR_SERVICE, - callingPid, callingUid, "DisplayPolicy"); - break; case TYPE_STATUS_BAR_ADDITIONAL: case TYPE_STATUS_BAR_SUB_PANEL: case TYPE_VOICE_INTERACTION_STARTING: - mContext.enforcePermission( - android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid, + mContext.enforcePermission(systemUiPermission, callingPid, callingUid, "DisplayPolicy"); break; case TYPE_STATUS_BAR_PANEL: @@ -1102,8 +1100,7 @@ public class DisplayPolicy { if (attrs.providedInsets != null) { // Recents component is allowed to add inset types. if (!mService.mAtmService.isCallerRecents(callingUid)) { - mContext.enforcePermission( - android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid, + mContext.enforcePermission(systemUiPermission, callingPid, callingUid, "DisplayPolicy"); } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 90b9a0452eb1..6b7ba66ca9c9 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1524,7 +1524,7 @@ public class WindowManagerService extends IWindowManager.Stub final boolean isRoundedCornerOverlay = (attrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0; int res = mPolicy.checkAddPermission(attrs.type, isRoundedCornerOverlay, attrs.packageName, - appOp); + appOp, displayId); if (res != ADD_OKAY) { return res; } @@ -10121,6 +10121,23 @@ public class WindowManagerService extends IWindowManager.Stub } } + /** + * Returns whether the given UID is the owner of a virtual device, which the given display + * belongs to. + */ + @Override + public boolean isCallerVirtualDeviceOwner(int displayId, int callingUid) { + if (!android.companion.virtualdevice.flags.Flags.statusBarAndInsets()) { + return false; + } + final long identity = Binder.clearCallingIdentity(); + try { + return mAtmService.mTaskSupervisor.isDeviceOwnerUid(displayId, callingUid); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + @RequiresPermission(ACCESS_SURFACE_FLINGER) @Override public boolean replaceContentOnDisplay(int displayId, SurfaceControl sc) { diff --git a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java index 07934ea90b7e..e694c0b4afc1 100644 --- a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java +++ b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java @@ -188,7 +188,7 @@ public class PhoneWindowManagerTests { .FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED); int[] outAppOp = new int[1]; assertEquals(ADD_OKAY, mPhoneWindowManager.checkAddPermission(TYPE_WALLPAPER, - /* isRoundedCornerOverlay= */ false, "test.pkg", outAppOp)); + /* isRoundedCornerOverlay= */ false, "test.pkg", outAppOp, DEFAULT_DISPLAY)); assertThat(outAppOp[0]).isEqualTo(AppOpsManager.OP_NONE); } @@ -198,7 +198,7 @@ public class PhoneWindowManagerTests { .FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED); int[] outAppOp = new int[1]; assertEquals(ADD_OKAY, mPhoneWindowManager.checkAddPermission(TYPE_ACCESSIBILITY_OVERLAY, - /* isRoundedCornerOverlay= */ false, "test.pkg", outAppOp)); + /* isRoundedCornerOverlay= */ false, "test.pkg", outAppOp, DEFAULT_DISPLAY)); assertThat(outAppOp[0]).isEqualTo(AppOpsManager.OP_CREATE_ACCESSIBILITY_OVERLAY); } @@ -208,7 +208,7 @@ public class PhoneWindowManagerTests { .FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED); int[] outAppOp = new int[1]; assertEquals(ADD_OKAY, mPhoneWindowManager.checkAddPermission(TYPE_ACCESSIBILITY_OVERLAY, - /* isRoundedCornerOverlay= */ false, "test.pkg", outAppOp)); + /* isRoundedCornerOverlay= */ false, "test.pkg", outAppOp, DEFAULT_DISPLAY)); assertThat(outAppOp[0]).isEqualTo(AppOpsManager.OP_NONE); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java index d62c626f9a90..eebb487d16cd 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -60,7 +60,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { @Override public int checkAddPermission(int type, boolean isRoundedCornerOverlay, String packageName, - int[] outAppOp) { + int[] outAppOp, int displayId) { return 0; } |