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

Commit 4457c44c authored by Kweku Adams's avatar Kweku Adams Committed by Automerger Merge Worker
Browse files

Merge "Expose job stop reasons." into sc-dev am: db348d44

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/13829001

Change-Id: Iea02c2123d84357a3699ad75f7dda3292b8d6548
parents 93f7cc09 db348d44
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -48,7 +48,8 @@ public class BlobStoreIdleJobService extends JobService {
    @Override
    public boolean onStopJob(final JobParameters params) {
        Slog.d(TAG, "Idle maintenance job is stopped; id=" + params.getJobId()
                + ", reason=" + JobParameters.getReasonCodeDescription(params.getStopReason()));
                + ", reason="
                + JobParameters.getLegacyReasonCodeDescription(params.getLegacyStopReason()));
        return false;
    }

+137 −10
Original line number Diff line number Diff line
@@ -16,10 +16,14 @@

package android.app.job;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.usage.UsageStatsManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ClipData;
import android.content.pm.PackageManager;
import android.net.Network;
import android.net.NetworkRequest;
import android.net.Uri;
@@ -30,6 +34,9 @@ import android.os.Parcelable;
import android.os.PersistableBundle;
import android.os.RemoteException;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * Contains the parameters used to configure/identify your job. You do not create this object
 * yourself, instead it is handed in to your application by the System.
