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

Commit f45997c0 authored by Jing Ji's avatar Jing Ji
Browse files

Add an am command to disable service restart backoff policy.

So service restart could happen sooner in testings.

BYPASS_INCLUSIVE_LANGUAGE_REASON=legacy API name

Bug: 170309420
Bug: 182832497
Test: atest FrameworksServicesTests:ServiceRestarterTest
Change-Id: I1180333f628c2bb3d974ae826a1657b0ada00594
parent 6c67db7b
Loading
Loading
Loading
Loading
+88 −20
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NA

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UptimeMillisLong;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityThread;
@@ -236,6 +237,12 @@ public final class ActiveServices {
    @GuardedBy("mAm")
    private final SparseArray<AppOpCallback> mFgsAppOpCallbacks = new SparseArray<>();

    /**
     * The list of packages with the service restart backoff disabled.
     */
    @GuardedBy("mAm")
    private final ArraySet<String> mRestartBackoffDisabledPackages = new ArraySet<>();

    /**
     * For keeping ActiveForegroundApps retaining state while the screen is off.
     */
@@ -3272,17 +3279,19 @@ public final class ActiveServices {
                }
            }

            if (isServiceRestartBackoffEnabledLocked(r.packageName)) {
                r.nextRestartTime = now + r.restartDelay;

                // Make sure that we don't end up restarting a bunch of services
                // all at the same time.
                boolean repeat;
                final long restartTimeBetween = mAm.mConstants.SERVICE_MIN_RESTART_TIME_BETWEEN;
                do {
                    repeat = false;
                final long restartTimeBetween = mAm.mConstants.SERVICE_MIN_RESTART_TIME_BETWEEN;
                    for (int i = mRestartingServices.size() - 1; i >= 0; i--) {
                    ServiceRecord r2 = mRestartingServices.get(i);
                    if (r2 != r && r.nextRestartTime >= (r2.nextRestartTime-restartTimeBetween)
                        final ServiceRecord r2 = mRestartingServices.get(i);
                        if (r2 != r
                                && r.nextRestartTime >= (r2.nextRestartTime - restartTimeBetween)
                                && r.nextRestartTime < (r2.nextRestartTime + restartTimeBetween)) {
                            r.nextRestartTime = r2.nextRestartTime + restartTimeBetween;
                            r.restartDelay = r.nextRestartTime - now;
@@ -3291,6 +3300,11 @@ public final class ActiveServices {
                        }
                    }
                } while (repeat);
            } else {
                // It's been forced to ignore the restart backoff, fix the delay here.
                r.restartDelay = mAm.mConstants.SERVICE_RESTART_DURATION;
                r.nextRestartTime = now + r.restartDelay;
            }

        } else {
            // Persistent processes are immediately restarted, so there is no
@@ -3310,15 +3324,22 @@ public final class ActiveServices {

        cancelForegroundNotificationLocked(r);

        performScheduleRestartLocked(r, "Scheduling", reason, SystemClock.uptimeMillis());

        return true;
    }

    @VisibleForTesting
    @GuardedBy("mAm")
    void performScheduleRestartLocked(ServiceRecord r, @NonNull String scheduling,
            @NonNull String reason, @UptimeMillisLong long now) {
        mAm.mHandler.removeCallbacks(r.restarter);
        mAm.mHandler.postAtTime(r.restarter, r.nextRestartTime);
        r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
        Slog.w(TAG, "Scheduling restart of crashed service "
        r.nextRestartTime = now + r.restartDelay;
        Slog.w(TAG, scheduling + " restart of crashed service "
                + r.shortInstanceName + " in " + r.restartDelay + "ms for " + reason);
        EventLog.writeEvent(EventLogTags.AM_SCHEDULE_SERVICE_RESTART,
                r.userId, r.shortInstanceName, r.restartDelay);

        return true;
    }

    final void performServiceRestartLocked(ServiceRecord r) {
@@ -3383,6 +3404,52 @@ public final class ActiveServices {
        }
    }

    /**
     * Toggle service restart backoff policy, used by {@link ActivityManagerShellCommand}.
     */
    @GuardedBy("mAm")
    void setServiceRestartBackoffEnabledLocked(@NonNull String packageName, boolean enable,
            @NonNull String reason) {
        if (!enable) {
            if (mRestartBackoffDisabledPackages.contains(packageName)) {
                // Already disabled, do nothing.
                return;
            }
            mRestartBackoffDisabledPackages.add(packageName);

            final long now = SystemClock.uptimeMillis();
            for (int i = 0, size = mRestartingServices.size(); i < size; i++) {
                final ServiceRecord r = mRestartingServices.get(i);
                if (TextUtils.equals(r.packageName, packageName)) {
                    final long remaining = r.nextRestartTime - now;
                    if (remaining > mAm.mConstants.SERVICE_RESTART_DURATION) {
                        r.restartDelay = mAm.mConstants.SERVICE_RESTART_DURATION;
                        r.nextRestartTime = now + r.restartDelay;
                        performScheduleRestartLocked(r, "Rescheduling", reason, now);
                    }
                }
            }
        } else {
            removeServiceRestartBackoffEnabledLocked(packageName);
            // For the simplicity, we are not going to reschedule its pending restarts
            // when we turn the backoff policy back on.
        }
    }

    @GuardedBy("mAm")
    private void removeServiceRestartBackoffEnabledLocked(@NonNull String packageName) {
        mRestartBackoffDisabledPackages.remove(packageName);
    }

    /**
     * @return {@code false} if the given package has been disable from enforcing the service
     * restart backoff policy, used by {@link ActivityManagerShellCommand}.
     */
    @GuardedBy("mAm")
    boolean isServiceRestartBackoffEnabledLocked(@NonNull String packageName) {
        return !mRestartBackoffDisabledPackages.contains(packageName);
    }

    private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired, boolean packageFrozen,
            boolean enqueueOomAdj)
@@ -4431,6 +4498,7 @@ public final class ActiveServices {
                mPendingBringups.removeAt(i);
            }
        }
        removeServiceRestartBackoffEnabledLocked(packageName);
    }

    void cleanUpServices(int userId, ComponentName component, Intent baseIntent) {
+20 −0
Original line number Diff line number Diff line
@@ -8436,6 +8436,26 @@ public class ActivityManagerService extends IActivityManager.Stub
        }
    }
    /**
     * Toggle service restart backoff policy, used by {@link ActivityManagerShellCommand}.
     */
    void setServiceRestartBackoffEnabled(@NonNull String packageName, boolean enable,
            @NonNull String reason) {
        synchronized (this) {
            mServices.setServiceRestartBackoffEnabledLocked(packageName, enable, reason);
        }
    }
    /**
     * @return {@code false} if the given package has been disable from enforcing the service
     * restart backoff policy, used by {@link ActivityManagerShellCommand}.
     */
    boolean isServiceRestartBackoffEnabled(@NonNull String packageName) {
        synchronized (this) {
            return mServices.isServiceRestartBackoffEnabledLocked(packageName);
        }
    }
    @Override
    public void onShellCommand(FileDescriptor in, FileDescriptor out,
            FileDescriptor err, String[] args, ShellCallback callback,
+29 −0
Original line number Diff line number Diff line
@@ -318,6 +318,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
                    return runRefreshSettingsCache();
                case "memory-factor":
                    return runMemoryFactor(pw);
                case "service-restart-backoff":
                    return runServiceRestartBackoff(pw);
                default:
                    return handleDefaultCommands(cmd);
            }
