一、 调用流程
JobScheduler.cancel(int jobId)
|
JobSchedulerImpl.cancel(int jobId)
|
IJobScheduler mBinder;
public void cancel(int jobId) {
try {
mBinder.cancel(jobId);
} catch (RemoteException e) {}
}
| 跨进程调用至 JobSchedulerService
|
JobSchedulerService.cancel(int jobId)
二、JobSchedulerService 取消 job 流程
1. 最终调用该方法
public void cancel(int jobId) throws RemoteException {
final int uid = Binder.getCallingUid();
long ident = Binder.clearCallingIdentity();
try {
JobSchedulerService.this.cancelJob(uid, jobId);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
public void cancelJob(int uid, int jobId) {
JobStatus toCancel;
synchronized (mJobs) {
// 根据 uid jobId 获取之前已经存在的 job
toCancel = mJobs.getJobByUidAndJobId(uid, jobId);
}
if (toCancel != null) {
cancelJobImpl(toCancel);
}
}
2. 从 mJobs 列表、待执行 Job 列表移除 job,处理正在执行的 job
/**
* 该方法做了三件事情:
* 1. 从 mJobs 中及各 Controller 的追踪列表中移除 job
* 2. 从 mPendingJobs 列表移除(待执行 job 列表)
* 3. 对正在被 JobServiceContext 执行的 job 进行处理
* @param cancelled
*/
private void cancelJobImpl(JobStatus cancelled) {
if (DEBUG) {
Slog.d(TAG, "Cancelling: " + cancelled);
}
// Remove from store as well as controllers.
// 从 mJobs 中及各 Controller 的追踪列表中移除 job
stopTrackingJob(cancelled);
synchronized (mJobs) {
// Remove from pending queue.
// 从 mPendingJobs 列表移除(待执行 job 列表)
mPendingJobs.remove(cancelled);
// Cancel if running.
// 对正在被 JobServiceContext 执行的 job 进行处理
stopJobOnServiceContextLocked(cancelled);
}
}
3. 处理正在执行的 job
private boolean stopJobOnServiceContextLocked(JobStatus job) {
for (int i=0; i<mActiveServices.size(); i++) {
JobServiceContext jsc = mActiveServices.get(i);
final JobStatus executing = jsc.getRunningJob();
if (executing != null && executing.matches(job.getUid(), job.getJobId())) {
// 找出正在执行的 job,进行处理
jsc.cancelExecutingJob();
return true;
}
}
return false;
}
三、取消正在执行的 job
1. 发出 MSG_CANCEL 消息
/** Called externally when a job that was scheduled for execution should be cancelled. */
void cancelExecutingJob() {
mCallbackHandler.obtainMessage(MSG_CANCEL).sendToTarget();
}
2. 接收 MSG_CANCEL 消息
private class JobServiceHandler extends Handler {
@Override
public void handleMessage(Message message) {
switch (message.what) {
case MSG_CANCEL:
handleCancelH();
break;
}
}
}
3. 处理 MSG_CANCEL 消息
a) cancel job 不影响正在执行的 job 进行 bindService
b) 调起 JobService 中的 startJob 前会检查 job 是否已被 cancel, 决定是否继续执行 JobService 中的 startJob
c) JobService 中的 onStartJob() 返回true 后会检查该值, 决定是否调用 sendStopMessageH()
/**
* A job can be in various states when a cancel request comes in:
* VERB_BINDING -> Cancelled before bind completed. Mark as cancelled and wait for
* {@link #onServiceConnected(android.content.ComponentName, android.os.IBinder)}
* _STARTING -> Mark as cancelled and wait for
* {@link JobServiceContext#acknowledgeStartMessage(int, boolean)}
* _EXECUTING -> call {@link #sendStopMessageH}}, but only if there are no callbacks
* in the message queue.
* _ENDING -> No point in doing anything here, so we ignore.
*/
private void handleCancelH() {
switch (mVerb) {
// bindService 前置为该值
case VERB_BINDING:
// 调用 JobService 的 onStartJob 前置为该值
case VERB_STARTING:
// 注意此处,当状态为 VERB_BINDING、VERB_STARTING 时,仅仅更改 mCancelled 值
// 在完成 bindService 后,调起 JobService 中的 startJob 前,会检查该值
// 在 JobService 中的 onStartJob() 返回true 后会检查该值
mCancelled.set(true);
break;
// 调用 JobService 的 onStartJob 返回后置为该值
case VERB_EXECUTING:
if (hasMessages(MSG_CALLBACK)) {
// If the client has called jobFinished, ignore this cancel.
return;
}
sendStopMessageH();
break;
case VERB_STOPPING:
// Nada.
break;
}
}
4. 调用 JobService 的 onStopJob()
/**
* Already running, need to stop. Will switch {@link #mVerb} from VERB_EXECUTING ->
* VERB_STOPPING.
*/
private void sendStopMessageH() {
removeOpTimeOut();
// 调用 JobService 的 onStartJob 返回后置为该值
if (mVerb != VERB_EXECUTING) {
// 走入这里说明,job 尚未执行,或者 job 不是正在执行状态,直接进行 job 的收尾工作
Slog.e(TAG, "Sending onStopJob for a job that isn't started. " + mRunningJob);
closeAndCleanupJobH(false /* reschedule */);
return;
}
try {
mVerb = VERB_STOPPING;
scheduleOpTimeOut();
// 调用 JobService 的 onStopJob()
service.stopJob(mParams);
} catch (RemoteException e) {
Slog.e(TAG, "Error sending onStopJob to client.", e);
closeAndCleanupJobH(false /* reschedule */);
}
}
5. JobService 的 onStopJob() 完成后回调 JobServiceContext 的 acknowledgeStopMessage()
/**
* JobService 的 onStopJob() 完成后回调该方法
*/
@Override
public void acknowledgeStopMessage(int jobId, boolean reschedule) {
if (!verifyCallingUid()) {
return;
}
mCallbackHandler.obtainMessage(MSG_CALLBACK, jobId, reschedule ? 1 : 0).sendToTarget();
}
public void handleMessage(Message message) {
switch (message.what) {
case MSG_CALLBACK:
if (DEBUG) {
Slog.d(TAG, "MSG_CALLBACK of : " + mRunningJob + " v:" + (mVerb >= 0 ? VERB_STRINGS[mVerb] : "[invalid]"));
}
removeOpTimeOut();
if (mVerb == VERB_STARTING) {
// JobService.onStartJob(params) 后回调至这里
final boolean workOngoing = message.arg2 == 1;
handleStartedH(workOngoing);
} else if (mVerb == VERB_EXECUTING || mVerb == VERB_STOPPING) {
// JobService.jobFinished() 及执行 onStopJob() 后会回调至这里
final boolean reschedule = message.arg2 == 1;
// unbindService(),把该 job 从 mJobs 中移除,同时会处理需要重新 schedule 或周期性的 Job
handleFinishedH(reschedule);
}
break;
}
}
/**
* VERB_EXECUTING -> Client called jobFinished(), clean up and notify done.
* _STOPPING -> Successful finish, clean up and notify done.
* _STARTING -> Error
* _PENDING -> Error
*/
private void handleFinishedH(boolean reschedule) {
switch (mVerb) {
case VERB_EXECUTING:
case VERB_STOPPING:
// unbindService(),把该 job 从 mJobs 中移除,同时会处理需要重新 schedule 或周期性的 Job
closeAndCleanupJobH(reschedule);
break;
default:
Slog.e(TAG, "Got an execution complete message for a job that wasn't being" + "executed. Was " + VERB_STRINGS[mVerb] + ".");
}
}
/**
* unbindService(),把该 job 从 mJobs 中移除,同时会处理需要重新 schedule 或周期性的 Job
* The provided job has finished, either by calling
* {@link android.app.job.JobService#jobFinished(android.app.job.JobParameters, boolean)}
* or from acknowledging the stop message we sent. Either way, we're done tracking it and
* we want to clean up internally.
*/
private void closeAndCleanupJobH(boolean reschedule) {
final JobStatus completedJob = mRunningJob;
synchronized (mLock) {
try {
mBatteryStats.noteJobFinish(mRunningJob.getName(), mRunningJob.getUid());
} catch (RemoteException e) {
// Whatever.
}
if (mWakeLock != null) {
mWakeLock.release();
}
// 注意此处,调用 unbindService
mContext.unbindService(JobServiceContext.this);
mWakeLock = null;
mRunningJob = null;
mParams = null;
mVerb = -1;
mCancelled.set(false);
service = null;
mAvailable = true;
}
removeOpTimeOut();
removeMessages(MSG_CALLBACK);
removeMessages(MSG_SERVICE_BOUND);
removeMessages(MSG_CANCEL);
removeMessages(MSG_SHUTDOWN_EXECUTION);
// onJobCompleted 中会把该 job 从 mJobs 中移除,同时会处理需要重新 schedule 或周期性的 Job
mCompletedListener.onJobCompleted(completedJob, reschedule);
}