Loading services/core/java/com/android/server/am/ActiveServices.java +227 −20 Original line number Diff line number Diff line Loading @@ -829,7 +829,8 @@ public final class ActiveServices { // Service.startForeground()), at that point we will consult the BFSL check and the timeout // and make the necessary decisions. setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, r, userId, backgroundStartPrivileges, false /* isBindService */); backgroundStartPrivileges, false /* isBindService */, !fgRequired /* isStartService */); if (!mAm.mUserController.exists(r.userId)) { Slog.w(TAG, "Trying to start service with non-existent user! " + r.userId); Loading Loading @@ -2119,7 +2120,11 @@ public final class ActiveServices { } } if (r.isForeground && isOldTypeShortFgs) { final boolean enableFgsWhileInUseFix = mAm.mConstants.mEnableFgsWhileInUseFix; final boolean fgsTypeChangingFromShortFgs = r.isForeground && isOldTypeShortFgs; if (fgsTypeChangingFromShortFgs) { // If we get here, that means startForeground(SHORT_SERVICE) is called again // on a SHORT_SERVICE FGS. Loading @@ -2128,7 +2133,7 @@ public final class ActiveServices { setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(), r.appInfo.uid, r.intent.getIntent(), r, r.userId, BackgroundStartPrivileges.NONE, false /* isBindService */); false /* isBindService */, false /* isStartService */); if (r.mAllowStartForeground == REASON_DENIED) { Slog.w(TAG_SERVICE, "FGS type change to/from SHORT_SERVICE: " + " BFSL DENIED."); Loading Loading @@ -2171,8 +2176,19 @@ public final class ActiveServices { // "if (r.mAllowStartForeground == REASON_DENIED...)" block below. } } } } else if (r.mStartForegroundCount == 0) { // Re-evaluate mAllowWhileInUsePermissionInFgs and mAllowStartForeground // (i.e. while-in-use and BFSL flags) if needed. // // Consider the below if-else section to be in the else of the above // `if (fgsTypeChangingFromShortFgs)`. // Using an else would increase the indent further, so we don't use it here // and instead just add !fgsTypeChangingFromShortFgs to all if's. // // The first if's are for the original while-in-use logic. if (!fgsTypeChangingFromShortFgs && !enableFgsWhileInUseFix && r.mStartForegroundCount == 0) { /* If the service was started with startService(), not startForegroundService(), and if startForeground() isn't called within Loading @@ -2193,7 +2209,7 @@ public final class ActiveServices { setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(), r.appInfo.uid, r.intent.getIntent(), r, r.userId, BackgroundStartPrivileges.NONE, false /* isBindService */); false /* isBindService */, false /* isStartService */); final String temp = "startForegroundDelayMs:" + delayMs; if (r.mInfoAllowStartForeground != null) { r.mInfoAllowStartForeground += "; " + temp; Loading @@ -2203,9 +2219,10 @@ public final class ActiveServices { r.mLoggedInfoAllowStartForeground = false; } } } else if (r.mStartForegroundCount >= 1) { } else if (!fgsTypeChangingFromShortFgs && !enableFgsWhileInUseFix && r.mStartForegroundCount >= 1) { // We get here if startForeground() is called multiple times // on the same sarvice after it's created, regardless of whether // on the same service after it's created, regardless of whether // stopForeground() has been called or not. // The second or later time startForeground() is called after service is Loading @@ -2213,7 +2230,71 @@ public final class ActiveServices { setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(), r.appInfo.uid, r.intent.getIntent(), r, r.userId, BackgroundStartPrivileges.NONE, false /* isBindService */); false /* isBindService */, false /* isStartService */); } else if (!fgsTypeChangingFromShortFgs && enableFgsWhileInUseFix) { // The new while-in-use logic. // // When startForeground() is called, we _always_ call // setFgsRestrictionLocked() to set the restrictions according to the // current state of the app. // (So if the app is now in TOP, for example, the service will now always // get while-in-use permissions.) // // Note, setFgsRestrictionLocked() will never disallow // mAllowWhileInUsePermissionInFgs nor mAllowStartForeground // (i.e. while-in-use and BFSL flags) once they're set to "allowed". // // HOWEVER, if these flags were set to "allowed" in Context.startService() // (as opposed to startForegroundService()), when the service wasn't yet // a foreground service, then we may not always // want to trust them -- for example, if the service has been running as a // BG service or a bound service for a long time when the app is not longer // in the foreground, then we shouldn't grant while-in-user nor BFSL. // So in that case, we need to reset it first. final long delayMs = (r.mLastUntrustedSetFgsRestrictionAllowedTime == 0) ? 0 : (SystemClock.elapsedRealtime() - r.mLastUntrustedSetFgsRestrictionAllowedTime); final boolean resetNeeded = !r.isForeground && delayMs > mAm.mConstants.mFgsStartForegroundTimeoutMs; if (resetNeeded) { resetFgsRestrictionLocked(r); } setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(), r.appInfo.uid, r.intent.getIntent(), r, r.userId, BackgroundStartPrivileges.NONE, false /* isBindService */, false /* isStartService */); final String temp = "startForegroundDelayMs:" + delayMs + "; started: " + r.startRequested + "; num_bindings: " + r.getConnections().size() + "; wasForeground: " + r.isForeground + "; resetNeeded:" + resetNeeded; if (r.mInfoAllowStartForeground != null) { r.mInfoAllowStartForeground += "; " + temp; } else { r.mInfoAllowStartForeground = temp; } r.mLoggedInfoAllowStartForeground = false; } // If the service has any bindings and it's not yet a FGS // we compare the new and old while-in-use logics. // (If it's not the first startForeground() call, we already reset the // while-in-use and BFSL flags, so the logic change wouldn't matter.) if (enableFgsWhileInUseFix && !r.isForeground && (r.getConnections().size() > 0) && (r.mDebugWhileInUseReasonInBindService != r.mDebugWhileInUseReasonInStartForeground)) { Slog.wtf(TAG, "FGS while-in-use changed (b/276963716): old=" + reasonCodeToString(r.mDebugWhileInUseReasonInBindService) + " new=" + reasonCodeToString(r.mDebugWhileInUseReasonInStartForeground) + " " + r.shortInstanceName); } // If the foreground service is not started from TOP process, do not allow it to Loading Loading @@ -2321,6 +2402,11 @@ public final class ActiveServices { active.mNumActive++; } r.isForeground = true; // Once the service becomes a foreground service, // the FGS restriction information always becomes "trustable". r.mLastUntrustedSetFgsRestrictionAllowedTime = 0; // The logging of FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER event could // be deferred, make a copy of mAllowStartForeground and // mAllowWhileInUsePermissionInFgs. Loading Loading @@ -3663,8 +3749,25 @@ public final class ActiveServices { return 0; } } if (!mAm.mConstants.mEnableFgsWhileInUseFix) { // Old while-in-use logic. setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, s, userId, BackgroundStartPrivileges.NONE, true /* isBindService */); BackgroundStartPrivileges.NONE, true /* isBindService */, false /* isStartService */); } else { // New logic will not call setFgsRestrictionLocked() here, but we still // keep track of the allow reason from the old logic here, so we can compare to // the new logic. // Once we're confident enough in the new logic, we should remove it. if (s.mDebugWhileInUseReasonInBindService == REASON_DENIED) { s.mDebugWhileInUseReasonInBindService = shouldAllowFgsWhileInUsePermissionLocked( callingPackage, callingPid, callingUid, s.app, BackgroundStartPrivileges.NONE, true /* isBindService */, false /* DO NOT enableFgsWhileInUseFix; use the old logic */); } } if (s.app != null) { ProcessServiceRecord servicePsr = s.app.mServices; Loading Loading @@ -7357,45 +7460,76 @@ public final class ActiveServices { * @param callingUid caller app's uid. * @param intent intent to start/bind service. * @param r the service to start. * @param isStartService True if it's called from Context.startService(). * False if it's called from Context.startForegroundService() or * Service.startService(). * @return true if allow, false otherwise. */ private void setFgsRestrictionLocked(String callingPackage, int callingPid, int callingUid, Intent intent, ServiceRecord r, int userId, BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService) { r.mLastSetFgsRestrictionTime = SystemClock.elapsedRealtime(); BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService, boolean isStartService) { final long now = SystemClock.elapsedRealtime(); // Check DeviceConfig flag. if (!mAm.mConstants.mFlagBackgroundFgsStartRestrictionEnabled) { r.mAllowWhileInUsePermissionInFgs = true; } final @ReasonCode int allowWhileInUse; // Either (or both) mAllowWhileInUsePermissionInFgs or mAllowStartForeground is // newly allowed? boolean newlyAllowed = false; if (!r.mAllowWhileInUsePermissionInFgs || (r.mAllowStartForeground == REASON_DENIED)) { allowWhileInUse = shouldAllowFgsWhileInUsePermissionLocked( callingPackage, callingPid, callingUid, r.app, backgroundStartPrivileges, isBindService); // We store them to compare the old and new while-in-use logics to each other. // (They're not used for any other purposes.) if (isBindService) { r.mDebugWhileInUseReasonInBindService = allowWhileInUse; } else { r.mDebugWhileInUseReasonInStartForeground = allowWhileInUse; } if (!r.mAllowWhileInUsePermissionInFgs) { r.mAllowWhileInUsePermissionInFgs = (allowWhileInUse != REASON_DENIED); newlyAllowed |= r.mAllowWhileInUsePermissionInFgs; } if (r.mAllowStartForeground == REASON_DENIED) { r.mAllowStartForeground = shouldAllowFgsStartForegroundWithBindingCheckLocked( allowWhileInUse, callingPackage, callingPid, callingUid, intent, r, backgroundStartPrivileges, isBindService); newlyAllowed |= r.mAllowStartForeground != REASON_DENIED; } } else { allowWhileInUse = REASON_UNKNOWN; } r.mAllowWhileInUsePermissionInFgsReason = allowWhileInUse; if (isStartService && !r.isForeground && newlyAllowed) { // If it's called by Context.startService() (not by startForegroundService()), // and we're setting "allowed", then we can't fully trust it yet -- we'll need to reset // the restrictions if startForeground() is called after the grace period. r.mLastUntrustedSetFgsRestrictionAllowedTime = now; } } void resetFgsRestrictionLocked(ServiceRecord r) { r.mAllowWhileInUsePermissionInFgs = false; r.mAllowWhileInUsePermissionInFgsReason = REASON_DENIED; r.mDebugWhileInUseReasonInStartForeground = REASON_DENIED; // We don't reset mWhileInUseReasonInBindService here, because if we do this, we would // lose it in the "reevaluation" case in startForeground(), where we call // resetFgsRestrictionLocked(). // Not resetting this is fine because it's only used in the first Service.startForeground() // case, and there's no situations where we call resetFgsRestrictionLocked() before that. r.mAllowStartForeground = REASON_DENIED; r.mInfoAllowStartForeground = null; r.mInfoTempFgsAllowListReason = null; r.mLoggedInfoAllowStartForeground = false; r.mLastSetFgsRestrictionTime = 0; r.mLastUntrustedSetFgsRestrictionAllowedTime = 0; r.updateAllowUiJobScheduling(r.mAllowWhileInUsePermissionInFgs); } Loading Loading @@ -7430,8 +7564,22 @@ public final class ActiveServices { private @ReasonCode int shouldAllowFgsWhileInUsePermissionLocked(String callingPackage, int callingPid, int callingUid, @Nullable ProcessRecord targetProcess, BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService) { return shouldAllowFgsWhileInUsePermissionLocked(callingPackage, callingPid, callingUid, targetProcess, backgroundStartPrivileges, isBindService, /* enableFgsWhileInUseFix =*/ mAm.mConstants.mEnableFgsWhileInUseFix); } private @ReasonCode int shouldAllowFgsWhileInUsePermissionLocked(String callingPackage, int callingPid, int callingUid, @Nullable ProcessRecord targetProcess, BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService, boolean enableFgsWhileInUseFix) { int ret = REASON_DENIED; // Define some local variables for better readability... final boolean useOldLogic = !enableFgsWhileInUseFix; final boolean forStartForeground = !isBindService; if (useOldLogic || forStartForeground) { final int uidState = mAm.getUidStateLocked(callingUid); if (ret == REASON_DENIED) { // Allow FGS while-in-use if the caller's process state is PROCESS_STATE_PERSISTENT, Loading @@ -7440,6 +7588,7 @@ public final class ActiveServices { ret = getReasonCodeFromProcState(uidState); } } } if (ret == REASON_DENIED) { // Allow FGS while-in-use if the caller has visible activity. Loading Loading @@ -7480,6 +7629,10 @@ public final class ActiveServices { } } if (enableFgsWhileInUseFix && ret == REASON_DENIED) { ret = shouldAllowFgsWhileInUsePermissionByBindingsLocked(callingUid); } if (ret == REASON_DENIED) { // Allow FGS while-in-use if the WindowManager allows background activity start. // This is mainly to get the 10 seconds grace period if any activity in the caller has Loading Loading @@ -7557,6 +7710,59 @@ public final class ActiveServices { return ret; } /** * Check all bindings into the calling UID, and see if: * - It's bound by a TOP app * - or, bound by a persistent process with BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS. */ private @ReasonCode int shouldAllowFgsWhileInUsePermissionByBindingsLocked(int callingUid) { final ArraySet<Integer> checkedClientUids = new ArraySet<>(); final Integer result = mAm.mProcessList.searchEachLruProcessesLOSP( false, pr -> { if (pr.uid != callingUid) { return null; } final ProcessServiceRecord psr = pr.mServices; final int serviceCount = psr.mServices.size(); for (int svc = 0; svc < serviceCount; svc++) { final ArrayMap<IBinder, ArrayList<ConnectionRecord>> conns = psr.mServices.valueAt(svc).getConnections(); final int size = conns.size(); for (int conni = 0; conni < size; conni++) { final ArrayList<ConnectionRecord> crs = conns.valueAt(conni); for (int con = 0; con < crs.size(); con++) { final ConnectionRecord cr = crs.get(con); final ProcessRecord clientPr = cr.binding.client; final int clientUid = clientPr.uid; // An UID can bind to itself, do not check on itself again. // Also skip already checked clientUid. if (clientUid == callingUid || checkedClientUids.contains(clientUid)) { continue; } // Binding found, check the client procstate and the flag. final int clientUidState = mAm.getUidStateLocked(callingUid); final boolean boundByTop = clientUidState == PROCESS_STATE_TOP; final boolean boundByPersistentWithBal = clientUidState < PROCESS_STATE_TOP && cr.hasFlag( Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS); if (boundByTop || boundByPersistentWithBal) { return getReasonCodeFromProcState(clientUidState); } // Don't check the same UID. checkedClientUids.add(clientUid); } } } return null; }); return result == null ? REASON_DENIED : result; } /** * The uid is not allowed to start FGS, but the uid has a service that is bound * by a clientUid, if the clientUid can start FGS, then the clientUid can propagate its Loading Loading @@ -8142,7 +8348,8 @@ public final class ActiveServices { r.mFgsEnterTime = SystemClock.uptimeMillis(); r.foregroundServiceType = options.mForegroundServiceTypes; setFgsRestrictionLocked(callingPackage, callingPid, callingUid, intent, r, userId, BackgroundStartPrivileges.NONE, false); BackgroundStartPrivileges.NONE, false /* isBindService */, false /* isStartService */); final ProcessServiceRecord psr = callerApp.mServices; final boolean newService = psr.startService(r); // updateOomAdj. Loading services/core/java/com/android/server/am/ActivityManagerConstants.java +19 −0 Original line number Diff line number Diff line Loading @@ -1058,6 +1058,13 @@ final class ActivityManagerConstants extends ContentObserver { /** @see #KEY_USE_MODERN_TRIM */ public boolean USE_MODERN_TRIM = DEFAULT_USE_MODERN_TRIM; private static final String KEY_ENABLE_FGS_WHILE_IN_USE_FIX = "key_enable_fgs_while_in_use_fix"; private static final boolean DEFAULT_ENABLE_FGS_WHILE_IN_USE_FIX = true; public volatile boolean mEnableFgsWhileInUseFix = DEFAULT_ENABLE_FGS_WHILE_IN_USE_FIX; private final OnPropertiesChangedListener mOnDeviceConfigChangedListener = new OnPropertiesChangedListener() { @Override Loading Loading @@ -1226,6 +1233,9 @@ final class ActivityManagerConstants extends ContentObserver { case KEY_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION: updateEnableWaitForFinishAttachApplication(); break; case KEY_ENABLE_FGS_WHILE_IN_USE_FIX: updateEnableFgsWhileInUseFix(); break; case KEY_MAX_PREVIOUS_TIME: updateMaxPreviousTime(); break; Loading Loading @@ -1995,6 +2005,12 @@ final class ActivityManagerConstants extends ContentObserver { DEFAULT_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION); } private void updateEnableFgsWhileInUseFix() { mEnableFgsWhileInUseFix = DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_ENABLE_FGS_WHILE_IN_USE_FIX, DEFAULT_ENABLE_FGS_WHILE_IN_USE_FIX); } private void updateUseTieredCachedAdj() { USE_TIERED_CACHED_ADJ = DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, Loading Loading @@ -2195,6 +2211,9 @@ final class ActivityManagerConstants extends ContentObserver { pw.print(" "); pw.print(KEY_SYSTEM_EXEMPT_POWER_RESTRICTIONS_ENABLED); pw.print("="); pw.println(mFlagSystemExemptPowerRestrictionsEnabled); pw.print(" "); pw.print(KEY_ENABLE_FGS_WHILE_IN_USE_FIX); pw.print("="); pw.println(mEnableFgsWhileInUseFix); pw.print(" "); pw.print(KEY_SHORT_FGS_TIMEOUT_DURATION); pw.print("="); pw.println(mShortFgsTimeoutDuration); pw.print(" "); pw.print(KEY_SHORT_FGS_PROC_STATE_EXTRA_WAIT_DURATION); Loading services/core/java/com/android/server/am/ServiceRecord.java +24 −4 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
services/core/java/com/android/server/am/ActiveServices.java +227 −20 Original line number Diff line number Diff line Loading @@ -829,7 +829,8 @@ public final class ActiveServices { // Service.startForeground()), at that point we will consult the BFSL check and the timeout // and make the necessary decisions. setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, r, userId, backgroundStartPrivileges, false /* isBindService */); backgroundStartPrivileges, false /* isBindService */, !fgRequired /* isStartService */); if (!mAm.mUserController.exists(r.userId)) { Slog.w(TAG, "Trying to start service with non-existent user! " + r.userId); Loading Loading @@ -2119,7 +2120,11 @@ public final class ActiveServices { } } if (r.isForeground && isOldTypeShortFgs) { final boolean enableFgsWhileInUseFix = mAm.mConstants.mEnableFgsWhileInUseFix; final boolean fgsTypeChangingFromShortFgs = r.isForeground && isOldTypeShortFgs; if (fgsTypeChangingFromShortFgs) { // If we get here, that means startForeground(SHORT_SERVICE) is called again // on a SHORT_SERVICE FGS. Loading @@ -2128,7 +2133,7 @@ public final class ActiveServices { setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(), r.appInfo.uid, r.intent.getIntent(), r, r.userId, BackgroundStartPrivileges.NONE, false /* isBindService */); false /* isBindService */, false /* isStartService */); if (r.mAllowStartForeground == REASON_DENIED) { Slog.w(TAG_SERVICE, "FGS type change to/from SHORT_SERVICE: " + " BFSL DENIED."); Loading Loading @@ -2171,8 +2176,19 @@ public final class ActiveServices { // "if (r.mAllowStartForeground == REASON_DENIED...)" block below. } } } } else if (r.mStartForegroundCount == 0) { // Re-evaluate mAllowWhileInUsePermissionInFgs and mAllowStartForeground // (i.e. while-in-use and BFSL flags) if needed. // // Consider the below if-else section to be in the else of the above // `if (fgsTypeChangingFromShortFgs)`. // Using an else would increase the indent further, so we don't use it here // and instead just add !fgsTypeChangingFromShortFgs to all if's. // // The first if's are for the original while-in-use logic. if (!fgsTypeChangingFromShortFgs && !enableFgsWhileInUseFix && r.mStartForegroundCount == 0) { /* If the service was started with startService(), not startForegroundService(), and if startForeground() isn't called within Loading @@ -2193,7 +2209,7 @@ public final class ActiveServices { setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(), r.appInfo.uid, r.intent.getIntent(), r, r.userId, BackgroundStartPrivileges.NONE, false /* isBindService */); false /* isBindService */, false /* isStartService */); final String temp = "startForegroundDelayMs:" + delayMs; if (r.mInfoAllowStartForeground != null) { r.mInfoAllowStartForeground += "; " + temp; Loading @@ -2203,9 +2219,10 @@ public final class ActiveServices { r.mLoggedInfoAllowStartForeground = false; } } } else if (r.mStartForegroundCount >= 1) { } else if (!fgsTypeChangingFromShortFgs && !enableFgsWhileInUseFix && r.mStartForegroundCount >= 1) { // We get here if startForeground() is called multiple times // on the same sarvice after it's created, regardless of whether // on the same service after it's created, regardless of whether // stopForeground() has been called or not. // The second or later time startForeground() is called after service is Loading @@ -2213,7 +2230,71 @@ public final class ActiveServices { setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(), r.appInfo.uid, r.intent.getIntent(), r, r.userId, BackgroundStartPrivileges.NONE, false /* isBindService */); false /* isBindService */, false /* isStartService */); } else if (!fgsTypeChangingFromShortFgs && enableFgsWhileInUseFix) { // The new while-in-use logic. // // When startForeground() is called, we _always_ call // setFgsRestrictionLocked() to set the restrictions according to the // current state of the app. // (So if the app is now in TOP, for example, the service will now always // get while-in-use permissions.) // // Note, setFgsRestrictionLocked() will never disallow // mAllowWhileInUsePermissionInFgs nor mAllowStartForeground // (i.e. while-in-use and BFSL flags) once they're set to "allowed". // // HOWEVER, if these flags were set to "allowed" in Context.startService() // (as opposed to startForegroundService()), when the service wasn't yet // a foreground service, then we may not always // want to trust them -- for example, if the service has been running as a // BG service or a bound service for a long time when the app is not longer // in the foreground, then we shouldn't grant while-in-user nor BFSL. // So in that case, we need to reset it first. final long delayMs = (r.mLastUntrustedSetFgsRestrictionAllowedTime == 0) ? 0 : (SystemClock.elapsedRealtime() - r.mLastUntrustedSetFgsRestrictionAllowedTime); final boolean resetNeeded = !r.isForeground && delayMs > mAm.mConstants.mFgsStartForegroundTimeoutMs; if (resetNeeded) { resetFgsRestrictionLocked(r); } setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(), r.appInfo.uid, r.intent.getIntent(), r, r.userId, BackgroundStartPrivileges.NONE, false /* isBindService */, false /* isStartService */); final String temp = "startForegroundDelayMs:" + delayMs + "; started: " + r.startRequested + "; num_bindings: " + r.getConnections().size() + "; wasForeground: " + r.isForeground + "; resetNeeded:" + resetNeeded; if (r.mInfoAllowStartForeground != null) { r.mInfoAllowStartForeground += "; " + temp; } else { r.mInfoAllowStartForeground = temp; } r.mLoggedInfoAllowStartForeground = false; } // If the service has any bindings and it's not yet a FGS // we compare the new and old while-in-use logics. // (If it's not the first startForeground() call, we already reset the // while-in-use and BFSL flags, so the logic change wouldn't matter.) if (enableFgsWhileInUseFix && !r.isForeground && (r.getConnections().size() > 0) && (r.mDebugWhileInUseReasonInBindService != r.mDebugWhileInUseReasonInStartForeground)) { Slog.wtf(TAG, "FGS while-in-use changed (b/276963716): old=" + reasonCodeToString(r.mDebugWhileInUseReasonInBindService) + " new=" + reasonCodeToString(r.mDebugWhileInUseReasonInStartForeground) + " " + r.shortInstanceName); } // If the foreground service is not started from TOP process, do not allow it to Loading Loading @@ -2321,6 +2402,11 @@ public final class ActiveServices { active.mNumActive++; } r.isForeground = true; // Once the service becomes a foreground service, // the FGS restriction information always becomes "trustable". r.mLastUntrustedSetFgsRestrictionAllowedTime = 0; // The logging of FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER event could // be deferred, make a copy of mAllowStartForeground and // mAllowWhileInUsePermissionInFgs. Loading Loading @@ -3663,8 +3749,25 @@ public final class ActiveServices { return 0; } } if (!mAm.mConstants.mEnableFgsWhileInUseFix) { // Old while-in-use logic. setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, s, userId, BackgroundStartPrivileges.NONE, true /* isBindService */); BackgroundStartPrivileges.NONE, true /* isBindService */, false /* isStartService */); } else { // New logic will not call setFgsRestrictionLocked() here, but we still // keep track of the allow reason from the old logic here, so we can compare to // the new logic. // Once we're confident enough in the new logic, we should remove it. if (s.mDebugWhileInUseReasonInBindService == REASON_DENIED) { s.mDebugWhileInUseReasonInBindService = shouldAllowFgsWhileInUsePermissionLocked( callingPackage, callingPid, callingUid, s.app, BackgroundStartPrivileges.NONE, true /* isBindService */, false /* DO NOT enableFgsWhileInUseFix; use the old logic */); } } if (s.app != null) { ProcessServiceRecord servicePsr = s.app.mServices; Loading Loading @@ -7357,45 +7460,76 @@ public final class ActiveServices { * @param callingUid caller app's uid. * @param intent intent to start/bind service. * @param r the service to start. * @param isStartService True if it's called from Context.startService(). * False if it's called from Context.startForegroundService() or * Service.startService(). * @return true if allow, false otherwise. */ private void setFgsRestrictionLocked(String callingPackage, int callingPid, int callingUid, Intent intent, ServiceRecord r, int userId, BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService) { r.mLastSetFgsRestrictionTime = SystemClock.elapsedRealtime(); BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService, boolean isStartService) { final long now = SystemClock.elapsedRealtime(); // Check DeviceConfig flag. if (!mAm.mConstants.mFlagBackgroundFgsStartRestrictionEnabled) { r.mAllowWhileInUsePermissionInFgs = true; } final @ReasonCode int allowWhileInUse; // Either (or both) mAllowWhileInUsePermissionInFgs or mAllowStartForeground is // newly allowed? boolean newlyAllowed = false; if (!r.mAllowWhileInUsePermissionInFgs || (r.mAllowStartForeground == REASON_DENIED)) { allowWhileInUse = shouldAllowFgsWhileInUsePermissionLocked( callingPackage, callingPid, callingUid, r.app, backgroundStartPrivileges, isBindService); // We store them to compare the old and new while-in-use logics to each other. // (They're not used for any other purposes.) if (isBindService) { r.mDebugWhileInUseReasonInBindService = allowWhileInUse; } else { r.mDebugWhileInUseReasonInStartForeground = allowWhileInUse; } if (!r.mAllowWhileInUsePermissionInFgs) { r.mAllowWhileInUsePermissionInFgs = (allowWhileInUse != REASON_DENIED); newlyAllowed |= r.mAllowWhileInUsePermissionInFgs; } if (r.mAllowStartForeground == REASON_DENIED) { r.mAllowStartForeground = shouldAllowFgsStartForegroundWithBindingCheckLocked( allowWhileInUse, callingPackage, callingPid, callingUid, intent, r, backgroundStartPrivileges, isBindService); newlyAllowed |= r.mAllowStartForeground != REASON_DENIED; } } else { allowWhileInUse = REASON_UNKNOWN; } r.mAllowWhileInUsePermissionInFgsReason = allowWhileInUse; if (isStartService && !r.isForeground && newlyAllowed) { // If it's called by Context.startService() (not by startForegroundService()), // and we're setting "allowed", then we can't fully trust it yet -- we'll need to reset // the restrictions if startForeground() is called after the grace period. r.mLastUntrustedSetFgsRestrictionAllowedTime = now; } } void resetFgsRestrictionLocked(ServiceRecord r) { r.mAllowWhileInUsePermissionInFgs = false; r.mAllowWhileInUsePermissionInFgsReason = REASON_DENIED; r.mDebugWhileInUseReasonInStartForeground = REASON_DENIED; // We don't reset mWhileInUseReasonInBindService here, because if we do this, we would // lose it in the "reevaluation" case in startForeground(), where we call // resetFgsRestrictionLocked(). // Not resetting this is fine because it's only used in the first Service.startForeground() // case, and there's no situations where we call resetFgsRestrictionLocked() before that. r.mAllowStartForeground = REASON_DENIED; r.mInfoAllowStartForeground = null; r.mInfoTempFgsAllowListReason = null; r.mLoggedInfoAllowStartForeground = false; r.mLastSetFgsRestrictionTime = 0; r.mLastUntrustedSetFgsRestrictionAllowedTime = 0; r.updateAllowUiJobScheduling(r.mAllowWhileInUsePermissionInFgs); } Loading Loading @@ -7430,8 +7564,22 @@ public final class ActiveServices { private @ReasonCode int shouldAllowFgsWhileInUsePermissionLocked(String callingPackage, int callingPid, int callingUid, @Nullable ProcessRecord targetProcess, BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService) { return shouldAllowFgsWhileInUsePermissionLocked(callingPackage, callingPid, callingUid, targetProcess, backgroundStartPrivileges, isBindService, /* enableFgsWhileInUseFix =*/ mAm.mConstants.mEnableFgsWhileInUseFix); } private @ReasonCode int shouldAllowFgsWhileInUsePermissionLocked(String callingPackage, int callingPid, int callingUid, @Nullable ProcessRecord targetProcess, BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService, boolean enableFgsWhileInUseFix) { int ret = REASON_DENIED; // Define some local variables for better readability... final boolean useOldLogic = !enableFgsWhileInUseFix; final boolean forStartForeground = !isBindService; if (useOldLogic || forStartForeground) { final int uidState = mAm.getUidStateLocked(callingUid); if (ret == REASON_DENIED) { // Allow FGS while-in-use if the caller's process state is PROCESS_STATE_PERSISTENT, Loading @@ -7440,6 +7588,7 @@ public final class ActiveServices { ret = getReasonCodeFromProcState(uidState); } } } if (ret == REASON_DENIED) { // Allow FGS while-in-use if the caller has visible activity. Loading Loading @@ -7480,6 +7629,10 @@ public final class ActiveServices { } } if (enableFgsWhileInUseFix && ret == REASON_DENIED) { ret = shouldAllowFgsWhileInUsePermissionByBindingsLocked(callingUid); } if (ret == REASON_DENIED) { // Allow FGS while-in-use if the WindowManager allows background activity start. // This is mainly to get the 10 seconds grace period if any activity in the caller has Loading Loading @@ -7557,6 +7710,59 @@ public final class ActiveServices { return ret; } /** * Check all bindings into the calling UID, and see if: * - It's bound by a TOP app * - or, bound by a persistent process with BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS. */ private @ReasonCode int shouldAllowFgsWhileInUsePermissionByBindingsLocked(int callingUid) { final ArraySet<Integer> checkedClientUids = new ArraySet<>(); final Integer result = mAm.mProcessList.searchEachLruProcessesLOSP( false, pr -> { if (pr.uid != callingUid) { return null; } final ProcessServiceRecord psr = pr.mServices; final int serviceCount = psr.mServices.size(); for (int svc = 0; svc < serviceCount; svc++) { final ArrayMap<IBinder, ArrayList<ConnectionRecord>> conns = psr.mServices.valueAt(svc).getConnections(); final int size = conns.size(); for (int conni = 0; conni < size; conni++) { final ArrayList<ConnectionRecord> crs = conns.valueAt(conni); for (int con = 0; con < crs.size(); con++) { final ConnectionRecord cr = crs.get(con); final ProcessRecord clientPr = cr.binding.client; final int clientUid = clientPr.uid; // An UID can bind to itself, do not check on itself again. // Also skip already checked clientUid. if (clientUid == callingUid || checkedClientUids.contains(clientUid)) { continue; } // Binding found, check the client procstate and the flag. final int clientUidState = mAm.getUidStateLocked(callingUid); final boolean boundByTop = clientUidState == PROCESS_STATE_TOP; final boolean boundByPersistentWithBal = clientUidState < PROCESS_STATE_TOP && cr.hasFlag( Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS); if (boundByTop || boundByPersistentWithBal) { return getReasonCodeFromProcState(clientUidState); } // Don't check the same UID. checkedClientUids.add(clientUid); } } } return null; }); return result == null ? REASON_DENIED : result; } /** * The uid is not allowed to start FGS, but the uid has a service that is bound * by a clientUid, if the clientUid can start FGS, then the clientUid can propagate its Loading Loading @@ -8142,7 +8348,8 @@ public final class ActiveServices { r.mFgsEnterTime = SystemClock.uptimeMillis(); r.foregroundServiceType = options.mForegroundServiceTypes; setFgsRestrictionLocked(callingPackage, callingPid, callingUid, intent, r, userId, BackgroundStartPrivileges.NONE, false); BackgroundStartPrivileges.NONE, false /* isBindService */, false /* isStartService */); final ProcessServiceRecord psr = callerApp.mServices; final boolean newService = psr.startService(r); // updateOomAdj. Loading
services/core/java/com/android/server/am/ActivityManagerConstants.java +19 −0 Original line number Diff line number Diff line Loading @@ -1058,6 +1058,13 @@ final class ActivityManagerConstants extends ContentObserver { /** @see #KEY_USE_MODERN_TRIM */ public boolean USE_MODERN_TRIM = DEFAULT_USE_MODERN_TRIM; private static final String KEY_ENABLE_FGS_WHILE_IN_USE_FIX = "key_enable_fgs_while_in_use_fix"; private static final boolean DEFAULT_ENABLE_FGS_WHILE_IN_USE_FIX = true; public volatile boolean mEnableFgsWhileInUseFix = DEFAULT_ENABLE_FGS_WHILE_IN_USE_FIX; private final OnPropertiesChangedListener mOnDeviceConfigChangedListener = new OnPropertiesChangedListener() { @Override Loading Loading @@ -1226,6 +1233,9 @@ final class ActivityManagerConstants extends ContentObserver { case KEY_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION: updateEnableWaitForFinishAttachApplication(); break; case KEY_ENABLE_FGS_WHILE_IN_USE_FIX: updateEnableFgsWhileInUseFix(); break; case KEY_MAX_PREVIOUS_TIME: updateMaxPreviousTime(); break; Loading Loading @@ -1995,6 +2005,12 @@ final class ActivityManagerConstants extends ContentObserver { DEFAULT_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION); } private void updateEnableFgsWhileInUseFix() { mEnableFgsWhileInUseFix = DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_ENABLE_FGS_WHILE_IN_USE_FIX, DEFAULT_ENABLE_FGS_WHILE_IN_USE_FIX); } private void updateUseTieredCachedAdj() { USE_TIERED_CACHED_ADJ = DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, Loading Loading @@ -2195,6 +2211,9 @@ final class ActivityManagerConstants extends ContentObserver { pw.print(" "); pw.print(KEY_SYSTEM_EXEMPT_POWER_RESTRICTIONS_ENABLED); pw.print("="); pw.println(mFlagSystemExemptPowerRestrictionsEnabled); pw.print(" "); pw.print(KEY_ENABLE_FGS_WHILE_IN_USE_FIX); pw.print("="); pw.println(mEnableFgsWhileInUseFix); pw.print(" "); pw.print(KEY_SHORT_FGS_TIMEOUT_DURATION); pw.print("="); pw.println(mShortFgsTimeoutDuration); pw.print(" "); pw.print(KEY_SHORT_FGS_PROC_STATE_EXTRA_WAIT_DURATION); Loading
services/core/java/com/android/server/am/ServiceRecord.java +24 −4 File changed.Preview size limit exceeded, changes collapsed. Show changes