一置森、 調(diào)用流程
JobScheduler.cancel(int jobId)
|
JobSchedulerImpl.cancel(int jobId)
|
IJobScheduler mBinder;
public void cancel(int jobId) {
try {
mBinder.cancel(jobId);
} catch (RemoteException e) {}
}
| 跨進(jìn)程調(diào)用至 JobSchedulerService
|
JobSchedulerService.cancel(int jobId)
二、JobSchedulerService 取消 job 流程
1. 最終調(diào)用該方法
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) {
// 根據(jù) uid jobId 獲取之前已經(jīng)存在的 job
toCancel = mJobs.getJobByUidAndJobId(uid, jobId);
}
if (toCancel != null) {
cancelJobImpl(toCancel);
}
}
2. 從 mJobs 列表符糊、待執(zhí)行 Job 列表移除 job凫海,處理正在執(zhí)行的 job
/**
* 該方法做了三件事情:
* 1. 從 mJobs 中及各 Controller 的追蹤列表中移除 job
* 2. 從 mPendingJobs 列表移除(待執(zhí)行 job 列表)
* 3. 對(duì)正在被 JobServiceContext 執(zhí)行的 job 進(jìn)行處理
* @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 列表移除(待執(zhí)行 job 列表)
mPendingJobs.remove(cancelled);
// Cancel if running.
// 對(duì)正在被 JobServiceContext 執(zhí)行的 job 進(jìn)行處理
stopJobOnServiceContextLocked(cancelled);
}
}
3. 處理正在執(zhí)行的 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())) {
// 找出正在執(zhí)行的 job,進(jìn)行處理
jsc.cancelExecutingJob();
return true;
}
}
return false;
}
三男娄、取消正在執(zhí)行的 job
1. 發(fā)出 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 不影響正在執(zhí)行的 job 進(jìn)行 bindService
b) 調(diào)起 JobService 中的 startJob 前會(huì)檢查 job 是否已被 cancel, 決定是否繼續(xù)執(zhí)行 JobService 中的 startJob
c) JobService 中的 onStartJob() 返回true 后會(huì)檢查該值, 決定是否調(diào)用 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:
// 調(diào)用 JobService 的 onStartJob 前置為該值
case VERB_STARTING:
// 注意此處行贪,當(dāng)狀態(tài)為 VERB_BINDING、VERB_STARTING 時(shí)模闲,僅僅更改 mCancelled 值
// 在完成 bindService 后建瘫,調(diào)起 JobService 中的 startJob 前,會(huì)檢查該值
// 在 JobService 中的 onStartJob() 返回true 后會(huì)檢查該值
mCancelled.set(true);
break;
// 調(diào)用 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. 調(diào)用 JobService 的 onStopJob()
/**
* Already running, need to stop. Will switch {@link #mVerb} from VERB_EXECUTING ->
* VERB_STOPPING.
*/
private void sendStopMessageH() {
removeOpTimeOut();
// 調(diào)用 JobService 的 onStartJob 返回后置為該值
if (mVerb != VERB_EXECUTING) {
// 走入這里說明尸折,job 尚未執(zhí)行啰脚,或者 job 不是正在執(zhí)行狀態(tài),直接進(jìn)行 job 的收尾工作
Slog.e(TAG, "Sending onStopJob for a job that isn't started. " + mRunningJob);
closeAndCleanupJobH(false /* reschedule */);
return;
}
try {
mVerb = VERB_STOPPING;
scheduleOpTimeOut();
// 調(diào)用 JobService 的 onStopJob()
service.stopJob(mParams);
} catch (RemoteException e) {
Slog.e(TAG, "Error sending onStopJob to client.", e);
closeAndCleanupJobH(false /* reschedule */);
}
}
5. JobService 的 onStopJob() 完成后回調(diào) JobServiceContext 的 acknowledgeStopMessage()
/**
* JobService 的 onStopJob() 完成后回調(diào)該方法
*/
@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) 后回調(diào)至這里
final boolean workOngoing = message.arg2 == 1;
handleStartedH(workOngoing);
} else if (mVerb == VERB_EXECUTING || mVerb == VERB_STOPPING) {
// JobService.jobFinished() 及執(zhí)行 onStopJob() 后會(huì)回調(diào)至這里
final boolean reschedule = message.arg2 == 1;
// unbindService()实夹,把該 job 從 mJobs 中移除橄浓,同時(shí)會(huì)處理需要重新 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 中移除,同時(shí)會(huì)處理需要重新 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 中移除匀们,同時(shí)會(huì)處理需要重新 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();
}
// 注意此處,調(diào)用 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 中會(huì)把該 job 從 mJobs 中移除准给,同時(shí)會(huì)處理需要重新 schedule 或周期性的 Job
mCompletedListener.onJobCompleted(completedJob, reschedule);
}