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

Commit dcba7756 authored by Varun Shah's avatar Varun Shah
Browse files

Introduce a new Service#onTimeout() callback with fgsType.

This new callback will be called when an fgs type associated to a
service has exceeded its time limit. If the app does not stop the
foreground service within a short period of time after the callback,
the app will be ANR'ed.

This new time limit will be initially imposed on two types: the new
MEDIA_PROCESSING type and the DATA_SYNC type.

The previous callback with the same name will still be called for short
service, however, since that callback did not include the fgs type which
caused the timeout, this overloaded callback will be the preferred
callback going forward for all types.

Bug: 317799821
Test: builds and flashes
Test: CTS to be added
Change-Id: I63a4460c6ddaec68f75099fa1fb4d319e0b7c8e0
parent 7bb4ff97
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -7379,6 +7379,7 @@ package android.app {
    method public int onStartCommand(android.content.Intent, int, int);
    method public int onStartCommand(android.content.Intent, int, int);
    method public void onTaskRemoved(android.content.Intent);
    method public void onTaskRemoved(android.content.Intent);
    method public void onTimeout(int);
    method public void onTimeout(int);
    method @FlaggedApi("android.app.introduce_new_service_ontimeout_callback") public void onTimeout(int, int);
    method public void onTrimMemory(int);
    method public void onTrimMemory(int);
    method public boolean onUnbind(android.content.Intent);
    method public boolean onUnbind(android.content.Intent);
    method public final void startForeground(int, android.app.Notification);
    method public final void startForeground(int, android.app.Notification);
+40 −0
Original line number Original line Diff line number Diff line
@@ -1229,6 +1229,15 @@ public final class ActivityThread extends ClientTransactionHandler
            sendMessage(H.PING, pong);
            sendMessage(H.PING, pong);
        }
        }


        @Override
        public final void scheduleTimeoutServiceForType(IBinder token, int startId, int fgsType) {
            if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
                Trace.instant(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                        "scheduleTimeoutServiceForType. token=" + token);
            }
            sendMessage(H.TIMEOUT_SERVICE_FOR_TYPE, token, startId, fgsType);
        }

        @Override
        @Override
        public final void bindApplication(
        public final void bindApplication(
                String processName,
                String processName,
@@ -2286,6 +2295,8 @@ public final class ActivityThread extends ClientTransactionHandler
        public static final int INSTRUMENT_WITHOUT_RESTART = 170;
        public static final int INSTRUMENT_WITHOUT_RESTART = 170;
        public static final int FINISH_INSTRUMENTATION_WITHOUT_RESTART = 171;
        public static final int FINISH_INSTRUMENTATION_WITHOUT_RESTART = 171;


        public static final int TIMEOUT_SERVICE_FOR_TYPE = 172;

        String codeToString(int code) {
        String codeToString(int code) {
            if (DEBUG_MESSAGES) {
            if (DEBUG_MESSAGES) {
                switch (code) {
                switch (code) {
@@ -2339,6 +2350,7 @@ public final class ActivityThread extends ClientTransactionHandler
                    case DUMP_RESOURCES: return "DUMP_RESOURCES";
                    case DUMP_RESOURCES: return "DUMP_RESOURCES";
                    case TIMEOUT_SERVICE: return "TIMEOUT_SERVICE";
                    case TIMEOUT_SERVICE: return "TIMEOUT_SERVICE";
                    case PING: return "PING";
                    case PING: return "PING";
                    case TIMEOUT_SERVICE_FOR_TYPE: return "TIMEOUT_SERVICE_FOR_TYPE";
                }
                }
            }
            }
            return Integer.toString(code);
            return Integer.toString(code);
@@ -2425,6 +2437,14 @@ public final class ActivityThread extends ClientTransactionHandler
                case PING:
                case PING:
                    ((RemoteCallback) msg.obj).sendResult(null);
                    ((RemoteCallback) msg.obj).sendResult(null);
                    break;
                    break;
                case TIMEOUT_SERVICE_FOR_TYPE:
                    if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
                        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                                "serviceTimeoutForType: " + msg.obj);
                    }
                    handleTimeoutServiceForType((IBinder) msg.obj, msg.arg1, msg.arg2);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case CONFIGURATION_CHANGED:
                case CONFIGURATION_CHANGED:
                    mConfigurationController.handleConfigurationChanged((Configuration) msg.obj);
                    mConfigurationController.handleConfigurationChanged((Configuration) msg.obj);
                    break;
                    break;
@@ -5134,6 +5154,26 @@ public final class ActivityThread extends ClientTransactionHandler
            Slog.wtf(TAG, "handleTimeoutService: token=" + token + " not found.");
            Slog.wtf(TAG, "handleTimeoutService: token=" + token + " not found.");
        }
        }
    }
    }

    private void handleTimeoutServiceForType(IBinder token, int startId, int fgsType) {
        Service s = mServices.get(token);
        if (s != null) {
            try {
                if (localLOGV) Slog.v(TAG, "Timeout service " + s);

                s.callOnTimeLimitExceeded(startId, fgsType);
            } catch (Exception e) {
                if (!mInstrumentation.onException(s, e)) {
                    throw new RuntimeException(
                            "Unable to call onTimeLimitExceeded on service " + s + ": " + e, e);
                }
                Slog.i(TAG, "handleTimeoutServiceForType: exception for " + token, e);
            }
        } else {
            Slog.wtf(TAG, "handleTimeoutServiceForType: token=" + token + " not found.");
        }
    }

    /**
    /**
     * Resume the activity.
     * Resume the activity.
     * @param r Target activity record.
     * @param r Target activity record.
+2 −0
Original line number Original line Diff line number Diff line
@@ -935,6 +935,8 @@ interface IActivityManager {


    /** Returns if the service is a short-service is still "alive" and past the timeout. */
    /** Returns if the service is a short-service is still "alive" and past the timeout. */
    boolean shouldServiceTimeOut(in ComponentName className, in IBinder token);
    boolean shouldServiceTimeOut(in ComponentName className, in IBinder token);
    /** Returns if the service has a time-limit restricted type and is past the time limit. */
    boolean hasServiceTimeLimitExceeded(in ComponentName className, in IBinder token);


    void registerUidFrozenStateChangedCallback(in IUidFrozenStateChangedCallback callback);
    void registerUidFrozenStateChangedCallback(in IUidFrozenStateChangedCallback callback);
    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)")
    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)")
