summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Varun Shah <varunshah@google.com> 2024-05-04 07:08:25 +0000
committer Varun Shah <varunshah@google.com> 2024-05-12 00:02:54 +0000
commited1cb5d46141fb7712047e5d6e37e9485dcf3203 (patch)
treeb4d5905c76fe7bc59ee377b7bfa7330ab305ce2f
parentc7942f24d7ad46703a872f2431a78e103c9918a2 (diff)
Update time-limited FGS logic to handle parallel services.
If there are multiple foreground services running of the same type from the same uid, update the total runtime immediately when another parallel service of the same type starts. Also keep a counter of how many services are running in parallel to reset the tracking properly. Also remove redundant calls to the stop-fgs-tracking method which could affect the new tracking logic. Bug: 330399444 Test: atest CtsFgsTimeoutTestCases Change-Id: I9681b5187406eb755016ee6b86cd4162f54a26c1
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java88
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java33
2 files changed, 69 insertions, 52 deletions
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 94bf813d3696..9be0e1ff464e 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -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
@@ -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);
- 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.
- }
+ final TimeLimitedFgsInfo fgsTypeInfo = getFgsTimeLimitedInfo(
+ sr.appInfo.uid, previouslyTimeLimitedType);
+ if (fgsTypeInfo != null) {
+ // Update the total runtime for the previous time-limited fgs type.
+ fgsTypeInfo.updateTotalRuntime(SystemClock.uptimeMillis());
+ fgsTypeInfo.decNumParallelServices();
}
if (!sr.isFgsTimeLimited()) {
@@ -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);
@@ -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);
- if (fgsTypeInfo != null) {
- // Update the total runtime for the previous time-limited fgs type.
- fgsTypeInfo.updateTotalRuntime();
- }
+ final TimeLimitedFgsInfo fgsTypeInfo = getFgsTimeLimitedInfo(
+ sr.appInfo.uid, timeLimitedType);
+ if (fgsTypeInfo != null) {
+ // Update the total runtime for the previous time-limited fgs type.
+ fgsTypeInfo.updateTotalRuntime(SystemClock.uptimeMillis());
+ fgsTypeInfo.decNumParallelServices();
}
Slog.d(TAG_SERVICE, "Stop FGS timeout: " + sr);
mFGSAnrTimer.cancel(sr);
@@ -3913,24 +3916,21 @@ 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);
- if (fgsTypeInfo != null) {
- // Update total runtime for the time-limited fgs type and mark it as timed out.
- fgsTypeInfo.updateTotalRuntime();
- fgsTypeInfo.setTimeLimitExceededAt(nowUptime);
-
- logFGSStateChangeLocked(sr,
- FOREGROUND_SERVICE_STATE_CHANGED__STATE__TIMED_OUT,
- 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,
- false /* fgsRestrictionRecalculated */
- );
- }
+ 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(nowUptime);
+ fgsTypeInfo.setTimeLimitExceededAt(nowUptime);
+
+ logFGSStateChangeLocked(sr,
+ FOREGROUND_SERVICE_STATE_CHANGED__STATE__TIMED_OUT,
+ 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 {
@@ -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();
@@ -3958,7 +3968,6 @@ public final class ActiveServices {
Slog.wtf(TAG, reason);
return;
}
-
if (android.app.Flags.enableFgsTimeoutCrashBehavior()) {
// Crash the app
synchronized (mAm) {
@@ -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();
@@ -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.
@@ -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();
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 8eca4fc0d2ff..218434049869 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -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) {
- mFirstFgsStartUptime = startTime;
- mFirstFgsStartRealtime = SystemClock.elapsedRealtime();
+ public void noteFgsFgsStart(@UptimeMillisLong long startTime) {
+ mNumParallelServices++;
+ if (mNumParallelServices == 1) {
+ mFirstFgsStartUptime = startTime;
+ mFirstFgsStartRealtime = SystemClock.elapsedRealtime();
+ }
mLastFgsStartTime = startTime;
}
@@ -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
@@ -735,6 +745,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
}
public void reset() {
+ mNumParallelServices = 0;
mFirstFgsStartUptime = 0;
mFirstFgsStartRealtime = 0;
mLastFgsStartTime = 0;
@@ -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();
}
/**