Loading core/java/android/app/ForegroundServiceTypePolicy.java +16 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SHORT_SERVICE; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED; Loading Loading @@ -377,6 +378,19 @@ public abstract class ForegroundServiceTypePolicy { }, false) ); /** * The policy for the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_SHORT_SERVICE}. * * @hide */ public static final @NonNull ForegroundServiceTypePolicyInfo FGS_TYPE_POLICY_SHORT_SERVICE = new ForegroundServiceTypePolicyInfo( FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, null /* no type specific permissions */, null /* no type specific permissions */ ); /** * The policy for the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_SPECIAL_USE}. * Loading Loading @@ -964,6 +978,8 @@ public abstract class ForegroundServiceTypePolicy { FGS_TYPE_POLICY_REMOTE_MESSAGING); mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED, FGS_TYPE_POLICY_SYSTEM_EXEMPTED); mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, FGS_TYPE_POLICY_SHORT_SERVICE); mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_SPECIAL_USE, FGS_TYPE_POLICY_SPECIAL_USE); } Loading services/core/java/com/android/server/am/ActiveServices.java +97 −13 Original line number Diff line number Diff line Loading @@ -225,7 +225,9 @@ public final class ActiveServices { private static final boolean DEBUG_DELAYED_SERVICE = DEBUG_SERVICE; private static final boolean DEBUG_DELAYED_STARTS = DEBUG_DELAYED_SERVICE; private static final boolean LOG_SERVICE_START_STOP = false; private static final boolean DEBUG_SHORT_SERVICE = DEBUG_SERVICE; private static final boolean LOG_SERVICE_START_STOP = DEBUG_SERVICE; // How long we wait for a service to finish executing. static final int SERVICE_TIMEOUT = 20 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; Loading Loading @@ -729,6 +731,12 @@ public final class ActiveServices { ? res.permission : "private to package"); } // TODO(short-service): This is inside startService() / startForegroundService(). // Consider if there's anything special we have to do if these are called on an already- // running short-FGS... But given these APIs shouldn't change the FGS type, we likely // don't need to do anything. (If they would change the FGS type, we'd have to stop // the timeout) ServiceRecord r = res.record; setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, r, userId, allowBackgroundActivityStarts, false /* isBindService */); Loading Loading @@ -1291,7 +1299,8 @@ public final class ActiveServices { } service.callStart = false; bringDownServiceIfNeededLocked(service, false, false, enqueueOomAdj); bringDownServiceIfNeededLocked(service, false, false, enqueueOomAdj, "stopService"); } finally { Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } Loading Loading @@ -1473,7 +1482,7 @@ public final class ActiveServices { } r.callStart = false; final long origId = Binder.clearCallingIdentity(); bringDownServiceIfNeededLocked(r, false, false, false); bringDownServiceIfNeededLocked(r, false, false, false, "stopServiceToken"); Binder.restoreCallingIdentity(origId); return true; } Loading Loading @@ -1801,15 +1810,23 @@ public final class ActiveServices { r.app.getPid(), r.appInfo.uid, "startForeground"); } // TODO(short-service): This part really should be above the if block, // so we'll apply the same check for instant apps too. int manifestType = r.serviceInfo.getForegroundServiceType(); // If passed in foreground service type is FOREGROUND_SERVICE_TYPE_MANIFEST, // consider it is the same as manifest foreground service type. if (foregroundServiceType == FOREGROUND_SERVICE_TYPE_MANIFEST) { foregroundServiceType = manifestType; } // Check the passed in foreground service type flags is a subset of manifest // foreground service type flags. if ((foregroundServiceType & manifestType) != foregroundServiceType) { final String prop = "debug.skip_fgs_manifest_type_check"; if (((foregroundServiceType & manifestType) != foregroundServiceType) // When building a test app on Studio, the SDK may not have all the // FGS types yet. This debug flag will allow using FGS types that are // not set in the manifest. && !SystemProperties.getBoolean(prop, false)) { throw new IllegalArgumentException("foregroundServiceType " + String.format("0x%08X", foregroundServiceType) + " is not a subset of foregroundServiceType attribute " Loading Loading @@ -1866,6 +1883,16 @@ public final class ActiveServices { int fgsTypeCheckCode = FGS_TYPE_POLICY_CHECK_UNKNOWN; if (!ignoreForeground) { // TODO(short-service): There's a known long-standing bug that allows // a abound service to become "foreground" if setForeground() is called // (without actually "starting" it). // Unfortunately we can't just "fix" it because some apps are relying on it, // but this will cause a problem to short-fgs, so we should disallow it if // this happens and the type is SHORT_SERVICE. // // OTOH, if a valid short-service (which has to be "started"), happens to // also be bound, then we still _will_ apply a timeout, because it still has // to be stopped. if (r.mStartForegroundCount == 0) { /* If the service was started with startService(), not Loading Loading @@ -1898,6 +1925,28 @@ public final class ActiveServices { } } } else if (r.mStartForegroundCount >= 1) { // We get here if startForeground() is called multiple times // on the same sarvice after it's created, regardless of whether // stopForeground() has been called or not. // TODO(short-service): Consider transitions: // A. Short -> other types: // Apply the BG restriction again. Don't just allow it. // i.e. unless the app is in a situation where it's allowed to start // a FGS, this transition shouldn't be allowed. // ... But think about it more, there may be a case this should be // allowed. // // If the transition is allowed, stop the timeout. // If the transition is _not_ allowed... keep the timeout? // // B. Short -> Short: // This should be the same as case A // If this is allowed, the new timeout should start. // C. Other -> short: // This should always be allowed. // A timeout should start. // The second or later time startForeground() is called after service is // started. Check for app state again. setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(), Loading Loading @@ -1977,6 +2026,10 @@ public final class ActiveServices { cancelForegroundNotificationLocked(r); r.foregroundId = id; } // TODO(short-service): Stop the short service timeout, if the type is changing // from short to non-short. (should we do it earlier?) notification.flags |= Notification.FLAG_FOREGROUND_SERVICE; r.foregroundNoti = notification; r.foregroundServiceType = foregroundServiceType; Loading Loading @@ -2048,6 +2101,9 @@ public final class ActiveServices { getServiceMapLocked(r.userId).ensureNotStartingBackgroundLocked(r); mAm.notifyPackageUse(r.serviceInfo.packageName, PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE); // TODO(short-service): Start counting a timeout. } else { if (DEBUG_FOREGROUND_SERVICE) { Slog.d(TAG, "Suppressing startForeground() for FAS " + r); Loading Loading @@ -2081,6 +2137,8 @@ public final class ActiveServices { decActiveForegroundAppLocked(smap, r); } // TODO(short-service): Stop the timeout. (any better place to do it?) // Adjust notification handling before setting isForeground to false, because // that state is relevant to the notification policy side. // Leave the time-to-display as already set: re-entering foreground mode will Loading Loading @@ -2121,6 +2179,10 @@ public final class ActiveServices { ? (int) (r.mFgsExitTime - r.mFgsEnterTime) : 0, FGS_STOP_REASON_STOP_FOREGROUND, FGS_TYPE_POLICY_CHECK_UNKNOWN); // foregroundServiceType is used in logFGSStateChangeLocked(), so we can't clear it // earlier. r.foregroundServiceType = 0; r.mFgsNotificationWasDeferred = false; signalForegroundServiceObserversLocked(r); resetFgsRestrictionLocked(r); Loading Loading @@ -2408,7 +2470,9 @@ public final class ActiveServices { final int uid = r.appInfo.uid; // schedule the actual notification post long when = now + mAm.mConstants.mFgsNotificationDeferralInterval; long when = now + (r.isShortFgs() ? mAm.mConstants.mFgsNotificationDeferralIntervalForShort : mAm.mConstants.mFgsNotificationDeferralInterval); // If there are already deferred FGS notifications for this app, // inherit that deferred-show timestamp for (int i = 0; i < mPendingFgsNotifications.size(); i++) { Loading @@ -2427,7 +2491,9 @@ public final class ActiveServices { } if (mFgsDeferralRateLimited) { final long nextEligible = when + mAm.mConstants.mFgsNotificationDeferralExclusionTime; final long nextEligible = when + (r.isShortFgs() ? mAm.mConstants.mFgsNotificationDeferralExclusionTimeForShort : mAm.mConstants.mFgsNotificationDeferralExclusionTime); mFgsDeferralEligible.put(uid, nextEligible); } r.fgDisplayTime = when; Loading Loading @@ -2791,14 +2857,19 @@ public final class ActiveServices { private void updateServiceForegroundLocked(ProcessServiceRecord psr, boolean oomAdj) { boolean anyForeground = false; int fgServiceTypes = 0; boolean hasTypeNone = false; for (int i = psr.numberOfRunningServices() - 1; i >= 0; i--) { ServiceRecord sr = psr.getRunningServiceAt(i); if (sr.isForeground || sr.fgRequired) { anyForeground = true; fgServiceTypes |= sr.foregroundServiceType; if (sr.foregroundServiceType == ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE) { hasTypeNone = true; } } mAm.updateProcessForegroundLocked(psr.mApp, anyForeground, fgServiceTypes, oomAdj); } mAm.updateProcessForegroundLocked(psr.mApp, anyForeground, fgServiceTypes, hasTypeNone, oomAdj); psr.setHasReportedForegroundServices(anyForeground); } Loading Loading @@ -4773,10 +4844,18 @@ public final class ActiveServices { return false; } private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn, boolean hasConn, boolean enqueueOomAdj) { //Slog.i(TAG, "Bring down service:"); //r.dump(" "); private void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn, boolean hasConn, boolean enqueueOomAdj, String debugReason) { if (DEBUG_SERVICE) { Slog.i(TAG, "Bring down service for " + debugReason + " :" + r.toString()); } // TODO(short-service): Hmm, when the app stops a short-fgs, we should stop the timeout // here. // However we have a couple if's here and if these conditions are met, we stop here // without bringing down the service. // We need to make sure this can't be used (somehow) to keep having a short-FGS running // while having the timeout stopped. if (isServiceNeededLocked(r, knowConn, hasConn)) { return; Loading Loading @@ -4844,6 +4923,8 @@ public final class ActiveServices { // Check to see if the service had been started as foreground, but being // brought down before actually showing a notification. That is not allowed. // TODO(short-service): This is unlikely related to short-FGS, but I'm curious why it's // not allowed. Look into it. if (r.fgRequired) { Slog.w(TAG_SERVICE, "Bringing down service while still waiting for start foreground: " + r); Loading Loading @@ -4934,6 +5015,8 @@ public final class ActiveServices { FGS_STOP_REASON_STOP_SERVICE, FGS_TYPE_POLICY_CHECK_UNKNOWN); mAm.updateForegroundServiceUsageStats(r.name, r.userId, false); // TODO(short-service): Make sure we stop the timeout by here. } r.isForeground = false; Loading Loading @@ -5161,7 +5244,8 @@ public final class ActiveServices { } } } bringDownServiceIfNeededLocked(s, true, hasAutoCreate, enqueueOomAdj); bringDownServiceIfNeededLocked(s, true, hasAutoCreate, enqueueOomAdj, "removeConnection"); } } } Loading Loading @@ -6988,7 +7072,7 @@ public final class ActiveServices { final Integer allowedType = mAm.mProcessList.searchEachLruProcessesLOSP(false, app -> { if (app.uid == callingUid) { final ProcessStateRecord state = app.mState; if (state.isAllowedStartFgs()) { if (state.isAllowedStartFgs()) { // Procstate <= BFGS? return getReasonCodeFromProcState(state.getCurProcState()); } else { final ActiveInstrumentation instr = app.getActiveInstrumentation(); Loading services/core/java/com/android/server/am/ActivityManagerService.java +13 −7 Original line number Diff line number Diff line Loading @@ -4945,7 +4945,7 @@ public class ActivityManagerService extends IActivityManager.Stub app.mState.setVerifiedAdj(ProcessList.INVALID_ADJ); mOomAdjuster.setAttachingSchedGroupLSP(app); app.mState.setForcingToImportant(null); updateProcessForegroundLocked(app, false, 0, false); clearProcessForegroundLocked(app); app.mState.setHasShownUi(false); app.mState.setCached(false); app.setDebugging(false); Loading Loading @@ -5805,7 +5805,7 @@ public class ActivityManagerService extends IActivityManager.Stub return; } pr.mState.setForcingToImportant(null); updateProcessForegroundLocked(pr, false, 0, false); clearProcessForegroundLocked(pr); } updateOomAdjLocked(pr, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); } Loading Loading @@ -12706,7 +12706,7 @@ public class ActivityManagerService extends IActivityManager.Stub for (BroadcastQueue queue : mBroadcastQueues) { queue.onApplicationCleanupLocked(app); } updateProcessForegroundLocked(app, false, 0, false); clearProcessForegroundLocked(app); mServices.killServicesLocked(app, allowRestart); mPhantomProcessList.onAppDied(pid); Loading Loading @@ -15829,13 +15829,19 @@ public class ActivityManagerService extends IActivityManager.Stub } } @GuardedBy("this") final void clearProcessForegroundLocked(ProcessRecord proc) { updateProcessForegroundLocked(proc, /* isForeground =*/ false, /* fgsTypes =*/0, /* hasTypeNoneFgs =*/false, /* oomAdj= */ false); } @GuardedBy("this") final void updateProcessForegroundLocked(ProcessRecord proc, boolean isForeground, int fgServiceTypes, boolean oomAdj) { int fgServiceTypes, boolean hasTypeNoneFgs, boolean oomAdj) { final ProcessServiceRecord psr = proc.mServices; final boolean foregroundStateChanged = isForeground != psr.hasForegroundServices(); if (foregroundStateChanged || psr.getForegroundServiceTypes() != fgServiceTypes) { || !psr.areForegroundServiceTypesSame(fgServiceTypes, hasTypeNoneFgs)) { if (foregroundStateChanged) { // Notify internal listeners. for (int i = mForegroundServiceStateListeners.size() - 1; i >= 0; i--) { Loading @@ -15843,7 +15849,7 @@ public class ActivityManagerService extends IActivityManager.Stub proc.info.packageName, proc.info.uid, proc.getPid(), isForeground); } } psr.setHasForegroundServices(isForeground, fgServiceTypes); psr.setHasForegroundServices(isForeground, fgServiceTypes, hasTypeNoneFgs); ArrayList<ProcessRecord> curProcs = mForegroundPackages.get(proc.info.packageName, proc.info.uid); if (isForeground) { Loading Loading @@ -17762,7 +17768,7 @@ public class ActivityManagerService extends IActivityManager.Stub return null; } if ((app.mServices.getForegroundServiceTypes() & foregroundServicetype) != 0) { if ((app.mServices.containsAnyForegroundServiceTypes(foregroundServicetype))) { return Boolean.TRUE; } return null; services/core/java/com/android/server/am/OomAdjuster.java +62 −23 Original line number Diff line number Diff line Loading @@ -1798,28 +1798,53 @@ public class OomAdjuster { } } int capabilityFromFGS = 0; // capability from foreground service. // Adjust for FGS or "has-overlay-ui". if (adj > PERCEPTIBLE_APP_ADJ || procState > PROCESS_STATE_FOREGROUND_SERVICE) { if (psr.hasForegroundServices()) { // The user is aware of this app, so make it visible. adj = PERCEPTIBLE_APP_ADJ; procState = PROCESS_STATE_FOREGROUND_SERVICE; state.setAdjType("fg-service"); state.setCached(false); schedGroup = SCHED_GROUP_DEFAULT; if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + state.getAdjType() + ": " + app + " "); } String adjType = null; int newAdj = 0; int newProcState = 0; if (psr.hasForegroundServices() && psr.hasNonShortForegroundServices()) { // For regular (non-short) FGS. adjType = "fg-service"; newAdj = PERCEPTIBLE_APP_ADJ; newProcState = PROCESS_STATE_FOREGROUND_SERVICE; } else if (state.hasOverlayUi()) { // The process is display an overlay UI. adj = PERCEPTIBLE_APP_ADJ; procState = PROCESS_STATE_IMPORTANT_FOREGROUND; adjType = "has-overlay-ui"; newAdj = PERCEPTIBLE_APP_ADJ; newProcState = PROCESS_STATE_IMPORTANT_FOREGROUND; } else if (psr.hasForegroundServices() && !psr.hasNonShortForegroundServices()) { // For short FGS. adjType = "fg-service-short"; // We use MEDIUM_APP_ADJ + 1 so we can tell apart EJ (which uses MEDIUM_APP_ADJ + 1) // from short-FGS. // (We use +1 and +2, not +0 and +1, to be consistent with the following // RECENT_FOREGROUND_APP_ADJ tweak) newAdj = PERCEPTIBLE_MEDIUM_APP_ADJ + 1; // Short-FGS gets a below-BFGS procstate, so it can't start another FGS from it. newProcState = PROCESS_STATE_IMPORTANT_FOREGROUND; // Same as EJ, we explicitly grant network access to short FGS, // even when battery saver or data saver is enabled. capabilityFromFGS |= PROCESS_CAPABILITY_NETWORK; } if (adjType != null) { adj = newAdj; procState = newProcState; state.setAdjType(adjType); state.setCached(false); state.setAdjType("has-overlay-ui"); schedGroup = SCHED_GROUP_DEFAULT; if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to overlay ui: " + app); reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType + ": " + app + " "); } } } Loading @@ -1830,8 +1855,15 @@ public class OomAdjuster { if (psr.hasForegroundServices() && adj > PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ && (state.getLastTopTime() + mConstants.TOP_TO_FGS_GRACE_DURATION > now || state.getSetProcState() <= PROCESS_STATE_TOP)) { if (psr.hasNonShortForegroundServices()) { adj = PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ; state.setAdjType("fg-service-act"); } else { // For short-service FGS, we +1 the value, so we'll be able to detect it in // various dashboards. adj = PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + 1; state.setAdjType("fg-service-short-act"); } if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to recent fg: " + app); } Loading @@ -1842,11 +1874,13 @@ public class OomAdjuster { // foreground services so that it can finish performing any persistence/processing of // in-memory state. if (psr.hasTopStartedAlmostPerceptibleServices() && adj > PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ && (adj > PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + 2) && (state.getLastTopTime() + mConstants.TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION > now || state.getSetProcState() <= PROCESS_STATE_TOP)) { adj = PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ; // For EJ, we +2 the value, so we'll be able to detect it in // various dashboards. adj = PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + 2; // This shall henceforth be called the "EJ" exemption, despite utilizing the // ALMOST_PERCEPTIBLE flag to work. state.setAdjType("top-ej-act"); Loading Loading @@ -1979,7 +2013,6 @@ public class OomAdjuster { } } int capabilityFromFGS = 0; // capability from foreground service. boolean boundByNonBgRestricted = state.isCurBoundByNonBgRestrictedApp(); boolean scheduleLikeTopApp = false; for (int is = psr.numberOfRunningServices() - 1; Loading Loading @@ -2031,6 +2064,8 @@ public class OomAdjuster { } } // TODO(short-service): While-in-user permissions. Do we need any change here for // short-FGS? (Likely not) if (s.isForeground) { final int fgsType = s.foregroundServiceType; if (s.mAllowWhileInUsePermissionInFgs) { Loading Loading @@ -2113,6 +2148,7 @@ public class OomAdjuster { // in this case unless they explicitly request it. if ((cstate.getCurCapability() & PROCESS_CAPABILITY_NETWORK) != 0) { if (clientProcState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) { // This is used to grant network access to Expedited Jobs. if ((cr.flags & Context.BIND_BYPASS_POWER_NETWORK_RESTRICTIONS) != 0) { capability |= PROCESS_CAPABILITY_NETWORK; Loading Loading @@ -2200,8 +2236,11 @@ public class OomAdjuster { newAdj = PERCEPTIBLE_LOW_APP_ADJ; } else if ((cr.flags & Context.BIND_ALMOST_PERCEPTIBLE) != 0 && clientAdj < PERCEPTIBLE_APP_ADJ && adj >= (lbAdj = PERCEPTIBLE_MEDIUM_APP_ADJ)) { newAdj = PERCEPTIBLE_MEDIUM_APP_ADJ; && adj >= (lbAdj = (PERCEPTIBLE_MEDIUM_APP_ADJ + 2))) { // This is for expedited jobs. // We use MEDIUM_APP_ADJ + 2 here, so we can tell apart // EJ and short-FGS. newAdj = PERCEPTIBLE_MEDIUM_APP_ADJ + 2; } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0 && clientAdj < PERCEPTIBLE_APP_ADJ && adj >= (lbAdj = PERCEPTIBLE_APP_ADJ)) { Loading services/core/java/com/android/server/am/ProcessServiceRecord.java +55 −3 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
core/java/android/app/ForegroundServiceTypePolicy.java +16 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SHORT_SERVICE; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED; Loading Loading @@ -377,6 +378,19 @@ public abstract class ForegroundServiceTypePolicy { }, false) ); /** * The policy for the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_SHORT_SERVICE}. * * @hide */ public static final @NonNull ForegroundServiceTypePolicyInfo FGS_TYPE_POLICY_SHORT_SERVICE = new ForegroundServiceTypePolicyInfo( FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, null /* no type specific permissions */, null /* no type specific permissions */ ); /** * The policy for the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_SPECIAL_USE}. * Loading Loading @@ -964,6 +978,8 @@ public abstract class ForegroundServiceTypePolicy { FGS_TYPE_POLICY_REMOTE_MESSAGING); mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED, FGS_TYPE_POLICY_SYSTEM_EXEMPTED); mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, FGS_TYPE_POLICY_SHORT_SERVICE); mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_SPECIAL_USE, FGS_TYPE_POLICY_SPECIAL_USE); } Loading
services/core/java/com/android/server/am/ActiveServices.java +97 −13 Original line number Diff line number Diff line Loading @@ -225,7 +225,9 @@ public final class ActiveServices { private static final boolean DEBUG_DELAYED_SERVICE = DEBUG_SERVICE; private static final boolean DEBUG_DELAYED_STARTS = DEBUG_DELAYED_SERVICE; private static final boolean LOG_SERVICE_START_STOP = false; private static final boolean DEBUG_SHORT_SERVICE = DEBUG_SERVICE; private static final boolean LOG_SERVICE_START_STOP = DEBUG_SERVICE; // How long we wait for a service to finish executing. static final int SERVICE_TIMEOUT = 20 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; Loading Loading @@ -729,6 +731,12 @@ public final class ActiveServices { ? res.permission : "private to package"); } // TODO(short-service): This is inside startService() / startForegroundService(). // Consider if there's anything special we have to do if these are called on an already- // running short-FGS... But given these APIs shouldn't change the FGS type, we likely // don't need to do anything. (If they would change the FGS type, we'd have to stop // the timeout) ServiceRecord r = res.record; setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, r, userId, allowBackgroundActivityStarts, false /* isBindService */); Loading Loading @@ -1291,7 +1299,8 @@ public final class ActiveServices { } service.callStart = false; bringDownServiceIfNeededLocked(service, false, false, enqueueOomAdj); bringDownServiceIfNeededLocked(service, false, false, enqueueOomAdj, "stopService"); } finally { Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } Loading Loading @@ -1473,7 +1482,7 @@ public final class ActiveServices { } r.callStart = false; final long origId = Binder.clearCallingIdentity(); bringDownServiceIfNeededLocked(r, false, false, false); bringDownServiceIfNeededLocked(r, false, false, false, "stopServiceToken"); Binder.restoreCallingIdentity(origId); return true; } Loading Loading @@ -1801,15 +1810,23 @@ public final class ActiveServices { r.app.getPid(), r.appInfo.uid, "startForeground"); } // TODO(short-service): This part really should be above the if block, // so we'll apply the same check for instant apps too. int manifestType = r.serviceInfo.getForegroundServiceType(); // If passed in foreground service type is FOREGROUND_SERVICE_TYPE_MANIFEST, // consider it is the same as manifest foreground service type. if (foregroundServiceType == FOREGROUND_SERVICE_TYPE_MANIFEST) { foregroundServiceType = manifestType; } // Check the passed in foreground service type flags is a subset of manifest // foreground service type flags. if ((foregroundServiceType & manifestType) != foregroundServiceType) { final String prop = "debug.skip_fgs_manifest_type_check"; if (((foregroundServiceType & manifestType) != foregroundServiceType) // When building a test app on Studio, the SDK may not have all the // FGS types yet. This debug flag will allow using FGS types that are // not set in the manifest. && !SystemProperties.getBoolean(prop, false)) { throw new IllegalArgumentException("foregroundServiceType " + String.format("0x%08X", foregroundServiceType) + " is not a subset of foregroundServiceType attribute " Loading Loading @@ -1866,6 +1883,16 @@ public final class ActiveServices { int fgsTypeCheckCode = FGS_TYPE_POLICY_CHECK_UNKNOWN; if (!ignoreForeground) { // TODO(short-service): There's a known long-standing bug that allows // a abound service to become "foreground" if setForeground() is called // (without actually "starting" it). // Unfortunately we can't just "fix" it because some apps are relying on it, // but this will cause a problem to short-fgs, so we should disallow it if // this happens and the type is SHORT_SERVICE. // // OTOH, if a valid short-service (which has to be "started"), happens to // also be bound, then we still _will_ apply a timeout, because it still has // to be stopped. if (r.mStartForegroundCount == 0) { /* If the service was started with startService(), not Loading Loading @@ -1898,6 +1925,28 @@ public final class ActiveServices { } } } else if (r.mStartForegroundCount >= 1) { // We get here if startForeground() is called multiple times // on the same sarvice after it's created, regardless of whether // stopForeground() has been called or not. // TODO(short-service): Consider transitions: // A. Short -> other types: // Apply the BG restriction again. Don't just allow it. // i.e. unless the app is in a situation where it's allowed to start // a FGS, this transition shouldn't be allowed. // ... But think about it more, there may be a case this should be // allowed. // // If the transition is allowed, stop the timeout. // If the transition is _not_ allowed... keep the timeout? // // B. Short -> Short: // This should be the same as case A // If this is allowed, the new timeout should start. // C. Other -> short: // This should always be allowed. // A timeout should start. // The second or later time startForeground() is called after service is // started. Check for app state again. setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(), Loading Loading @@ -1977,6 +2026,10 @@ public final class ActiveServices { cancelForegroundNotificationLocked(r); r.foregroundId = id; } // TODO(short-service): Stop the short service timeout, if the type is changing // from short to non-short. (should we do it earlier?) notification.flags |= Notification.FLAG_FOREGROUND_SERVICE; r.foregroundNoti = notification; r.foregroundServiceType = foregroundServiceType; Loading Loading @@ -2048,6 +2101,9 @@ public final class ActiveServices { getServiceMapLocked(r.userId).ensureNotStartingBackgroundLocked(r); mAm.notifyPackageUse(r.serviceInfo.packageName, PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE); // TODO(short-service): Start counting a timeout. } else { if (DEBUG_FOREGROUND_SERVICE) { Slog.d(TAG, "Suppressing startForeground() for FAS " + r); Loading Loading @@ -2081,6 +2137,8 @@ public final class ActiveServices { decActiveForegroundAppLocked(smap, r); } // TODO(short-service): Stop the timeout. (any better place to do it?) // Adjust notification handling before setting isForeground to false, because // that state is relevant to the notification policy side. // Leave the time-to-display as already set: re-entering foreground mode will Loading Loading @@ -2121,6 +2179,10 @@ public final class ActiveServices { ? (int) (r.mFgsExitTime - r.mFgsEnterTime) : 0, FGS_STOP_REASON_STOP_FOREGROUND, FGS_TYPE_POLICY_CHECK_UNKNOWN); // foregroundServiceType is used in logFGSStateChangeLocked(), so we can't clear it // earlier. r.foregroundServiceType = 0; r.mFgsNotificationWasDeferred = false; signalForegroundServiceObserversLocked(r); resetFgsRestrictionLocked(r); Loading Loading @@ -2408,7 +2470,9 @@ public final class ActiveServices { final int uid = r.appInfo.uid; // schedule the actual notification post long when = now + mAm.mConstants.mFgsNotificationDeferralInterval; long when = now + (r.isShortFgs() ? mAm.mConstants.mFgsNotificationDeferralIntervalForShort : mAm.mConstants.mFgsNotificationDeferralInterval); // If there are already deferred FGS notifications for this app, // inherit that deferred-show timestamp for (int i = 0; i < mPendingFgsNotifications.size(); i++) { Loading @@ -2427,7 +2491,9 @@ public final class ActiveServices { } if (mFgsDeferralRateLimited) { final long nextEligible = when + mAm.mConstants.mFgsNotificationDeferralExclusionTime; final long nextEligible = when + (r.isShortFgs() ? mAm.mConstants.mFgsNotificationDeferralExclusionTimeForShort : mAm.mConstants.mFgsNotificationDeferralExclusionTime); mFgsDeferralEligible.put(uid, nextEligible); } r.fgDisplayTime = when; Loading Loading @@ -2791,14 +2857,19 @@ public final class ActiveServices { private void updateServiceForegroundLocked(ProcessServiceRecord psr, boolean oomAdj) { boolean anyForeground = false; int fgServiceTypes = 0; boolean hasTypeNone = false; for (int i = psr.numberOfRunningServices() - 1; i >= 0; i--) { ServiceRecord sr = psr.getRunningServiceAt(i); if (sr.isForeground || sr.fgRequired) { anyForeground = true; fgServiceTypes |= sr.foregroundServiceType; if (sr.foregroundServiceType == ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE) { hasTypeNone = true; } } mAm.updateProcessForegroundLocked(psr.mApp, anyForeground, fgServiceTypes, oomAdj); } mAm.updateProcessForegroundLocked(psr.mApp, anyForeground, fgServiceTypes, hasTypeNone, oomAdj); psr.setHasReportedForegroundServices(anyForeground); } Loading Loading @@ -4773,10 +4844,18 @@ public final class ActiveServices { return false; } private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn, boolean hasConn, boolean enqueueOomAdj) { //Slog.i(TAG, "Bring down service:"); //r.dump(" "); private void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn, boolean hasConn, boolean enqueueOomAdj, String debugReason) { if (DEBUG_SERVICE) { Slog.i(TAG, "Bring down service for " + debugReason + " :" + r.toString()); } // TODO(short-service): Hmm, when the app stops a short-fgs, we should stop the timeout // here. // However we have a couple if's here and if these conditions are met, we stop here // without bringing down the service. // We need to make sure this can't be used (somehow) to keep having a short-FGS running // while having the timeout stopped. if (isServiceNeededLocked(r, knowConn, hasConn)) { return; Loading Loading @@ -4844,6 +4923,8 @@ public final class ActiveServices { // Check to see if the service had been started as foreground, but being // brought down before actually showing a notification. That is not allowed. // TODO(short-service): This is unlikely related to short-FGS, but I'm curious why it's // not allowed. Look into it. if (r.fgRequired) { Slog.w(TAG_SERVICE, "Bringing down service while still waiting for start foreground: " + r); Loading Loading @@ -4934,6 +5015,8 @@ public final class ActiveServices { FGS_STOP_REASON_STOP_SERVICE, FGS_TYPE_POLICY_CHECK_UNKNOWN); mAm.updateForegroundServiceUsageStats(r.name, r.userId, false); // TODO(short-service): Make sure we stop the timeout by here. } r.isForeground = false; Loading Loading @@ -5161,7 +5244,8 @@ public final class ActiveServices { } } } bringDownServiceIfNeededLocked(s, true, hasAutoCreate, enqueueOomAdj); bringDownServiceIfNeededLocked(s, true, hasAutoCreate, enqueueOomAdj, "removeConnection"); } } } Loading Loading @@ -6988,7 +7072,7 @@ public final class ActiveServices { final Integer allowedType = mAm.mProcessList.searchEachLruProcessesLOSP(false, app -> { if (app.uid == callingUid) { final ProcessStateRecord state = app.mState; if (state.isAllowedStartFgs()) { if (state.isAllowedStartFgs()) { // Procstate <= BFGS? return getReasonCodeFromProcState(state.getCurProcState()); } else { final ActiveInstrumentation instr = app.getActiveInstrumentation(); Loading
services/core/java/com/android/server/am/ActivityManagerService.java +13 −7 Original line number Diff line number Diff line Loading @@ -4945,7 +4945,7 @@ public class ActivityManagerService extends IActivityManager.Stub app.mState.setVerifiedAdj(ProcessList.INVALID_ADJ); mOomAdjuster.setAttachingSchedGroupLSP(app); app.mState.setForcingToImportant(null); updateProcessForegroundLocked(app, false, 0, false); clearProcessForegroundLocked(app); app.mState.setHasShownUi(false); app.mState.setCached(false); app.setDebugging(false); Loading Loading @@ -5805,7 +5805,7 @@ public class ActivityManagerService extends IActivityManager.Stub return; } pr.mState.setForcingToImportant(null); updateProcessForegroundLocked(pr, false, 0, false); clearProcessForegroundLocked(pr); } updateOomAdjLocked(pr, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); } Loading Loading @@ -12706,7 +12706,7 @@ public class ActivityManagerService extends IActivityManager.Stub for (BroadcastQueue queue : mBroadcastQueues) { queue.onApplicationCleanupLocked(app); } updateProcessForegroundLocked(app, false, 0, false); clearProcessForegroundLocked(app); mServices.killServicesLocked(app, allowRestart); mPhantomProcessList.onAppDied(pid); Loading Loading @@ -15829,13 +15829,19 @@ public class ActivityManagerService extends IActivityManager.Stub } } @GuardedBy("this") final void clearProcessForegroundLocked(ProcessRecord proc) { updateProcessForegroundLocked(proc, /* isForeground =*/ false, /* fgsTypes =*/0, /* hasTypeNoneFgs =*/false, /* oomAdj= */ false); } @GuardedBy("this") final void updateProcessForegroundLocked(ProcessRecord proc, boolean isForeground, int fgServiceTypes, boolean oomAdj) { int fgServiceTypes, boolean hasTypeNoneFgs, boolean oomAdj) { final ProcessServiceRecord psr = proc.mServices; final boolean foregroundStateChanged = isForeground != psr.hasForegroundServices(); if (foregroundStateChanged || psr.getForegroundServiceTypes() != fgServiceTypes) { || !psr.areForegroundServiceTypesSame(fgServiceTypes, hasTypeNoneFgs)) { if (foregroundStateChanged) { // Notify internal listeners. for (int i = mForegroundServiceStateListeners.size() - 1; i >= 0; i--) { Loading @@ -15843,7 +15849,7 @@ public class ActivityManagerService extends IActivityManager.Stub proc.info.packageName, proc.info.uid, proc.getPid(), isForeground); } } psr.setHasForegroundServices(isForeground, fgServiceTypes); psr.setHasForegroundServices(isForeground, fgServiceTypes, hasTypeNoneFgs); ArrayList<ProcessRecord> curProcs = mForegroundPackages.get(proc.info.packageName, proc.info.uid); if (isForeground) { Loading Loading @@ -17762,7 +17768,7 @@ public class ActivityManagerService extends IActivityManager.Stub return null; } if ((app.mServices.getForegroundServiceTypes() & foregroundServicetype) != 0) { if ((app.mServices.containsAnyForegroundServiceTypes(foregroundServicetype))) { return Boolean.TRUE; } return null;
services/core/java/com/android/server/am/OomAdjuster.java +62 −23 Original line number Diff line number Diff line Loading @@ -1798,28 +1798,53 @@ public class OomAdjuster { } } int capabilityFromFGS = 0; // capability from foreground service. // Adjust for FGS or "has-overlay-ui". if (adj > PERCEPTIBLE_APP_ADJ || procState > PROCESS_STATE_FOREGROUND_SERVICE) { if (psr.hasForegroundServices()) { // The user is aware of this app, so make it visible. adj = PERCEPTIBLE_APP_ADJ; procState = PROCESS_STATE_FOREGROUND_SERVICE; state.setAdjType("fg-service"); state.setCached(false); schedGroup = SCHED_GROUP_DEFAULT; if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + state.getAdjType() + ": " + app + " "); } String adjType = null; int newAdj = 0; int newProcState = 0; if (psr.hasForegroundServices() && psr.hasNonShortForegroundServices()) { // For regular (non-short) FGS. adjType = "fg-service"; newAdj = PERCEPTIBLE_APP_ADJ; newProcState = PROCESS_STATE_FOREGROUND_SERVICE; } else if (state.hasOverlayUi()) { // The process is display an overlay UI. adj = PERCEPTIBLE_APP_ADJ; procState = PROCESS_STATE_IMPORTANT_FOREGROUND; adjType = "has-overlay-ui"; newAdj = PERCEPTIBLE_APP_ADJ; newProcState = PROCESS_STATE_IMPORTANT_FOREGROUND; } else if (psr.hasForegroundServices() && !psr.hasNonShortForegroundServices()) { // For short FGS. adjType = "fg-service-short"; // We use MEDIUM_APP_ADJ + 1 so we can tell apart EJ (which uses MEDIUM_APP_ADJ + 1) // from short-FGS. // (We use +1 and +2, not +0 and +1, to be consistent with the following // RECENT_FOREGROUND_APP_ADJ tweak) newAdj = PERCEPTIBLE_MEDIUM_APP_ADJ + 1; // Short-FGS gets a below-BFGS procstate, so it can't start another FGS from it. newProcState = PROCESS_STATE_IMPORTANT_FOREGROUND; // Same as EJ, we explicitly grant network access to short FGS, // even when battery saver or data saver is enabled. capabilityFromFGS |= PROCESS_CAPABILITY_NETWORK; } if (adjType != null) { adj = newAdj; procState = newProcState; state.setAdjType(adjType); state.setCached(false); state.setAdjType("has-overlay-ui"); schedGroup = SCHED_GROUP_DEFAULT; if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to overlay ui: " + app); reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType + ": " + app + " "); } } } Loading @@ -1830,8 +1855,15 @@ public class OomAdjuster { if (psr.hasForegroundServices() && adj > PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ && (state.getLastTopTime() + mConstants.TOP_TO_FGS_GRACE_DURATION > now || state.getSetProcState() <= PROCESS_STATE_TOP)) { if (psr.hasNonShortForegroundServices()) { adj = PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ; state.setAdjType("fg-service-act"); } else { // For short-service FGS, we +1 the value, so we'll be able to detect it in // various dashboards. adj = PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + 1; state.setAdjType("fg-service-short-act"); } if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to recent fg: " + app); } Loading @@ -1842,11 +1874,13 @@ public class OomAdjuster { // foreground services so that it can finish performing any persistence/processing of // in-memory state. if (psr.hasTopStartedAlmostPerceptibleServices() && adj > PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ && (adj > PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + 2) && (state.getLastTopTime() + mConstants.TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION > now || state.getSetProcState() <= PROCESS_STATE_TOP)) { adj = PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ; // For EJ, we +2 the value, so we'll be able to detect it in // various dashboards. adj = PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + 2; // This shall henceforth be called the "EJ" exemption, despite utilizing the // ALMOST_PERCEPTIBLE flag to work. state.setAdjType("top-ej-act"); Loading Loading @@ -1979,7 +2013,6 @@ public class OomAdjuster { } } int capabilityFromFGS = 0; // capability from foreground service. boolean boundByNonBgRestricted = state.isCurBoundByNonBgRestrictedApp(); boolean scheduleLikeTopApp = false; for (int is = psr.numberOfRunningServices() - 1; Loading Loading @@ -2031,6 +2064,8 @@ public class OomAdjuster { } } // TODO(short-service): While-in-user permissions. Do we need any change here for // short-FGS? (Likely not) if (s.isForeground) { final int fgsType = s.foregroundServiceType; if (s.mAllowWhileInUsePermissionInFgs) { Loading Loading @@ -2113,6 +2148,7 @@ public class OomAdjuster { // in this case unless they explicitly request it. if ((cstate.getCurCapability() & PROCESS_CAPABILITY_NETWORK) != 0) { if (clientProcState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) { // This is used to grant network access to Expedited Jobs. if ((cr.flags & Context.BIND_BYPASS_POWER_NETWORK_RESTRICTIONS) != 0) { capability |= PROCESS_CAPABILITY_NETWORK; Loading Loading @@ -2200,8 +2236,11 @@ public class OomAdjuster { newAdj = PERCEPTIBLE_LOW_APP_ADJ; } else if ((cr.flags & Context.BIND_ALMOST_PERCEPTIBLE) != 0 && clientAdj < PERCEPTIBLE_APP_ADJ && adj >= (lbAdj = PERCEPTIBLE_MEDIUM_APP_ADJ)) { newAdj = PERCEPTIBLE_MEDIUM_APP_ADJ; && adj >= (lbAdj = (PERCEPTIBLE_MEDIUM_APP_ADJ + 2))) { // This is for expedited jobs. // We use MEDIUM_APP_ADJ + 2 here, so we can tell apart // EJ and short-FGS. newAdj = PERCEPTIBLE_MEDIUM_APP_ADJ + 2; } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0 && clientAdj < PERCEPTIBLE_APP_ADJ && adj >= (lbAdj = PERCEPTIBLE_APP_ADJ)) { Loading
services/core/java/com/android/server/am/ProcessServiceRecord.java +55 −3 File changed.Preview size limit exceeded, changes collapsed. Show changes