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

Commit ff6ab128 authored by Lee Shombert's avatar Lee Shombert Committed by Android (Google) Code Review
Browse files

Merge "Connect the JobService timeout to AnrTimer" into main

parents 004451be 34116940
Loading
Loading
Loading
Loading
+49 −7
Original line number Diff line number Diff line
@@ -73,6 +73,7 @@ import com.android.modules.expresslog.Histogram;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.job.controllers.JobStatus;
import com.android.server.utils.AnrTimer;

import java.util.Objects;

@@ -319,6 +320,40 @@ public final class JobServiceContext implements ServiceConnection {
        }
    }

    // All instances of JobAnrTimer share the same arguments.
    private static final AnrTimer.Args sAnrTimerArgs =
            new AnrTimer.Args().enable(com.android.server.utils.Flags.anrTimerJobService());

    /**
     * An AnrTimer for the JobServiceContext.  There is one instance for each JobServiceContext
     * (these objects are not large).  For convenience, simple no-argument methods are provided
     * which use 'this'.
     */
    private class JobAnrTimer extends AnrTimer<JobCallback> {
        JobAnrTimer() {
            super(mCallbackHandler, MSG_TIMEOUT, "JobScheduler", sAnrTimerArgs);
        }

        public void start(long timeout) {
            start(mRunningCallback, /* pid */ 0, mRunningJob.getUid(), timeout);
        }

        public boolean cancel() {
            return cancel(mRunningCallback);
        }

        public void accept(TimeoutRecord tr) {
            accept(mRunningCallback, tr);
        }

        public boolean discard() {
            return discard(mRunningCallback);
        }
    }

    // The AnrTimer for this instance.
    private final JobAnrTimer mAnrTimer;

    JobServiceContext(JobSchedulerService service, JobConcurrencyManager concurrencyManager,
            JobNotificationCoordinator notificationCoordinator,
            IBatteryStats batteryStats, JobPackageTracker tracker, Looper looper) {
@@ -337,6 +372,7 @@ public final class JobServiceContext implements ServiceConnection {
        mAvailable = true;
        mVerb = VERB_FINISHED;
        mPreferredUid = NO_PREFERRED_UID;
        mAnrTimer = new JobAnrTimer();
    }

    /**
@@ -1177,6 +1213,7 @@ public final class JobServiceContext implements ServiceConnection {
                            handleOpTimeoutLocked();
                        } else {
                            JobCallback jc = (JobCallback)message.obj;
                            mAnrTimer.discard(jc);
                            StringBuilder sb = new StringBuilder(128);
                            sb.append("Ignoring timeout of no longer active job");
                            if (jc.mStoppedReason != null) {
@@ -1433,6 +1470,8 @@ public final class JobServiceContext implements ServiceConnection {
                            mRunningJob.getUid()));
                break;
            case VERB_EXECUTING:
                // This is the tricky one.  Some of banches here accept the timeout and some
                // discard it.
                if (mPendingStopReason != JobParameters.STOP_REASON_UNDEFINED) {
                    if (mService.isReadyToBeExecutedLocked(mRunningJob, false)) {
                        // Job became ready again while we were waiting to stop it (for example,
@@ -1447,6 +1486,7 @@ public final class JobServiceContext implements ServiceConnection {
                        mParams.setStopReason(mPendingStopReason, mPendingInternalStopReason,
                                mPendingDebugStopReason);
                        sendStopMessageLocked(mPendingDebugStopReason);
                        mAnrTimer.discard();
                        break;
                    }
                }
@@ -1481,6 +1521,7 @@ public final class JobServiceContext implements ServiceConnection {
                    mParams.setStopReason(stopReason,
                                    internalStopReason, debugStopReason.toString());
                    sendStopMessageLocked(stopMessage.toString());
                    mAnrTimer.discard();
                } else if (nowElapsed >= earliestStopTimeElapsed) {
                    // We've given the app the minimum execution time. See if we should stop it or
                    // let it continue running
@@ -1522,6 +1563,7 @@ public final class JobServiceContext implements ServiceConnection {
            default:
                Slog.e(TAG, "Handling timeout for an invalid job state: "
                        + getRunningJobNameLocked() + ", dropping.");
                mAnrTimer.discard();
                closeAndCleanupJobLocked(false /* needsReschedule */, "invalid timeout");
        }
    }
@@ -1565,9 +1607,12 @@ public final class JobServiceContext implements ServiceConnection {
                    debugReason);
        }
        if (triggerAnr) {
            final TimeoutRecord tr = TimeoutRecord.forJobService(anrMessage);
            mAnrTimer.accept(tr);
            mActivityManagerInternal.appNotResponding(
                    mRunningJob.serviceProcessName, mRunningJob.getUid(),
                    TimeoutRecord.forJobService(anrMessage));
                    mRunningJob.serviceProcessName, mRunningJob.getUid(), tr);
        } else {
            mAnrTimer.discard();
        }
        closeAndCleanupJobLocked(reschedule, debugReason);
    }
