Loading services/core/java/com/android/server/am/ActiveServices.java +48 −8 Original line number Diff line number Diff line Loading @@ -3724,6 +3724,33 @@ public final class ActiveServices { return fgsType; } /** * @return the constant time limit defined for the given foreground service type. */ private long getTimeLimitForFgsType(int foregroundServiceType) { return switch (foregroundServiceType) { case ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROCESSING -> mAm.mConstants.mMediaProcessingFgsTimeoutDuration; case ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC -> mAm.mConstants.mDataSyncFgsTimeoutDuration; // Add logic for time limits introduced in the future for other fgs types above. default -> Long.MAX_VALUE; }; } /** * @return the next stop time for the given type, based on how long it has already ran for. * The total runtime is automatically reset 24hrs after the first fgs start of this type * or if the app has recently been in the TOP state when the app calls startForeground(). */ private long getNextFgsStopTime(int fgsType, TimeLimitedFgsInfo fgsInfo) { final long timeLimit = getTimeLimitForFgsType(fgsType); if (timeLimit == Long.MAX_VALUE) { return Long.MAX_VALUE; } return fgsInfo.getLastFgsStartTime() + Math.max(0, timeLimit - fgsInfo.getTotalRuntime()); } private void maybeUpdateFgsTrackingLocked(ServiceRecord sr, int previousFgsType) { final int previouslyTimeLimitedType = getTimeLimitedFgsType(previousFgsType); if (previouslyTimeLimitedType == ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE Loading Loading @@ -3755,7 +3782,7 @@ public final class ActiveServices { } traceInstant("FGS start: ", sr); final long nowRealtime = SystemClock.elapsedRealtime(); final long nowUptime = SystemClock.uptimeMillis(); // Fetch/create/update the fgs info for the time-limited type. SparseArray<TimeLimitedFgsInfo> fgsInfo = mTimeLimitedFgsInfo.get(sr.appInfo.uid); Loading @@ -3766,10 +3793,10 @@ public final class ActiveServices { final int timeLimitedFgsType = getTimeLimitedFgsType(sr.foregroundServiceType); TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(timeLimitedFgsType); if (fgsTypeInfo == null) { fgsTypeInfo = sr.createTimeLimitedFgsInfo(nowRealtime); fgsTypeInfo = sr.createTimeLimitedFgsInfo(nowUptime); fgsInfo.put(timeLimitedFgsType, fgsTypeInfo); } fgsTypeInfo.setLastFgsStartTime(nowRealtime); fgsTypeInfo.setLastFgsStartTime(nowUptime); // We'll cancel the previous ANR timer and start a fresh one below. mFGSAnrTimer.cancel(sr); Loading @@ -3777,7 +3804,7 @@ public final class ActiveServices { final Message msg = mAm.mHandler.obtainMessage( ActivityManagerService.SERVICE_FGS_TIMEOUT_MSG, sr); final long timeoutCallbackTime = sr.getNextFgsStopTime(timeLimitedFgsType, fgsTypeInfo); final long timeoutCallbackTime = getNextFgsStopTime(timeLimitedFgsType, fgsTypeInfo); if (timeoutCallbackTime == Long.MAX_VALUE) { // This should never happen since we only get to this point if the service record's // foregroundServiceType attribute contains a type that can be timed-out. Loading Loading @@ -3833,6 +3860,20 @@ public final class ActiveServices { mFGSAnrTimer.discard(sr); return; } final long lastTopTime = sr.app.mState.getLastTopTime(); final long constantTimeLimit = getTimeLimitForFgsType(fgsType); final long nowUptime = SystemClock.uptimeMillis(); if (constantTimeLimit > (nowUptime - lastTopTime)) { // The app was in the TOP state after the FGS was started so its time allowance // should be counted from that time since this is considered a user interaction mFGSAnrTimer.discard(sr); final Message msg = mAm.mHandler.obtainMessage( ActivityManagerService.SERVICE_FGS_TIMEOUT_MSG, sr); mAm.mHandler.sendMessageAtTime(msg, lastTopTime + constantTimeLimit); return; } Slog.e(TAG_SERVICE, "FGS (" + ServiceInfo.foregroundServiceTypeToLabel(fgsType) + ") timed out: " + sr); mFGSAnrTimer.accept(sr); Loading @@ -3843,14 +3884,13 @@ public final class ActiveServices { final TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(fgsType); if (fgsTypeInfo != null) { // Update total runtime for the time-limited fgs type and mark it as timed out. final long nowRealtime = SystemClock.elapsedRealtime(); fgsTypeInfo.updateTotalRuntime(); fgsTypeInfo.setTimeLimitExceededAt(nowRealtime); fgsTypeInfo.setTimeLimitExceededAt(nowUptime); logFGSStateChangeLocked(sr, FOREGROUND_SERVICE_STATE_CHANGED__STATE__TIMED_OUT, nowRealtime > fgsTypeInfo.getLastFgsStartTime() ? (int) (nowRealtime - fgsTypeInfo.getLastFgsStartTime()) : 0, nowUptime > fgsTypeInfo.getLastFgsStartTime() ? (int) (nowUptime - fgsTypeInfo.getLastFgsStartTime()) : 0, FGS_STOP_REASON_UNKNOWN, FGS_TYPE_POLICY_CHECK_UNKNOWN, FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA, Loading services/core/java/com/android/server/am/ServiceRecord.java +12 −33 Original line number Diff line number Diff line Loading @@ -30,9 +30,9 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOREGROUND_ import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import android.annotation.ElapsedRealtimeLong; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UptimeMillisLong; import android.app.BackgroundStartPrivileges; import android.app.IApplicationThread; import android.app.Notification; Loading Loading @@ -677,29 +677,29 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN * Data container class to help track certain fgs info for time-restricted types. */ static class TimeLimitedFgsInfo { @ElapsedRealtimeLong @UptimeMillisLong private long mFirstFgsStartTime; @ElapsedRealtimeLong @UptimeMillisLong private long mLastFgsStartTime; @ElapsedRealtimeLong @UptimeMillisLong private long mTimeLimitExceededAt = Long.MIN_VALUE; private long mTotalRuntime = 0; TimeLimitedFgsInfo(@ElapsedRealtimeLong long startTime) { TimeLimitedFgsInfo(@UptimeMillisLong long startTime) { mFirstFgsStartTime = startTime; mLastFgsStartTime = startTime; } @ElapsedRealtimeLong @UptimeMillisLong public long getFirstFgsStartTime() { return mFirstFgsStartTime; } public void setLastFgsStartTime(@ElapsedRealtimeLong long startTime) { public void setLastFgsStartTime(@UptimeMillisLong long startTime) { mLastFgsStartTime = startTime; } @ElapsedRealtimeLong @UptimeMillisLong public long getLastFgsStartTime() { return mLastFgsStartTime; } Loading @@ -712,11 +712,11 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN return mTotalRuntime; } public void setTimeLimitExceededAt(@ElapsedRealtimeLong long timeLimitExceededAt) { public void setTimeLimitExceededAt(@UptimeMillisLong long timeLimitExceededAt) { mTimeLimitExceededAt = timeLimitExceededAt; } @ElapsedRealtimeLong @UptimeMillisLong public long getTimeLimitExceededAt() { return mTimeLimitExceededAt; } Loading Loading @@ -1858,8 +1858,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN /** * Called when a time-limited FGS starts. */ public TimeLimitedFgsInfo createTimeLimitedFgsInfo(@ElapsedRealtimeLong long nowRealtime) { return new TimeLimitedFgsInfo(nowRealtime); public TimeLimitedFgsInfo createTimeLimitedFgsInfo(@UptimeMillisLong long nowUptime) { return new TimeLimitedFgsInfo(nowUptime); } /** Loading @@ -1872,27 +1872,6 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN != ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE; } /** * @return the next stop time for the given type, based on how long it has already ran for. * The total runtime is automatically reset 24hrs after the first fgs start of this type * or if the app has recently been in the TOP state when the app calls startForeground(). */ long getNextFgsStopTime(int fgsType, TimeLimitedFgsInfo fgsInfo) { final long timeLimit; switch (ams.mServices.getTimeLimitedFgsType(fgsType)) { case ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROCESSING: timeLimit = ams.mConstants.mMediaProcessingFgsTimeoutDuration; break; case ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC: timeLimit = ams.mConstants.mDataSyncFgsTimeoutDuration; break; // Add logic for time limits introduced in the future for other fgs types above. default: return Long.MAX_VALUE; } return fgsInfo.mLastFgsStartTime + Math.max(0, timeLimit - fgsInfo.mTotalRuntime); } private boolean isAppAlive() { if (app == null) { return false; Loading Loading
services/core/java/com/android/server/am/ActiveServices.java +48 −8 Original line number Diff line number Diff line Loading @@ -3724,6 +3724,33 @@ public final class ActiveServices { return fgsType; } /** * @return the constant time limit defined for the given foreground service type. */ private long getTimeLimitForFgsType(int foregroundServiceType) { return switch (foregroundServiceType) { case ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROCESSING -> mAm.mConstants.mMediaProcessingFgsTimeoutDuration; case ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC -> mAm.mConstants.mDataSyncFgsTimeoutDuration; // Add logic for time limits introduced in the future for other fgs types above. default -> Long.MAX_VALUE; }; } /** * @return the next stop time for the given type, based on how long it has already ran for. * The total runtime is automatically reset 24hrs after the first fgs start of this type * or if the app has recently been in the TOP state when the app calls startForeground(). */ private long getNextFgsStopTime(int fgsType, TimeLimitedFgsInfo fgsInfo) { final long timeLimit = getTimeLimitForFgsType(fgsType); if (timeLimit == Long.MAX_VALUE) { return Long.MAX_VALUE; } return fgsInfo.getLastFgsStartTime() + Math.max(0, timeLimit - fgsInfo.getTotalRuntime()); } private void maybeUpdateFgsTrackingLocked(ServiceRecord sr, int previousFgsType) { final int previouslyTimeLimitedType = getTimeLimitedFgsType(previousFgsType); if (previouslyTimeLimitedType == ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE Loading Loading @@ -3755,7 +3782,7 @@ public final class ActiveServices { } traceInstant("FGS start: ", sr); final long nowRealtime = SystemClock.elapsedRealtime(); final long nowUptime = SystemClock.uptimeMillis(); // Fetch/create/update the fgs info for the time-limited type. SparseArray<TimeLimitedFgsInfo> fgsInfo = mTimeLimitedFgsInfo.get(sr.appInfo.uid); Loading @@ -3766,10 +3793,10 @@ public final class ActiveServices { final int timeLimitedFgsType = getTimeLimitedFgsType(sr.foregroundServiceType); TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(timeLimitedFgsType); if (fgsTypeInfo == null) { fgsTypeInfo = sr.createTimeLimitedFgsInfo(nowRealtime); fgsTypeInfo = sr.createTimeLimitedFgsInfo(nowUptime); fgsInfo.put(timeLimitedFgsType, fgsTypeInfo); } fgsTypeInfo.setLastFgsStartTime(nowRealtime); fgsTypeInfo.setLastFgsStartTime(nowUptime); // We'll cancel the previous ANR timer and start a fresh one below. mFGSAnrTimer.cancel(sr); Loading @@ -3777,7 +3804,7 @@ public final class ActiveServices { final Message msg = mAm.mHandler.obtainMessage( ActivityManagerService.SERVICE_FGS_TIMEOUT_MSG, sr); final long timeoutCallbackTime = sr.getNextFgsStopTime(timeLimitedFgsType, fgsTypeInfo); final long timeoutCallbackTime = getNextFgsStopTime(timeLimitedFgsType, fgsTypeInfo); if (timeoutCallbackTime == Long.MAX_VALUE) { // This should never happen since we only get to this point if the service record's // foregroundServiceType attribute contains a type that can be timed-out. Loading Loading @@ -3833,6 +3860,20 @@ public final class ActiveServices { mFGSAnrTimer.discard(sr); return; } final long lastTopTime = sr.app.mState.getLastTopTime(); final long constantTimeLimit = getTimeLimitForFgsType(fgsType); final long nowUptime = SystemClock.uptimeMillis(); if (constantTimeLimit > (nowUptime - lastTopTime)) { // The app was in the TOP state after the FGS was started so its time allowance // should be counted from that time since this is considered a user interaction mFGSAnrTimer.discard(sr); final Message msg = mAm.mHandler.obtainMessage( ActivityManagerService.SERVICE_FGS_TIMEOUT_MSG, sr); mAm.mHandler.sendMessageAtTime(msg, lastTopTime + constantTimeLimit); return; } Slog.e(TAG_SERVICE, "FGS (" + ServiceInfo.foregroundServiceTypeToLabel(fgsType) + ") timed out: " + sr); mFGSAnrTimer.accept(sr); Loading @@ -3843,14 +3884,13 @@ public final class ActiveServices { final TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(fgsType); if (fgsTypeInfo != null) { // Update total runtime for the time-limited fgs type and mark it as timed out. final long nowRealtime = SystemClock.elapsedRealtime(); fgsTypeInfo.updateTotalRuntime(); fgsTypeInfo.setTimeLimitExceededAt(nowRealtime); fgsTypeInfo.setTimeLimitExceededAt(nowUptime); logFGSStateChangeLocked(sr, FOREGROUND_SERVICE_STATE_CHANGED__STATE__TIMED_OUT, nowRealtime > fgsTypeInfo.getLastFgsStartTime() ? (int) (nowRealtime - fgsTypeInfo.getLastFgsStartTime()) : 0, nowUptime > fgsTypeInfo.getLastFgsStartTime() ? (int) (nowUptime - fgsTypeInfo.getLastFgsStartTime()) : 0, FGS_STOP_REASON_UNKNOWN, FGS_TYPE_POLICY_CHECK_UNKNOWN, FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA, Loading
services/core/java/com/android/server/am/ServiceRecord.java +12 −33 Original line number Diff line number Diff line Loading @@ -30,9 +30,9 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOREGROUND_ import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import android.annotation.ElapsedRealtimeLong; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UptimeMillisLong; import android.app.BackgroundStartPrivileges; import android.app.IApplicationThread; import android.app.Notification; Loading Loading @@ -677,29 +677,29 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN * Data container class to help track certain fgs info for time-restricted types. */ static class TimeLimitedFgsInfo { @ElapsedRealtimeLong @UptimeMillisLong private long mFirstFgsStartTime; @ElapsedRealtimeLong @UptimeMillisLong private long mLastFgsStartTime; @ElapsedRealtimeLong @UptimeMillisLong private long mTimeLimitExceededAt = Long.MIN_VALUE; private long mTotalRuntime = 0; TimeLimitedFgsInfo(@ElapsedRealtimeLong long startTime) { TimeLimitedFgsInfo(@UptimeMillisLong long startTime) { mFirstFgsStartTime = startTime; mLastFgsStartTime = startTime; } @ElapsedRealtimeLong @UptimeMillisLong public long getFirstFgsStartTime() { return mFirstFgsStartTime; } public void setLastFgsStartTime(@ElapsedRealtimeLong long startTime) { public void setLastFgsStartTime(@UptimeMillisLong long startTime) { mLastFgsStartTime = startTime; } @ElapsedRealtimeLong @UptimeMillisLong public long getLastFgsStartTime() { return mLastFgsStartTime; } Loading @@ -712,11 +712,11 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN return mTotalRuntime; } public void setTimeLimitExceededAt(@ElapsedRealtimeLong long timeLimitExceededAt) { public void setTimeLimitExceededAt(@UptimeMillisLong long timeLimitExceededAt) { mTimeLimitExceededAt = timeLimitExceededAt; } @ElapsedRealtimeLong @UptimeMillisLong public long getTimeLimitExceededAt() { return mTimeLimitExceededAt; } Loading Loading @@ -1858,8 +1858,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN /** * Called when a time-limited FGS starts. */ public TimeLimitedFgsInfo createTimeLimitedFgsInfo(@ElapsedRealtimeLong long nowRealtime) { return new TimeLimitedFgsInfo(nowRealtime); public TimeLimitedFgsInfo createTimeLimitedFgsInfo(@UptimeMillisLong long nowUptime) { return new TimeLimitedFgsInfo(nowUptime); } /** Loading @@ -1872,27 +1872,6 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN != ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE; } /** * @return the next stop time for the given type, based on how long it has already ran for. * The total runtime is automatically reset 24hrs after the first fgs start of this type * or if the app has recently been in the TOP state when the app calls startForeground(). */ long getNextFgsStopTime(int fgsType, TimeLimitedFgsInfo fgsInfo) { final long timeLimit; switch (ams.mServices.getTimeLimitedFgsType(fgsType)) { case ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROCESSING: timeLimit = ams.mConstants.mMediaProcessingFgsTimeoutDuration; break; case ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC: timeLimit = ams.mConstants.mDataSyncFgsTimeoutDuration; break; // Add logic for time limits introduced in the future for other fgs types above. default: return Long.MAX_VALUE; } return fgsInfo.mLastFgsStartTime + Math.max(0, timeLimit - fgsInfo.mTotalRuntime); } private boolean isAppAlive() { if (app == null) { return false; Loading