Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ba74bb1b authored by Varun Shah's avatar Varun Shah Committed by Android (Google) Code Review
Browse files

Merge "Update time-limited FGS logic to handle parallel services." into main

parents 3f08d749 ed1cb5d4
Loading
Loading
Loading
Loading
+47 −41
Original line number Diff line number Diff line
@@ -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);
            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()) {
@@ -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);
        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);
@@ -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);
@@ -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();
+22 −11
Original line number Diff line number Diff line
@@ -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;
        }

@@ -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();
    }

    /**