@@ -3095,6 +3097,28 @@ final class ActivityManagerShellCommand extends ShellCommand {
        }
    }

    private int runServiceRestartBackoff(PrintWriter pw) throws RemoteException {
        mInternal.enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
                "runServiceRestartBackoff()");

        final String opt = getNextArgRequired();
        switch (opt) {
            case "enable":
                mInternal.setServiceRestartBackoffEnabled(getNextArgRequired(), true, "shell");
                return 0;
            case "disable":
                mInternal.setServiceRestartBackoffEnabled(getNextArgRequired(), false, "shell");
                return 0;
            case "show":
                pw.println(mInternal.isServiceRestartBackoffEnabled(getNextArgRequired())
                        ? "enabled" : "disabled");
                return 0;
            default:
                getErrPrintWriter().println("Error: unknown command '" + opt + "'");
                return -1;
        }
    }

    private Resources getResources(PrintWriter pw) throws RemoteException {
        // system resources does not contain all the device configuration, construct it manually.
        Configuration config = mInterface.getConfiguration();
@@ -3418,6 +3442,11 @@ final class ActivityManagerShellCommand extends ShellCommand {
            pw.println("            Shows the existing memory pressure factor");
            pw.println("         reset");
            pw.println("            Removes existing override for memory pressure factor");
            pw.println("  service-restart-backoff <COMMAND> [...]: sub-commands to toggle service restart backoff policy.");
            pw.println("         enable|disable <PACKAGE_NAME>");
            pw.println("            Toggles the restart backoff policy on/off for <PACKAGE_NAME>.");
            pw.println("         show <PACKAGE_NAME>");
            pw.println("            Shows the restart backoff policy state for <PACKAGE_NAME>.");
            pw.println();
            Intent.printIntentArgsHelp(pw, "");
        }
+1 −0
Original line number Diff line number Diff line
@@ -91,6 +91,7 @@
    <uses-permission android:name="android.permission.VIBRATE_ALWAYS_ON"/>
    <uses-permission android:name="android.permission.CONTROL_DEVICE_STATE"/>
    <uses-permission android:name="android.permission.READ_PROJECTION_STATE"/>
    <uses-permission android:name="android.permission.KILL_UID"/>

    <!-- Uses API introduced in O (26) -->
    <uses-sdk android:minSdkVersion="1"
+3 −1
Original line number Diff line number Diff line
@@ -23,7 +23,9 @@
        <option name="test-file-name" value="JobTestApp.apk" />
        <option name="test-file-name" value="ConnTestApp.apk" />
        <option name="test-file-name" value="SuspendTestApp.apk" />
        <option name="test-file-name" value="SimpleServiceTestApp.apk" />
        <option name="test-file-name" value="SimpleServiceTestApp1.apk" />
        <option name="test-file-name" value="SimpleServiceTestApp2.apk" />
        <option name="test-file-name" value="SimpleServiceTestApp3.apk" />
    </target_preparer>

    <option name="test-tag" value="FrameworksServicesTests" />
Loading