Loading services/core/java/com/android/server/am/ActiveServices.java +4 −3 Original line number Diff line number Diff line Loading @@ -482,13 +482,14 @@ public final class ActiveServices { String callingPackage, @Nullable String callingFeatureId, final int userId) throws TransactionTooLargeException { return startServiceLocked(caller, service, resolvedType, callingPid, callingUid, fgRequired, hideFgNotification, callingPackage, callingFeatureId, userId, false); hideFgNotification, callingPackage, callingFeatureId, userId, false, null); } ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType, int callingPid, int callingUid, boolean fgRequired, boolean hideFgNotification, String callingPackage, @Nullable String callingFeatureId, final int userId, boolean allowBackgroundActivityStarts) throws TransactionTooLargeException { boolean allowBackgroundActivityStarts, @Nullable IBinder backgroundActivityStartsToken) throws TransactionTooLargeException { if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service + " type=" + resolvedType + " args=" + service.getExtras()); Loading Loading @@ -733,7 +734,7 @@ public final class ActiveServices { } } if (allowBackgroundActivityStarts) { r.allowBgActivityStartsOnServiceStart(); r.allowBgActivityStartsOnServiceStart(backgroundActivityStartsToken); } ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting); return cmp; Loading services/core/java/com/android/server/am/ActivityManagerService.java +2 −1 Original line number Diff line number Diff line Loading @@ -16306,7 +16306,8 @@ public class ActivityManagerService extends IActivityManager.Stub try { res = mServices.startServiceLocked(null, service, resolvedType, -1, uid, fgRequired, false, callingPackage, callingFeatureId, userId, allowBackgroundActivityStarts); callingFeatureId, userId, allowBackgroundActivityStarts, backgroundActivityStartsToken); } finally { Binder.restoreCallingIdentity(origId); } services/core/java/com/android/server/am/BroadcastQueue.java +1 −1 Original line number Diff line number Diff line Loading @@ -1686,7 +1686,7 @@ public final class BroadcastQueue { // that request - we don't want the token to be swept from under our feet... mHandler.removeCallbacksAndMessages(msgToken); // ...then add the token proc.addAllowBackgroundActivityStartsToken(r, r.mBackgroundActivityStartsToken); proc.addOrUpdateAllowBackgroundActivityStartsToken(r, r.mBackgroundActivityStartsToken); } final void setBroadcastTimeoutLocked(long timeoutTime) { Loading services/core/java/com/android/server/am/ProcessRecord.java +7 −4 Original line number Diff line number Diff line Loading @@ -77,6 +77,7 @@ import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.function.Consumer; /** Loading Loading @@ -1338,13 +1339,15 @@ class ProcessRecord implements WindowProcessListener { * {@param originatingToken} if you have one such originating token, this is useful for tracing * back the grant in the case of the notification token. */ void addAllowBackgroundActivityStartsToken(Binder entity, @Nullable IBinder originatingToken) { if (entity == null) return; mWindowProcessController.addAllowBackgroundActivityStartsToken(entity, originatingToken); void addOrUpdateAllowBackgroundActivityStartsToken(Binder entity, @Nullable IBinder originatingToken) { Objects.requireNonNull(entity); mWindowProcessController.addOrUpdateAllowBackgroundActivityStartsToken(entity, originatingToken); } void removeAllowBackgroundActivityStartsToken(Binder entity) { if (entity == null) return; Objects.requireNonNull(entity); mWindowProcessController.removeAllowBackgroundActivityStartsToken(entity); } Loading services/core/java/com/android/server/am/ServiceRecord.java +74 −25 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.app.PendingIntent.FLAG_UPDATE_CURRENT; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import android.annotation.Nullable; import android.app.Notification; import android.app.PendingIntent; import android.content.ComponentName; Loading Loading @@ -139,6 +140,12 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN // used to clean up the state of mIsAllowedBgActivityStartsByStart after a timeout private Runnable mCleanUpAllowBgActivityStartsByStartCallback; private ProcessRecord mAppForAllowingBgActivityStartsByStart; // These are the originating tokens that currently allow bg activity starts by service start. // This is used to trace back the grant when starting activities. We only pass such token to the // ProcessRecord if it's the *only* cause for bg activity starts exemption, otherwise we pass // null. @GuardedBy("ams") private List<IBinder> mBgActivityStartsByStartOriginatingTokens = new ArrayList<>(); // allow while-in-use permissions in foreground service or not. // while-in-use permissions in FGS started from background might be restricted. Loading Loading @@ -588,7 +595,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN ? _proc : null; if (mIsAllowedBgActivityStartsByStart || mIsAllowedBgActivityStartsByBinding) { _proc.addAllowBackgroundActivityStartsToken(this, null); _proc.addOrUpdateAllowBackgroundActivityStartsToken(this, getExclusiveOriginatingToken()); } else { _proc.removeAllowBackgroundActivityStartsToken(this); } Loading Loading @@ -679,11 +687,9 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN } void setAllowedBgActivityStartsByBinding(boolean newValue) { if (mIsAllowedBgActivityStartsByBinding != newValue) { mIsAllowedBgActivityStartsByBinding = newValue; updateParentProcessBgActivityStartsToken(); } } /** * Called when the service is started with allowBackgroundActivityStarts set. We allow Loading @@ -691,7 +697,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN * timeout. Note that the ability for starting background activities persists for the process * even if the service is subsequently stopped. */ void allowBgActivityStartsOnServiceStart() { void allowBgActivityStartsOnServiceStart(@Nullable IBinder originatingToken) { mBgActivityStartsByStartOriginatingTokens.add(originatingToken); setAllowedBgActivityStartsByStart(true); if (app != null) { mAppForAllowingBgActivityStartsByStart = app; Loading @@ -701,33 +708,50 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN if (mCleanUpAllowBgActivityStartsByStartCallback == null) { mCleanUpAllowBgActivityStartsByStartCallback = () -> { synchronized (ams) { mBgActivityStartsByStartOriginatingTokens.remove(0); if (!mBgActivityStartsByStartOriginatingTokens.isEmpty()) { // There are other callbacks in the queue, let's just update the originating // token if (mIsAllowedBgActivityStartsByStart) { mAppForAllowingBgActivityStartsByStart .addOrUpdateAllowBackgroundActivityStartsToken( this, getExclusiveOriginatingToken()); } else { Slog.wtf(TAG, "Service callback to revoke bg activity starts by service " + "start triggered but " + "mIsAllowedBgActivityStartsByStart = false. This " + "should never happen."); } } else { // Last callback on the queue if (app == mAppForAllowingBgActivityStartsByStart) { // The process we allowed is still running the service. We remove // the ability by start, but it may still be allowed via bound connections. // the ability by start, but it may still be allowed via bound // connections. setAllowedBgActivityStartsByStart(false); } else if (mAppForAllowingBgActivityStartsByStart != null) { // The process we allowed is not running the service. It therefore can't be // bound so we can unconditionally remove the ability. // The process we allowed is not running the service. It therefore can't // be bound so we can unconditionally remove the ability. mAppForAllowingBgActivityStartsByStart .removeAllowBackgroundActivityStartsToken(ServiceRecord.this); } mAppForAllowingBgActivityStartsByStart = null; } } }; } // if there's a request pending from the past, drop it before scheduling a new one ams.mHandler.removeCallbacks(mCleanUpAllowBgActivityStartsByStartCallback); // Existing callbacks will only update the originating token, only when the last callback is // executed is the grant revoked. ams.mHandler.postDelayed(mCleanUpAllowBgActivityStartsByStartCallback, ams.mConstants.SERVICE_BG_ACTIVITY_START_TIMEOUT); } private void setAllowedBgActivityStartsByStart(boolean newValue) { if (mIsAllowedBgActivityStartsByStart != newValue) { mIsAllowedBgActivityStartsByStart = newValue; updateParentProcessBgActivityStartsToken(); } } /** * Whether the process this service runs in should be temporarily allowed to start Loading @@ -736,8 +760,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN * {@code mIsAllowedBgActivityStartsByBinding}. If either is true, this ServiceRecord * should be contributing as a token in parent ProcessRecord. * * @see com.android.server.am.ProcessRecord#addAllowBackgroundActivityStartsToken(Binder, * IBinder) * @see com.android.server.am.ProcessRecord#addOrUpdateAllowBackgroundActivityStartsToken( * Binder, IBinder) * @see com.android.server.am.ProcessRecord#removeAllowBackgroundActivityStartsToken(Binder) */ private void updateParentProcessBgActivityStartsToken() { Loading @@ -747,12 +771,37 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN if (mIsAllowedBgActivityStartsByStart || mIsAllowedBgActivityStartsByBinding) { // if the token is already there it's safe to "re-add it" - we're dealing with // a set of Binder objects app.addAllowBackgroundActivityStartsToken(this, null); app.addOrUpdateAllowBackgroundActivityStartsToken(this, getExclusiveOriginatingToken()); } else { app.removeAllowBackgroundActivityStartsToken(this); } } /** * Returns the originating token if that's the only reason background activity starts are * allowed. In order for that to happen the service has to be allowed only due to starts, since * bindings are not associated with originating tokens, and all the start tokens have to be the * same and there can't be any null originating token in the queue. * * Originating tokens are optional, so the caller could provide null when it allows bg activity * starts. */ @Nullable private IBinder getExclusiveOriginatingToken() { if (mIsAllowedBgActivityStartsByBinding || mBgActivityStartsByStartOriginatingTokens.isEmpty()) { return null; } IBinder firstToken = mBgActivityStartsByStartOriginatingTokens.get(0); for (int i = 1, n = mBgActivityStartsByStartOriginatingTokens.size(); i < n; i++) { IBinder token = mBgActivityStartsByStartOriginatingTokens.get(i); if (token != firstToken) { return null; } } return firstToken; } @GuardedBy("ams") void updateKeepWarmLocked() { mKeepWarming = ams.mConstants.KEEP_WARMING_SERVICES.contains(name) Loading Loading
services/core/java/com/android/server/am/ActiveServices.java +4 −3 Original line number Diff line number Diff line Loading @@ -482,13 +482,14 @@ public final class ActiveServices { String callingPackage, @Nullable String callingFeatureId, final int userId) throws TransactionTooLargeException { return startServiceLocked(caller, service, resolvedType, callingPid, callingUid, fgRequired, hideFgNotification, callingPackage, callingFeatureId, userId, false); hideFgNotification, callingPackage, callingFeatureId, userId, false, null); } ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType, int callingPid, int callingUid, boolean fgRequired, boolean hideFgNotification, String callingPackage, @Nullable String callingFeatureId, final int userId, boolean allowBackgroundActivityStarts) throws TransactionTooLargeException { boolean allowBackgroundActivityStarts, @Nullable IBinder backgroundActivityStartsToken) throws TransactionTooLargeException { if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service + " type=" + resolvedType + " args=" + service.getExtras()); Loading Loading @@ -733,7 +734,7 @@ public final class ActiveServices { } } if (allowBackgroundActivityStarts) { r.allowBgActivityStartsOnServiceStart(); r.allowBgActivityStartsOnServiceStart(backgroundActivityStartsToken); } ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting); return cmp; Loading
services/core/java/com/android/server/am/ActivityManagerService.java +2 −1 Original line number Diff line number Diff line Loading @@ -16306,7 +16306,8 @@ public class ActivityManagerService extends IActivityManager.Stub try { res = mServices.startServiceLocked(null, service, resolvedType, -1, uid, fgRequired, false, callingPackage, callingFeatureId, userId, allowBackgroundActivityStarts); callingFeatureId, userId, allowBackgroundActivityStarts, backgroundActivityStartsToken); } finally { Binder.restoreCallingIdentity(origId); }
services/core/java/com/android/server/am/BroadcastQueue.java +1 −1 Original line number Diff line number Diff line Loading @@ -1686,7 +1686,7 @@ public final class BroadcastQueue { // that request - we don't want the token to be swept from under our feet... mHandler.removeCallbacksAndMessages(msgToken); // ...then add the token proc.addAllowBackgroundActivityStartsToken(r, r.mBackgroundActivityStartsToken); proc.addOrUpdateAllowBackgroundActivityStartsToken(r, r.mBackgroundActivityStartsToken); } final void setBroadcastTimeoutLocked(long timeoutTime) { Loading
services/core/java/com/android/server/am/ProcessRecord.java +7 −4 Original line number Diff line number Diff line Loading @@ -77,6 +77,7 @@ import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.function.Consumer; /** Loading Loading @@ -1338,13 +1339,15 @@ class ProcessRecord implements WindowProcessListener { * {@param originatingToken} if you have one such originating token, this is useful for tracing * back the grant in the case of the notification token. */ void addAllowBackgroundActivityStartsToken(Binder entity, @Nullable IBinder originatingToken) { if (entity == null) return; mWindowProcessController.addAllowBackgroundActivityStartsToken(entity, originatingToken); void addOrUpdateAllowBackgroundActivityStartsToken(Binder entity, @Nullable IBinder originatingToken) { Objects.requireNonNull(entity); mWindowProcessController.addOrUpdateAllowBackgroundActivityStartsToken(entity, originatingToken); } void removeAllowBackgroundActivityStartsToken(Binder entity) { if (entity == null) return; Objects.requireNonNull(entity); mWindowProcessController.removeAllowBackgroundActivityStartsToken(entity); } Loading
services/core/java/com/android/server/am/ServiceRecord.java +74 −25 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.app.PendingIntent.FLAG_UPDATE_CURRENT; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import android.annotation.Nullable; import android.app.Notification; import android.app.PendingIntent; import android.content.ComponentName; Loading Loading @@ -139,6 +140,12 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN // used to clean up the state of mIsAllowedBgActivityStartsByStart after a timeout private Runnable mCleanUpAllowBgActivityStartsByStartCallback; private ProcessRecord mAppForAllowingBgActivityStartsByStart; // These are the originating tokens that currently allow bg activity starts by service start. // This is used to trace back the grant when starting activities. We only pass such token to the // ProcessRecord if it's the *only* cause for bg activity starts exemption, otherwise we pass // null. @GuardedBy("ams") private List<IBinder> mBgActivityStartsByStartOriginatingTokens = new ArrayList<>(); // allow while-in-use permissions in foreground service or not. // while-in-use permissions in FGS started from background might be restricted. Loading Loading @@ -588,7 +595,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN ? _proc : null; if (mIsAllowedBgActivityStartsByStart || mIsAllowedBgActivityStartsByBinding) { _proc.addAllowBackgroundActivityStartsToken(this, null); _proc.addOrUpdateAllowBackgroundActivityStartsToken(this, getExclusiveOriginatingToken()); } else { _proc.removeAllowBackgroundActivityStartsToken(this); } Loading Loading @@ -679,11 +687,9 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN } void setAllowedBgActivityStartsByBinding(boolean newValue) { if (mIsAllowedBgActivityStartsByBinding != newValue) { mIsAllowedBgActivityStartsByBinding = newValue; updateParentProcessBgActivityStartsToken(); } } /** * Called when the service is started with allowBackgroundActivityStarts set. We allow Loading @@ -691,7 +697,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN * timeout. Note that the ability for starting background activities persists for the process * even if the service is subsequently stopped. */ void allowBgActivityStartsOnServiceStart() { void allowBgActivityStartsOnServiceStart(@Nullable IBinder originatingToken) { mBgActivityStartsByStartOriginatingTokens.add(originatingToken); setAllowedBgActivityStartsByStart(true); if (app != null) { mAppForAllowingBgActivityStartsByStart = app; Loading @@ -701,33 +708,50 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN if (mCleanUpAllowBgActivityStartsByStartCallback == null) { mCleanUpAllowBgActivityStartsByStartCallback = () -> { synchronized (ams) { mBgActivityStartsByStartOriginatingTokens.remove(0); if (!mBgActivityStartsByStartOriginatingTokens.isEmpty()) { // There are other callbacks in the queue, let's just update the originating // token if (mIsAllowedBgActivityStartsByStart) { mAppForAllowingBgActivityStartsByStart .addOrUpdateAllowBackgroundActivityStartsToken( this, getExclusiveOriginatingToken()); } else { Slog.wtf(TAG, "Service callback to revoke bg activity starts by service " + "start triggered but " + "mIsAllowedBgActivityStartsByStart = false. This " + "should never happen."); } } else { // Last callback on the queue if (app == mAppForAllowingBgActivityStartsByStart) { // The process we allowed is still running the service. We remove // the ability by start, but it may still be allowed via bound connections. // the ability by start, but it may still be allowed via bound // connections. setAllowedBgActivityStartsByStart(false); } else if (mAppForAllowingBgActivityStartsByStart != null) { // The process we allowed is not running the service. It therefore can't be // bound so we can unconditionally remove the ability. // The process we allowed is not running the service. It therefore can't // be bound so we can unconditionally remove the ability. mAppForAllowingBgActivityStartsByStart .removeAllowBackgroundActivityStartsToken(ServiceRecord.this); } mAppForAllowingBgActivityStartsByStart = null; } } }; } // if there's a request pending from the past, drop it before scheduling a new one ams.mHandler.removeCallbacks(mCleanUpAllowBgActivityStartsByStartCallback); // Existing callbacks will only update the originating token, only when the last callback is // executed is the grant revoked. ams.mHandler.postDelayed(mCleanUpAllowBgActivityStartsByStartCallback, ams.mConstants.SERVICE_BG_ACTIVITY_START_TIMEOUT); } private void setAllowedBgActivityStartsByStart(boolean newValue) { if (mIsAllowedBgActivityStartsByStart != newValue) { mIsAllowedBgActivityStartsByStart = newValue; updateParentProcessBgActivityStartsToken(); } } /** * Whether the process this service runs in should be temporarily allowed to start Loading @@ -736,8 +760,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN * {@code mIsAllowedBgActivityStartsByBinding}. If either is true, this ServiceRecord * should be contributing as a token in parent ProcessRecord. * * @see com.android.server.am.ProcessRecord#addAllowBackgroundActivityStartsToken(Binder, * IBinder) * @see com.android.server.am.ProcessRecord#addOrUpdateAllowBackgroundActivityStartsToken( * Binder, IBinder) * @see com.android.server.am.ProcessRecord#removeAllowBackgroundActivityStartsToken(Binder) */ private void updateParentProcessBgActivityStartsToken() { Loading @@ -747,12 +771,37 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN if (mIsAllowedBgActivityStartsByStart || mIsAllowedBgActivityStartsByBinding) { // if the token is already there it's safe to "re-add it" - we're dealing with // a set of Binder objects app.addAllowBackgroundActivityStartsToken(this, null); app.addOrUpdateAllowBackgroundActivityStartsToken(this, getExclusiveOriginatingToken()); } else { app.removeAllowBackgroundActivityStartsToken(this); } } /** * Returns the originating token if that's the only reason background activity starts are * allowed. In order for that to happen the service has to be allowed only due to starts, since * bindings are not associated with originating tokens, and all the start tokens have to be the * same and there can't be any null originating token in the queue. * * Originating tokens are optional, so the caller could provide null when it allows bg activity * starts. */ @Nullable private IBinder getExclusiveOriginatingToken() { if (mIsAllowedBgActivityStartsByBinding || mBgActivityStartsByStartOriginatingTokens.isEmpty()) { return null; } IBinder firstToken = mBgActivityStartsByStartOriginatingTokens.get(0); for (int i = 1, n = mBgActivityStartsByStartOriginatingTokens.size(); i < n; i++) { IBinder token = mBgActivityStartsByStartOriginatingTokens.get(i); if (token != firstToken) { return null; } } return firstToken; } @GuardedBy("ams") void updateKeepWarmLocked() { mKeepWarming = ams.mConstants.KEEP_WARMING_SERVICES.contains(name) Loading