一、JobServiceContext 通过 bindService 的方式启动 JobService
1. JobServiceContext 中的 executeRunnableJob 执行 bindService
boolean binding = mContext.bindServiceAsUser(intent, this,
Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND,
new UserHandle(job.getUserId()));
2. ActivityThread 调用 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 调用 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();
// 发出与 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. 跨进程调起 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();
// 注意此处,调起 JobService 中的 startJob(JobParameters jobParams)
service.startJob(mParams);
} catch (RemoteException e) {
Slog.e(TAG, "Error sending onStart message to '" + mRunningJob.getServiceComponent().getShortClassName() + "' ", e);
}
}
三、跨进程调起 JobService 中的 IJobService 的 startJob(JobParameters jobParams)
1. 发出 MSG_EXECUTE_JOB 消息
/**
* JobServiceContext 通过 bindService 的方式与 JobService 建立连接,
* mBinder 会被传递到 JobServiceContext 的 onServiceConnected(ComponentName name, IBinder service) 中
* JobServiceContext 通过 IBinder service 调用 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 消息,调起 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. 跨进程回调至 JobServiceContext 中的 acknowledgeStartMessage()
private void ackStartMessage(JobParameters params, boolean workOngoing) {
final IJobCallback callback = params.getCallback();
final int jobId = params.getJobId();
if (callback != null) {
try {
// 跨进程调用,IJobCallback 对应于 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 调用 acknowledgeStartMessage(int jobId, boolean ongoing)
1. 发出消息 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) 后回调至这里
final boolean workOngoing = message.arg2 == 1;
handleStartedH(workOngoing);
}
break;
}
}
}
3. 根据 JobService 中的 onStartJob() 返回值做相应处理
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.
// 这里会层层调用到 service.stopJob(mParams);
handleCancelH();
return;
}
// 注意这里,触发超时机制,1min 后若 APP 无反馈,则 job 状态改为 VERB_STOPPING
// 并再次触发超时机制,若 1min 后仍然没反应,则走 job 处理完成流程
// 对应 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 时需要调用 jobFinished(),(不调用也没关系,有超时机制)
1. 发出 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 {
// 跨进程调用,IJobCallback 对应于 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. 跨进程回调至 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) 后回调至这里
final boolean workOngoing = message.arg2 == 1;
handleStartedH(workOngoing);
} else if (mVerb == VERB_EXECUTING || mVerb == VERB_STOPPING) {
// JobService.jobFinished() 会回调至这里
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();
}
// 注意此处,调用 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. 调用 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) {
// 处理设置了失败处理策略的 job
JobStatus rescheduled = getRescheduleJobForFailure(jobStatus);
startTrackingJob(rescheduled);
} else if (jobStatus.getJob().isPeriodic()) {
// 重新 tracking 周期性的 job
JobStatus rescheduledPeriodic = getRescheduleJobForPeriodic(jobStatus);
startTrackingJob(rescheduledPeriodic);
}
// 检查所有满足执行条件的 Job,根据策略决定是否放入 mPendingJobs,随后执行 mPendingJobs 中的 Job
mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
}
网友评论