Loading services/core/java/com/android/server/notification/NotificationManagerService.java +29 −14 Original line number Diff line number Diff line Loading @@ -140,6 +140,7 @@ import android.app.StatusBarManager; import android.app.UriGrantsManager; import android.app.admin.DevicePolicyManagerInternal; import android.app.backup.BackupManager; import android.app.compat.CompatChanges; import android.app.role.OnRoleHoldersChangedListener; import android.app.role.RoleManager; import android.app.usage.UsageEvents; Loading Loading @@ -408,6 +409,15 @@ public class NotificationManagerService extends SystemService { @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) private static final long CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK = 128611929L; /** * Activity starts coming from broadcast receivers or services in response to notification and * notification action clicks will be blocked for UX and performance reasons. Instead start the * activity directly from the PendingIntent. */ @ChangeId @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R) private static final long NOTIFICATION_TRAMPOLINE_BLOCK = 167676448L; private IActivityManager mAm; private ActivityTaskManagerInternal mAtm; private ActivityManager mActivityManager; Loading Loading @@ -10013,7 +10023,7 @@ public class NotificationManagerService extends SystemService { * TODO(b/161957908): Remove dogfooder toast. */ private class NotificationTrampolineCallback implements BackgroundActivityStartCallback { private Set<String> mPackagesShown = new ArraySet<>(); private final Set<String> mPackagesShown = new ArraySet<>(); @Override public IBinder getToken() { Loading @@ -10021,13 +10031,9 @@ public class NotificationManagerService extends SystemService { } @Override public void onExclusiveTokenActivityStart(String packageName) { Slog.w(TAG, "Indirect notification activity start from " + packageName); boolean isFirstOccurrence = mPackagesShown.add(packageName); if (!isFirstOccurrence) { return; } public boolean isActivityStartAllowed(int uid, String packageName) { boolean block = CompatChanges.isChangeEnabled(NOTIFICATION_TRAMPOLINE_BLOCK, uid); if (block || mPackagesShown.add(packageName)) { mUiHandler.post(() -> Toast.makeText(getUiContext(), "Indirect activity start from " Loading @@ -10036,5 +10042,14 @@ public class NotificationManagerService extends SystemService { + "See go/s-trampolines.", Toast.LENGTH_LONG).show()); } String message = "Indirect notification activity start (trampoline) from " + packageName; if (block) { Slog.e(TAG, message + " blocked"); return false; } Slog.w(TAG, message + ", this should be avoided for performance reasons"); return true; } } } services/core/java/com/android/server/wm/ActivityStarter.java +6 −6 Original line number Diff line number Diff line Loading @@ -1358,6 +1358,12 @@ class ActivityStarter { } return false; } // don't abort if the callingUid has SYSTEM_ALERT_WINDOW permission if (mService.hasSystemAlertWindowPermission(callingUid, callingPid, callingPackage)) { Slog.w(TAG, "Background activity start for " + callingPackage + " allowed because SYSTEM_ALERT_WINDOW permission is granted."); return false; } // If we don't have callerApp at this point, no caller was provided to startActivity(). // That's the case for PendingIntent-based starts, since the creator's process might not be // up and alive. If that's the case, we retrieve the WindowProcessController for the send() Loading Loading @@ -1394,12 +1400,6 @@ class ActivityStarter { } } } // don't abort if the callingUid has SYSTEM_ALERT_WINDOW permission if (mService.hasSystemAlertWindowPermission(callingUid, callingPid, callingPackage)) { Slog.w(TAG, "Background activity start for " + callingPackage + " allowed because SYSTEM_ALERT_WINDOW permission is granted."); return false; } // anything that has fallen through would currently be aborted Slog.w(TAG, "Background activity start [callingPackage: " + callingPackage + "; callingUid: " + callingUid Loading services/core/java/com/android/server/wm/BackgroundActivityStartCallback.java +7 −4 Original line number Diff line number Diff line Loading @@ -24,8 +24,8 @@ import android.os.IBinder; */ public interface BackgroundActivityStartCallback { /** * The token that allowed the activity start that triggered {@link * #onExclusiveTokenActivityStart()}. * The token for which this callback is responsible for deciding whether the app can start * background activities or not. * * Ideally this should just return a final variable, don't do anything costly here (don't hold * any locks). Loading @@ -33,7 +33,10 @@ public interface BackgroundActivityStartCallback { IBinder getToken(); /** * Called when the background activity start happens. * Returns true if the background activity start due to originating token in {@link #getToken()} * should be allowed or not. * * This will be called holding the WM lock, don't do anything costly here. */ void onExclusiveTokenActivityStart(String packageName); boolean isActivityStartAllowed(int uid, String packageName); } services/core/java/com/android/server/wm/WindowProcessController.java +18 −8 Original line number Diff line number Diff line Loading @@ -223,7 +223,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio private boolean mRunningRemoteAnimation; @Nullable private BackgroundActivityStartCallback mBackgroundActivityStartCallback; private final BackgroundActivityStartCallback mBackgroundActivityStartCallback; /** The state for oom-adjustment calculation. */ private final OomScoreReferenceState mOomRefState; Loading Loading @@ -555,8 +555,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio return true; } // allow if the flag was explicitly set if (!mBackgroundActivityStartTokens.isEmpty()) { onBackgroundStartAllowedByToken(); if (isBackgroundStartAllowedByToken()) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "[WindowProcessController(" + mPid + ")] Activity start allowed: process allowed by token"); Loading @@ -566,18 +565,29 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio return false; } private void onBackgroundStartAllowedByToken() { /** * If there are no tokens, we don't allow *by token*. If there are tokens, we need to check if * the callback handles all the tokens, if so we ask the callback if the activity should be * started, otherwise we allow. */ private boolean isBackgroundStartAllowedByToken() { if (mBackgroundActivityStartTokens.isEmpty()) { return false; } if (mBackgroundActivityStartCallback == null) { return; // We have tokens but no callback to decide => allow return true; } IBinder callbackToken = mBackgroundActivityStartCallback.getToken(); for (IBinder token : mBackgroundActivityStartTokens.values()) { if (token != callbackToken) { return; // The callback doesn't handle all the tokens => allow return true; } } mAtm.mH.post(() -> mBackgroundActivityStartCallback.onExclusiveTokenActivityStart(mInfo.packageName)); // The callback handles all the tokens => callback decides return mBackgroundActivityStartCallback.isActivityStartAllowed(mInfo.uid, mInfo.packageName); } private boolean isBoundByForegroundUid() { Loading Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +29 −14 Original line number Diff line number Diff line Loading @@ -140,6 +140,7 @@ import android.app.StatusBarManager; import android.app.UriGrantsManager; import android.app.admin.DevicePolicyManagerInternal; import android.app.backup.BackupManager; import android.app.compat.CompatChanges; import android.app.role.OnRoleHoldersChangedListener; import android.app.role.RoleManager; import android.app.usage.UsageEvents; Loading Loading @@ -408,6 +409,15 @@ public class NotificationManagerService extends SystemService { @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) private static final long CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK = 128611929L; /** * Activity starts coming from broadcast receivers or services in response to notification and * notification action clicks will be blocked for UX and performance reasons. Instead start the * activity directly from the PendingIntent. */ @ChangeId @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R) private static final long NOTIFICATION_TRAMPOLINE_BLOCK = 167676448L; private IActivityManager mAm; private ActivityTaskManagerInternal mAtm; private ActivityManager mActivityManager; Loading Loading @@ -10013,7 +10023,7 @@ public class NotificationManagerService extends SystemService { * TODO(b/161957908): Remove dogfooder toast. */ private class NotificationTrampolineCallback implements BackgroundActivityStartCallback { private Set<String> mPackagesShown = new ArraySet<>(); private final Set<String> mPackagesShown = new ArraySet<>(); @Override public IBinder getToken() { Loading @@ -10021,13 +10031,9 @@ public class NotificationManagerService extends SystemService { } @Override public void onExclusiveTokenActivityStart(String packageName) { Slog.w(TAG, "Indirect notification activity start from " + packageName); boolean isFirstOccurrence = mPackagesShown.add(packageName); if (!isFirstOccurrence) { return; } public boolean isActivityStartAllowed(int uid, String packageName) { boolean block = CompatChanges.isChangeEnabled(NOTIFICATION_TRAMPOLINE_BLOCK, uid); if (block || mPackagesShown.add(packageName)) { mUiHandler.post(() -> Toast.makeText(getUiContext(), "Indirect activity start from " Loading @@ -10036,5 +10042,14 @@ public class NotificationManagerService extends SystemService { + "See go/s-trampolines.", Toast.LENGTH_LONG).show()); } String message = "Indirect notification activity start (trampoline) from " + packageName; if (block) { Slog.e(TAG, message + " blocked"); return false; } Slog.w(TAG, message + ", this should be avoided for performance reasons"); return true; } } }
services/core/java/com/android/server/wm/ActivityStarter.java +6 −6 Original line number Diff line number Diff line Loading @@ -1358,6 +1358,12 @@ class ActivityStarter { } return false; } // don't abort if the callingUid has SYSTEM_ALERT_WINDOW permission if (mService.hasSystemAlertWindowPermission(callingUid, callingPid, callingPackage)) { Slog.w(TAG, "Background activity start for " + callingPackage + " allowed because SYSTEM_ALERT_WINDOW permission is granted."); return false; } // If we don't have callerApp at this point, no caller was provided to startActivity(). // That's the case for PendingIntent-based starts, since the creator's process might not be // up and alive. If that's the case, we retrieve the WindowProcessController for the send() Loading Loading @@ -1394,12 +1400,6 @@ class ActivityStarter { } } } // don't abort if the callingUid has SYSTEM_ALERT_WINDOW permission if (mService.hasSystemAlertWindowPermission(callingUid, callingPid, callingPackage)) { Slog.w(TAG, "Background activity start for " + callingPackage + " allowed because SYSTEM_ALERT_WINDOW permission is granted."); return false; } // anything that has fallen through would currently be aborted Slog.w(TAG, "Background activity start [callingPackage: " + callingPackage + "; callingUid: " + callingUid Loading
services/core/java/com/android/server/wm/BackgroundActivityStartCallback.java +7 −4 Original line number Diff line number Diff line Loading @@ -24,8 +24,8 @@ import android.os.IBinder; */ public interface BackgroundActivityStartCallback { /** * The token that allowed the activity start that triggered {@link * #onExclusiveTokenActivityStart()}. * The token for which this callback is responsible for deciding whether the app can start * background activities or not. * * Ideally this should just return a final variable, don't do anything costly here (don't hold * any locks). Loading @@ -33,7 +33,10 @@ public interface BackgroundActivityStartCallback { IBinder getToken(); /** * Called when the background activity start happens. * Returns true if the background activity start due to originating token in {@link #getToken()} * should be allowed or not. * * This will be called holding the WM lock, don't do anything costly here. */ void onExclusiveTokenActivityStart(String packageName); boolean isActivityStartAllowed(int uid, String packageName); }
services/core/java/com/android/server/wm/WindowProcessController.java +18 −8 Original line number Diff line number Diff line Loading @@ -223,7 +223,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio private boolean mRunningRemoteAnimation; @Nullable private BackgroundActivityStartCallback mBackgroundActivityStartCallback; private final BackgroundActivityStartCallback mBackgroundActivityStartCallback; /** The state for oom-adjustment calculation. */ private final OomScoreReferenceState mOomRefState; Loading Loading @@ -555,8 +555,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio return true; } // allow if the flag was explicitly set if (!mBackgroundActivityStartTokens.isEmpty()) { onBackgroundStartAllowedByToken(); if (isBackgroundStartAllowedByToken()) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "[WindowProcessController(" + mPid + ")] Activity start allowed: process allowed by token"); Loading @@ -566,18 +565,29 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio return false; } private void onBackgroundStartAllowedByToken() { /** * If there are no tokens, we don't allow *by token*. If there are tokens, we need to check if * the callback handles all the tokens, if so we ask the callback if the activity should be * started, otherwise we allow. */ private boolean isBackgroundStartAllowedByToken() { if (mBackgroundActivityStartTokens.isEmpty()) { return false; } if (mBackgroundActivityStartCallback == null) { return; // We have tokens but no callback to decide => allow return true; } IBinder callbackToken = mBackgroundActivityStartCallback.getToken(); for (IBinder token : mBackgroundActivityStartTokens.values()) { if (token != callbackToken) { return; // The callback doesn't handle all the tokens => allow return true; } } mAtm.mH.post(() -> mBackgroundActivityStartCallback.onExclusiveTokenActivityStart(mInfo.packageName)); // The callback handles all the tokens => callback decides return mBackgroundActivityStartCallback.isActivityStartAllowed(mInfo.uid, mInfo.packageName); } private boolean isBoundByForegroundUid() { Loading