上章节遗留的疑问二,本章将继续探究缘由。
疑问二
自行cancel了JobService后,onStopJob()即使返回true也不能被重新启动?
照例直接上源码。
cancel是IJobScheduler的API,我们直接查看该API的实现。
frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java
public final class JobSchedulerService extends com.android.server.SystemService implements StateChangedListener, JobCompletedListener { ... final class JobSchedulerStub extends IJobScheduler.Stub { ... @Override public void cancel(int jobId) throws RemoteException { final int uid = Binder.getCallingUid(); long ident = Binder.clearCallingIdentity(); try { JobSchedulerService.this.cancelJob(uid, jobId);★1 }... } } ... public void cancelJob(int uid, int jobId) { JobStatus toCancel; synchronized (mLock) { toCancel = mJobs.getJobByUidAndJobId(uid, jobId); // 从JobStore中获取指定UID下的指定ID的JobStatus if (toCancel != null) { cancelJobImplLocked(toCancel, null, "cancel() called by app");★2 } } } ... private void cancelJobImplLocked(JobStatus cancelled, JobStatus incomingJob, String reason) { cancelled.unprepareLocked(ActivityManager.getService()); stopTrackingJobLocked(cancelled, incomingJob, true /* writeBack */); // 从JobStore中移除该Job的追踪记录 // Remove from pending queue. if (mPendingJobs.remove(cancelled)) {// 从运行中JobStatus列表中移除该Job mJobPackageTracker.noteNonpending(cancelled); } // Cancel if running. stopJobOnServiceContextLocked(cancelled, JobParameters.REASON_CANCELED, reason);★3 即将执行Job停止处理 reportActiveLocked(); } ... private boolean stopJobOnServiceContextLocked(JobStatus job, int reason, String debugReason) { for (int i=0; i<mActiveServices.size(); i++) { JobServiceContext jsc = mActiveServices.get(i); final JobStatus executing = jsc.getRunningJobLocked(); if (executing != null && executing.matches(job.getUid(), job.getJobId())) { jsc.cancelExecutingJobLocked(reason, debugReason);★4告诉JobServiceContext去停止该Job return true; } } return false; } }
我们继续看看JobServiceContext具体做了什么处理。
public final class JobServiceContext implements ServiceConnection { ... void cancelExecutingJobLocked(int reason, String debugReason) { doCancelLocked(reason, debugReason);★1 } ... void doCancelLocked(int arg1, String debugReason) { ... mParams.setStopReason(arg1);// 设置REASON_CANCELED作为停止Job原因 if (arg1 == JobParameters.REASON_PREEMPT) { mPreferredUid = mRunningJob != null ? mRunningJob.getUid() : NO_PREFERRED_UID; } handleCancelLocked(debugReason);★2 } ... private void handleCancelLocked(String reason) { ... switch (mVerb) { case VERB_BINDING: case VERB_STARTING: mCancelled = true; applyStoppedReasonLocked(reason);★3-1 如果JobService还未执行走这个处理 break; case VERB_EXECUTING: sendStopMessageLocked(reason);★3-2 如果JobService已经执行走这个处理 break; ... } } // 假设JobService已经执行,那直接走到这 private void sendStopMessageLocked(String reason) { removeOpTimeOutLocked(); ... try { mVerb = VERB_STOPPING;//将Job状态置为VERB_STOPPING scheduleOpTimeOutLocked(); service.stopJob(mParams);★4 IPC调用JobService的onStopJob() }... } }
同样的JobServcie处理完onStopJob()后会将返回值通过IJobCallback会发给JobServiceContext。
public abstract class JobServiceEngine { static final class JobInterface extends IJobService.Stub { ... public void stopJob(JobParameters jobParams) throws RemoteException { JobServiceEngine service = mService.get(); if (service != null) { Message m = Message.obtain(service.mHandler, MSG_STOP_JOB, jobParams);★1 m.sendToTarget(); } } } ... class JobHandler extends Handler { ... @Override public void handleMessage(Message msg) { final JobParameters params = (JobParameters) msg.obj; switch (msg.what) { case MSG_STOP_JOB: try { boolean ret = JobServiceEngine.this.onStopJob(params);★2 ackStopMessage(params, ret);★3 }... ... } } } ... private void ackStopMessage(JobParameters params, boolean reschedule) { final IJobCallback callback = params.getCallback(); final int jobId = params.getJobId(); if (callback != null) { try { callback.acknowledgeStopMessage(jobId, reschedule);★4 }... }... } }
我们假设onStopJob()返回的是true,那么★4传给JobServiceContext的reschedule就是true。
再次回到JobServiceContext。
public final class JobServiceContext implements ServiceConnection { ... final class JobCallback extends IJobCallback.Stub { @Override public void acknowledgeStopMessage(int jobId, boolean reschedule) { doAcknowledgeStopMessage(this, jobId, reschedule);★1 } ... } ... void doAcknowledgeStopMessage(JobCallback cb, int jobId, boolean reschedule) { doCallback(cb, reschedule, null);★2 } ... void doCallback(JobCallback cb, boolean reschedule, String reason) { final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { if (!verifyCallerLocked(cb)) { return; } doCallbackLocked(reschedule, reason);★3 此刻的reschedule为true } }... } ... void doCallbackLocked(boolean reschedule, String reason) { ... removeOpTimeOutLocked();//在这里移除回调onStopJob时发送的8s延时msg if (mVerb == VERB_STARTING) { handleStartedLocked(reschedule); } else if (mVerb == VERB_EXECUTING || mVerb == VERB_STOPPING) { handleFinishedLocked(reschedule, reason);★4 此刻状态为STOPPING,调用finish逻辑 }... } ... private void handleFinishedLocked(boolean reschedule, String reason) { switch (mVerb) { case VERB_EXECUTING: case VERB_STOPPING: closeAndCleanupJobLocked(reschedule, reason);★5 break; ... } } ... private void closeAndCleanupJobLocked(boolean reschedule, String reason) { ... applyStoppedReasonLocked(reason); completedJob = mRunningJob; mJobPackageTracker.noteInactive(completedJob); ... if (mWakeLock != null) { mWakeLock.release();//释放WakeLock } mContext.unbindService(JobServiceContext.this);★6告诉AMS解绑该JobService,最终会调到它的onDestroy() mWakeLock = null; mRunningJob = null; mRunningCallback = null; mParams = null; mVerb = VERB_FINISHED;// 将Job状态置为VERB_FINISHED mCancelled = false; service = null; mAvailable = true; removeOpTimeOutLocked(); mCompletedListener.onJobCompletedLocked(completedJob, reschedule); ★7 将结束的Job当作参数调用结束后回调处理 } ... public void onJobCompletedLocked(JobStatus jobStatus, boolean needsReschedule) { ... final JobStatus rescheduledJob = needsReschedule ? getRescheduleJobForFailureLocked(jobStatus) : null; // 从结束的Job中复制出新的JobStatus ... // 从JobStore中移除原有Job的追踪记录,因为之前的JobStatus在cancel的时候已经从JobStore中移除了。所以本函数返回false // 然后发送MSG_CHECK_JOB_GREEDY的msg if (!stopTrackingJobLocked(jobStatus, rescheduledJob, !jobStatus.getJob().isPeriodic())) { ... mHandler.obtainMessage(MSG_CHECK_JOB_GREEDY).sendToTarget();★8 return; } ... } final private class JobHandler extends Handler { ... @Override public void handleMessage(Message message) { synchronized (mLock) { ... switch (message.what) { ... case MSG_CHECK_JOB_GREEDY: queueReadyJobsForExecutionLocked();★9 将准备好执行的Jobs排入队列 break; ... } maybeRunPendingJobsLocked(); ★10 轮循mPendingJobs准备执行JobService ... } } } private void queueReadyJobsForExecutionLocked() { ... // ★9-1 遍历通过JobStore中存储的所有Job,然后回调ReadyQueueFunctor添加Job到ReadyJobQueueFunctor中 mJobs.forEachJob(mReadyQueueFunctor); // 将ReadyJobQueueFunctor中保存的jobs列表添加到待执行列表mPendingJobs中 mReadyQueueFunctor.postProcess(); } }
执行cancel处理的时候已经从JobStore里移除了原有的JobStatus对象,
同时在发送MSG_CHECK_JOB_GREEDY前有没有将新的JobStatus对象保存到JobStore中。
所以★9-1在遍历存储的Jobs时候,并不会将新的JobStatus插入到待执行队列里。
进而导致★10的时候不会重新执行该JobService。
那为什么发生条件不满足时候Job被强制停止后能再度启动呢?
查看源码我们知道。
比如设备进入IDLE状态的时候,JobSchedulerService直接通知JobServiceContext去取消没有设置IDLE条件下运行的Job。
而并没有事先去JobStore理移除该Job。
等到JobServiceContext成功停止了该Job后。
JobSchedulerService在执行Job结束的回调(onJobCompletedLocked)时,将会把JobStore里保存的原有JobStatus移除,然后添加为新创建的JobStaus。
这样一来在MSG_CHECK_JOB_GREEDY的msg响应的时候,新的Job就可以得到执行。
到这里,疑问二就解决了。
下次我们探讨下之前遗留的两个思考以及一个总结。
思考一
如果我们在onStartJob()里处理耗时逻辑,导致onStartJob()没有及时返回给JobSchedulerContext。
最终结果是怎么样?
是ANR?
还是因为超时,该Job可能被强制停止和销毁?
思考二
如果onStartJob()里起了新线程处理耗时逻辑,但是返回值返回了false,那么系统还会销毁Job吗?
如果会的话,新线程是否会导致内存泄漏?
总结
JobService和Service的区别