Loading services/core/java/com/android/server/notification/NotificationManagerService.java +5 −5 Original line number Diff line number Diff line Loading @@ -14544,23 +14544,23 @@ public class NotificationManagerService extends SystemService { */ private class NotificationTrampolineCallback implements BackgroundActivityStartCallback { @Override public boolean isActivityStartAllowed(Collection<IBinder> tokens, int uid, String packageName) { public BackgroundActivityStartCallbackResult isActivityStartAllowed( Collection<IBinder> tokens, int uid, String packageName) { checkArgument(!tokens.isEmpty()); for (IBinder token : tokens) { if (token != ALLOWLIST_TOKEN) { // We only block or warn if the start is exclusively due to notification return true; return RESULT_TRUE; } } String logcatMessage = "Indirect notification activity start (trampoline) from " + packageName; if (blockTrampoline(uid)) { Slog.e(TAG, logcatMessage + " blocked"); return false; return RESULT_FALSE; } else { Slog.w(TAG, logcatMessage + ", this should be avoided for performance reasons"); return true; return new BackgroundActivityStartCallbackResult(true, ALLOWLIST_TOKEN); } } services/core/java/com/android/server/wm/BackgroundActivityStartCallback.java +12 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,16 @@ import java.util.Collection; * Callback to decide activity starts and related operations based on originating tokens. */ public interface BackgroundActivityStartCallback { BackgroundActivityStartCallbackResult RESULT_FALSE = new BackgroundActivityStartCallbackResult(false, null); BackgroundActivityStartCallbackResult RESULT_TRUE = new BackgroundActivityStartCallbackResult(true, null); record BackgroundActivityStartCallbackResult( boolean allowed, IBinder token ) {} /** * Returns true if the background activity start originating from {@code tokens} should be * allowed or not. Loading @@ -34,7 +44,8 @@ public interface BackgroundActivityStartCallback { * This will be called holding the WM and local lock, don't do anything costly or invoke AM/WM * methods here directly. */ boolean isActivityStartAllowed(Collection<IBinder> tokens, int uid, String packageName); BackgroundActivityStartCallbackResult isActivityStartAllowed(Collection<IBinder> tokens, int uid, String packageName); /** * Returns whether {@code uid} can send {@link android.content.Intent Loading services/core/java/com/android/server/wm/BackgroundActivityStartController.java +6 −2 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ import static com.android.window.flags.Flags.balRequireOptInByPendingIntentCreat import static com.android.window.flags.Flags.balShowToastsBlocked; import static com.android.window.flags.Flags.balStrictModeGracePeriod; import static com.android.window.flags.Flags.balStrictModeRo; import static com.android.window.flags.Flags.balAdditionalLogging; import static java.lang.annotation.RetentionPolicy.SOURCE; import static java.util.Objects.requireNonNull; Loading Loading @@ -1939,6 +1940,7 @@ public class BackgroundActivityStartController { } } logIfOnlyAllowedBy(finalVerdict, state, BAL_ALLOW_NON_APP_VISIBLE_WINDOW); logIfOnlyAllowedBy(finalVerdict, state, BAL_ALLOW_TOKEN); if (balImprovedMetrics()) { if (shouldLogStats(finalVerdict, state)) { Loading Loading @@ -1998,8 +2000,10 @@ public class BackgroundActivityStartController { return false; } else { // log to determine grace period length distribution if (balAdditionalLogging()) { Slog.wtf(TAG, "Activity start ONLY allowed by " + balCodeToString(balCode) + " " + finalVerdict.mMessage + ": " + state); } return true; } } Loading services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java +29 −13 Original line number Diff line number Diff line Loading @@ -128,11 +128,16 @@ class BackgroundLaunchProcessController { return new BalVerdict(BAL_ALLOW_PERMISSION, /*background*/ "process instrumenting with background activity starts privileges"); } // Allow if the flag was explicitly set. if (checkConfiguration.checkOtherExemptions && isBackgroundStartAllowedByToken(uid, packageName, checkConfiguration.isCheckingForFgsStart)) { return new BalVerdict(balImprovedMetrics() ? BAL_ALLOW_TOKEN : BAL_ALLOW_PERMISSION, /*background*/ "process allowed by token"); // Allow if the token is explicitly allowed. if (checkConfiguration.checkOtherExemptions) { BalVerdict tokenVerdict = isBackgroundStartAllowedByToken(uid, packageName, checkConfiguration.isCheckingForFgsStart); if (tokenVerdict.allows()) { if (!balImprovedMetrics()) { return new BalVerdict(BAL_ALLOW_PERMISSION, tokenVerdict.toString()); } return tokenVerdict; } } // Allow if the caller is bound by a UID that's currently foreground. // But still respect the appSwitchState. Loading Loading @@ -174,42 +179,53 @@ class BackgroundLaunchProcessController { * isCheckingForFgsStart is false, we ask the callback if the start is allowed for these tokens, * otherwise if there is no callback we allow. */ private boolean isBackgroundStartAllowedByToken(int uid, String packageName, private BalVerdict isBackgroundStartAllowedByToken(int uid, String packageName, boolean isCheckingForFgsStart) { synchronized (this) { if (mBackgroundStartPrivileges == null || mBackgroundStartPrivileges.isEmpty()) { // no tokens to allow anything return false; return BalVerdict.BLOCK; } if (isCheckingForFgsStart) { // check if any token allows foreground service starts for (int i = mBackgroundStartPrivileges.size(); i-- > 0; ) { if (mBackgroundStartPrivileges.valueAt(i).allowsBackgroundFgsStarts()) { return true; return new BalVerdict(BAL_ALLOW_TOKEN, "process allowed by token"); } } return false; return BalVerdict.BLOCK; } if (mBackgroundActivityStartCallback == null) { // without a callback just check if any token allows background activity starts for (int i = mBackgroundStartPrivileges.size(); i-- > 0; ) { if (mBackgroundStartPrivileges.valueAt(i) .allowsBackgroundActivityStarts()) { return true; return new BalVerdict(BAL_ALLOW_TOKEN, "process allowed by token"); } } return false; return BalVerdict.BLOCK; } List<IBinder> binderTokens = getOriginatingTokensThatAllowBal(); if (binderTokens.isEmpty()) { // no tokens to allow anything return false; return BalVerdict.BLOCK; } // The callback will decide. return mBackgroundActivityStartCallback.isActivityStartAllowed( BackgroundActivityStartCallback.BackgroundActivityStartCallbackResult activityStartAllowed = mBackgroundActivityStartCallback.isActivityStartAllowed( binderTokens, uid, packageName); if (!activityStartAllowed.allowed()) { return BalVerdict.BLOCK; } if (activityStartAllowed.token() == null) { return new BalVerdict(BAL_ALLOW_TOKEN, "process allowed by callback (token ignored) tokens: " + binderTokens); } return new BalVerdict(BAL_ALLOW_TOKEN, "process allowed by callback (token: " + activityStartAllowed.token() + ") tokens: " + binderTokens); } } Loading services/tests/wmtests/src/com/android/server/wm/BackgroundLaunchProcessControllerTests.java +4 −4 Original line number Diff line number Diff line Loading @@ -74,14 +74,14 @@ public class BackgroundLaunchProcessControllerTests { BackgroundActivityStartCallback mCallback = new BackgroundActivityStartCallback() { @Override public boolean isActivityStartAllowed(Collection<IBinder> tokens, int uid, String packageName) { public BackgroundActivityStartCallbackResult isActivityStartAllowed( Collection<IBinder> tokens, int uid, String packageName) { for (IBinder token : tokens) { if (token == null || mActivityStartAllowed.contains(token)) { return true; return new BackgroundActivityStartCallbackResult(true, token); } } return false; return RESULT_FALSE; } @Override Loading Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +5 −5 Original line number Diff line number Diff line Loading @@ -14544,23 +14544,23 @@ public class NotificationManagerService extends SystemService { */ private class NotificationTrampolineCallback implements BackgroundActivityStartCallback { @Override public boolean isActivityStartAllowed(Collection<IBinder> tokens, int uid, String packageName) { public BackgroundActivityStartCallbackResult isActivityStartAllowed( Collection<IBinder> tokens, int uid, String packageName) { checkArgument(!tokens.isEmpty()); for (IBinder token : tokens) { if (token != ALLOWLIST_TOKEN) { // We only block or warn if the start is exclusively due to notification return true; return RESULT_TRUE; } } String logcatMessage = "Indirect notification activity start (trampoline) from " + packageName; if (blockTrampoline(uid)) { Slog.e(TAG, logcatMessage + " blocked"); return false; return RESULT_FALSE; } else { Slog.w(TAG, logcatMessage + ", this should be avoided for performance reasons"); return true; return new BackgroundActivityStartCallbackResult(true, ALLOWLIST_TOKEN); } }
services/core/java/com/android/server/wm/BackgroundActivityStartCallback.java +12 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,16 @@ import java.util.Collection; * Callback to decide activity starts and related operations based on originating tokens. */ public interface BackgroundActivityStartCallback { BackgroundActivityStartCallbackResult RESULT_FALSE = new BackgroundActivityStartCallbackResult(false, null); BackgroundActivityStartCallbackResult RESULT_TRUE = new BackgroundActivityStartCallbackResult(true, null); record BackgroundActivityStartCallbackResult( boolean allowed, IBinder token ) {} /** * Returns true if the background activity start originating from {@code tokens} should be * allowed or not. Loading @@ -34,7 +44,8 @@ public interface BackgroundActivityStartCallback { * This will be called holding the WM and local lock, don't do anything costly or invoke AM/WM * methods here directly. */ boolean isActivityStartAllowed(Collection<IBinder> tokens, int uid, String packageName); BackgroundActivityStartCallbackResult isActivityStartAllowed(Collection<IBinder> tokens, int uid, String packageName); /** * Returns whether {@code uid} can send {@link android.content.Intent Loading
services/core/java/com/android/server/wm/BackgroundActivityStartController.java +6 −2 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ import static com.android.window.flags.Flags.balRequireOptInByPendingIntentCreat import static com.android.window.flags.Flags.balShowToastsBlocked; import static com.android.window.flags.Flags.balStrictModeGracePeriod; import static com.android.window.flags.Flags.balStrictModeRo; import static com.android.window.flags.Flags.balAdditionalLogging; import static java.lang.annotation.RetentionPolicy.SOURCE; import static java.util.Objects.requireNonNull; Loading Loading @@ -1939,6 +1940,7 @@ public class BackgroundActivityStartController { } } logIfOnlyAllowedBy(finalVerdict, state, BAL_ALLOW_NON_APP_VISIBLE_WINDOW); logIfOnlyAllowedBy(finalVerdict, state, BAL_ALLOW_TOKEN); if (balImprovedMetrics()) { if (shouldLogStats(finalVerdict, state)) { Loading Loading @@ -1998,8 +2000,10 @@ public class BackgroundActivityStartController { return false; } else { // log to determine grace period length distribution if (balAdditionalLogging()) { Slog.wtf(TAG, "Activity start ONLY allowed by " + balCodeToString(balCode) + " " + finalVerdict.mMessage + ": " + state); } return true; } } Loading
services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java +29 −13 Original line number Diff line number Diff line Loading @@ -128,11 +128,16 @@ class BackgroundLaunchProcessController { return new BalVerdict(BAL_ALLOW_PERMISSION, /*background*/ "process instrumenting with background activity starts privileges"); } // Allow if the flag was explicitly set. if (checkConfiguration.checkOtherExemptions && isBackgroundStartAllowedByToken(uid, packageName, checkConfiguration.isCheckingForFgsStart)) { return new BalVerdict(balImprovedMetrics() ? BAL_ALLOW_TOKEN : BAL_ALLOW_PERMISSION, /*background*/ "process allowed by token"); // Allow if the token is explicitly allowed. if (checkConfiguration.checkOtherExemptions) { BalVerdict tokenVerdict = isBackgroundStartAllowedByToken(uid, packageName, checkConfiguration.isCheckingForFgsStart); if (tokenVerdict.allows()) { if (!balImprovedMetrics()) { return new BalVerdict(BAL_ALLOW_PERMISSION, tokenVerdict.toString()); } return tokenVerdict; } } // Allow if the caller is bound by a UID that's currently foreground. // But still respect the appSwitchState. Loading Loading @@ -174,42 +179,53 @@ class BackgroundLaunchProcessController { * isCheckingForFgsStart is false, we ask the callback if the start is allowed for these tokens, * otherwise if there is no callback we allow. */ private boolean isBackgroundStartAllowedByToken(int uid, String packageName, private BalVerdict isBackgroundStartAllowedByToken(int uid, String packageName, boolean isCheckingForFgsStart) { synchronized (this) { if (mBackgroundStartPrivileges == null || mBackgroundStartPrivileges.isEmpty()) { // no tokens to allow anything return false; return BalVerdict.BLOCK; } if (isCheckingForFgsStart) { // check if any token allows foreground service starts for (int i = mBackgroundStartPrivileges.size(); i-- > 0; ) { if (mBackgroundStartPrivileges.valueAt(i).allowsBackgroundFgsStarts()) { return true; return new BalVerdict(BAL_ALLOW_TOKEN, "process allowed by token"); } } return false; return BalVerdict.BLOCK; } if (mBackgroundActivityStartCallback == null) { // without a callback just check if any token allows background activity starts for (int i = mBackgroundStartPrivileges.size(); i-- > 0; ) { if (mBackgroundStartPrivileges.valueAt(i) .allowsBackgroundActivityStarts()) { return true; return new BalVerdict(BAL_ALLOW_TOKEN, "process allowed by token"); } } return false; return BalVerdict.BLOCK; } List<IBinder> binderTokens = getOriginatingTokensThatAllowBal(); if (binderTokens.isEmpty()) { // no tokens to allow anything return false; return BalVerdict.BLOCK; } // The callback will decide. return mBackgroundActivityStartCallback.isActivityStartAllowed( BackgroundActivityStartCallback.BackgroundActivityStartCallbackResult activityStartAllowed = mBackgroundActivityStartCallback.isActivityStartAllowed( binderTokens, uid, packageName); if (!activityStartAllowed.allowed()) { return BalVerdict.BLOCK; } if (activityStartAllowed.token() == null) { return new BalVerdict(BAL_ALLOW_TOKEN, "process allowed by callback (token ignored) tokens: " + binderTokens); } return new BalVerdict(BAL_ALLOW_TOKEN, "process allowed by callback (token: " + activityStartAllowed.token() + ") tokens: " + binderTokens); } } Loading
services/tests/wmtests/src/com/android/server/wm/BackgroundLaunchProcessControllerTests.java +4 −4 Original line number Diff line number Diff line Loading @@ -74,14 +74,14 @@ public class BackgroundLaunchProcessControllerTests { BackgroundActivityStartCallback mCallback = new BackgroundActivityStartCallback() { @Override public boolean isActivityStartAllowed(Collection<IBinder> tokens, int uid, String packageName) { public BackgroundActivityStartCallbackResult isActivityStartAllowed( Collection<IBinder> tokens, int uid, String packageName) { for (IBinder token : tokens) { if (token == null || mActivityStartAllowed.contains(token)) { return true; return new BackgroundActivityStartCallbackResult(true, token); } } return false; return RESULT_FALSE; } @Override Loading