@@ -82,7 +89,7 @@ public class JobParameters implements Parcelable {
     */
    // TODO(142420609): make it @SystemApi for mainline
    @NonNull
    public static String getReasonCodeDescription(int reasonCode) {
    public static String getLegacyReasonCodeDescription(int reasonCode) {
        switch (reasonCode) {
            case REASON_CANCELED: return "canceled";
            case REASON_CONSTRAINTS_NOT_SATISFIED: return "constraints";
@@ -96,12 +103,119 @@ public class JobParameters implements Parcelable {
    }

    /** @hide */
    // @SystemApi TODO make it a system api for mainline
    // TODO: move current users of legacy reasons to new public reasons
    @NonNull
    public static int[] getJobStopReasonCodes() {
        return JOB_STOP_REASON_CODES;
    }

    /**
     * There is no reason the job is stopped. This is the value returned from the JobParameters
     * object passed to {@link JobService#onStartJob(JobParameters)}.
     */
    public static final int STOP_REASON_UNDEFINED = 0;
    /**
     * The job was cancelled directly by the app, either by calling
     * {@link JobScheduler#cancel(int)}, {@link JobScheduler#cancelAll()}, or by scheduling a
     * new job with the same job ID.
     */
    public static final int STOP_REASON_CANCELLED_BY_APP = 1;
    /** The job was stopped to run a higher priority job of the app. */
    public static final int STOP_REASON_PREEMPT = 2;
    /**
     * The job used up its maximum execution time and timed out. Each individual job has a maximum
     * execution time limit, regardless of how much total quota the app has. See the note on
     * {@link JobScheduler} for the execution time limits.
     */
    public static final int STOP_REASON_TIMEOUT = 3;
    /**
     * The device state (eg. Doze, battery saver, memory usage, etc) requires JobScheduler stop this
     * job.
     */
    public static final int STOP_REASON_DEVICE_STATE = 4;
    /**
     * The requested battery-not-low constraint is no longer satisfied.
     *
     * @see JobInfo.Builder#setRequiresBatteryNotLow(boolean)
     */
    public static final int STOP_REASON_CONSTRAINT_BATTERY_NOT_LOW = 5;
    /**
     * The requested charging constraint is no longer satisfied.
     *
     * @see JobInfo.Builder#setRequiresCharging(boolean)
     */
    public static final int STOP_REASON_CONSTRAINT_CHARGING = 6;
    /**
     * The requested connectivity constraint is no longer satisfied.
     *
     * @see JobInfo.Builder#setRequiredNetwork(NetworkRequest)
     * @see JobInfo.Builder#setRequiredNetworkType(int)
     */
    public static final int STOP_REASON_CONSTRAINT_CONNECTIVITY = 7;
    /**
     * The requested idle constraint is no longer satisfied.
     *
     * @see JobInfo.Builder#setRequiresDeviceIdle(boolean)
     */
    public static final int STOP_REASON_CONSTRAINT_DEVICE_IDLE = 8;
    /**
     * The requested storage-not-low constraint is no longer satisfied.
     *
     * @see JobInfo.Builder#setRequiresStorageNotLow(boolean)
     */
    public static final int STOP_REASON_CONSTRAINT_STORAGE_NOT_LOW = 9;
    /**
     * The app has consumed all of its current quota. Each app is assigned a quota of how much
     * it can run jobs within a certain time frame. The quota is informed, in part, by app standby
     * buckets. Once an app has used up all of its quota, it won't be able to start jobs until
     * quota is replenished, is changed, or is temporarily not applied.
     *
     * @see UsageStatsManager#getAppStandbyBucket()
     */
    public static final int STOP_REASON_QUOTA = 10;
    /**
     * The app is restricted from running in the background.
     *
     * @see ActivityManager#isBackgroundRestricted()
     * @see PackageManager#isInstantApp()
     */
    public static final int STOP_REASON_BACKGROUND_RESTRICTION = 11;
    /**
     * The current standby bucket requires that the job stop now.
     *
     * @see UsageStatsManager#STANDBY_BUCKET_RESTRICTED
     */
    public static final int STOP_REASON_APP_STANDBY = 12;
    /**
     * The user stopped the job. This can happen either through force-stop, or via adb shell
     * commands.
     */
    public static final int STOP_REASON_USER = 13;
    /** The system is doing some processing that requires stopping this job. */
    public static final int STOP_REASON_SYSTEM_PROCESSING = 14;

    /** @hide */
    @IntDef(prefix = {"STOP_REASON_"}, value = {
            STOP_REASON_UNDEFINED,
            STOP_REASON_CANCELLED_BY_APP,
            STOP_REASON_PREEMPT,
            STOP_REASON_TIMEOUT,
            STOP_REASON_DEVICE_STATE,
            STOP_REASON_CONSTRAINT_BATTERY_NOT_LOW,
            STOP_REASON_CONSTRAINT_CHARGING,
            STOP_REASON_CONSTRAINT_CONNECTIVITY,
            STOP_REASON_CONSTRAINT_DEVICE_IDLE,
            STOP_REASON_CONSTRAINT_STORAGE_NOT_LOW,
            STOP_REASON_QUOTA,
            STOP_REASON_BACKGROUND_RESTRICTION,
            STOP_REASON_APP_STANDBY,
            STOP_REASON_USER,
            STOP_REASON_SYSTEM_PROCESSING,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface StopReason {
    }

    @UnsupportedAppUsage
    private final int jobId;
    private final PersistableBundle extras;
@@ -116,7 +230,8 @@ public class JobParameters implements Parcelable {
    private final String[] mTriggeredContentAuthorities;
    private final Network network;

    private int stopReason; // Default value of stopReason is REASON_CANCELED
    private int mStopReason = STOP_REASON_UNDEFINED;
    private int mLegacyStopReason; // Default value of stopReason is REASON_CANCELED
    private String debugStopReason; // Human readable stop reason for debugging.

    /** @hide */
@@ -145,15 +260,23 @@ public class JobParameters implements Parcelable {
    }

    /**
     * Reason onStopJob() was called on this job.
     * @hide
     * @return The reason {@link JobService#onStopJob(JobParameters)} was called on this job. Will
     * be {@link #STOP_REASON_UNDEFINED} if {@link JobService#onStopJob(JobParameters)} has not
     * yet been called.
     */
    @StopReason
    public int getStopReason() {
        return stopReason;
        return mStopReason;
    }

    /** @hide */
    public int getLegacyStopReason() {
        return mLegacyStopReason;
    }

    /**
     * Reason onStopJob() was called on this job.
     *
     * @hide
     */
    public String getDebugStopReason() {
@@ -368,13 +491,16 @@ public class JobParameters implements Parcelable {
        } else {
            network = null;
        }
        stopReason = in.readInt();
        mStopReason = in.readInt();
        mLegacyStopReason = in.readInt();
        debugStopReason = in.readString();
    }

    /** @hide */
    public void setStopReason(int reason, String debugStopReason) {
        stopReason = reason;
    public void setStopReason(@StopReason int reason, int legacyStopReason,
            String debugStopReason) {
        mStopReason = reason;
        mLegacyStopReason = legacyStopReason;
        this.debugStopReason = debugStopReason;
    }

@@ -406,7 +532,8 @@ public class JobParameters implements Parcelable {
        } else {
            dest.writeInt(0);
        }
        dest.writeInt(stopReason);
        dest.writeInt(mStopReason);
        dest.writeInt(mLegacyStopReason);
        dest.writeString(debugStopReason);
    }

+10 −6
Original line number Diff line number Diff line
@@ -139,19 +139,23 @@ public abstract class JobService extends Service {
     * Once this method is called, you no longer need to call
     * {@link #jobFinished(JobParameters, boolean)}.
     *
     * <p>This will happen if the requirements specified at schedule time are no longer met. For
     * <p>This may happen if the requirements specified at schedule time are no longer met. For
     * example you may have requested WiFi with
     * {@link android.app.job.JobInfo.Builder#setRequiredNetworkType(int)}, yet while your
     * job was executing the user toggled WiFi. Another example is if you had specified
     * {@link android.app.job.JobInfo.Builder#setRequiresDeviceIdle(boolean)}, and the phone left its
     * idle maintenance window. You are solely responsible for the behavior of your application
     * upon receipt of this message; your app will likely start to misbehave if you ignore it.
     * {@link android.app.job.JobInfo.Builder#setRequiresDeviceIdle(boolean)}, and the phone left
     * its idle maintenance window. There are many other reasons a job can be stopped early besides
     * constraints no longer being satisfied. {@link JobParameters#getStopReason()} will return the
     * reason this method was called. You are solely responsible for the behavior of your
     * application upon receipt of this message; your app will likely start to misbehave if you
     * ignore it.
     * <p>
     * Once this method returns (or times out), the system releases the wakelock that it is holding
     * on behalf of the job.</p>
     *
     * @param params The parameters identifying this job, as supplied to
     *               the job in the {@link #onStartJob(JobParameters)} callback.
     * @param params The parameters identifying this job, similar to what was supplied to the job in
     *               the {@link #onStartJob(JobParameters)} callback, but with the stop reason
     *               included.
     * @return {@code true} to indicate to the JobManager whether you'd like to reschedule
     * this job based on the retry criteria provided at job creation-time; or {@code false}
     * to end the job entirely.  Regardless of the value returned, your job must stop executing.
+2 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.job;

import android.annotation.NonNull;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.util.proto.ProtoOutputStream;

import java.util.List;
@@ -36,7 +37,7 @@ public interface JobSchedulerInternal {
    /**
     * Cancel the jobs for a given uid (e.g. when app data is cleared)
     */
    void cancelJobsForUid(int uid, String reason);
    void cancelJobsForUid(int uid, @JobParameters.StopReason int reason, String debugReason);

    /**
     * These are for activity manager to communicate to use what is currently performing backups.
+16 −2
Original line number Diff line number Diff line
@@ -266,6 +266,8 @@ class JobConcurrencyManager {

    String[] mRecycledPreemptReasonForContext = new String[MAX_JOB_CONTEXTS_COUNT];

    int[] mRecycledPreemptReasonCodeForContext = new int[MAX_JOB_CONTEXTS_COUNT];

    String[] mRecycledShouldStopJobReason = new String[MAX_JOB_CONTEXTS_COUNT];

    private final ArraySet<JobStatus> mRunningJobs = new ArraySet<>();
@@ -505,6 +507,7 @@ class JobConcurrencyManager {
        int[] preferredUidForContext = mRecycledPreferredUidForContext;
        int[] workTypeForContext = mRecycledWorkTypeForContext;
        String[] preemptReasonForContext = mRecycledPreemptReasonForContext;
        int[] preemptReasonCodeForContext = mRecycledPreemptReasonCodeForContext;
        String[] shouldStopJobReason = mRecycledShouldStopJobReason;

        updateCounterConfigLocked();
@@ -528,6 +531,7 @@ class JobConcurrencyManager {
            slotChanged[i] = false;
            preferredUidForContext[i] = js.getPreferredUid();
            preemptReasonForContext[i] = null;
            preemptReasonCodeForContext[i] = JobParameters.STOP_REASON_UNDEFINED;
            shouldStopJobReason[i] = shouldStopRunningJobLocked(js);
        }
        if (DEBUG) {
@@ -551,6 +555,7 @@ class JobConcurrencyManager {
            int allWorkTypes = getJobWorkTypes(nextPending);
            int workType = mWorkCountTracker.canJobStart(allWorkTypes);
            boolean startingJob = false;
            int preemptReasonCode = JobParameters.STOP_REASON_UNDEFINED;
            String preemptReason = null;
            // TODO(141645789): rewrite this to look at empty contexts first so we don't
            // unnecessarily preempt
@@ -582,6 +587,7 @@ class JobConcurrencyManager {
                        // assign the new job to this context since we'll reassign when the
                        // preempted job finally stops.
                        preemptReason = reason;
                        preemptReasonCode = JobParameters.STOP_REASON_DEVICE_STATE;
                    }
                    continue;
                }
@@ -597,6 +603,7 @@ class JobConcurrencyManager {
                    minPriorityForPreemption = jobPriority;
                    selectedContextId = j;
                    preemptReason = "higher priority job found";
                    preemptReasonCode = JobParameters.STOP_REASON_PREEMPT;
                    // In this case, we're just going to preempt a low priority job, we're not
                    // actually starting a job, so don't set startingJob.
                }
@@ -604,6 +611,7 @@ class JobConcurrencyManager {
            if (selectedContextId != -1) {
                contextIdToJobMap[selectedContextId] = nextPending;
                slotChanged[selectedContextId] = true;
                preemptReasonCodeForContext[selectedContextId] = preemptReasonCode;
                preemptReasonForContext[selectedContextId] = preemptReason;
            }
            if (startingJob) {
@@ -631,8 +639,13 @@ class JobConcurrencyManager {
                    }
                    // preferredUid will be set to uid of currently running job.
                    activeServices.get(i).cancelExecutingJobLocked(
                            preemptReasonCodeForContext[i],
                            JobParameters.REASON_PREEMPT, preemptReasonForContext[i]);
                    preservePreferredUid = true;
                    // Only preserve the UID if we're preempting for the same UID. If we're stopping
                    // the job because something is pending (eg. EJs), then we shouldn't preserve
                    // the UID.
                    preservePreferredUid =
                            preemptReasonCodeForContext[i] == JobParameters.STOP_REASON_PREEMPT;
                } else {
                    final JobStatus pendingJob = contextIdToJobMap[i];
                    if (DEBUG) {
@@ -657,7 +670,8 @@ class JobConcurrencyManager {
            final JobStatus jobStatus = jsc.getRunningJobLocked();

            if (jobStatus != null && !jsc.isWithinExecutionGuaranteeTime()) {
                jsc.cancelExecutingJobLocked(JobParameters.REASON_TIMEOUT, debugReason);
                jsc.cancelExecutingJobLocked(JobParameters.STOP_REASON_DEVICE_STATE,
                        JobParameters.REASON_TIMEOUT, debugReason);
            }
        }
    }
Loading