Home | History | Annotate | Download | only in controllers
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License
     15  */
     16 
     17 package com.android.server.job.controllers;
     18 
     19 import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
     20 
     21 import android.app.AppGlobals;
     22 import android.app.IActivityManager;
     23 import android.app.job.JobInfo;
     24 import android.app.job.JobWorkItem;
     25 import android.content.ClipData;
     26 import android.content.ComponentName;
     27 import android.content.pm.PackageManagerInternal;
     28 import android.net.Network;
     29 import android.net.Uri;
     30 import android.os.RemoteException;
     31 import android.os.UserHandle;
     32 import android.text.format.Time;
     33 import android.util.ArraySet;
     34 import android.util.Pair;
     35 import android.util.Slog;
     36 import android.util.TimeUtils;
     37 import android.util.proto.ProtoOutputStream;
     38 
     39 import com.android.server.LocalServices;
     40 import com.android.server.job.GrantedUriPermissions;
     41 import com.android.server.job.JobSchedulerInternal;
     42 import com.android.server.job.JobSchedulerService;
     43 import com.android.server.job.JobStatusDumpProto;
     44 import com.android.server.job.JobStatusShortInfoProto;
     45 
     46 import java.io.PrintWriter;
     47 import java.util.ArrayList;
     48 import java.util.Arrays;
     49 import java.util.function.Predicate;
     50 
     51 /**
     52  * Uniquely identifies a job internally.
     53  * Created from the public {@link android.app.job.JobInfo} object when it lands on the scheduler.
     54  * Contains current state of the requirements of the job, as well as a function to evaluate
     55  * whether it's ready to run.
     56  * This object is shared among the various controllers - hence why the different fields are atomic.
     57  * This isn't strictly necessary because each controller is only interested in a specific field,
     58  * and the receivers that are listening for global state change will all run on the main looper,
     59  * but we don't enforce that so this is safer.
     60  * @hide
     61  */
     62 public final class JobStatus {
     63     static final String TAG = "JobSchedulerService";
     64     static final boolean DEBUG = JobSchedulerService.DEBUG;
     65 
     66     public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE;
     67     public static final long NO_EARLIEST_RUNTIME = 0L;
     68 
     69     static final int CONSTRAINT_CHARGING = JobInfo.CONSTRAINT_FLAG_CHARGING;
     70     static final int CONSTRAINT_IDLE = JobInfo.CONSTRAINT_FLAG_DEVICE_IDLE;
     71     static final int CONSTRAINT_BATTERY_NOT_LOW = JobInfo.CONSTRAINT_FLAG_BATTERY_NOT_LOW;
     72     static final int CONSTRAINT_STORAGE_NOT_LOW = JobInfo.CONSTRAINT_FLAG_STORAGE_NOT_LOW;
     73     static final int CONSTRAINT_TIMING_DELAY = 1<<31;
     74     static final int CONSTRAINT_DEADLINE = 1<<30;
     75     static final int CONSTRAINT_CONNECTIVITY = 1<<28;
     76     static final int CONSTRAINT_CONTENT_TRIGGER = 1<<26;
     77     static final int CONSTRAINT_DEVICE_NOT_DOZING = 1<<25;
     78     static final int CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 1<<22;
     79 
     80     // Soft override: ignore constraints like time that don't affect API availability
     81     public static final int OVERRIDE_SOFT = 1;
     82     // Full override: ignore all constraints including API-affecting like connectivity
     83     public static final int OVERRIDE_FULL = 2;
     84 
     85     /** If not specified, trigger update delay is 10 seconds. */
     86     public static final long DEFAULT_TRIGGER_UPDATE_DELAY = 10*1000;
     87 
     88     /** The minimum possible update delay is 1/2 second. */
     89     public static final long MIN_TRIGGER_UPDATE_DELAY = 500;
     90 
     91     /** If not specified, trigger maxumum delay is 2 minutes. */
     92     public static final long DEFAULT_TRIGGER_MAX_DELAY = 2*60*1000;
     93 
     94     /** The minimum possible update delay is 1 second. */
     95     public static final long MIN_TRIGGER_MAX_DELAY = 1000;
     96 
     97     final JobInfo job;
     98     /**
     99      * Uid of the package requesting this job.  This can differ from the "source"
    100      * uid when the job was scheduled on the app's behalf, such as with the jobs
    101      * that underly Sync Manager operation.
    102      */
    103     final int callingUid;
    104     final int targetSdkVersion;
    105     final String batteryName;
    106 
    107     /**
    108      * Identity of the app in which the job is hosted.
    109      */
    110     final String sourcePackageName;
    111     final int sourceUserId;
    112     final int sourceUid;
    113     final String sourceTag;
    114 
    115     final String tag;
    116 
    117     private GrantedUriPermissions uriPerms;
    118     private boolean prepared;
    119 
    120     static final boolean DEBUG_PREPARE = true;
    121     private Throwable unpreparedPoint = null;
    122 
    123     /**
    124      * Earliest point in the future at which this job will be eligible to run. A value of 0
    125      * indicates there is no delay constraint. See {@link #hasTimingDelayConstraint()}.
    126      */
    127     private final long earliestRunTimeElapsedMillis;
    128     /**
    129      * Latest point in the future at which this job must be run. A value of {@link Long#MAX_VALUE}
    130      * indicates there is no deadline constraint. See {@link #hasDeadlineConstraint()}.
    131      */
    132     private final long latestRunTimeElapsedMillis;
    133 
    134     /** How many times this job has failed, used to compute back-off. */
    135     private final int numFailures;
    136 
    137     /**
    138      * Current standby heartbeat when this job was scheduled or last ran.  Used to
    139      * pin the runnability check regardless of the job's app moving between buckets.
    140      */
    141     private final long baseHeartbeat;
    142 
    143     /**
    144      * Which app standby bucket this job's app is in.  Updated when the app is moved to a
    145      * different bucket.
    146      */
    147     private int standbyBucket;
    148 
    149     /**
    150      * Debugging: timestamp if we ever defer this job based on standby bucketing, this
    151      * is when we did so.
    152      */
    153     private long whenStandbyDeferred;
    154 
    155     // Constraints.
    156     final int requiredConstraints;
    157     int satisfiedConstraints = 0;
    158 
    159     // Set to true if doze constraint was satisfied due to app being whitelisted.
    160     public boolean dozeWhitelisted;
    161 
    162     // Set to true when the app is "active" per AppStateTracker
    163     public boolean uidActive;
    164 
    165     /**
    166      * Flag for {@link #trackingControllers}: the battery controller is currently tracking this job.
    167      */
    168     public static final int TRACKING_BATTERY = 1<<0;
    169     /**
    170      * Flag for {@link #trackingControllers}: the network connectivity controller is currently
    171      * tracking this job.
    172      */
    173     public static final int TRACKING_CONNECTIVITY = 1<<1;
    174     /**
    175      * Flag for {@link #trackingControllers}: the content observer controller is currently
    176      * tracking this job.
    177      */
    178     public static final int TRACKING_CONTENT = 1<<2;
    179     /**
    180      * Flag for {@link #trackingControllers}: the idle controller is currently tracking this job.
    181      */
    182     public static final int TRACKING_IDLE = 1<<3;
    183     /**
    184      * Flag for {@link #trackingControllers}: the storage controller is currently tracking this job.
    185      */
    186     public static final int TRACKING_STORAGE = 1<<4;
    187     /**
    188      * Flag for {@link #trackingControllers}: the time controller is currently tracking this job.
    189      */
    190     public static final int TRACKING_TIME = 1<<5;
    191 
    192     /**
    193      * Bit mask of controllers that are currently tracking the job.
    194      */
    195     private int trackingControllers;
    196 
    197     /**
    198      * Flag for {@link #mInternalFlags}: this job was scheduled when the app that owns the job
    199      * service (not necessarily the caller) was in the foreground and the job has no time
    200      * constraints, which makes it exempted from the battery saver job restriction.
    201      *
    202      * @hide
    203      */
    204     public static final int INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION = 1 << 0;
    205 
    206     /**
    207      * Versatile, persistable flags for a job that's updated within the system server,
    208      * as opposed to {@link JobInfo#flags} that's set by callers.
    209      */
    210     private int mInternalFlags;
    211 
    212     // These are filled in by controllers when preparing for execution.
    213     public ArraySet<Uri> changedUris;
    214     public ArraySet<String> changedAuthorities;
    215     public Network network;
    216 
    217     public int lastEvaluatedPriority;
    218 
    219     // If non-null, this is work that has been enqueued for the job.
    220     public ArrayList<JobWorkItem> pendingWork;
    221 
    222     // If non-null, this is work that is currently being executed.
    223     public ArrayList<JobWorkItem> executingWork;
    224 
    225     public int nextPendingWorkId = 1;
    226 
    227     // Used by shell commands
    228     public int overrideState = 0;
    229 
    230     // When this job was enqueued, for ordering.  (in elapsedRealtimeMillis)
    231     public long enqueueTime;
    232 
    233     // Metrics about queue latency.  (in uptimeMillis)
    234     public long madePending;
    235     public long madeActive;
    236 
    237     /**
    238      * Last time a job finished successfully for a periodic job, in the currentTimeMillis time,
    239      * for dumpsys.
    240      */
    241     private long mLastSuccessfulRunTime;
    242 
    243     /**
    244      * Last time a job finished unsuccessfully, in the currentTimeMillis time, for dumpsys.
    245      */
    246     private long mLastFailedRunTime;
    247 
    248     /**
    249      * Transient: when a job is inflated from disk before we have a reliable RTC clock time,
    250      * we retain the canonical (delay, deadline) scheduling tuple read out of the persistent
    251      * store in UTC so that we can fix up the job's scheduling criteria once we get a good
    252      * wall-clock time.  If we have to persist the job again before the clock has been updated,
    253      * we record these times again rather than calculating based on the earliest/latest elapsed
    254      * time base figures.
    255      *
    256      * 'first' is the earliest/delay time, and 'second' is the latest/deadline time.
    257      */
    258     private Pair<Long, Long> mPersistedUtcTimes;
    259 
    260     /**
    261      * For use only by ContentObserverController: state it is maintaining about content URIs
    262      * being observed.
    263      */
    264     ContentObserverController.JobInstance contentObserverJobInstance;
    265 
    266     private long totalNetworkBytes = JobInfo.NETWORK_BYTES_UNKNOWN;
    267 
    268     /** Provide a handle to the service that this job will be run on. */
    269     public int getServiceToken() {
    270         return callingUid;
    271     }
    272 
    273     /**
    274      * Core constructor for JobStatus instances.  All other ctors funnel down to this one.
    275      *
    276      * @param job The actual requested parameters for the job
    277      * @param callingUid Identity of the app that is scheduling the job.  This may not be the
    278      *     app in which the job is implemented; such as with sync jobs.
    279      * @param targetSdkVersion The targetSdkVersion of the app in which the job will run.
    280      * @param sourcePackageName The package name of the app in which the job will run.
    281      * @param sourceUserId The user in which the job will run
    282      * @param standbyBucket The standby bucket that the source package is currently assigned to,
    283      *     cached here for speed of handling during runnability evaluations (and updated when bucket
    284      *     assignments are changed)
    285      * @param heartbeat Timestamp of when the job was created, in the standby-related
    286      *     timebase.
    287      * @param tag A string associated with the job for debugging/logging purposes.
    288      * @param numFailures Count of how many times this job has requested a reschedule because
    289      *     its work was not yet finished.
    290      * @param earliestRunTimeElapsedMillis Milestone: earliest point in time at which the job
    291      *     is to be considered runnable
    292      * @param latestRunTimeElapsedMillis Milestone: point in time at which the job will be
    293      *     considered overdue
    294      * @param lastSuccessfulRunTime When did we last run this job to completion?
    295      * @param lastFailedRunTime When did we last run this job only to have it stop incomplete?
    296      * @param internalFlags Non-API property flags about this job
    297      */
    298     private JobStatus(JobInfo job, int callingUid, int targetSdkVersion, String sourcePackageName,
    299             int sourceUserId, int standbyBucket, long heartbeat, String tag, int numFailures,
    300             long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
    301             long lastSuccessfulRunTime, long lastFailedRunTime, int internalFlags) {
    302         this.job = job;
    303         this.callingUid = callingUid;
    304         this.targetSdkVersion = targetSdkVersion;
    305         this.standbyBucket = standbyBucket;
    306         this.baseHeartbeat = heartbeat;
    307 
    308         int tempSourceUid = -1;
    309         if (sourceUserId != -1 && sourcePackageName != null) {
    310             try {
    311                 tempSourceUid = AppGlobals.getPackageManager().getPackageUid(sourcePackageName, 0,
    312                         sourceUserId);
    313             } catch (RemoteException ex) {
    314                 // Can't happen, PackageManager runs in the same process.
    315             }
    316         }
    317         if (tempSourceUid == -1) {
    318             this.sourceUid = callingUid;
    319             this.sourceUserId = UserHandle.getUserId(callingUid);
    320             this.sourcePackageName = job.getService().getPackageName();
    321             this.sourceTag = null;
    322         } else {
    323             this.sourceUid = tempSourceUid;
    324             this.sourceUserId = sourceUserId;
    325             this.sourcePackageName = sourcePackageName;
    326             this.sourceTag = tag;
    327         }
    328 
    329         this.batteryName = this.sourceTag != null
    330                 ? this.sourceTag + ":" + job.getService().getPackageName()
    331                 : job.getService().flattenToShortString();
    332         this.tag = "*job*/" + this.batteryName;
    333 
    334         this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
    335         this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
    336         this.numFailures = numFailures;
    337 
    338         int requiredConstraints = job.getConstraintFlags();
    339         if (job.getRequiredNetwork() != null) {
    340             requiredConstraints |= CONSTRAINT_CONNECTIVITY;
    341         }
    342         if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME) {
    343             requiredConstraints |= CONSTRAINT_TIMING_DELAY;
    344         }
    345         if (latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
    346             requiredConstraints |= CONSTRAINT_DEADLINE;
    347         }
    348         if (job.getTriggerContentUris() != null) {
    349             requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER;
    350         }
    351         this.requiredConstraints = requiredConstraints;
    352 
    353         mLastSuccessfulRunTime = lastSuccessfulRunTime;
    354         mLastFailedRunTime = lastFailedRunTime;
    355 
    356         mInternalFlags = internalFlags;
    357 
    358         updateEstimatedNetworkBytesLocked();
    359 
    360         if (job.getRequiredNetwork() != null) {
    361             // Later, when we check if a given network satisfies the required
    362             // network, we need to know the UID that is requesting it, so push
    363             // our source UID into place.
    364             job.getRequiredNetwork().networkCapabilities.setSingleUid(this.sourceUid);
    365         }
    366     }
    367 
    368     /** Copy constructor: used specifically when cloning JobStatus objects for persistence,
    369      *   so we preserve RTC window bounds if the source object has them. */
    370     public JobStatus(JobStatus jobStatus) {
    371         this(jobStatus.getJob(), jobStatus.getUid(), jobStatus.targetSdkVersion,
    372                 jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(),
    373                 jobStatus.getStandbyBucket(), jobStatus.getBaseHeartbeat(),
    374                 jobStatus.getSourceTag(), jobStatus.getNumFailures(),
    375                 jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed(),
    376                 jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime(),
    377                 jobStatus.getInternalFlags());
    378         mPersistedUtcTimes = jobStatus.mPersistedUtcTimes;
    379         if (jobStatus.mPersistedUtcTimes != null) {
    380             if (DEBUG) {
    381                 Slog.i(TAG, "Cloning job with persisted run times", new RuntimeException("here"));
    382             }
    383         }
    384     }
    385 
    386     /**
    387      * Create a new JobStatus that was loaded from disk. We ignore the provided
    388      * {@link android.app.job.JobInfo} time criteria because we can load a persisted periodic job
    389      * from the {@link com.android.server.job.JobStore} and still want to respect its
    390      * wallclock runtime rather than resetting it on every boot.
    391      * We consider a freshly loaded job to no longer be in back-off, and the associated
    392      * standby bucket is whatever the OS thinks it should be at this moment.
    393      */
    394     public JobStatus(JobInfo job, int callingUid, String sourcePkgName, int sourceUserId,
    395             int standbyBucket, long baseHeartbeat, String sourceTag,
    396             long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
    397             long lastSuccessfulRunTime, long lastFailedRunTime,
    398             Pair<Long, Long> persistedExecutionTimesUTC,
    399             int innerFlags) {
    400         this(job, callingUid, resolveTargetSdkVersion(job), sourcePkgName, sourceUserId,
    401                 standbyBucket, baseHeartbeat,
    402                 sourceTag, 0,
    403                 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
    404                 lastSuccessfulRunTime, lastFailedRunTime, innerFlags);
    405 
    406         // Only during initial inflation do we record the UTC-timebase execution bounds
    407         // read from the persistent store.  If we ever have to recreate the JobStatus on
    408         // the fly, it means we're rescheduling the job; and this means that the calculated
    409         // elapsed timebase bounds intrinsically become correct.
    410         this.mPersistedUtcTimes = persistedExecutionTimesUTC;
    411         if (persistedExecutionTimesUTC != null) {
    412             if (DEBUG) {
    413                 Slog.i(TAG, "+ restored job with RTC times because of bad boot clock");
    414             }
    415         }
    416     }
    417 
    418     /** Create a new job to be rescheduled with the provided parameters. */
    419     public JobStatus(JobStatus rescheduling, long newBaseHeartbeat,
    420             long newEarliestRuntimeElapsedMillis,
    421             long newLatestRuntimeElapsedMillis, int backoffAttempt,
    422             long lastSuccessfulRunTime, long lastFailedRunTime) {
    423         this(rescheduling.job, rescheduling.getUid(), resolveTargetSdkVersion(rescheduling.job),
    424                 rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(),
    425                 rescheduling.getStandbyBucket(), newBaseHeartbeat,
    426                 rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis,
    427                 newLatestRuntimeElapsedMillis,
    428                 lastSuccessfulRunTime, lastFailedRunTime, rescheduling.getInternalFlags());
    429     }
    430 
    431     /**
    432      * Create a newly scheduled job.
    433      * @param callingUid Uid of the package that scheduled this job.
    434      * @param sourcePkg Package name of the app that will actually run the job.  Null indicates
    435      *     that the calling package is the source.
    436      * @param sourceUserId User id for whom this job is scheduled. -1 indicates this is same as the
    437      *     caller.
    438      */
    439     public static JobStatus createFromJobInfo(JobInfo job, int callingUid, String sourcePkg,
    440             int sourceUserId, String tag) {
    441         final long elapsedNow = sElapsedRealtimeClock.millis();
    442         final long earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis;
    443         if (job.isPeriodic()) {
    444             latestRunTimeElapsedMillis = elapsedNow + job.getIntervalMillis();
    445             earliestRunTimeElapsedMillis = latestRunTimeElapsedMillis - job.getFlexMillis();
    446         } else {
    447             earliestRunTimeElapsedMillis = job.hasEarlyConstraint() ?
    448                     elapsedNow + job.getMinLatencyMillis() : NO_EARLIEST_RUNTIME;
    449             latestRunTimeElapsedMillis = job.hasLateConstraint() ?
    450                     elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
    451         }
    452         String jobPackage = (sourcePkg != null) ? sourcePkg : job.getService().getPackageName();
    453 
    454         int standbyBucket = JobSchedulerService.standbyBucketForPackage(jobPackage,
    455                 sourceUserId, elapsedNow);
    456         JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
    457         long currentHeartbeat = js != null
    458                 ? js.baseHeartbeatForApp(jobPackage, sourceUserId, standbyBucket)
    459                 : 0;
    460         return new JobStatus(job, callingUid, resolveTargetSdkVersion(job), sourcePkg, sourceUserId,
    461                 standbyBucket, currentHeartbeat, tag, 0,
    462                 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
    463                 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */,
    464                 /*innerFlags=*/ 0);
    465     }
    466 
    467     public void enqueueWorkLocked(IActivityManager am, JobWorkItem work) {
    468         if (pendingWork == null) {
    469             pendingWork = new ArrayList<>();
    470         }
    471         work.setWorkId(nextPendingWorkId);
    472         nextPendingWorkId++;
    473         if (work.getIntent() != null
    474                 && GrantedUriPermissions.checkGrantFlags(work.getIntent().getFlags())) {
    475             work.setGrants(GrantedUriPermissions.createFromIntent(am, work.getIntent(), sourceUid,
    476                     sourcePackageName, sourceUserId, toShortString()));
    477         }
    478         pendingWork.add(work);
    479         updateEstimatedNetworkBytesLocked();
    480     }
    481 
    482     public JobWorkItem dequeueWorkLocked() {
    483         if (pendingWork != null && pendingWork.size() > 0) {
    484             JobWorkItem work = pendingWork.remove(0);
    485             if (work != null) {
    486                 if (executingWork == null) {
    487                     executingWork = new ArrayList<>();
    488                 }
    489                 executingWork.add(work);
    490                 work.bumpDeliveryCount();
    491             }
    492             updateEstimatedNetworkBytesLocked();
    493             return work;
    494         }
    495         return null;
    496     }
    497 
    498     public boolean hasWorkLocked() {
    499         return (pendingWork != null && pendingWork.size() > 0) || hasExecutingWorkLocked();
    500     }
    501 
    502     public boolean hasExecutingWorkLocked() {
    503         return executingWork != null && executingWork.size() > 0;
    504     }
    505 
    506     private static void ungrantWorkItem(IActivityManager am, JobWorkItem work) {
    507         if (work.getGrants() != null) {
    508             ((GrantedUriPermissions)work.getGrants()).revoke(am);
    509         }
    510     }
    511 
    512     public boolean completeWorkLocked(IActivityManager am, int workId) {
    513         if (executingWork != null) {
    514             final int N = executingWork.size();
    515             for (int i = 0; i < N; i++) {
    516                 JobWorkItem work = executingWork.get(i);
    517                 if (work.getWorkId() == workId) {
    518                     executingWork.remove(i);
    519                     ungrantWorkItem(am, work);
    520                     return true;
    521                 }
    522             }
    523         }
    524         return false;
    525     }
    526 
    527     private static void ungrantWorkList(IActivityManager am, ArrayList<JobWorkItem> list) {
    528         if (list != null) {
    529             final int N = list.size();
    530             for (int i = 0; i < N; i++) {
    531                 ungrantWorkItem(am, list.get(i));
    532             }
    533         }
    534     }
    535 
    536     public void stopTrackingJobLocked(IActivityManager am, JobStatus incomingJob) {
    537         if (incomingJob != null) {
    538             // We are replacing with a new job -- transfer the work!  We do any executing
    539             // work first, since that was originally at the front of the pending work.
    540             if (executingWork != null && executingWork.size() > 0) {
    541                 incomingJob.pendingWork = executingWork;
    542             }
    543             if (incomingJob.pendingWork == null) {
    544                 incomingJob.pendingWork = pendingWork;
    545             } else if (pendingWork != null && pendingWork.size() > 0) {
    546                 incomingJob.pendingWork.addAll(pendingWork);
    547             }
    548             pendingWork = null;
    549             executingWork = null;
    550             incomingJob.nextPendingWorkId = nextPendingWorkId;
    551             incomingJob.updateEstimatedNetworkBytesLocked();
    552         } else {
    553             // We are completely stopping the job...  need to clean up work.
    554             ungrantWorkList(am, pendingWork);
    555             pendingWork = null;
    556             ungrantWorkList(am, executingWork);
    557             executingWork = null;
    558         }
    559         updateEstimatedNetworkBytesLocked();
    560     }
    561 
    562     public void prepareLocked(IActivityManager am) {
    563         if (prepared) {
    564             Slog.wtf(TAG, "Already prepared: " + this);
    565             return;
    566         }
    567         prepared = true;
    568         if (DEBUG_PREPARE) {
    569             unpreparedPoint = null;
    570         }
    571         final ClipData clip = job.getClipData();
    572         if (clip != null) {
    573             uriPerms = GrantedUriPermissions.createFromClip(am, clip, sourceUid, sourcePackageName,
    574                     sourceUserId, job.getClipGrantFlags(), toShortString());
    575         }
    576     }
    577 
    578     public void unprepareLocked(IActivityManager am) {
    579         if (!prepared) {
    580             Slog.wtf(TAG, "Hasn't been prepared: " + this);
    581             if (DEBUG_PREPARE && unpreparedPoint != null) {
    582                 Slog.e(TAG, "Was already unprepared at ", unpreparedPoint);
    583             }
    584             return;
    585         }
    586         prepared = false;
    587         if (DEBUG_PREPARE) {
    588             unpreparedPoint = new Throwable().fillInStackTrace();
    589         }
    590         if (uriPerms != null) {
    591             uriPerms.revoke(am);
    592             uriPerms = null;
    593         }
    594     }
    595 
    596     public boolean isPreparedLocked() {
    597         return prepared;
    598     }
    599 
    600     public JobInfo getJob() {
    601         return job;
    602     }
    603 
    604     public int getJobId() {
    605         return job.getId();
    606     }
    607 
    608     public int getTargetSdkVersion() {
    609         return targetSdkVersion;
    610     }
    611 
    612     public void printUniqueId(PrintWriter pw) {
    613         UserHandle.formatUid(pw, callingUid);
    614         pw.print("/");
    615         pw.print(job.getId());
    616     }
    617 
    618     public int getNumFailures() {
    619         return numFailures;
    620     }
    621 
    622     public ComponentName getServiceComponent() {
    623         return job.getService();
    624     }
    625 
    626     public String getSourcePackageName() {
    627         return sourcePackageName;
    628     }
    629 
    630     public int getSourceUid() {
    631         return sourceUid;
    632     }
    633 
    634     public int getSourceUserId() {
    635         return sourceUserId;
    636     }
    637 
    638     public int getUserId() {
    639         return UserHandle.getUserId(callingUid);
    640     }
    641 
    642     public int getStandbyBucket() {
    643         return standbyBucket;
    644     }
    645 
    646     public long getBaseHeartbeat() {
    647         return baseHeartbeat;
    648     }
    649 
    650     // Called only by the standby monitoring code
    651     public void setStandbyBucket(int newBucket) {
    652         standbyBucket = newBucket;
    653     }
    654 
    655     // Called only by the standby monitoring code
    656     public long getWhenStandbyDeferred() {
    657         return whenStandbyDeferred;
    658     }
    659 
    660     // Called only by the standby monitoring code
    661     public void setWhenStandbyDeferred(long now) {
    662         whenStandbyDeferred = now;
    663     }
    664 
    665     public String getSourceTag() {
    666         return sourceTag;
    667     }
    668 
    669     public int getUid() {
    670         return callingUid;
    671     }
    672 
    673     public String getBatteryName() {
    674         return batteryName;
    675     }
    676 
    677     public String getTag() {
    678         return tag;
    679     }
    680 
    681     public int getPriority() {
    682         return job.getPriority();
    683     }
    684 
    685     public int getFlags() {
    686         return job.getFlags();
    687     }
    688 
    689     public int getInternalFlags() {
    690         return mInternalFlags;
    691     }
    692 
    693     public void addInternalFlags(int flags) {
    694         mInternalFlags |= flags;
    695     }
    696 
    697     public void maybeAddForegroundExemption(Predicate<Integer> uidForegroundChecker) {
    698         // Jobs with time constraints shouldn't be exempted.
    699         if (job.hasEarlyConstraint() || job.hasLateConstraint()) {
    700             return;
    701         }
    702         // Already exempted, skip the foreground check.
    703         if ((mInternalFlags & INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION) != 0) {
    704             return;
    705         }
    706         if (uidForegroundChecker.test(getSourceUid())) {
    707             addInternalFlags(INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION);
    708         }
    709     }
    710 
    711     private void updateEstimatedNetworkBytesLocked() {
    712         totalNetworkBytes = computeEstimatedNetworkBytesLocked();
    713     }
    714 
    715     private long computeEstimatedNetworkBytesLocked() {
    716         // If any component of the job has unknown usage, we don't have a
    717         // complete picture of what data will be used, and we have to treat the
    718         // entire job as unknown.
    719         long totalNetworkBytes = 0;
    720         long networkBytes = job.getEstimatedNetworkBytes();
    721         if (networkBytes == JobInfo.NETWORK_BYTES_UNKNOWN) {
    722             return JobInfo.NETWORK_BYTES_UNKNOWN;
    723         } else {
    724             totalNetworkBytes += networkBytes;
    725         }
    726         if (pendingWork != null) {
    727             for (int i = 0; i < pendingWork.size(); i++) {
    728                 networkBytes = pendingWork.get(i).getEstimatedNetworkBytes();
    729                 if (networkBytes == JobInfo.NETWORK_BYTES_UNKNOWN) {
    730                     return JobInfo.NETWORK_BYTES_UNKNOWN;
    731                 } else {
    732                     totalNetworkBytes += networkBytes;
    733                 }
    734             }
    735         }
    736         return totalNetworkBytes;
    737     }
    738 
    739     public long getEstimatedNetworkBytes() {
    740         return totalNetworkBytes;
    741     }
    742 
    743     /** Does this job have any sort of networking constraint? */
    744     public boolean hasConnectivityConstraint() {
    745         return (requiredConstraints&CONSTRAINT_CONNECTIVITY) != 0;
    746     }
    747 
    748     public boolean hasChargingConstraint() {
    749         return (requiredConstraints&CONSTRAINT_CHARGING) != 0;
    750     }
    751 
    752     public boolean hasBatteryNotLowConstraint() {
    753         return (requiredConstraints&CONSTRAINT_BATTERY_NOT_LOW) != 0;
    754     }
    755 
    756     public boolean hasPowerConstraint() {
    757         return (requiredConstraints&(CONSTRAINT_CHARGING|CONSTRAINT_BATTERY_NOT_LOW)) != 0;
    758     }
    759 
    760     public boolean hasStorageNotLowConstraint() {
    761         return (requiredConstraints&CONSTRAINT_STORAGE_NOT_LOW) != 0;
    762     }
    763 
    764     public boolean hasTimingDelayConstraint() {
    765         return (requiredConstraints&CONSTRAINT_TIMING_DELAY) != 0;
    766     }
    767 
    768     public boolean hasDeadlineConstraint() {
    769         return (requiredConstraints&CONSTRAINT_DEADLINE) != 0;
    770     }
    771 
    772     public boolean hasIdleConstraint() {
    773         return (requiredConstraints&CONSTRAINT_IDLE) != 0;
    774     }
    775 
    776     public boolean hasContentTriggerConstraint() {
    777         return (requiredConstraints&CONSTRAINT_CONTENT_TRIGGER) != 0;
    778     }
    779 
    780     public long getTriggerContentUpdateDelay() {
    781         long time = job.getTriggerContentUpdateDelay();
    782         if (time < 0) {
    783             return DEFAULT_TRIGGER_UPDATE_DELAY;
    784         }
    785         return Math.max(time, MIN_TRIGGER_UPDATE_DELAY);
    786     }
    787 
    788     public long getTriggerContentMaxDelay() {
    789         long time = job.getTriggerContentMaxDelay();
    790         if (time < 0) {
    791             return DEFAULT_TRIGGER_MAX_DELAY;
    792         }
    793         return Math.max(time, MIN_TRIGGER_MAX_DELAY);
    794     }
    795 
    796     public boolean isPersisted() {
    797         return job.isPersisted();
    798     }
    799 
    800     public long getEarliestRunTime() {
    801         return earliestRunTimeElapsedMillis;
    802     }
    803 
    804     public long getLatestRunTimeElapsed() {
    805         return latestRunTimeElapsedMillis;
    806     }
    807 
    808     /**
    809      * Return the fractional position of "now" within the "run time" window of
    810      * this job.
    811      * <p>
    812      * For example, if the earliest run time was 10 minutes ago, and the latest
    813      * run time is 30 minutes from now, this would return 0.25.
    814      * <p>
    815      * If the job has no window defined, returns 1. When only an earliest or
    816      * latest time is defined, it's treated as an infinitely small window at
    817      * that time.
    818      */
    819     public float getFractionRunTime() {
    820         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
    821         if (earliestRunTimeElapsedMillis == 0 && latestRunTimeElapsedMillis == Long.MAX_VALUE) {
    822             return 1;
    823         } else if (earliestRunTimeElapsedMillis == 0) {
    824             return now >= latestRunTimeElapsedMillis ? 1 : 0;
    825         } else if (latestRunTimeElapsedMillis == Long.MAX_VALUE) {
    826             return now >= earliestRunTimeElapsedMillis ? 1 : 0;
    827         } else {
    828             if (now <= earliestRunTimeElapsedMillis) {
    829                 return 0;
    830             } else if (now >= latestRunTimeElapsedMillis) {
    831                 return 1;
    832             } else {
    833                 return (float) (now - earliestRunTimeElapsedMillis)
    834                         / (float) (latestRunTimeElapsedMillis - earliestRunTimeElapsedMillis);
    835             }
    836         }
    837     }
    838 
    839     public Pair<Long, Long> getPersistedUtcTimes() {
    840         return mPersistedUtcTimes;
    841     }
    842 
    843     public void clearPersistedUtcTimes() {
    844         mPersistedUtcTimes = null;
    845     }
    846 
    847     boolean setChargingConstraintSatisfied(boolean state) {
    848         return setConstraintSatisfied(CONSTRAINT_CHARGING, state);
    849     }
    850 
    851     boolean setBatteryNotLowConstraintSatisfied(boolean state) {
    852         return setConstraintSatisfied(CONSTRAINT_BATTERY_NOT_LOW, state);
    853     }
    854 
    855     boolean setStorageNotLowConstraintSatisfied(boolean state) {
    856         return setConstraintSatisfied(CONSTRAINT_STORAGE_NOT_LOW, state);
    857     }
    858 
    859     boolean setTimingDelayConstraintSatisfied(boolean state) {
    860         return setConstraintSatisfied(CONSTRAINT_TIMING_DELAY, state);
    861     }
    862 
    863     boolean setDeadlineConstraintSatisfied(boolean state) {
    864         return setConstraintSatisfied(CONSTRAINT_DEADLINE, state);
    865     }
    866 
    867     boolean setIdleConstraintSatisfied(boolean state) {
    868         return setConstraintSatisfied(CONSTRAINT_IDLE, state);
    869     }
    870 
    871     boolean setConnectivityConstraintSatisfied(boolean state) {
    872         return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, state);
    873     }
    874 
    875     boolean setContentTriggerConstraintSatisfied(boolean state) {
    876         return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, state);
    877     }
    878 
    879     boolean setDeviceNotDozingConstraintSatisfied(boolean state, boolean whitelisted) {
    880         dozeWhitelisted = whitelisted;
    881         return setConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING, state);
    882     }
    883 
    884     boolean setBackgroundNotRestrictedConstraintSatisfied(boolean state) {
    885         return setConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED, state);
    886     }
    887 
    888     boolean setUidActive(final boolean newActiveState) {
    889         if (newActiveState != uidActive) {
    890             uidActive = newActiveState;
    891             return true;
    892         }
    893         return false; /* unchanged */
    894     }
    895 
    896     boolean setConstraintSatisfied(int constraint, boolean state) {
    897         boolean old = (satisfiedConstraints&constraint) != 0;
    898         if (old == state) {
    899             return false;
    900         }
    901         satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0);
    902         return true;
    903     }
    904 
    905     boolean isConstraintSatisfied(int constraint) {
    906         return (satisfiedConstraints&constraint) != 0;
    907     }
    908 
    909     boolean clearTrackingController(int which) {
    910         if ((trackingControllers&which) != 0) {
    911             trackingControllers &= ~which;
    912             return true;
    913         }
    914         return false;
    915     }
    916 
    917     void setTrackingController(int which) {
    918         trackingControllers |= which;
    919     }
    920 
    921     public long getLastSuccessfulRunTime() {
    922         return mLastSuccessfulRunTime;
    923     }
    924 
    925     public long getLastFailedRunTime() {
    926         return mLastFailedRunTime;
    927     }
    928 
    929     /**
    930      * @return Whether or not this job is ready to run, based on its requirements. This is true if
    931      * the constraints are satisfied <strong>or</strong> the deadline on the job has expired.
    932      * TODO: This function is called a *lot*.  We should probably just have it check an
    933      * already-computed boolean, which we updated whenever we see one of the states it depends
    934      * on here change.
    935      */
    936     public boolean isReady() {
    937         // Deadline constraint trumps other constraints (except for periodic jobs where deadline
    938         // is an implementation detail. A periodic job should only run if its constraints are
    939         // satisfied).
    940         // AppNotIdle implicit constraint must be satisfied
    941         // DeviceNotDozing implicit constraint must be satisfied
    942         // NotRestrictedInBackground implicit constraint must be satisfied
    943         final boolean deadlineSatisfied = (!job.isPeriodic() && hasDeadlineConstraint()
    944                 && (satisfiedConstraints & CONSTRAINT_DEADLINE) != 0);
    945         final boolean notDozing = (satisfiedConstraints & CONSTRAINT_DEVICE_NOT_DOZING) != 0
    946                 || (job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
    947         final boolean notRestrictedInBg =
    948                 (satisfiedConstraints & CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0;
    949         return (isConstraintsSatisfied() || deadlineSatisfied) && notDozing && notRestrictedInBg;
    950     }
    951 
    952     static final int CONSTRAINTS_OF_INTEREST = CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW
    953             | CONSTRAINT_STORAGE_NOT_LOW | CONSTRAINT_TIMING_DELAY | CONSTRAINT_CONNECTIVITY
    954             | CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER;
    955 
    956     // Soft override covers all non-"functional" constraints
    957     static final int SOFT_OVERRIDE_CONSTRAINTS =
    958             CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW | CONSTRAINT_STORAGE_NOT_LOW
    959                     | CONSTRAINT_TIMING_DELAY | CONSTRAINT_IDLE;
    960 
    961     /**
    962      * @return Whether the constraints set on this job are satisfied.
    963      */
    964     public boolean isConstraintsSatisfied() {
    965         if (overrideState == OVERRIDE_FULL) {
    966             // force override: the job is always runnable
    967             return true;
    968         }
    969 
    970         final int req = requiredConstraints & CONSTRAINTS_OF_INTEREST;
    971 
    972         int sat = satisfiedConstraints & CONSTRAINTS_OF_INTEREST;
    973         if (overrideState == OVERRIDE_SOFT) {
    974             // override: pretend all 'soft' requirements are satisfied
    975             sat |= (requiredConstraints & SOFT_OVERRIDE_CONSTRAINTS);
    976         }
    977 
    978         return (sat & req) == req;
    979     }
    980 
    981     public boolean matches(int uid, int jobId) {
    982         return this.job.getId() == jobId && this.callingUid == uid;
    983     }
    984 
    985     @Override
    986     public String toString() {
    987         StringBuilder sb = new StringBuilder(128);
    988         sb.append("JobStatus{");
    989         sb.append(Integer.toHexString(System.identityHashCode(this)));
    990         sb.append(" #");
    991         UserHandle.formatUid(sb, callingUid);
    992         sb.append("/");
    993         sb.append(job.getId());
    994         sb.append(' ');
    995         sb.append(batteryName);
    996         sb.append(" u=");
    997         sb.append(getUserId());
    998         sb.append(" s=");
    999         sb.append(getSourceUid());
   1000         if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME
   1001                 || latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
   1002             long now = sElapsedRealtimeClock.millis();
   1003             sb.append(" TIME=");
   1004             formatRunTime(sb, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, now);
   1005             sb.append(":");
   1006             formatRunTime(sb, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, now);
   1007         }
   1008         if (job.getRequiredNetwork() != null) {
   1009             sb.append(" NET");
   1010         }
   1011         if (job.isRequireCharging()) {
   1012             sb.append(" CHARGING");
   1013         }
   1014         if (job.isRequireBatteryNotLow()) {
   1015             sb.append(" BATNOTLOW");
   1016         }
   1017         if (job.isRequireStorageNotLow()) {
   1018             sb.append(" STORENOTLOW");
   1019         }
   1020         if (job.isRequireDeviceIdle()) {
   1021             sb.append(" IDLE");
   1022         }
   1023         if (job.isPeriodic()) {
   1024             sb.append(" PERIODIC");
   1025         }
   1026         if (job.isPersisted()) {
   1027             sb.append(" PERSISTED");
   1028         }
   1029         if ((satisfiedConstraints&CONSTRAINT_DEVICE_NOT_DOZING) == 0) {
   1030             sb.append(" WAIT:DEV_NOT_DOZING");
   1031         }
   1032         if (job.getTriggerContentUris() != null) {
   1033             sb.append(" URIS=");
   1034             sb.append(Arrays.toString(job.getTriggerContentUris()));
   1035         }
   1036         if (numFailures != 0) {
   1037             sb.append(" failures=");
   1038             sb.append(numFailures);
   1039         }
   1040         if (isReady()) {
   1041             sb.append(" READY");
   1042         }
   1043         sb.append("}");
   1044         return sb.toString();
   1045     }
   1046 
   1047     private void formatRunTime(PrintWriter pw, long runtime, long  defaultValue, long now) {
   1048         if (runtime == defaultValue) {
   1049             pw.print("none");
   1050         } else {
   1051             TimeUtils.formatDuration(runtime - now, pw);
   1052         }
   1053     }
   1054 
   1055     private void formatRunTime(StringBuilder sb, long runtime, long  defaultValue, long now) {
   1056         if (runtime == defaultValue) {
   1057             sb.append("none");
   1058         } else {
   1059             TimeUtils.formatDuration(runtime - now, sb);
   1060         }
   1061     }
   1062 
   1063     /**
   1064      * Convenience function to identify a job uniquely without pulling all the data that
   1065      * {@link #toString()} returns.
   1066      */
   1067     public String toShortString() {
   1068         StringBuilder sb = new StringBuilder();
   1069         sb.append(Integer.toHexString(System.identityHashCode(this)));
   1070         sb.append(" #");
   1071         UserHandle.formatUid(sb, callingUid);
   1072         sb.append("/");
   1073         sb.append(job.getId());
   1074         sb.append(' ');
   1075         sb.append(batteryName);
   1076         return sb.toString();
   1077     }
   1078 
   1079     /**
   1080      * Convenience function to identify a job uniquely without pulling all the data that
   1081      * {@link #toString()} returns.
   1082      */
   1083     public String toShortStringExceptUniqueId() {
   1084         StringBuilder sb = new StringBuilder();
   1085         sb.append(Integer.toHexString(System.identityHashCode(this)));
   1086         sb.append(' ');
   1087         sb.append(batteryName);
   1088         return sb.toString();
   1089     }
   1090 
   1091     /**
   1092      * Convenience function to dump data that identifies a job uniquely to proto. This is intended
   1093      * to mimic {@link #toShortString}.
   1094      */
   1095     public void writeToShortProto(ProtoOutputStream proto, long fieldId) {
   1096         final long token = proto.start(fieldId);
   1097 
   1098         proto.write(JobStatusShortInfoProto.CALLING_UID, callingUid);
   1099         proto.write(JobStatusShortInfoProto.JOB_ID, job.getId());
   1100         proto.write(JobStatusShortInfoProto.BATTERY_NAME, batteryName);
   1101 
   1102         proto.end(token);
   1103     }
   1104 
   1105     void dumpConstraints(PrintWriter pw, int constraints) {
   1106         if ((constraints&CONSTRAINT_CHARGING) != 0) {
   1107             pw.print(" CHARGING");
   1108         }
   1109         if ((constraints& CONSTRAINT_BATTERY_NOT_LOW) != 0) {
   1110             pw.print(" BATTERY_NOT_LOW");
   1111         }
   1112         if ((constraints& CONSTRAINT_STORAGE_NOT_LOW) != 0) {
   1113             pw.print(" STORAGE_NOT_LOW");
   1114         }
   1115         if ((constraints&CONSTRAINT_TIMING_DELAY) != 0) {
   1116             pw.print(" TIMING_DELAY");
   1117         }
   1118         if ((constraints&CONSTRAINT_DEADLINE) != 0) {
   1119             pw.print(" DEADLINE");
   1120         }
   1121         if ((constraints&CONSTRAINT_IDLE) != 0) {
   1122             pw.print(" IDLE");
   1123         }
   1124         if ((constraints&CONSTRAINT_CONNECTIVITY) != 0) {
   1125             pw.print(" CONNECTIVITY");
   1126         }
   1127         if ((constraints&CONSTRAINT_CONTENT_TRIGGER) != 0) {
   1128             pw.print(" CONTENT_TRIGGER");
   1129         }
   1130         if ((constraints&CONSTRAINT_DEVICE_NOT_DOZING) != 0) {
   1131             pw.print(" DEVICE_NOT_DOZING");
   1132         }
   1133         if ((constraints&CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0) {
   1134             pw.print(" BACKGROUND_NOT_RESTRICTED");
   1135         }
   1136         if (constraints != 0) {
   1137             pw.print(" [0x");
   1138             pw.print(Integer.toHexString(constraints));
   1139             pw.print("]");
   1140         }
   1141     }
   1142 
   1143     /** Writes constraints to the given repeating proto field. */
   1144     void dumpConstraints(ProtoOutputStream proto, long fieldId, int constraints) {
   1145         if ((constraints & CONSTRAINT_CHARGING) != 0) {
   1146             proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_CHARGING);
   1147         }
   1148         if ((constraints & CONSTRAINT_BATTERY_NOT_LOW) != 0) {
   1149             proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_BATTERY_NOT_LOW);
   1150         }
   1151         if ((constraints & CONSTRAINT_STORAGE_NOT_LOW) != 0) {
   1152             proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_STORAGE_NOT_LOW);
   1153         }
   1154         if ((constraints & CONSTRAINT_TIMING_DELAY) != 0) {
   1155             proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_TIMING_DELAY);
   1156         }
   1157         if ((constraints & CONSTRAINT_DEADLINE) != 0) {
   1158             proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_DEADLINE);
   1159         }
   1160         if ((constraints & CONSTRAINT_IDLE) != 0) {
   1161             proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_IDLE);
   1162         }
   1163         if ((constraints & CONSTRAINT_CONNECTIVITY) != 0) {
   1164             proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_CONNECTIVITY);
   1165         }
   1166         if ((constraints & CONSTRAINT_CONTENT_TRIGGER) != 0) {
   1167             proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_CONTENT_TRIGGER);
   1168         }
   1169         if ((constraints & CONSTRAINT_DEVICE_NOT_DOZING) != 0) {
   1170             proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_DEVICE_NOT_DOZING);
   1171         }
   1172     }
   1173 
   1174     private void dumpJobWorkItem(PrintWriter pw, String prefix, JobWorkItem work, int index) {
   1175         pw.print(prefix); pw.print("  #"); pw.print(index); pw.print(": #");
   1176         pw.print(work.getWorkId()); pw.print(" "); pw.print(work.getDeliveryCount());
   1177         pw.print("x "); pw.println(work.getIntent());
   1178         if (work.getGrants() != null) {
   1179             pw.print(prefix); pw.println("  URI grants:");
   1180             ((GrantedUriPermissions)work.getGrants()).dump(pw, prefix + "    ");
   1181         }
   1182     }
   1183 
   1184     private void dumpJobWorkItem(ProtoOutputStream proto, long fieldId, JobWorkItem work) {
   1185         final long token = proto.start(fieldId);
   1186 
   1187         proto.write(JobStatusDumpProto.JobWorkItem.WORK_ID, work.getWorkId());
   1188         proto.write(JobStatusDumpProto.JobWorkItem.DELIVERY_COUNT, work.getDeliveryCount());
   1189         if (work.getIntent() != null) {
   1190             work.getIntent().writeToProto(proto, JobStatusDumpProto.JobWorkItem.INTENT);
   1191         }
   1192         Object grants = work.getGrants();
   1193         if (grants != null) {
   1194             ((GrantedUriPermissions) grants).dump(proto, JobStatusDumpProto.JobWorkItem.URI_GRANTS);
   1195         }
   1196 
   1197         proto.end(token);
   1198     }
   1199 
   1200     // normalized bucket indices, not the AppStandby constants
   1201     private String bucketName(int bucket) {
   1202         switch (bucket) {
   1203             case 0: return "ACTIVE";
   1204             case 1: return "WORKING_SET";
   1205             case 2: return "FREQUENT";
   1206             case 3: return "RARE";
   1207             case 4: return "NEVER";
   1208             default:
   1209                 return "Unknown: " + bucket;
   1210         }
   1211     }
   1212 
   1213     private static int resolveTargetSdkVersion(JobInfo job) {
   1214         return LocalServices.getService(PackageManagerInternal.class)
   1215                 .getPackageTargetSdkVersion(job.getService().getPackageName());
   1216     }
   1217 
   1218     // Dumpsys infrastructure
   1219     public void dump(PrintWriter pw, String prefix, boolean full, long elapsedRealtimeMillis) {
   1220         pw.print(prefix); UserHandle.formatUid(pw, callingUid);
   1221         pw.print(" tag="); pw.println(tag);
   1222         pw.print(prefix);
   1223         pw.print("Source: uid="); UserHandle.formatUid(pw, getSourceUid());
   1224         pw.print(" user="); pw.print(getSourceUserId());
   1225         pw.print(" pkg="); pw.println(getSourcePackageName());
   1226         if (full) {
   1227             pw.print(prefix); pw.println("JobInfo:");
   1228             pw.print(prefix); pw.print("  Service: ");
   1229             pw.println(job.getService().flattenToShortString());
   1230             if (job.isPeriodic()) {
   1231                 pw.print(prefix); pw.print("  PERIODIC: interval=");
   1232                 TimeUtils.formatDuration(job.getIntervalMillis(), pw);
   1233                 pw.print(" flex="); TimeUtils.formatDuration(job.getFlexMillis(), pw);
   1234                 pw.println();
   1235             }
   1236             if (job.isPersisted()) {
   1237                 pw.print(prefix); pw.println("  PERSISTED");
   1238             }
   1239             if (job.getPriority() != 0) {
   1240                 pw.print(prefix); pw.print("  Priority: "); pw.println(job.getPriority());
   1241             }
   1242             if (job.getFlags() != 0) {
   1243                 pw.print(prefix); pw.print("  Flags: ");
   1244                 pw.println(Integer.toHexString(job.getFlags()));
   1245             }
   1246             if (getInternalFlags() != 0) {
   1247                 pw.print(prefix); pw.print("  Internal flags: ");
   1248                 pw.print(Integer.toHexString(getInternalFlags()));
   1249 
   1250                 if ((getInternalFlags()&INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION) != 0) {
   1251                     pw.print(" HAS_FOREGROUND_EXEMPTION");
   1252                 }
   1253                 pw.println();
   1254             }
   1255             pw.print(prefix); pw.print("  Requires: charging=");
   1256             pw.print(job.isRequireCharging()); pw.print(" batteryNotLow=");
   1257             pw.print(job.isRequireBatteryNotLow()); pw.print(" deviceIdle=");
   1258             pw.println(job.isRequireDeviceIdle());
   1259             if (job.getTriggerContentUris() != null) {
   1260                 pw.print(prefix); pw.println("  Trigger content URIs:");
   1261                 for (int i = 0; i < job.getTriggerContentUris().length; i++) {
   1262                     JobInfo.TriggerContentUri trig = job.getTriggerContentUris()[i];
   1263                     pw.print(prefix); pw.print("    ");
   1264                     pw.print(Integer.toHexString(trig.getFlags()));
   1265                     pw.print(' '); pw.println(trig.getUri());
   1266                 }
   1267                 if (job.getTriggerContentUpdateDelay() >= 0) {
   1268                     pw.print(prefix); pw.print("  Trigger update delay: ");
   1269                     TimeUtils.formatDuration(job.getTriggerContentUpdateDelay(), pw);
   1270                     pw.println();
   1271                 }
   1272                 if (job.getTriggerContentMaxDelay() >= 0) {
   1273                     pw.print(prefix); pw.print("  Trigger max delay: ");
   1274                     TimeUtils.formatDuration(job.getTriggerContentMaxDelay(), pw);
   1275                     pw.println();
   1276                 }
   1277             }
   1278             if (job.getExtras() != null && !job.getExtras().maybeIsEmpty()) {
   1279                 pw.print(prefix); pw.print("  Extras: ");
   1280                 pw.println(job.getExtras().toShortString());
   1281             }
   1282             if (job.getTransientExtras() != null && !job.getTransientExtras().maybeIsEmpty()) {
   1283                 pw.print(prefix); pw.print("  Transient extras: ");
   1284                 pw.println(job.getTransientExtras().toShortString());
   1285             }
   1286             if (job.getClipData() != null) {
   1287                 pw.print(prefix); pw.print("  Clip data: ");
   1288                 StringBuilder b = new StringBuilder(128);
   1289                 job.getClipData().toShortString(b);
   1290                 pw.println(b);
   1291             }
   1292             if (uriPerms != null) {
   1293                 pw.print(prefix); pw.println("  Granted URI permissions:");
   1294                 uriPerms.dump(pw, prefix + "  ");
   1295             }
   1296             if (job.getRequiredNetwork() != null) {
   1297                 pw.print(prefix); pw.print("  Network type: ");
   1298                 pw.println(job.getRequiredNetwork());
   1299             }
   1300             if (totalNetworkBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
   1301                 pw.print(prefix); pw.print("  Network bytes: ");
   1302                 pw.println(totalNetworkBytes);
   1303             }
   1304             if (job.getMinLatencyMillis() != 0) {
   1305                 pw.print(prefix); pw.print("  Minimum latency: ");
   1306                 TimeUtils.formatDuration(job.getMinLatencyMillis(), pw);
   1307                 pw.println();
   1308             }
   1309             if (job.getMaxExecutionDelayMillis() != 0) {
   1310                 pw.print(prefix); pw.print("  Max execution delay: ");
   1311                 TimeUtils.formatDuration(job.getMaxExecutionDelayMillis(), pw);
   1312                 pw.println();
   1313             }
   1314             pw.print(prefix); pw.print("  Backoff: policy="); pw.print(job.getBackoffPolicy());
   1315             pw.print(" initial="); TimeUtils.formatDuration(job.getInitialBackoffMillis(), pw);
   1316             pw.println();
   1317             if (job.hasEarlyConstraint()) {
   1318                 pw.print(prefix); pw.println("  Has early constraint");
   1319             }
   1320             if (job.hasLateConstraint()) {
   1321                 pw.print(prefix); pw.println("  Has late constraint");
   1322             }
   1323         }
   1324         pw.print(prefix); pw.print("Required constraints:");
   1325         dumpConstraints(pw, requiredConstraints);
   1326         pw.println();
   1327         if (full) {
   1328             pw.print(prefix); pw.print("Satisfied constraints:");
   1329             dumpConstraints(pw, satisfiedConstraints);
   1330             pw.println();
   1331             pw.print(prefix); pw.print("Unsatisfied constraints:");
   1332             dumpConstraints(pw, (requiredConstraints & ~satisfiedConstraints));
   1333             pw.println();
   1334             if (dozeWhitelisted) {
   1335                 pw.print(prefix); pw.println("Doze whitelisted: true");
   1336             }
   1337             if (uidActive) {
   1338                 pw.print(prefix); pw.println("Uid: active");
   1339             }
   1340         }
   1341         if (trackingControllers != 0) {
   1342             pw.print(prefix); pw.print("Tracking:");
   1343             if ((trackingControllers&TRACKING_BATTERY) != 0) pw.print(" BATTERY");
   1344             if ((trackingControllers&TRACKING_CONNECTIVITY) != 0) pw.print(" CONNECTIVITY");
   1345             if ((trackingControllers&TRACKING_CONTENT) != 0) pw.print(" CONTENT");
   1346             if ((trackingControllers&TRACKING_IDLE) != 0) pw.print(" IDLE");
   1347             if ((trackingControllers&TRACKING_STORAGE) != 0) pw.print(" STORAGE");
   1348             if ((trackingControllers&TRACKING_TIME) != 0) pw.print(" TIME");
   1349             pw.println();
   1350         }
   1351         if (changedAuthorities != null) {
   1352             pw.print(prefix); pw.println("Changed authorities:");
   1353             for (int i=0; i<changedAuthorities.size(); i++) {
   1354                 pw.print(prefix); pw.print("  "); pw.println(changedAuthorities.valueAt(i));
   1355             }
   1356             if (changedUris != null) {
   1357                 pw.print(prefix); pw.println("Changed URIs:");
   1358                 for (int i=0; i<changedUris.size(); i++) {
   1359                     pw.print(prefix); pw.print("  "); pw.println(changedUris.valueAt(i));
   1360                 }
   1361             }
   1362         }
   1363         if (network != null) {
   1364             pw.print(prefix); pw.print("Network: "); pw.println(network);
   1365         }
   1366         if (pendingWork != null && pendingWork.size() > 0) {
   1367             pw.print(prefix); pw.println("Pending work:");
   1368             for (int i = 0; i < pendingWork.size(); i++) {
   1369                 dumpJobWorkItem(pw, prefix, pendingWork.get(i), i);
   1370             }
   1371         }
   1372         if (executingWork != null && executingWork.size() > 0) {
   1373             pw.print(prefix); pw.println("Executing work:");
   1374             for (int i = 0; i < executingWork.size(); i++) {
   1375                 dumpJobWorkItem(pw, prefix, executingWork.get(i), i);
   1376             }
   1377         }
   1378         pw.print(prefix); pw.print("Standby bucket: ");
   1379         pw.println(bucketName(standbyBucket));
   1380         if (standbyBucket > 0) {
   1381             pw.print(prefix); pw.print("Base heartbeat: ");
   1382             pw.println(baseHeartbeat);
   1383         }
   1384         if (whenStandbyDeferred != 0) {
   1385             pw.print(prefix); pw.print("  Deferred since: ");
   1386             TimeUtils.formatDuration(whenStandbyDeferred, elapsedRealtimeMillis, pw);
   1387             pw.println();
   1388         }
   1389         pw.print(prefix); pw.print("Enqueue time: ");
   1390         TimeUtils.formatDuration(enqueueTime, elapsedRealtimeMillis, pw);
   1391         pw.println();
   1392         pw.print(prefix); pw.print("Run time: earliest=");
   1393         formatRunTime(pw, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, elapsedRealtimeMillis);
   1394         pw.print(", latest=");
   1395         formatRunTime(pw, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, elapsedRealtimeMillis);
   1396         pw.println();
   1397         if (numFailures != 0) {
   1398             pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures);
   1399         }
   1400         final Time t = new Time();
   1401         final String format = "%Y-%m-%d %H:%M:%S";
   1402         if (mLastSuccessfulRunTime != 0) {
   1403             pw.print(prefix); pw.print("Last successful run: ");
   1404             t.set(mLastSuccessfulRunTime);
   1405             pw.println(t.format(format));
   1406         }
   1407         if (mLastFailedRunTime != 0) {
   1408             pw.print(prefix); pw.print("Last failed run: ");
   1409             t.set(mLastFailedRunTime);
   1410             pw.println(t.format(format));
   1411         }
   1412     }
   1413 
   1414     public void dump(ProtoOutputStream proto, long fieldId, boolean full, long elapsedRealtimeMillis) {
   1415         final long token = proto.start(fieldId);
   1416 
   1417         proto.write(JobStatusDumpProto.CALLING_UID, callingUid);
   1418         proto.write(JobStatusDumpProto.TAG, tag);
   1419         proto.write(JobStatusDumpProto.SOURCE_UID, getSourceUid());
   1420         proto.write(JobStatusDumpProto.SOURCE_USER_ID, getSourceUserId());
   1421         proto.write(JobStatusDumpProto.SOURCE_PACKAGE_NAME, getSourcePackageName());
   1422         proto.write(JobStatusDumpProto.INTERNAL_FLAGS, getInternalFlags());
   1423 
   1424         if (full) {
   1425             final long jiToken = proto.start(JobStatusDumpProto.JOB_INFO);
   1426 
   1427             job.getService().writeToProto(proto, JobStatusDumpProto.JobInfo.SERVICE);
   1428 
   1429             proto.write(JobStatusDumpProto.JobInfo.IS_PERIODIC, job.isPeriodic());
   1430             proto.write(JobStatusDumpProto.JobInfo.PERIOD_INTERVAL_MS, job.getIntervalMillis());
   1431             proto.write(JobStatusDumpProto.JobInfo.PERIOD_FLEX_MS, job.getFlexMillis());
   1432 
   1433             proto.write(JobStatusDumpProto.JobInfo.IS_PERSISTED, job.isPersisted());
   1434             proto.write(JobStatusDumpProto.JobInfo.PRIORITY, job.getPriority());
   1435             proto.write(JobStatusDumpProto.JobInfo.FLAGS, job.getFlags());
   1436 
   1437             proto.write(JobStatusDumpProto.JobInfo.REQUIRES_CHARGING, job.isRequireCharging());
   1438             proto.write(JobStatusDumpProto.JobInfo.REQUIRES_BATTERY_NOT_LOW, job.isRequireBatteryNotLow());
   1439             proto.write(JobStatusDumpProto.JobInfo.REQUIRES_DEVICE_IDLE, job.isRequireDeviceIdle());
   1440 
   1441             if (job.getTriggerContentUris() != null) {
   1442                 for (int i = 0; i < job.getTriggerContentUris().length; i++) {
   1443                     final long tcuToken = proto.start(JobStatusDumpProto.JobInfo.TRIGGER_CONTENT_URIS);
   1444                     JobInfo.TriggerContentUri trig = job.getTriggerContentUris()[i];
   1445 
   1446                     proto.write(JobStatusDumpProto.JobInfo.TriggerContentUri.FLAGS, trig.getFlags());
   1447                     Uri u = trig.getUri();
   1448                     if (u != null) {
   1449                         proto.write(JobStatusDumpProto.JobInfo.TriggerContentUri.URI, u.toString());
   1450                     }
   1451 
   1452                     proto.end(tcuToken);
   1453                 }
   1454                 if (job.getTriggerContentUpdateDelay() >= 0) {
   1455                     proto.write(JobStatusDumpProto.JobInfo.TRIGGER_CONTENT_UPDATE_DELAY_MS,
   1456                             job.getTriggerContentUpdateDelay());
   1457                 }
   1458                 if (job.getTriggerContentMaxDelay() >= 0) {
   1459                     proto.write(JobStatusDumpProto.JobInfo.TRIGGER_CONTENT_MAX_DELAY_MS,
   1460                             job.getTriggerContentMaxDelay());
   1461                 }
   1462             }
   1463             if (job.getExtras() != null && !job.getExtras().maybeIsEmpty()) {
   1464                 job.getExtras().writeToProto(proto, JobStatusDumpProto.JobInfo.EXTRAS);
   1465             }
   1466             if (job.getTransientExtras() != null && !job.getTransientExtras().maybeIsEmpty()) {
   1467                 job.getTransientExtras().writeToProto(proto, JobStatusDumpProto.JobInfo.TRANSIENT_EXTRAS);
   1468             }
   1469             if (job.getClipData() != null) {
   1470                 job.getClipData().writeToProto(proto, JobStatusDumpProto.JobInfo.CLIP_DATA);
   1471             }
   1472             if (uriPerms != null) {
   1473                 uriPerms.dump(proto, JobStatusDumpProto.JobInfo.GRANTED_URI_PERMISSIONS);
   1474             }
   1475             if (job.getRequiredNetwork() != null) {
   1476                 job.getRequiredNetwork().writeToProto(proto, JobStatusDumpProto.JobInfo.REQUIRED_NETWORK);
   1477             }
   1478             if (totalNetworkBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
   1479                 proto.write(JobStatusDumpProto.JobInfo.TOTAL_NETWORK_BYTES, totalNetworkBytes);
   1480             }
   1481             proto.write(JobStatusDumpProto.JobInfo.MIN_LATENCY_MS, job.getMinLatencyMillis());
   1482             proto.write(JobStatusDumpProto.JobInfo.MAX_EXECUTION_DELAY_MS, job.getMaxExecutionDelayMillis());
   1483 
   1484             final long bpToken = proto.start(JobStatusDumpProto.JobInfo.BACKOFF_POLICY);
   1485             proto.write(JobStatusDumpProto.JobInfo.Backoff.POLICY, job.getBackoffPolicy());
   1486             proto.write(JobStatusDumpProto.JobInfo.Backoff.INITIAL_BACKOFF_MS,
   1487                     job.getInitialBackoffMillis());
   1488             proto.end(bpToken);
   1489 
   1490             proto.write(JobStatusDumpProto.JobInfo.HAS_EARLY_CONSTRAINT, job.hasEarlyConstraint());
   1491             proto.write(JobStatusDumpProto.JobInfo.HAS_LATE_CONSTRAINT, job.hasLateConstraint());
   1492 
   1493             proto.end(jiToken);
   1494         }
   1495 
   1496         dumpConstraints(proto, JobStatusDumpProto.REQUIRED_CONSTRAINTS, requiredConstraints);
   1497         if (full) {
   1498             dumpConstraints(proto, JobStatusDumpProto.SATISFIED_CONSTRAINTS, satisfiedConstraints);
   1499             dumpConstraints(proto, JobStatusDumpProto.UNSATISFIED_CONSTRAINTS,
   1500                     (requiredConstraints & ~satisfiedConstraints));
   1501             proto.write(JobStatusDumpProto.IS_DOZE_WHITELISTED, dozeWhitelisted);
   1502         }
   1503 
   1504         // Tracking controllers
   1505         if ((trackingControllers&TRACKING_BATTERY) != 0) {
   1506             proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS,
   1507                     JobStatusDumpProto.TRACKING_BATTERY);
   1508         }
   1509         if ((trackingControllers&TRACKING_CONNECTIVITY) != 0) {
   1510             proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS,
   1511                     JobStatusDumpProto.TRACKING_CONNECTIVITY);
   1512         }
   1513         if ((trackingControllers&TRACKING_CONTENT) != 0) {
   1514             proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS,
   1515                     JobStatusDumpProto.TRACKING_CONTENT);
   1516         }
   1517         if ((trackingControllers&TRACKING_IDLE) != 0) {
   1518             proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS,
   1519                     JobStatusDumpProto.TRACKING_IDLE);
   1520         }
   1521         if ((trackingControllers&TRACKING_STORAGE) != 0) {
   1522             proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS,
   1523                     JobStatusDumpProto.TRACKING_STORAGE);
   1524         }
   1525         if ((trackingControllers&TRACKING_TIME) != 0) {
   1526             proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS,
   1527                     JobStatusDumpProto.TRACKING_TIME);
   1528         }
   1529 
   1530         if (changedAuthorities != null) {
   1531             for (int k = 0; k < changedAuthorities.size(); k++) {
   1532                 proto.write(JobStatusDumpProto.CHANGED_AUTHORITIES, changedAuthorities.valueAt(k));
   1533             }
   1534         }
   1535         if (changedUris != null) {
   1536             for (int i = 0; i < changedUris.size(); i++) {
   1537                 Uri u = changedUris.valueAt(i);
   1538                 proto.write(JobStatusDumpProto.CHANGED_URIS, u.toString());
   1539             }
   1540         }
   1541 
   1542         if (network != null) {
   1543             network.writeToProto(proto, JobStatusDumpProto.NETWORK);
   1544         }
   1545 
   1546         if (pendingWork != null && pendingWork.size() > 0) {
   1547             for (int i = 0; i < pendingWork.size(); i++) {
   1548                 dumpJobWorkItem(proto, JobStatusDumpProto.PENDING_WORK, pendingWork.get(i));
   1549             }
   1550         }
   1551         if (executingWork != null && executingWork.size() > 0) {
   1552             for (int i = 0; i < executingWork.size(); i++) {
   1553                 dumpJobWorkItem(proto, JobStatusDumpProto.EXECUTING_WORK, executingWork.get(i));
   1554             }
   1555         }
   1556 
   1557         proto.write(JobStatusDumpProto.STANDBY_BUCKET, standbyBucket);
   1558         proto.write(JobStatusDumpProto.ENQUEUE_DURATION_MS, elapsedRealtimeMillis - enqueueTime);
   1559         if (earliestRunTimeElapsedMillis == NO_EARLIEST_RUNTIME) {
   1560             proto.write(JobStatusDumpProto.TIME_UNTIL_EARLIEST_RUNTIME_MS, 0);
   1561         } else {
   1562             proto.write(JobStatusDumpProto.TIME_UNTIL_EARLIEST_RUNTIME_MS,
   1563                     earliestRunTimeElapsedMillis - elapsedRealtimeMillis);
   1564         }
   1565         if (latestRunTimeElapsedMillis == NO_LATEST_RUNTIME) {
   1566             proto.write(JobStatusDumpProto.TIME_UNTIL_LATEST_RUNTIME_MS, 0);
   1567         } else {
   1568             proto.write(JobStatusDumpProto.TIME_UNTIL_LATEST_RUNTIME_MS,
   1569                     latestRunTimeElapsedMillis - elapsedRealtimeMillis);
   1570         }
   1571 
   1572         proto.write(JobStatusDumpProto.NUM_FAILURES, numFailures);
   1573         proto.write(JobStatusDumpProto.LAST_SUCCESSFUL_RUN_TIME, mLastSuccessfulRunTime);
   1574         proto.write(JobStatusDumpProto.LAST_FAILED_RUN_TIME, mLastFailedRunTime);
   1575 
   1576         proto.end(token);
   1577     }
   1578 }
   1579