Loading core/java/android/app/AppOpsManager.java +18 −2 Original line number Diff line number Diff line Loading @@ -1715,9 +1715,13 @@ public class AppOpsManager { public static final int OP_SCENE_UNDERSTANDING_FINE = AppOpEnums.APP_OP_SCENE_UNDERSTANDING_FINE; /** @hide */ public static final int OP_SYSTEM_APPLICATION_OVERLAY = AppOpEnums.APP_OP_SYSTEM_APPLICATION_OVERLAY; /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static final int _NUM_OP = 164; public static final int _NUM_OP = 165; /** * All app ops represented as strings. Loading Loading @@ -1884,7 +1888,8 @@ public class AppOpsManager { OPSTR_HEAD_TRACKING, OPSTR_SCENE_UNDERSTANDING_COARSE, OPSTR_SCENE_UNDERSTANDING_FINE, OPSTR_POST_PROMOTED_NOTIFICATIONS OPSTR_POST_PROMOTED_NOTIFICATIONS, OPSTR_SYSTEM_APPLICATION_OVERLAY }) public @interface AppOpString {} Loading Loading @@ -2691,6 +2696,10 @@ public class AppOpsManager { public static final String OPSTR_SCENE_UNDERSTANDING_FINE = "android:scene_understanding_fine"; /** @hide Required to draw system application overlays. */ public static final String OPSTR_SYSTEM_APPLICATION_OVERLAY = "android:system_application_overlay"; /** {@link #sAppOpsToNote} not initialized yet for this op */ private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0; /** Should not collect noting of this app-op in {@link #sAppOpsToNote} */ Loading Loading @@ -2818,6 +2827,8 @@ public class AppOpsManager { OP_WRITE_SYSTEM_PREFERENCES, android.app.Flags.apiRichOngoingPermission() ? OP_POST_PROMOTED_NOTIFICATIONS : OP_NONE, com.android.media.projection.flags.Flags.recordingOverlay() ? OP_SYSTEM_APPLICATION_OVERLAY : OP_NONE, }; @SuppressWarnings("FlaggedApi") Loading Loading @@ -3354,6 +3365,11 @@ public class AppOpsManager { .setPermission(android.app.Flags.apiRichOngoingPermission() ? Manifest.permission.POST_PROMOTED_NOTIFICATIONS : null) .build(), new AppOpInfo.Builder(OP_SYSTEM_APPLICATION_OVERLAY, OPSTR_SYSTEM_APPLICATION_OVERLAY, "SYSTEM_APPLICATION_OVERLAY") .setPermission(com.android.media.projection.flags.Flags.recordingOverlay() ? Manifest.permission.SYSTEM_APPLICATION_OVERLAY : null) .build(), }; // The number of longs needed to form a full bitmask of app ops Loading core/java/android/view/ViewRootImpl.java +47 −0 Original line number Diff line number Diff line Loading @@ -99,8 +99,10 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OVERRIDE_LAYOUT_IN_DISPLAY_CUTOUT_MODE; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL; Loading Loading @@ -149,6 +151,7 @@ import android.annotation.Size; import android.annotation.UiContext; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.AppOpsManager; import android.app.ResourcesManager; import android.app.UiModeManager; import android.app.UiModeManager.ForceInvertStateChangeListener; Loading Loading @@ -1594,6 +1597,14 @@ public final class ViewRootImpl implements ViewParent, mWindowAttributes.privateFlags |= PRIVATE_FLAG_APP_PROGRESS_GENERATION_ALLOWED; } // TODO(b/395054309): Replace with calls to LayoutParams#setSystemApplicationOverlay // in next API bump if (com.android.media.projection.flags.Flags.recordingOverlay() && mWindowAttributes.type == TYPE_APPLICATION_OVERLAY && hasSystemApplicationOverlayAppOp()) { mWindowAttributes.privateFlags |= PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY; } try { mOrigWindowType = mWindowAttributes.type; mAttachInfo.mRecomputeGlobalAttributes = true; Loading Loading @@ -2143,6 +2154,13 @@ public final class ViewRootImpl implements ViewParent, // Calling this before copying prevents redundant LAYOUT_CHANGED. final int layoutInDisplayCutoutModeFromCaller = adjustLayoutInDisplayCutoutMode(attrs); // Keep PRIVATE_FLAG_SYSTEM_APPLICATION overlay if AppOp is granted // TODO(b/395054309): Replace with calls to LayoutParams#setSystemApplicationOverlay // in next API bump if (shouldKeepSystemApplicationOverlay(mWindowAttributes, attrs)) { attrs.privateFlags |= PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY; } final int changes = mWindowAttributes.copyFrom(attrs); if ((changes & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) { // Recompute system ui visibility. Loading Loading @@ -2204,6 +2222,35 @@ public final class ViewRootImpl implements ViewParent, } } private boolean shouldKeepSystemApplicationOverlay(WindowManager.LayoutParams current, WindowManager.LayoutParams incoming) { if (!com.android.media.projection.flags.Flags.recordingOverlay()) { return false; } final boolean hasSystemApplicationOverlay = (current.privateFlags & PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY) != 0; if (!hasSystemApplicationOverlay) { return false; } if ((incoming.privateFlags & PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY) != 0) { return false; } if (!hasSystemApplicationOverlayAppOp()) { return false; } return true; } private boolean hasSystemApplicationOverlayAppOp() { return mContext.getSystemService(AppOpsManager.class).checkOpRawNoThrow( AppOpsManager.OPSTR_SYSTEM_APPLICATION_OVERLAY, mView.mContext.getAttributionSource().getUid(), mView.mContext.getPackageName(), null) == AppOpsManager.MODE_ALLOWED; } private int adjustLayoutInDisplayCutoutMode(WindowManager.LayoutParams attrs) { final int originalMode = attrs.layoutInDisplayCutoutMode; if ((attrs.privateFlags & (PRIVATE_FLAG_EDGE_TO_EDGE_ENFORCED Loading core/res/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -186,6 +186,7 @@ android_app { "update_engine_aconfig_declarations", "appsearch_aconfig_flags", "aconfig_trade_in_mode_flags", "com.android.media.flags.projection-aconfig", ], } Loading core/res/AndroidManifest.xml +16 −1 Original line number Diff line number Diff line Loading @@ -4480,7 +4480,22 @@ <p>Not for use by third-party applications. --> <permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY" android:protectionLevel="signature|recents|role|installer"/> android:protectionLevel="signature|recents|role|installer|appop" android:featureFlag="com.android.media.projection.flags.recording_overlay" /> <!-- @SystemApi @hide Allows an application to create windows using the type {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY}, shown on top of all other apps. Allows an application to use {@link android.view.WindowManager.LayoutsParams#setSystemApplicationOverlay(boolean)} to create overlays that will stay visible, even if another window is requesting overlays to be hidden through {@link android.view.Window#setHideOverlayWindows(boolean)}. <p>Not for use by third-party applications. --> <permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY" android:protectionLevel="signature|recents|role|installer" android:featureFlag="!com.android.media.projection.flags.recording_overlay" /> <!-- @deprecated Use {@link android.Manifest.permission#REQUEST_COMPANION_RUN_IN_BACKGROUND} @hide Loading services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java +32 −6 Original line number Diff line number Diff line Loading @@ -1090,6 +1090,7 @@ public final class MediaProjectionManagerService extends SystemService private IBinder mToken; private IBinder.DeathRecipient mDeathEater; private boolean mRestoreSystemAlertWindow; private boolean mRestoreSystemApplicationOverlay; private int mTaskId = -1; private LaunchCookie mLaunchCookie = null; private boolean mIsRecordingOverlay = false; Loading Loading @@ -1230,8 +1231,20 @@ public final class MediaProjectionManagerService extends SystemService mRestoreSystemAlertWindow = true; } } // Recording overlays are only allowed for privileged, allowlisted callers. // Those callers are allowed to hold APPLICATION_OVERLAY for the duration // of the MediaProjection. if (mIsRecordingOverlay) { final int currentMode = mAppOps.unsafeCheckOpRawNoThrow( AppOpsManager.OP_SYSTEM_APPLICATION_OVERLAY, uid, packageName); if (currentMode == AppOpsManager.MODE_DEFAULT) { mAppOps.setUidMode(AppOpsManager.OP_SYSTEM_APPLICATION_OVERLAY, uid, AppOpsManager.MODE_ALLOWED); mRestoreSystemApplicationOverlay = true; } } } catch (PackageManager.NameNotFoundException e) { Slog.w(TAG, "Package not found, aborting MediaProjection", e); return; } finally { Binder.restoreCallingIdentity(token); Loading @@ -1257,9 +1270,10 @@ public final class MediaProjectionManagerService extends SystemService + "pid=" + Binder.getCallingPid() + ")"); return; } if (mRestoreSystemAlertWindow) { final long token = Binder.clearCallingIdentity(); try { if (mRestoreSystemAlertWindow) { // Put the appop back how it was, unless it has been changed from what // we set it to. // Note that WindowManager takes care of removing any existing overlay Loading @@ -1271,10 +1285,22 @@ public final class MediaProjectionManagerService extends SystemService AppOpsManager.MODE_DEFAULT); } mRestoreSystemAlertWindow = false; } if (mRestoreSystemApplicationOverlay) { final int appOverlayMode = mAppOps.unsafeCheckOpRawNoThrow( AppOpsManager.OP_SYSTEM_APPLICATION_OVERLAY, uid, packageName); if (appOverlayMode == AppOpsManager.MODE_ALLOWED) { mAppOps.setUidMode(AppOpsManager.OP_SYSTEM_APPLICATION_OVERLAY, uid, AppOpsManager.MODE_DEFAULT); } mRestoreSystemApplicationOverlay = false; } } finally { Binder.restoreCallingIdentity(token); } } Slog.d(TAG, "Content Recording: handling stopping this projection token" + " createTime= " + mCreateTimeMillis + " countStarts= " + mCountStarts); Loading Loading
core/java/android/app/AppOpsManager.java +18 −2 Original line number Diff line number Diff line Loading @@ -1715,9 +1715,13 @@ public class AppOpsManager { public static final int OP_SCENE_UNDERSTANDING_FINE = AppOpEnums.APP_OP_SCENE_UNDERSTANDING_FINE; /** @hide */ public static final int OP_SYSTEM_APPLICATION_OVERLAY = AppOpEnums.APP_OP_SYSTEM_APPLICATION_OVERLAY; /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static final int _NUM_OP = 164; public static final int _NUM_OP = 165; /** * All app ops represented as strings. Loading Loading @@ -1884,7 +1888,8 @@ public class AppOpsManager { OPSTR_HEAD_TRACKING, OPSTR_SCENE_UNDERSTANDING_COARSE, OPSTR_SCENE_UNDERSTANDING_FINE, OPSTR_POST_PROMOTED_NOTIFICATIONS OPSTR_POST_PROMOTED_NOTIFICATIONS, OPSTR_SYSTEM_APPLICATION_OVERLAY }) public @interface AppOpString {} Loading Loading @@ -2691,6 +2696,10 @@ public class AppOpsManager { public static final String OPSTR_SCENE_UNDERSTANDING_FINE = "android:scene_understanding_fine"; /** @hide Required to draw system application overlays. */ public static final String OPSTR_SYSTEM_APPLICATION_OVERLAY = "android:system_application_overlay"; /** {@link #sAppOpsToNote} not initialized yet for this op */ private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0; /** Should not collect noting of this app-op in {@link #sAppOpsToNote} */ Loading Loading @@ -2818,6 +2827,8 @@ public class AppOpsManager { OP_WRITE_SYSTEM_PREFERENCES, android.app.Flags.apiRichOngoingPermission() ? OP_POST_PROMOTED_NOTIFICATIONS : OP_NONE, com.android.media.projection.flags.Flags.recordingOverlay() ? OP_SYSTEM_APPLICATION_OVERLAY : OP_NONE, }; @SuppressWarnings("FlaggedApi") Loading Loading @@ -3354,6 +3365,11 @@ public class AppOpsManager { .setPermission(android.app.Flags.apiRichOngoingPermission() ? Manifest.permission.POST_PROMOTED_NOTIFICATIONS : null) .build(), new AppOpInfo.Builder(OP_SYSTEM_APPLICATION_OVERLAY, OPSTR_SYSTEM_APPLICATION_OVERLAY, "SYSTEM_APPLICATION_OVERLAY") .setPermission(com.android.media.projection.flags.Flags.recordingOverlay() ? Manifest.permission.SYSTEM_APPLICATION_OVERLAY : null) .build(), }; // The number of longs needed to form a full bitmask of app ops Loading
core/java/android/view/ViewRootImpl.java +47 −0 Original line number Diff line number Diff line Loading @@ -99,8 +99,10 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OVERRIDE_LAYOUT_IN_DISPLAY_CUTOUT_MODE; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL; Loading Loading @@ -149,6 +151,7 @@ import android.annotation.Size; import android.annotation.UiContext; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.AppOpsManager; import android.app.ResourcesManager; import android.app.UiModeManager; import android.app.UiModeManager.ForceInvertStateChangeListener; Loading Loading @@ -1594,6 +1597,14 @@ public final class ViewRootImpl implements ViewParent, mWindowAttributes.privateFlags |= PRIVATE_FLAG_APP_PROGRESS_GENERATION_ALLOWED; } // TODO(b/395054309): Replace with calls to LayoutParams#setSystemApplicationOverlay // in next API bump if (com.android.media.projection.flags.Flags.recordingOverlay() && mWindowAttributes.type == TYPE_APPLICATION_OVERLAY && hasSystemApplicationOverlayAppOp()) { mWindowAttributes.privateFlags |= PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY; } try { mOrigWindowType = mWindowAttributes.type; mAttachInfo.mRecomputeGlobalAttributes = true; Loading Loading @@ -2143,6 +2154,13 @@ public final class ViewRootImpl implements ViewParent, // Calling this before copying prevents redundant LAYOUT_CHANGED. final int layoutInDisplayCutoutModeFromCaller = adjustLayoutInDisplayCutoutMode(attrs); // Keep PRIVATE_FLAG_SYSTEM_APPLICATION overlay if AppOp is granted // TODO(b/395054309): Replace with calls to LayoutParams#setSystemApplicationOverlay // in next API bump if (shouldKeepSystemApplicationOverlay(mWindowAttributes, attrs)) { attrs.privateFlags |= PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY; } final int changes = mWindowAttributes.copyFrom(attrs); if ((changes & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) { // Recompute system ui visibility. Loading Loading @@ -2204,6 +2222,35 @@ public final class ViewRootImpl implements ViewParent, } } private boolean shouldKeepSystemApplicationOverlay(WindowManager.LayoutParams current, WindowManager.LayoutParams incoming) { if (!com.android.media.projection.flags.Flags.recordingOverlay()) { return false; } final boolean hasSystemApplicationOverlay = (current.privateFlags & PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY) != 0; if (!hasSystemApplicationOverlay) { return false; } if ((incoming.privateFlags & PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY) != 0) { return false; } if (!hasSystemApplicationOverlayAppOp()) { return false; } return true; } private boolean hasSystemApplicationOverlayAppOp() { return mContext.getSystemService(AppOpsManager.class).checkOpRawNoThrow( AppOpsManager.OPSTR_SYSTEM_APPLICATION_OVERLAY, mView.mContext.getAttributionSource().getUid(), mView.mContext.getPackageName(), null) == AppOpsManager.MODE_ALLOWED; } private int adjustLayoutInDisplayCutoutMode(WindowManager.LayoutParams attrs) { final int originalMode = attrs.layoutInDisplayCutoutMode; if ((attrs.privateFlags & (PRIVATE_FLAG_EDGE_TO_EDGE_ENFORCED Loading
core/res/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -186,6 +186,7 @@ android_app { "update_engine_aconfig_declarations", "appsearch_aconfig_flags", "aconfig_trade_in_mode_flags", "com.android.media.flags.projection-aconfig", ], } Loading
core/res/AndroidManifest.xml +16 −1 Original line number Diff line number Diff line Loading @@ -4480,7 +4480,22 @@ <p>Not for use by third-party applications. --> <permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY" android:protectionLevel="signature|recents|role|installer"/> android:protectionLevel="signature|recents|role|installer|appop" android:featureFlag="com.android.media.projection.flags.recording_overlay" /> <!-- @SystemApi @hide Allows an application to create windows using the type {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY}, shown on top of all other apps. Allows an application to use {@link android.view.WindowManager.LayoutsParams#setSystemApplicationOverlay(boolean)} to create overlays that will stay visible, even if another window is requesting overlays to be hidden through {@link android.view.Window#setHideOverlayWindows(boolean)}. <p>Not for use by third-party applications. --> <permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY" android:protectionLevel="signature|recents|role|installer" android:featureFlag="!com.android.media.projection.flags.recording_overlay" /> <!-- @deprecated Use {@link android.Manifest.permission#REQUEST_COMPANION_RUN_IN_BACKGROUND} @hide Loading
services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java +32 −6 Original line number Diff line number Diff line Loading @@ -1090,6 +1090,7 @@ public final class MediaProjectionManagerService extends SystemService private IBinder mToken; private IBinder.DeathRecipient mDeathEater; private boolean mRestoreSystemAlertWindow; private boolean mRestoreSystemApplicationOverlay; private int mTaskId = -1; private LaunchCookie mLaunchCookie = null; private boolean mIsRecordingOverlay = false; Loading Loading @@ -1230,8 +1231,20 @@ public final class MediaProjectionManagerService extends SystemService mRestoreSystemAlertWindow = true; } } // Recording overlays are only allowed for privileged, allowlisted callers. // Those callers are allowed to hold APPLICATION_OVERLAY for the duration // of the MediaProjection. if (mIsRecordingOverlay) { final int currentMode = mAppOps.unsafeCheckOpRawNoThrow( AppOpsManager.OP_SYSTEM_APPLICATION_OVERLAY, uid, packageName); if (currentMode == AppOpsManager.MODE_DEFAULT) { mAppOps.setUidMode(AppOpsManager.OP_SYSTEM_APPLICATION_OVERLAY, uid, AppOpsManager.MODE_ALLOWED); mRestoreSystemApplicationOverlay = true; } } } catch (PackageManager.NameNotFoundException e) { Slog.w(TAG, "Package not found, aborting MediaProjection", e); return; } finally { Binder.restoreCallingIdentity(token); Loading @@ -1257,9 +1270,10 @@ public final class MediaProjectionManagerService extends SystemService + "pid=" + Binder.getCallingPid() + ")"); return; } if (mRestoreSystemAlertWindow) { final long token = Binder.clearCallingIdentity(); try { if (mRestoreSystemAlertWindow) { // Put the appop back how it was, unless it has been changed from what // we set it to. // Note that WindowManager takes care of removing any existing overlay Loading @@ -1271,10 +1285,22 @@ public final class MediaProjectionManagerService extends SystemService AppOpsManager.MODE_DEFAULT); } mRestoreSystemAlertWindow = false; } if (mRestoreSystemApplicationOverlay) { final int appOverlayMode = mAppOps.unsafeCheckOpRawNoThrow( AppOpsManager.OP_SYSTEM_APPLICATION_OVERLAY, uid, packageName); if (appOverlayMode == AppOpsManager.MODE_ALLOWED) { mAppOps.setUidMode(AppOpsManager.OP_SYSTEM_APPLICATION_OVERLAY, uid, AppOpsManager.MODE_DEFAULT); } mRestoreSystemApplicationOverlay = false; } } finally { Binder.restoreCallingIdentity(token); } } Slog.d(TAG, "Content Recording: handling stopping this projection token" + " createTime= " + mCreateTimeMillis + " countStarts= " + mCountStarts); Loading