Loading services/core/java/com/android/server/am/ActiveServices.java +47 −41 Original line number Diff line number Diff line Loading @@ -3783,6 +3783,14 @@ public final class ActiveServices { return fgsInfo.getLastFgsStartTime() + Math.max(0, timeLimit - fgsInfo.getTotalRuntime()); } private TimeLimitedFgsInfo getFgsTimeLimitedInfo(int uid, int fgsType) { final SparseArray<TimeLimitedFgsInfo> fgsInfo = mTimeLimitedFgsInfo.get(uid); if (fgsInfo != null) { return fgsInfo.get(fgsType); } return null; } private void maybeUpdateFgsTrackingLocked(ServiceRecord sr, int previousFgsType) { final int previouslyTimeLimitedType = getTimeLimitedFgsType(previousFgsType); if (previouslyTimeLimitedType == ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE Loading @@ -3793,16 +3801,12 @@ public final class ActiveServices { if (previouslyTimeLimitedType != ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE) { // FGS is switching types and the previous type was time-limited so update the runtime. final SparseArray<TimeLimitedFgsInfo> fgsInfo = mTimeLimitedFgsInfo.get(sr.appInfo.uid); if (fgsInfo != null) { final TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(previouslyTimeLimitedType); final TimeLimitedFgsInfo fgsTypeInfo = getFgsTimeLimitedInfo( sr.appInfo.uid, previouslyTimeLimitedType); if (fgsTypeInfo != null) { // Update the total runtime for the previous time-limited fgs type. fgsTypeInfo.updateTotalRuntime(); // TODO(b/330399444): handle the case where an app is running 2 services of the // same time-limited type in parallel and stops one of them which leads to the // second running one gaining additional runtime. } fgsTypeInfo.updateTotalRuntime(SystemClock.uptimeMillis()); fgsTypeInfo.decNumParallelServices(); } if (!sr.isFgsTimeLimited()) { Loading @@ -3825,10 +3829,10 @@ public final class ActiveServices { final int timeLimitedFgsType = getTimeLimitedFgsType(sr.foregroundServiceType); TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(timeLimitedFgsType); if (fgsTypeInfo == null) { fgsTypeInfo = sr.createTimeLimitedFgsInfo(nowUptime); fgsTypeInfo = sr.createTimeLimitedFgsInfo(); fgsInfo.put(timeLimitedFgsType, fgsTypeInfo); } fgsTypeInfo.setLastFgsStartTime(nowUptime); fgsTypeInfo.noteFgsFgsStart(nowUptime); // We'll cancel the previous ANR timer and start a fresh one below. mFGSAnrTimer.cancel(sr); Loading @@ -3852,13 +3856,12 @@ public final class ActiveServices { return; // if the current fgs type is not time-limited, return. } final SparseArray<TimeLimitedFgsInfo> fgsInfo = mTimeLimitedFgsInfo.get(sr.appInfo.uid); if (fgsInfo != null) { final TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(timeLimitedType); final TimeLimitedFgsInfo fgsTypeInfo = getFgsTimeLimitedInfo( sr.appInfo.uid, timeLimitedType); if (fgsTypeInfo != null) { // Update the total runtime for the previous time-limited fgs type. fgsTypeInfo.updateTotalRuntime(); } fgsTypeInfo.updateTotalRuntime(SystemClock.uptimeMillis()); fgsTypeInfo.decNumParallelServices(); } Slog.d(TAG_SERVICE, "Stop FGS timeout: " + sr); mFGSAnrTimer.cancel(sr); Loading Loading @@ -3913,25 +3916,22 @@ public final class ActiveServices { mFGSAnrTimer.accept(sr); traceInstant("FGS timed out: ", sr); final SparseArray<TimeLimitedFgsInfo> fgsInfo = mTimeLimitedFgsInfo.get(sr.appInfo.uid); if (fgsInfo != null) { final TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(fgsType); final TimeLimitedFgsInfo fgsTypeInfo = getFgsTimeLimitedInfo(sr.appInfo.uid, fgsType); if (fgsTypeInfo != null) { // Update total runtime for the time-limited fgs type and mark it as timed out. fgsTypeInfo.updateTotalRuntime(); fgsTypeInfo.updateTotalRuntime(nowUptime); fgsTypeInfo.setTimeLimitExceededAt(nowUptime); logFGSStateChangeLocked(sr, FOREGROUND_SERVICE_STATE_CHANGED__STATE__TIMED_OUT, nowUptime > fgsTypeInfo.getLastFgsStartTime() ? (int) (nowUptime - fgsTypeInfo.getLastFgsStartTime()) : 0, nowUptime > fgsTypeInfo.getFirstFgsStartUptime() ? (int) (nowUptime - fgsTypeInfo.getFirstFgsStartUptime()) : 0, FGS_STOP_REASON_UNKNOWN, FGS_TYPE_POLICY_CHECK_UNKNOWN, FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA, false /* fgsRestrictionRecalculated */ ); } } try { sr.app.getThread().scheduleTimeoutServiceForType(sr, sr.getLastStartId(), fgsType); Loading @@ -3949,6 +3949,16 @@ public final class ActiveServices { if (fgsType == ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE) { return; // no timed out FGS type was found (either it was stopped or it switched types) } synchronized (mAm) { final TimeLimitedFgsInfo fgsTypeInfo = getFgsTimeLimitedInfo(sr.appInfo.uid, fgsType); if (fgsTypeInfo != null) { // Runtime is already updated when the service times out - if the app didn't // stop the service, decrement the number of parallel running services here. fgsTypeInfo.decNumParallelServices(); } } final String reason = "A foreground service of type " + ServiceInfo.foregroundServiceTypeToLabel(fgsType) + " did not stop within its timeout: " + sr.getComponentName(); Loading @@ -3958,7 +3968,6 @@ public final class ActiveServices { Slog.wtf(TAG, reason); return; } if (android.app.Flags.enableFgsTimeoutCrashBehavior()) { // Crash the app synchronized (mAm) { Loading Loading @@ -4005,7 +4014,6 @@ public final class ActiveServices { private void stopServiceAndUpdateAllowlistManagerLocked(ServiceRecord service) { maybeStopShortFgsTimeoutLocked(service); maybeStopFgsTimeoutLocked(service); final ProcessServiceRecord psr = service.app.mServices; psr.stopService(service); psr.updateBoundClientUids(); Loading Loading @@ -6291,7 +6299,6 @@ public final class ActiveServices { Slog.w(TAG_SERVICE, "Short FGS brought down without stopping: " + r); maybeStopShortFgsTimeoutLocked(r); } maybeStopFgsTimeoutLocked(r); // Report to all of the connections that the service is no longer // available. Loading Loading @@ -6416,7 +6423,6 @@ public final class ActiveServices { final boolean exitingFg = r.isForeground; if (exitingFg) { maybeStopShortFgsTimeoutLocked(r); maybeStopFgsTimeoutLocked(r); decActiveForegroundAppLocked(smap, r); synchronized (mAm.mProcessStats.mLock) { ServiceState stracker = r.getTracker(); Loading services/core/java/com/android/server/am/ServiceRecord.java +22 −11 Original line number Diff line number Diff line Loading @@ -690,10 +690,14 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN private long mTimeLimitExceededAt = Long.MIN_VALUE; @UptimeMillisLong private long mTotalRuntime = 0; private int mNumParallelServices = 0; TimeLimitedFgsInfo(@UptimeMillisLong long startTime) { public void noteFgsFgsStart(@UptimeMillisLong long startTime) { mNumParallelServices++; if (mNumParallelServices == 1) { mFirstFgsStartUptime = startTime; mFirstFgsStartRealtime = SystemClock.elapsedRealtime(); } mLastFgsStartTime = startTime; } Loading @@ -707,17 +711,23 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN return mFirstFgsStartRealtime; } public void setLastFgsStartTime(@UptimeMillisLong long startTime) { mLastFgsStartTime = startTime; } @UptimeMillisLong public long getLastFgsStartTime() { return mLastFgsStartTime; } public void updateTotalRuntime() { mTotalRuntime += SystemClock.uptimeMillis() - mLastFgsStartTime; public void decNumParallelServices() { if (mNumParallelServices > 0) { mNumParallelServices--; } if (mNumParallelServices == 0) { mLastFgsStartTime = 0; } } public void updateTotalRuntime(@UptimeMillisLong long nowUptime) { mTotalRuntime += nowUptime - mLastFgsStartTime; mLastFgsStartTime = nowUptime; } @UptimeMillisLong Loading @@ -735,6 +745,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN } public void reset() { mNumParallelServices = 0; mFirstFgsStartUptime = 0; mFirstFgsStartRealtime = 0; mLastFgsStartTime = 0; Loading Loading @@ -1872,8 +1883,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN /** * Called when a time-limited FGS starts. */ public TimeLimitedFgsInfo createTimeLimitedFgsInfo(@UptimeMillisLong long nowUptime) { return new TimeLimitedFgsInfo(nowUptime); public TimeLimitedFgsInfo createTimeLimitedFgsInfo() { return new TimeLimitedFgsInfo(); } /** Loading Loading
services/core/java/com/android/server/am/ActiveServices.java +47 −41 Original line number Diff line number Diff line Loading @@ -3783,6 +3783,14 @@ public final class ActiveServices { return fgsInfo.getLastFgsStartTime() + Math.max(0, timeLimit - fgsInfo.getTotalRuntime()); } private TimeLimitedFgsInfo getFgsTimeLimitedInfo(int uid, int fgsType) { final SparseArray<TimeLimitedFgsInfo> fgsInfo = mTimeLimitedFgsInfo.get(uid); if (fgsInfo != null) { return fgsInfo.get(fgsType); } return null; } private void maybeUpdateFgsTrackingLocked(ServiceRecord sr, int previousFgsType) { final int previouslyTimeLimitedType = getTimeLimitedFgsType(previousFgsType); if (previouslyTimeLimitedType == ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE Loading @@ -3793,16 +3801,12 @@ public final class ActiveServices { if (previouslyTimeLimitedType != ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE) { // FGS is switching types and the previous type was time-limited so update the runtime. final SparseArray<TimeLimitedFgsInfo> fgsInfo = mTimeLimitedFgsInfo.get(sr.appInfo.uid); if (fgsInfo != null) { final TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(previouslyTimeLimitedType); final TimeLimitedFgsInfo fgsTypeInfo = getFgsTimeLimitedInfo( sr.appInfo.uid, previouslyTimeLimitedType); if (fgsTypeInfo != null) { // Update the total runtime for the previous time-limited fgs type. fgsTypeInfo.updateTotalRuntime(); // TODO(b/330399444): handle the case where an app is running 2 services of the // same time-limited type in parallel and stops one of them which leads to the // second running one gaining additional runtime. } fgsTypeInfo.updateTotalRuntime(SystemClock.uptimeMillis()); fgsTypeInfo.decNumParallelServices(); } if (!sr.isFgsTimeLimited()) { Loading @@ -3825,10 +3829,10 @@ public final class ActiveServices { final int timeLimitedFgsType = getTimeLimitedFgsType(sr.foregroundServiceType); TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(timeLimitedFgsType); if (fgsTypeInfo == null) { fgsTypeInfo = sr.createTimeLimitedFgsInfo(nowUptime); fgsTypeInfo = sr.createTimeLimitedFgsInfo(); fgsInfo.put(timeLimitedFgsType, fgsTypeInfo); } fgsTypeInfo.setLastFgsStartTime(nowUptime); fgsTypeInfo.noteFgsFgsStart(nowUptime); // We'll cancel the previous ANR timer and start a fresh one below. mFGSAnrTimer.cancel(sr); Loading @@ -3852,13 +3856,12 @@ public final class ActiveServices { return; // if the current fgs type is not time-limited, return. } final SparseArray<TimeLimitedFgsInfo> fgsInfo = mTimeLimitedFgsInfo.get(sr.appInfo.uid); if (fgsInfo != null) { final TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(timeLimitedType); final TimeLimitedFgsInfo fgsTypeInfo = getFgsTimeLimitedInfo( sr.appInfo.uid, timeLimitedType); if (fgsTypeInfo != null) { // Update the total runtime for the previous time-limited fgs type. fgsTypeInfo.updateTotalRuntime(); } fgsTypeInfo.updateTotalRuntime(SystemClock.uptimeMillis()); fgsTypeInfo.decNumParallelServices(); } Slog.d(TAG_SERVICE, "Stop FGS timeout: " + sr); mFGSAnrTimer.cancel(sr); Loading Loading @@ -3913,25 +3916,22 @@ public final class ActiveServices { mFGSAnrTimer.accept(sr); traceInstant("FGS timed out: ", sr); final SparseArray<TimeLimitedFgsInfo> fgsInfo = mTimeLimitedFgsInfo.get(sr.appInfo.uid); if (fgsInfo != null) { final TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(fgsType); final TimeLimitedFgsInfo fgsTypeInfo = getFgsTimeLimitedInfo(sr.appInfo.uid, fgsType); if (fgsTypeInfo != null) { // Update total runtime for the time-limited fgs type and mark it as timed out. fgsTypeInfo.updateTotalRuntime(); fgsTypeInfo.updateTotalRuntime(nowUptime); fgsTypeInfo.setTimeLimitExceededAt(nowUptime); logFGSStateChangeLocked(sr, FOREGROUND_SERVICE_STATE_CHANGED__STATE__TIMED_OUT, nowUptime > fgsTypeInfo.getLastFgsStartTime() ? (int) (nowUptime - fgsTypeInfo.getLastFgsStartTime()) : 0, nowUptime > fgsTypeInfo.getFirstFgsStartUptime() ? (int) (nowUptime - fgsTypeInfo.getFirstFgsStartUptime()) : 0, FGS_STOP_REASON_UNKNOWN, FGS_TYPE_POLICY_CHECK_UNKNOWN, FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA, false /* fgsRestrictionRecalculated */ ); } } try { sr.app.getThread().scheduleTimeoutServiceForType(sr, sr.getLastStartId(), fgsType); Loading @@ -3949,6 +3949,16 @@ public final class ActiveServices { if (fgsType == ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE) { return; // no timed out FGS type was found (either it was stopped or it switched types) } synchronized (mAm) { final TimeLimitedFgsInfo fgsTypeInfo = getFgsTimeLimitedInfo(sr.appInfo.uid, fgsType); if (fgsTypeInfo != null) { // Runtime is already updated when the service times out - if the app didn't // stop the service, decrement the number of parallel running services here. fgsTypeInfo.decNumParallelServices(); } } final String reason = "A foreground service of type " + ServiceInfo.foregroundServiceTypeToLabel(fgsType) + " did not stop within its timeout: " + sr.getComponentName(); Loading @@ -3958,7 +3968,6 @@ public final class ActiveServices { Slog.wtf(TAG, reason); return; } if (android.app.Flags.enableFgsTimeoutCrashBehavior()) { // Crash the app synchronized (mAm) { Loading Loading @@ -4005,7 +4014,6 @@ public final class ActiveServices { private void stopServiceAndUpdateAllowlistManagerLocked(ServiceRecord service) { maybeStopShortFgsTimeoutLocked(service); maybeStopFgsTimeoutLocked(service); final ProcessServiceRecord psr = service.app.mServices; psr.stopService(service); psr.updateBoundClientUids(); Loading Loading @@ -6291,7 +6299,6 @@ public final class ActiveServices { Slog.w(TAG_SERVICE, "Short FGS brought down without stopping: " + r); maybeStopShortFgsTimeoutLocked(r); } maybeStopFgsTimeoutLocked(r); // Report to all of the connections that the service is no longer // available. Loading Loading @@ -6416,7 +6423,6 @@ public final class ActiveServices { final boolean exitingFg = r.isForeground; if (exitingFg) { maybeStopShortFgsTimeoutLocked(r); maybeStopFgsTimeoutLocked(r); decActiveForegroundAppLocked(smap, r); synchronized (mAm.mProcessStats.mLock) { ServiceState stracker = r.getTracker(); Loading
services/core/java/com/android/server/am/ServiceRecord.java +22 −11 Original line number Diff line number Diff line Loading @@ -690,10 +690,14 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN private long mTimeLimitExceededAt = Long.MIN_VALUE; @UptimeMillisLong private long mTotalRuntime = 0; private int mNumParallelServices = 0; TimeLimitedFgsInfo(@UptimeMillisLong long startTime) { public void noteFgsFgsStart(@UptimeMillisLong long startTime) { mNumParallelServices++; if (mNumParallelServices == 1) { mFirstFgsStartUptime = startTime; mFirstFgsStartRealtime = SystemClock.elapsedRealtime(); } mLastFgsStartTime = startTime; } Loading @@ -707,17 +711,23 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN return mFirstFgsStartRealtime; } public void setLastFgsStartTime(@UptimeMillisLong long startTime) { mLastFgsStartTime = startTime; } @UptimeMillisLong public long getLastFgsStartTime() { return mLastFgsStartTime; } public void updateTotalRuntime() { mTotalRuntime += SystemClock.uptimeMillis() - mLastFgsStartTime; public void decNumParallelServices() { if (mNumParallelServices > 0) { mNumParallelServices--; } if (mNumParallelServices == 0) { mLastFgsStartTime = 0; } } public void updateTotalRuntime(@UptimeMillisLong long nowUptime) { mTotalRuntime += nowUptime - mLastFgsStartTime; mLastFgsStartTime = nowUptime; } @UptimeMillisLong Loading @@ -735,6 +745,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN } public void reset() { mNumParallelServices = 0; mFirstFgsStartUptime = 0; mFirstFgsStartRealtime = 0; mLastFgsStartTime = 0; Loading Loading @@ -1872,8 +1883,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN /** * Called when a time-limited FGS starts. */ public TimeLimitedFgsInfo createTimeLimitedFgsInfo(@UptimeMillisLong long nowUptime) { return new TimeLimitedFgsInfo(nowUptime); public TimeLimitedFgsInfo createTimeLimitedFgsInfo() { return new TimeLimitedFgsInfo(); } /** Loading