+1 −0
Original line number Original line Diff line number Diff line
@@ -178,5 +178,6 @@ oneway interface IApplicationThread {
            in TranslationSpec targetSpec, in List<AutofillId> viewIds,
            in TranslationSpec targetSpec, in List<AutofillId> viewIds,
            in UiTranslationSpec uiTranslationSpec);
            in UiTranslationSpec uiTranslationSpec);
    void scheduleTimeoutService(IBinder token, int startId);
    void scheduleTimeoutService(IBinder token, int startId);
    void scheduleTimeoutServiceForType(IBinder token, int startId, int fgsType);
    void schedulePing(in RemoteCallback pong);
    void schedulePing(in RemoteCallback pong);
}
}
+34 −0
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@ import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.text.TextUtils.formatSimple;
import static android.text.TextUtils.formatSimple;


import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
@@ -1161,4 +1162,37 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac
     */
     */
    public void onTimeout(int startId) {
    public void onTimeout(int startId) {
    }
    }

    /** @hide */
    public final void callOnTimeLimitExceeded(int startId, int fgsType) {
        // 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 onTimeLimitExceeded()");
            return;
        }
        try {
            if (!mActivityManager.hasServiceTimeLimitExceeded(
                    new ComponentName(this, mClassName), mToken)) {
                Log.w(TAG, "Service no longer relevant, skipping onTimeLimitExceeded()");
                return;
            }
        } catch (RemoteException ex) {
        }
        if (Flags.introduceNewServiceOntimeoutCallback()) {
            onTimeout(startId, fgsType);
        }
    }

    /**
     * Callback called when a particular foreground service type has timed out.
     *
     * @param startId the startId passed to {@link #onStartCommand(Intent, int, int)} when
     * the service started.
     * @param fgsType the foreground service type which caused the timeout.
     */
    @FlaggedApi(Flags.FLAG_INTRODUCE_NEW_SERVICE_ONTIMEOUT_CALLBACK)
    public void onTimeout(int startId, int fgsType) {
    }
}
}
Loading