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

Commit 1a42bcae authored by Makoto Onuki's avatar Makoto Onuki Committed by Android (Google) Code Review
Browse files

Merge "More work on SHORT_SERVICE FGS"

parents ae4bee73 bd621a18
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -4763,14 +4763,16 @@ public final class ActivityThread extends ClientTransactionHandler
        if (s != null) {
            try {
                if (localLOGV) Slog.v(TAG, "Timeout short service " + s);
                s.callOnTimeout(startId);

                // TODO(short-service): Do we need "service executing" for timeout?
                // (see handleStopService())
                // Unlike other service callbacks, we don't do serviceDoneExecuting() here.
                // "service executing" state is used to boost the procstate / oom-adj, but
                // for short-FGS timeout, we have a specific control for them anyway, so
                // we don't have to do that.
                s.callOnTimeout(startId);
            } catch (Exception e) {
                if (!mInstrumentation.onException(s, e)) {
                    throw new RuntimeException(
                            "Unable to timeout service " + s
                            "Unable to call onTimeout on service " + s
                                    + ": " + e.toString(), e);
                }
                Slog.i(TAG, "handleTimeoutService: exception for " + token, e);
+3 −0
Original line number Diff line number Diff line
@@ -799,4 +799,7 @@ interface IActivityManager {
     * <p>Typically used only by automotive builds when the vehicle has multiple displays.
     */
    @nullable int[] getSecondaryDisplayIdsForStartingBackgroundUsers();

    /** Returns if the service is a short-service is still "alive" and past the timeout. */
    boolean shouldServiceTimeOut(in ComponentName className, in IBinder token);
}
+15 −4
Original line number Diff line number Diff line
@@ -1119,10 +1119,21 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac

    /** @hide */
    public final void callOnTimeout(int startId) {
        // TODO(short-service): Do we need any check here, to avoid races?
        // e.g. if the service is already stopped, but ActivityThread.handleTimeoutService() is
        // already scheduled, then we'll call this method anyway. It should be doable to prevent
        // that if we keep track of startForeground, stopForeground, and onDestroy.
        // Note, because all the service callbacks (and other similar callbacks, e.g. activity
        // callbacks) are delivered using the main handler, it's possible the service is already
        // stopped when before this method is called, so we do a double check here.
        if (mToken == null) {
            Log.w(TAG, "Service already destroyed, skipping onTimeout()");
            return;
        }
        try {
            if (!mActivityManager.shouldServiceTimeOut(
                    new ComponentName(this, mClassName), mToken)) {
                Log.w(TAG, "Service no longer relevant, skipping onTimeout()");
                return;
            }
        } catch (RemoteException ex) {
        }
        onTimeout(startId);
    }

+57 −28
Original line number Diff line number Diff line
@@ -132,6 +132,7 @@ import android.app.compat.CompatChanges;
import android.app.usage.UsageEvents;
import android.appwidget.AppWidgetManagerInternal;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.compat.annotation.EnabledSince;
import android.compat.annotation.Overridable;
import android.content.ComponentName;
@@ -150,6 +151,7 @@ import android.content.pm.ServiceInfo;
import android.content.pm.ServiceInfo.ForegroundServiceType;
import android.os.Binder;
import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.Handler;
@@ -390,6 +392,14 @@ public final class ActiveServices {
    @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S)
    static final long FGS_START_EXCEPTION_CHANGE_ID = 174041399L;

    /**
     * If enabled, the FGS type check against the manifest FSG type will be enabled for
     * instant apps too. Before U, this check was only done for non-instant apps.
     */
    @ChangeId
    @EnabledAfter(targetSdkVersion = VERSION_CODES.TIRAMISU)
    static final long FGS_TYPE_CHECK_FOR_INSTANT_APPS = 261055255L;

    final Runnable mLastAnrDumpClearer = new Runnable() {
        @Override public void run() {
            synchronized (mAm) {
@@ -1818,10 +1828,8 @@ public final class ActiveServices {
                            android.Manifest.permission.FOREGROUND_SERVICE,
                            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();
            }
            final 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) {
@@ -1836,11 +1844,19 @@ public final class ActiveServices {
                    // 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 "
                final String message = "foregroundServiceType "
                        + String.format("0x%08X", foregroundServiceType)
                        + " is not a subset of foregroundServiceType attribute "
                        + String.format("0x%08X", manifestType)
                        + " in service element of manifest file");
                        + " in service element of manifest file";
                if (!r.appInfo.isInstantApp()
                        || CompatChanges.isChangeEnabled(FGS_TYPE_CHECK_FOR_INSTANT_APPS,
                        r.appInfo.uid)) {
                    throw new IllegalArgumentException(message);
                } else {
                    Slog.w(TAG, message + "\n"
                            + "This will be an exception once the target SDK level is UDC");
                }
            }
            if ((foregroundServiceType & FOREGROUND_SERVICE_TYPE_SHORT_SERVICE) != 0
                    && foregroundServiceType != FOREGROUND_SERVICE_TYPE_SHORT_SERVICE) {
@@ -1850,7 +1866,6 @@ public final class ActiveServices {
                // anyway, so we just remove the SHORT_SERVICE type.
                foregroundServiceType &= ~FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
            }
            }

            boolean alreadyStartedOp = false;
            boolean stopProcStatsOp = false;
@@ -2981,6 +2996,20 @@ public final class ActiveServices {
        }
    }

    boolean shouldServiceTimeOutLocked(ComponentName className, IBinder token) {
        final int userId = UserHandle.getCallingUserId();
        final long ident = Binder.clearCallingIdentity();
        try {
            ServiceRecord sr = findServiceLocked(className, token, userId);
            if (sr == null) {
                return false;
            }
            return sr.shouldTriggerShortFgsTimeout();
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }

    void onShortFgsAnrTimeout(ServiceRecord sr) {
        final String reason = "A foreground service of FOREGROUND_SERVICE_TYPE_SHORT_SERVICE"
                + " did not stop within a timeout: " + sr.getComponentName();
+7 −0
Original line number Diff line number Diff line
@@ -12982,6 +12982,13 @@ public class ActivityManagerService extends IActivityManager.Stub
        }
    }
    @Override
    public boolean shouldServiceTimeOut(ComponentName className, IBinder token) {
        synchronized (this) {
            return mServices.shouldServiceTimeOutLocked(className, token);
        }
    }
    @Override
    public int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll,
            boolean requireFull, String name, String callerPackage) {
Loading