零. JobSchedule机制
请参考:http://gityuan.com/2017/03/10/job_scheduler_service/
简单理解:
JobScheduleService作为系统服务,负责job的调度.
JobScheduler作为JobScheduleService系统服务的本地应用代理
JobService作为本地应用的回调服务供JobScheduleService回调
JobInfo 作为job的信息描述实体. 为上述job的传递,存储,执行提供信息支持.
一.JobService是什么?
Entry point for the callback from the {@link android.app.job.JobScheduler}.
This is the base class that handles asynchronous requests that were previously scheduled. You are responsible for overriding {@link JobService#onStartJob(JobParameters)}, which is where you will implement your job logic.
This service executes each incoming job on a {@link android.os.Handler} running on your application's main thread. This means that you must offload your execution logic to another thread/handler/{@link android.os.AsyncTask} of your choosing. Not doing so will result in blocking any future callbacks from the JobManager - specifically {@link #onStopJob(android.app.job.JobParameters)}, which is meant to inform you that the scheduling requirements are no longer being met.
public abstract class JobService extends Service {
private static final String TAG = "JobService";
/**
* Job services must be protected with this permission:
*
* <pre class="prettyprint">
* <service android:name="MyJobService"
* android:permission="android.permission.BIND_JOB_SERVICE" >
* ...
* </service>
* </pre>
*
* <p>If a job service is declared in the manifest but not protected with this
* permission, that service will be ignored by the system.
*/
public static final String PERMISSION_BIND =
"android.permission.BIND_JOB_SERVICE";
private JobServiceEngine mEngine;
/** @hide */
public final IBinder onBind(Intent intent) {
if (mEngine == null) {
mEngine = new JobServiceEngine(this) {
@Override
public boolean onStartJob(JobParameters params) {
return JobService.this.onStartJob(params);
}
@Override
public boolean onStopJob(JobParameters params) {
return JobService.this.onStopJob(params);
}
};
}
return mEngine.getBinder();
}
/**
* Call this to inform the JobScheduler that the job has finished its work. When the
* system receives this message, it releases the wakelock being held for the job.
* <p>
* You can request that the job be scheduled again by passing {@code true} as
* the <code>wantsReschedule</code> parameter. This will apply back-off policy
* for the job; this policy can be adjusted through the
* {@link android.app.job.JobInfo.Builder#setBackoffCriteria(long, int)} method
* when the job is originally scheduled. The job's initial
* requirements are preserved when jobs are rescheduled, regardless of backed-off
* policy.
* <p class="note">
* A job running while the device is dozing will not be rescheduled with the normal back-off
* policy. Instead, the job will be re-added to the queue and executed again during
* a future idle maintenance window.
* </p>
*
* @param params The parameters identifying this job, as supplied to
* the job in the {@link #onStartJob(JobParameters)} callback.
* @param wantsReschedule {@code true} if this job should be rescheduled according
* to the back-off criteria specified when it was first scheduled; {@code false}
* otherwise.
*/
public final void jobFinished(JobParameters params, boolean wantsReschedule) {
mEngine.jobFinished(params, wantsReschedule);
}
/**
* Called to indicate that the job has begun executing. Override this method with the
* logic for your job. Like all other component lifecycle callbacks, this method executes
* on your application's main thread.
* <p>
* Return {@code true} from this method if your job needs to continue running. If you
* do this, the job remains active until you call
* {@link #jobFinished(JobParameters, boolean)} to tell the system that it has completed
* its work, or until the job's recriteriaquired constraints are no longer satisfied. For
* example, if the job was scheduled using
* {@link JobInfo.Builder#setRequiresCharging(boolean) setRequiresCharging(true)},
* it will be immediately halted by the system if the user unplugs the device from power,
* the job's {@link #onStopJob(JobParameters)} callback will be invoked, and the app
* will be expected to shut down all ongoing work connected with that job.
* <p>
* The system holds a wakelock on behalf of your app as long as your job is executing.
* This wakelock is acquired before this method is invoked, and is not released until either
* you call {@link #jobFinished(JobParameters, boolean)}, or after the system invokes
* {@link #onStopJob(JobParameters)} to notify your job that it is being shut down
* prematurely.
* <p>
* Returning {@code false} from this method means your job is already finished. The
* system's wakelock for the job will be released, and {@link #onStopJob(JobParameters)}
* will not be invoked.
*
* @param params Parameters specifying info about this job, including the optional
* extras configured with {@link JobInfo.Builder#setExtras(android.os.PersistableBundle).
* This object serves to identify this specific running job instance when calling
* {@link #jobFinished(JobParameters, boolean)}.
* @return {@code true} if your service will continue running, using a separate thread
* when appropriate. {@code false} means that this job has completed its work.
*/
public abstract boolean onStartJob(JobParameters params);
/**
* This method is called if the system has determined that you must stop execution of your job
* even before you've had a chance to call {@link #jobFinished(JobParameters, boolean)}.
*
* <p>This will 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.
* <p>
* Once this method returns, 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.
* @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.
*/
public abstract boolean onStopJob(JobParameters params);
}
当手机灭屏状态下保持一段时间后,系统会进入休眠,一些后台运行的任务就可能得不到正常执行,比如网络下载中断,后台播放音乐暂停等。WakeLock正是为了解决这类问题,应用只要申请了WakeLock,那么在释放WakeLock之前,系统不会进入休眠,即使在灭屏的状态下,应用要执行的任务依旧不会被系统打断。
二, JobScheduler是什么?
This is an API for scheduling various types of jobs against the framework that will be executed in your application’s own process.
See {@link android.app.job.JobInfo} for more description of the types of jobs that can be run
and how to construct them. You will construct these JobInfo objects and pass them to the
JobScheduler with {@link #schedule(JobInfo)}.
When the criteria declared are met, the
system will execute this job on your application’s {@link android.app.job.JobService}.
You identify the service component that implements the logic for your job when you
construct the JobInfo using
{@link android.app.job.JobInfo.Builder#JobInfo.Builder(int,android.content.ComponentName)}.
-
- The framework will be intelligent about when it executes jobs, and attempt to batch
- and defer them as much as possible. Typically if you don’t specify a deadline on a job, it
- can be run at any moment depending on the current state of the JobScheduler’s internal queue.
-
* While a job is running, the system holds a wakelock on behalf of your app. For this reason, you do not need to take any action to guarantee that the device stays awake for the *duration of the job. *
You do not instantiate this class directly; instead, retrieve it through {@link android.content.Context#getSystemService Context.getSystemService(Context.JOB_SCHEDULER_SERVICE)}.
三, JobSchedulerService
JobScheduleService是系统处理Job的核心系统服务类,位于system_server进程;其在app进程常用的代理类为JobSchedule,(其中JobScheduleImpl实现JobSchedule).
1.下面是schedule的实际执行方法.
995 public int scheduleAsPackage(JobInfo job, JobWorkItem work, int uId, String packageName,
996 int userId, String tag) {
997 try {
998 if (ActivityManager.getService().isAppStartModeDisabled(uId,
999 job.getService().getPackageName())) {
1000 Slog.w(TAG, "Not scheduling job " + uId + ":" + job.toString()
1001 + " -- package not allowed to start");
1002 return JobScheduler.RESULT_FAILURE;
1003 }
1004 } catch (RemoteException e) {
1005 }
1006
1007 synchronized (mLock) {
1008 final JobStatus toCancel = mJobs.getJobByUidAndJobId(uId, job.getId());
1009
1010 if (work != null && toCancel != null) {
1011 // Fast path: we are adding work to an existing job, and the JobInfo is not
1012 // changing. We can just directly enqueue this work in to the job.
1013 if (toCancel.getJob().equals(job)) {
1014
1015 toCancel.enqueueWorkLocked(ActivityManager.getService(), work);
1016
1017 // If any of work item is enqueued when the source is in the foreground,
1018 // exempt the entire job.
1019 toCancel.maybeAddForegroundExemption(mIsUidActivePredicate);
1020
1021 return JobScheduler.RESULT_SUCCESS;
1022 }
1023 }
1024
1025 JobStatus jobStatus = JobStatus.createFromJobInfo(job, uId, packageName, userId, tag);
1026
1027 // Give exemption if the source is in the foreground just now.
1028 // Note if it's a sync job, this method is called on the handler so it's not exactly
1029 // the state when requestSync() was called, but that should be fine because of the
1030 // 1 minute foreground grace period.
1031 jobStatus.maybeAddForegroundExemption(mIsUidActivePredicate);
1032
1033 if (DEBUG) Slog.d(TAG, "SCHEDULE: " + jobStatus.toShortString());
1034 // Jobs on behalf of others don't apply to the per-app job cap
1035 if (ENFORCE_MAX_JOBS && packageName == null) {
1036 if (mJobs.countJobsForUid(uId) > MAX_JOBS_PER_APP) {
1037 Slog.w(TAG, "Too many jobs for uid " + uId);
1038 throw new IllegalStateException("Apps may not schedule more than "
1039 + MAX_JOBS_PER_APP + " distinct jobs");
1040 }
1041 }
1042
1043 // This may throw a SecurityException.
1044 jobStatus.prepareLocked(ActivityManager.getService());
1045
1046 if (work != null) {
1047 // If work has been supplied, enqueue it into the new job.
1048 jobStatus.enqueueWorkLocked(ActivityManager.getService(), work);
1049 }
1050
1051 if (toCancel != null) {
1052 // Implicitly replaces the existing job record with the new instance
1053 cancelJobImplLocked(toCancel, jobStatus, "job rescheduled by app");
1054 } else {
1055 startTrackingJobLocked(jobStatus, null);
1056 }
1057 StatsLog.write_non_chained(StatsLog.SCHEDULED_JOB_STATE_CHANGED,
1058 uId, null, jobStatus.getBatteryName(),
1059 StatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__SCHEDULED,
1060 JobProtoEnums.STOP_REASON_CANCELLED, jobStatus.getStandbyBucket(),
1061 jobStatus.getJobId());
1062
1063 // If the job is immediately ready to run, then we can just immediately
1064 // put it in the pending list and try to schedule it. This is especially
1065 // important for jobs with a 0 deadline constraint, since they will happen a fair
1066 // amount, we want to handle them as quickly as possible, and semantically we want to
1067 // make sure we have started holding the wake lock for the job before returning to
1068 // the caller.
1069 // If the job is not yet ready to run, there is nothing more to do -- we are
1070 // now just waiting for one of its controllers to change state and schedule
1071 // the job appropriately.
1072 if (isReadyToBeExecutedLocked(jobStatus)) {
1073 // This is a new job, we can just immediately put it on the pending
1074 // list and try to run it.
1075 mJobPackageTracker.notePending(jobStatus);
1076 addOrderedItem(mPendingJobs, jobStatus, mEnqueueTimeComparator);
1077 maybeRunPendingJobsLocked();
1078 } else {
1079 evaluateControllerStatesLocked(jobStatus);
1080 }
1081 }
1082 return JobScheduler.RESULT_SUCCESS;
1083 }
三.参考
1.https://developer.android.com/reference/android/app/job/JobService
1+.Android 功耗分析之wakelock
https://www.jianshu.com/p/67ccdac38271
1++.Android电源管理基础知识整理
https://www.cnblogs.com/linhaostudy/p/12119487.html
2.理解JobScheduler机制
http://gityuan.com/2017/03/10/job_scheduler_service/
3.深入理解JobScheduler与JobService的使用
https://www.jianshu.com/p/1f2103d3d2a2
4.后台任务 - 保持设备唤醒状态
https://www.jianshu.com/p/5db15ce7de1e