一、JobServiceContext 通過 bindService 的方式啟動 JobService
1. JobServiceContext 中的 executeRunnableJob 執(zhí)行 bindService
boolean binding = mContext.bindServiceAsUser(intent, this,
Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND,
new UserHandle(job.getUserId()));
2. ActivityThread 調(diào)用 handleBindService() 回傳 JobService 中的 IJobService mBinder
public final class ActivityThread {
private final void handleBindService(BindServiceData data) {
...
try {
if (!data.rebind) {
IBinder binder = s.onBind(data.intent);
ActivityManagerNative.getDefault().publishService(data.token, data.intent, binder);
} else {
}
} catch (RemoteException ex) {
}
}
}
public final IBinder onBind(Intent intent) {
return mBinder.asBinder();
}
3. JobService 中的 IJobService mBinder 代碼
/**
* JobServiceContext 通過 bindService 的方式與 JobService 建立連接,
* mBinder 會被傳遞到 JobServiceContext 的 onServiceConnected(ComponentName name, IBinder service) 中
* JobServiceContext 通過 IBinder service 調(diào)用 IJobService 中的 startJob(), stopJob()
*/
/** Binder for this service. */
IJobService mBinder = new IJobService.Stub() {
@Override
public void startJob(JobParameters jobParams) {
ensureHandler();
Message m = Message.obtain(mHandler, MSG_EXECUTE_JOB, jobParams);
m.sendToTarget();
}
@Override
public void stopJob(JobParameters jobParams) {
ensureHandler();
Message m = Message.obtain(mHandler, MSG_STOP_JOB, jobParams);
m.sendToTarget();
}
};
4. JobServiceContext 在 onServiceConnected(ComponentName name, IBinder service) 中接收 IJobService mBinder
/**
* 建立與 JobService 的連接是通過 bindService 的方式
* IBinder service 來自 JobService 中的 IJobService mBinder
*
* We acquire/release a wakelock on onServiceConnected/unbindService. This mirrors the work
* we intend to send to the client - we stop sending work when the service is unbound so until
* then we keep the wakelock.
* @param name The concrete component name of the service that has been connected.
* @param service The IBinder of the Service's communication channel,
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (!name.equals(mRunningJob.getServiceComponent())) {
mCallbackHandler.obtainMessage(MSG_SHUTDOWN_EXECUTION).sendToTarget();
return;
}
this.service = IJobService.Stub.asInterface(service);
final PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mRunningJob.getTag());
mWakeLock.setWorkSource(new WorkSource(mRunningJob.getUid()));
mWakeLock.setReferenceCounted(false);
mWakeLock.acquire();
// 發(fā)出與 JobService 成功建立連接的消息
mCallbackHandler.obtainMessage(MSG_SERVICE_BOUND).sendToTarget();
}
二、JobServiceContext 處理 MSG_SERVICE_BOUND 消息
1. 接收 MSG_SERVICE_BOUND 消息
private class JobServiceHandler extends Handler {
JobServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message message) {
switch (message.what) {
case MSG_SERVICE_BOUND:
removeOpTimeOut();
handleServiceBoundH();
break;
}
}
}
2. 跨進程調(diào)起 JobService 中的 IJobService 的 startJob(JobParameters jobParams)
/** Start the job on the service. */
private void handleServiceBoundH() {
if (DEBUG) {
Slog.d(TAG, "MSG_SERVICE_BOUND for " + mRunningJob.toShortString());
}
if (mVerb != VERB_BINDING) {// 剛完成 bingService 時,mVerb = VERB_BINDING;
Slog.e(TAG, "Sending onStartJob for a job that isn't pending. " + VERB_STRINGS[mVerb]);
closeAndCleanupJobH(false /* reschedule */);
return;
}
if (mCancelled.get()) {
if (DEBUG) {
Slog.d(TAG, "Job cancelled while waiting for bind to complete. " + mRunningJob);
}
closeAndCleanupJobH(true /* reschedule */);
return;
}
try {
// 修改 mVerb 為 VERB_STARTING
mVerb = VERB_STARTING;
scheduleOpTimeOut();
// 注意此處,調(diào)起 JobService 中的 startJob(JobParameters jobParams)
service.startJob(mParams);
} catch (RemoteException e) {
Slog.e(TAG, "Error sending onStart message to '" + mRunningJob.getServiceComponent().getShortClassName() + "' ", e);
}
}
三、跨進程調(diào)起 JobService 中的 IJobService 的 startJob(JobParameters jobParams)
1. 發(fā)出 MSG_EXECUTE_JOB 消息
/**
* JobServiceContext 通過 bindService 的方式與 JobService 建立連接,
* mBinder 會被傳遞到 JobServiceContext 的 onServiceConnected(ComponentName name, IBinder service) 中
* JobServiceContext 通過 IBinder service 調(diào)用 IJobService 中的 startJob(), stopJob()
*/
/** Binder for this service. */
IJobService mBinder = new IJobService.Stub() {
@Override
public void startJob(JobParameters jobParams) {
ensureHandler();
Message m = Message.obtain(mHandler, MSG_EXECUTE_JOB, jobParams);
m.sendToTarget();
}
@Override
public void stopJob(JobParameters jobParams) {
ensureHandler();
Message m = Message.obtain(mHandler, MSG_STOP_JOB, jobParams);
m.sendToTarget();
}
};
2. 接收 MSG_EXECUTE_JOB 消息,調(diào)起 onStartJob(params)
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_EXECUTE_JOB:
try {
// 注意此處接收 onStartJob() 的返回值
boolean workOngoing = JobService.this.onStartJob(params);
ackStartMessage(params, workOngoing);
} catch (Exception e) {
Log.e(TAG, "Error while executing job: " + params.getJobId());
throw new RuntimeException(e);
}
break;
}
}
}
3. 跨進程回調(diào)至 JobServiceContext 中的 acknowledgeStartMessage()
private void ackStartMessage(JobParameters params, boolean workOngoing) {
final IJobCallback callback = params.getCallback();
final int jobId = params.getJobId();
if (callback != null) {
try {
// 跨進程調(diào)用,IJobCallback 對應(yīng)于 JobServiceContext
callback.acknowledgeStartMessage(jobId, workOngoing);
} catch(RemoteException e) {
Log.e(TAG, "System unreachable for starting job.");
}
} else {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Attempting to ack a job that has already been processed.");
}
}
}
四、JobServiceContext 調(diào)用 acknowledgeStartMessage(int jobId, boolean ongoing)
1. 發(fā)出消息 MSG_CALLBACK
public void acknowledgeStartMessage(int jobId, boolean ongoing) {
if (!verifyCallingUid()) {
return;
}
mCallbackHandler.obtainMessage(MSG_CALLBACK, jobId, ongoing ? 1 : 0).sendToTarget();
}
2. 接收消息 MSG_CALLBACK
private class JobServiceHandler extends Handler {
JobServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message message) {
switch (message.what) {
case MSG_CALLBACK:
removeOpTimeOut();
if (mVerb == VERB_STARTING) {
// JobService.onStartJob(params) 后回調(diào)至這里
final boolean workOngoing = message.arg2 == 1;
handleStartedH(workOngoing);
}
break;
}
}
}
3. 根據(jù) JobService 中的 onStartJob() 返回值做相應(yīng)處理
private void handleStartedH(boolean workOngoing) {
switch (mVerb) {
case VERB_STARTING:
// 此處修改 mVerb 為 VERB_EXECUTING
mVerb = VERB_EXECUTING;
if (!workOngoing) {
// Job is finished already so fast-forward to handleFinished.
// unbindService(),把該 job 從 mJobs 中移除,同時會處理需要重新 schedule 或周期性的 Job
handleFinishedH(false);
return;
}
// JobService 中的 onStartJob() 返回true 時才會走下面邏輯
if (mCancelled.get()) {
if (DEBUG) {
Slog.d(TAG, "Job cancelled while waiting for onStartJob to complete.");
}
// Cancelled *while* waiting for acknowledgeStartMessage from client.
// 這里會層層調(diào)用到 service.stopJob(mParams);
handleCancelH();
return;
}
// 注意這里,觸發(fā)超時機制,1min 后若 APP 無反饋,則 job 狀態(tài)改為 VERB_STOPPING
// 并再次觸發(fā)超時機制,若 1min 后仍然沒反應(yīng),則走 job 處理完成流程
// 對應(yīng) API24 來說,超時時間是 10min
scheduleOpTimeOut();
break;
default:
Slog.e(TAG, "Handling started job but job wasn't starting! Was "
+ VERB_STRINGS[mVerb] + ".");
return;
}
}
五、JobService 在 onStartJob(JobParameters params) 返回 true 時需要調(diào)用 jobFinished(),(不調(diào)用也沒關(guān)系,有超時機制)
1. 發(fā)出 MSG_JOB_FINISHED 消息
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();
}
2. 處理 MSG_JOB_FINISHED 消息
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);
IJobCallback callback = params.getCallback();
if (callback != null) {
try {
// 跨進程調(diào)用,IJobCallback 對應(yīng)于 JobServiceContext
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;
}
}
}
3. 跨進程回調(diào)至 JobServiceContext
public void jobFinished(int jobId, boolean reschedule) {
if (!verifyCallingUid()) {
return;
}
mCallbackHandler.obtainMessage(MSG_CALLBACK, jobId, reschedule ? 1 : 0).sendToTarget();
}
private class JobServiceHandler extends Handler {
JobServiceHandler(Looper looper) {
super(looper);
}
@Override
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() 會回調(diào)至這里
final boolean reschedule = message.arg2 == 1;
// unbindService(),把該 job 從 mJobs 中移除,同時會處理需要重新 schedule 或周期性的 Job
handleFinishedH(reschedule);
} else {
if (DEBUG) {
Slog.d(TAG, "Unrecognised callback: " + mRunningJob);
}
}
break;
}
}
}
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();
}
// 注意此處,調(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 中會把該 job 從 mJobs 中移除,同時會處理需要重新 schedule 或周期性的 Job
mCompletedListener.onJobCompleted(completedJob, reschedule);
}
4. 調(diào)用 JobSchedulerService 中的 onJobCompleted()
public void onJobCompleted(JobStatus jobStatus, boolean needsReschedule) {
if (DEBUG) {
Slog.d(TAG, "Completed " + jobStatus + ", reschedule=" + needsReschedule);
}
// 從 mJobs 及各 controller 中移除 job
if (!stopTrackingJob(jobStatus)) {
if (DEBUG) {
Slog.d(TAG, "Could not find job to remove. Was job removed while executing?");
}
return;
}
if (needsReschedule) {
// 處理設(shè)置了失敗處理策略的 job
JobStatus rescheduled = getRescheduleJobForFailure(jobStatus);
startTrackingJob(rescheduled);
} else if (jobStatus.getJob().isPeriodic()) {
// 重新 tracking 周期性的 job
JobStatus rescheduledPeriodic = getRescheduleJobForPeriodic(jobStatus);
startTrackingJob(rescheduledPeriodic);
}
// 檢查所有滿足執(zhí)行條件的 Job,根據(jù)策略決定是否放入 mPendingJobs,隨后執(zhí)行 mPendingJobs 中的 Job
mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
}