基于 Android 7.1.1 源码分析
前言
当任务完成时,应用需要手动调用 jobFinished 方法,这个方法是属于 JobService 的:
public final void jobFinished(JobParameters params, boolean needsReschedule) {
ensureHandler();
Message m = Message.obtain(mHandler, MSG_JOB_FINISHED, params);
m.arg2 = needsReschedule ? 1 : 0;
m.sendToTarget();
}
其实,参数很简单,这个消息 MSG_JOB_FINISHED 会发送到 JobHandler 中!
1 JS.JobHandler
进入 JobHandler 中来看看:
class JobHandler extends Handler {
JobHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
final JobParameters params = (JobParameters) msg.obj;
switch (msg.what) {
- ... ... ... ...
case MSG_JOB_FINISHED:
final boolean needsReschedule = (msg.arg2 == 1);
// callback 是 JobServiceContext
IJobCallback callback = params.getCallback();
if (callback != null) {
try {
callback.jobFinished(params.getJobId(), needsReschedule);
} catch (RemoteException e) {
Log.e(TAG, "Error reporting job finish to system: binder has gone" +
" away.");}
} else {
Log.e(TAG, "finishJob() called for a nonexistent job id.");
}
break;
default:
Log.e(TAG, "Unrecognised message received.");
break;
}
}
}
这里调用了 JObServiceContext 的 jobFinished 方法!
2 JSC.jobFinished
我们来看看 JobServiceContext 的 jobFinished 方法:
@Override
public void jobFinished(int jobId, boolean reschedule) {
if (!verifyCallingUid()) {
return;
}
mCallbackHandler.obtainMessage(MSG_CALLBACK, jobId, reschedule ? 1 : 0)
.sendToTarget();
}
这里先调用了 JobServiceContext 的 verifyCallingUid,校验 uid!
private boolean verifyCallingUid() {
synchronized (mLock) {
if (mRunningJob == null || Binder.getCallingUid() != mRunningJob.getUid()) {
if (DEBUG) {
Slog.d(TAG, "Stale callback received, ignoring.");
}
return false;
}
return true;
}
}
接着发送了一个 MSG_CALLBACK 的消息给了 JobServiceHandler!
3 JSC.JobServiceHandler
接着进入了 JobServiceHandler,来看主要代码:
case MSG_CALLBACK:
if (DEBUG) {
Slog.d(TAG, "MSG_CALLBACK of : " + mRunningJob
+ " v:" + VERB_STRINGS[mVerb]);
}
removeOpTimeOut();
if (mVerb == VERB_STARTING) {
final boolean workOngoing = message.arg2 == 1;
handleStartedH(workOngoing);
} else if (mVerb == VERB_EXECUTING || // 此时 mVerb 的状态为 VERB_EXECUTING
mVerb == VERB_STOPPING) {
final boolean reschedule = message.arg2 == 1;
handleFinishedH(reschedule);
} else {
if (DEBUG) {
Slog.d(TAG, "Unrecognised callback: " + mRunningJob);
}
}
break;
调用了 handleFinishedH:
private void handleFinishedH(boolean reschedule) {
switch (mVerb) {
case VERB_EXECUTING:
case VERB_STOPPING:
closeAndCleanupJobH(reschedule);
break;
default:
Slog.e(TAG, "Got an execution complete message for a job that wasn't being" +
"executed. Was " + VERB_STRINGS[mVerb] + ".");
}
}
这里就很简单了,调用了 closeAndCleanupJobH 来解除 bind 和将 JObServiceContext 恢复初始化!
private void closeAndCleanupJobH(boolean reschedule) {
final JobStatus completedJob;
synchronized (mLock) {
if (mVerb == VERB_FINISHED) {
return;
}
completedJob = mRunningJob;
mJobPackageTracker.noteInactive(completedJob);
try {
mBatteryStats.noteJobFinish(mRunningJob.getBatteryName(),
mRunningJob.getSourceUid());
} catch (RemoteException e) {
// Whatever.
}
if (mWakeLock != null) {
mWakeLock.release();
}
mContext.unbindService(JobServiceContext.this);
mWakeLock = null;
mRunningJob = null;
mParams = null;
mVerb = VERB_FINISHED; // 状态变为
VERB_FINISHEDmCancelled.set(false);
service = null;
mAvailable = true;
}
removeOpTimeOut();
removeMessages(MSG_CALLBACK);
removeMessages(MSG_SERVICE_BOUND);
removeMessages(MSG_CANCEL);
removeMessages(MSG_SHUTDOWN_EXECUTION);
// 通知 JobSchedulerService,这个 job 已经 finished 了
mCompletedListener.onJobCompleted(completedJob, reschedule);
}
}
接着,进入了 JobSchedulerService 方法中:
4 JSS.onJobCompleted
调用了 onJobCompleted 方法,来
@Override
public void onJobCompleted(JobStatus jobStatus, boolean needsReschedule) {
if (DEBUG) {
Slog.d(TAG, "Completed " + jobStatus + ", reschedule=" + needsReschedule);
}
// Do not write back immediately if this is a periodic job. The job may get lost if system
// shuts down before it is added back.
// 停止 track job,这里是第一次 stop,所以会将 job 从 JobStore 中删除!
if (!stopTrackingJob(jobStatus, null, !jobStatus.getJob().isPeriodic())) {
if (DEBUG) {
Slog.d(TAG, "Could not find job to remove. Was job removed while executing?");
}
// We still want to check for jobs to execute, because this job may have
// scheduled a new job under the same job id, and now we can run it.
mHandler.obtainMessage(MSG_CHECK_JOB_GREEDY).sendToTarget();
return;
}
// Note: there is a small window of time in here where, when rescheduling a job,
// we will stop monitoring its content providers. This should be fixed by stopping
// the old job after scheduling the new one, but since we have no lock held here
// that may cause ordering problems if the app removes jobStatus while in here.
// 判断是否要 reschedule 这个 job,如果需要,就 startTrackingJob
if (needsReschedule) {
JobStatus rescheduled = getRescheduleJobForFailure(jobStatus);
startTrackingJob(rescheduled, jobStatus);
} else if (jobStatus.getJob().isPeriodic()) {
JobStatus rescheduledPeriodic = getRescheduleJobForPeriodic(jobStatus);
startTrackingJob(rescheduledPeriodic, jobStatus);
}
reportActive();
// 继续开始新一轮的 job 执行!
mHandler.obtainMessage(MSG_CHECK_JOB_GREEDY).sendToTarget();
}
这里和 cancel 就一样了,所以这里就不细说了!