@@ -1763,8 +1808,6 @@ public final class JobServiceContext implements ServiceConnection {
     * on with life.
     */
    private void scheduleOpTimeOutLocked() {
        removeOpTimeOutLocked();

        final long timeoutMillis;
        switch (mVerb) {
            case VERB_EXECUTING:
@@ -1799,13 +1842,12 @@ public final class JobServiceContext implements ServiceConnection {
                    mRunningJob.getServiceComponent().getShortClassName() + "' jId: " +
                    mParams.getJobId() + ", in " + (timeoutMillis / 1000) + " s");
        }
        Message m = mCallbackHandler.obtainMessage(MSG_TIMEOUT, mRunningCallback);
        mCallbackHandler.sendMessageDelayed(m, timeoutMillis);
        mAnrTimer.start(timeoutMillis);
        mTimeoutElapsed = sElapsedRealtimeClock.millis() + timeoutMillis;
    }

    private void removeOpTimeOutLocked() {
        mCallbackHandler.removeMessages(MSG_TIMEOUT);
        mAnrTimer.cancel();
    }

    void dumpLocked(IndentingPrintWriter pw, final long nowElapsed) {
+25 −4
Original line number Diff line number Diff line
@@ -84,7 +84,7 @@ import java.util.Objects;
 *
 * @hide
 */
public abstract class AnrTimer<V> implements AutoCloseable {
public class AnrTimer<V> implements AutoCloseable {

    /**
     * The log tag.
@@ -113,14 +113,18 @@ public abstract class AnrTimer<V> implements AutoCloseable {
     * is no valid pid available.
     * @return a valid pid or zero.
     */
    public abstract int getPid(V obj);
    public int getPid(V obj) {
        return 0;
    }

    /**
     * Fetch the Linux uid from the object. The returned value may be zero to indicate that there
     * is no valid uid available.
     * @return a valid uid or zero.
     */
    public abstract int getUid(V obj);
    public int getUid(V obj) {
        return 0;
    }

    /**
     * Return true if tracing is feature-enabled.  This has no effect unless tracing is configured.
@@ -437,6 +441,7 @@ public abstract class AnrTimer<V> implements AutoCloseable {
        /** Start a timer by sending a message to the client's handler. */
        @Override
        void start(@NonNull V arg, int pid, int uid, long timeoutMs) {
            cancel(arg);
            final Message msg = mHandler.obtainMessage(mWhat, arg);
            mHandler.sendMessageDelayed(msg, timeoutMs);
        }
@@ -667,8 +672,24 @@ public abstract class AnrTimer<V> implements AutoCloseable {
     * @param timeoutMs The timer timeout, in milliseconds.
     */
    public void start(@NonNull V arg, long timeoutMs) {
        start(arg, getPid(arg), getUid(arg), timeoutMs);
    }

    /**
     * Start a timer associated with arg, pid, and uid.  The same object must be used to cancel,
     * accept, or discard a timer later.  If a timer already exists with the same arg, then the
     * existing timer is canceled and a new timer is created.  The timeout is signed but negative
     * delays are nonsensical.  Rather than throw an exception, timeouts less than 0ms are forced to
     * 0ms.  This allows a client to deliver an immediate timeout via the AnrTimer.
     *
     * @param arg The key by which the timer is known.  This is never examined or modified.
     * @param pid The process ID of the process that is being timed.
     * @param uid The UID of the process that is being timed.
     * @param timeoutMs The timer timeout, in milliseconds.
     */
    public void start(@NonNull V arg, int pid, int uid, long timeoutMs) {
        if (timeoutMs < 0) timeoutMs = 0;
        mFeature.start(arg, getPid(arg), getUid(arg), timeoutMs);
        mFeature.start(arg, pid, uid, timeoutMs);
    }

    /**
+8 −0
Original line number Diff line number Diff line
@@ -8,3 +8,11 @@ flag {
     description: "When true, start a trace if an ANR timer reaches 50%"
     bug: "352085328"
}

flag {
     name: "anr_timer_job_service"
     namespace: "system_performance"
     is_fixed_read_only: true
     description: "Use AnrTimer to signal ANRs in JobScheduler"
     bug: "408440679"
}
+0 −4
Original line number Diff line number Diff line
@@ -700,10 +700,6 @@ class AnrTimerService::Timer {
        if (extend && pid != 0) {
            initial.fill(pid);
        }

        // A zero-pid is odd but it means the upper layers will never ANR the process.  Freezing
        // is always disabled.  (It won't work anyway, but disabling it avoids error messages.)
        ALOGI_IF(DEBUG_ERROR && pid == 0, "error: zero-pid %s", toString().c_str());
    }

    // Start a timer.  This interface exists to generate log messages, if enabled.