基于 Android 7.1.1 源码分析
前提
接下来,我们来看看 JobServiceService 服务中和 cancel 相关的服务:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56// 取消指定设备用户的所有的 job!
void cancelJobsForUser(int userHandle) {
List<JobStatus> jobsForUser;
synchronized (mLock) {
jobsForUser = mJobs.getJobsByUser(userHandle);
}
for (int i=0; i<jobsForUser.size(); i++) {
JobStatus toRemove = jobsForUser.get(i);
cancelJobImpl(toRemove, null);
}
}
// 取消指定 package 和指定 uid 的所有的 job!
void cancelJobsForPackageAndUid(String pkgName, int uid) {
List<JobStatus> jobsForUid;
synchronized (mLock) {
jobsForUid = mJobs.getJobsByUid(uid);
}
for (int i = jobsForUid.size() - 1; i >= 0; i--) {
final JobStatus job = jobsForUid.get(i);
if (job.getSourcePackageName().equals(pkgName)) {
cancelJobImpl(job, null);
}
}
}
// 取消指定 uid 的应用程序的所有的 job!
public void cancelJobsForUid(int uid, boolean forceAll) {
List<JobStatus> jobsForUid;
synchronized (mLock) {
jobsForUid = mJobs.getJobsByUid(uid);
}
for (int i=0; i<jobsForUid.size(); i++) {
JobStatus toRemove = jobsForUid.get(i);
if (!forceAll) {
String packageName = toRemove.getServiceComponent().getPackageName();
try {
if (ActivityManagerNative.getDefault().getAppStartMode(uid, packageName)
!= ActivityManager.APP_START_MODE_DISABLED) {
continue;
}
} catch (RemoteException e) {
}
}
cancelJobImpl(toRemove, null);
}
}
// 取消指定 uid 的应用程序的 id 为 jobId 的 job!
public void cancelJob(int uid, int jobId) {
JobStatus toCancel;
synchronized (mLock) {
toCancel = mJobs.getJobByUidAndJobId(uid, jobId);
}
if (toCancel != null) {
cancelJobImpl(toCancel, null);
}
}
JobSchedulerService 提供了很多个接口来取消 job,但是他们都疯了似的调用了同一个方法,我们来继续看!
1 JSS.cancelJobImpl
同一个取消接口:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16private void cancelJobImpl(JobStatus cancelled, JobStatus incomingJob) {
if (DEBUG) Slog.d(TAG, "CANCEL: " + cancelled.toShortString());
// 停止监视这个 job,writeBack 为 true!
stopTrackingJob(cancelled, incomingJob, true /* writeBack */);
synchronized (mLock) {
// Remove from pending queue.
// 从 mPendingJobs 中移除!
if (mPendingJobs.remove(cancelled)) {
mJobPackageTracker.noteNonpending(cancelled);
}
// Cancel if running.
// 如果正在运行,就要停止这个 job
stopJobOnServiceContextLocked(cancelled, JobParameters.REASON_CANCELED);
reportActive();
}
}
这里我们一个一个来看:
1.1 JSS.stopTrackingJob
停止 stopTrackingJob 如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16private boolean stopTrackingJob(JobStatus jobStatus, JobStatus incomingJob,
boolean writeBack) {
synchronized (mLock) {
// Remove from store as well as controllers.
// 先从 JobStore 中移除这个 job,因为 writeBack 为 true,则需要更新 jobxs.xml 文件!
final boolean removed = mJobs.remove(jobStatus, writeBack);
if (removed && mReadyToRock) {
for (int i=0; i<mControllers.size(); i++) {
// 通知控制器,取消 track!
StateController controller = mControllers.get(i);
controller.maybeStopTrackingJobLocked(jobStatus, incomingJob, false);
}
}
return removed;
}
}
先从 JobStore 中移除这个 job,因为 writeBack 为 true,则需要更新 jobxs.xml 文件,通知控制器,取消 track!
1.2 JSS.stopJobOnServiceContextLocked
如果这个 job 是在运行中,就要取消它!1
2
3
4
5
6
7
8
9
10
11private boolean stopJobOnServiceContextLocked(JobStatus job, int reason) {
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())) {
jsc.cancelExecutingJob(reason);
return true;
}
}
return false;
}
每一个运行着的 job,都是和一个 JobServiceContext 绑定着的,这里是遍历所有的 JobServiceContext,找到要 cancel 的 job,调用 jobServiceContext 的 cancelExecutingJob 方法:
1.2.1 JSC.cancelExecutingJob
这个方法很简单,发送了 MSG_CANCEL 消息给 JobServiceHandler,reason 为 JobParameters.REASON_CANCELED1
2
3void cancelExecutingJob(int reason) {
mCallbackHandler.obtainMessage(MSG_CANCEL, reason, 0 /* unused */).sendToTarget();
}
我们继续看,进入 JobServiceHandler:
1.2.2 JSH.MSG_CANCEL
JobServiceHander 会处理 MSG_CANCEL 消息!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38private class JobServiceHandler extends Handler {
JobServiceHandler(Looper looper) {
super(looper);
}
public void handleMessage(Message message) {
... ... ... ...
case MSG_CANCEL: // 接受到了 MSG_CANCEL.
if (mVerb == VERB_FINISHED) {
if (DEBUG) {
Slog.d(TAG,
"Trying to process cancel for torn-down context, ignoring.");
}
return;
}
mParams.setStopReason(message.arg1); // reason 为 JobParameters.REASON_CANCELED
if (message.arg1 == JobParameters.REASON_PREEMPT) { // 不进入,因为这不是优先级取代!
mPreferredUid = mRunningJob != null ? mRunningJob.getUid() :
NO_PREFERRED_UID;
}
handleCancelH();
break;
case MSG_TIMEOUT:
handleOpTimeoutH();
break;
case MSG_SHUTDOWN_EXECUTION:
closeAndCleanupJobH(true /* needsReschedule */);
break;
default:
Slog.e(TAG, "Unrecognised message: " + message);
}
}
... ... ... ... ...
}
调用 handleCancelH 方法来取消 Job:
1.2.3 JSH.handleCancelH
1 | /** |
我们来看看 sendStopMessageH 方法:
1.2.4 JSH.sendStopMessageH
1 | /** |
这里会根据 mVerb 中存储的 job 的动作状态,来做相应的处理:
如果 job 的状态已经不是 VERB_EXECUTING,那就清除资源,恢复初始化;
否则,job 状态设置为 VERB_STOPPING,调用 jobService 的 stopJob,停止服务!
1.2.4.1 JobService.stopJob
通过 Binder 机制,停止 job:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32public abstract class JobService extends Service {
... ... ... ...
private static final String TAG = "JobService";
static final class JobInterface extends IJobService.Stub {
final WeakReference<JobService> mService;
JobInterface(JobService service) {
mService = new WeakReference<>(service);
}
public void startJob(JobParameters jobParams) throws RemoteException {
JobService service = mService.get();
if (service != null) {
service.ensureHandler();
Message m = Message.obtain(service.mHandler, MSG_EXECUTE_JOB, jobParams);
m.sendToTarget();
}
}
public void stopJob(JobParameters jobParams) throws RemoteException {
JobService service = mService.get();
if (service != null) {
service.ensureHandler(); // 确保 Handler 已经创建
Message m = Message.obtain(service.mHandler, MSG_STOP_JOB, jobParams); // 发送 MSG_STOP_JOB 到 JobHandler!
m.sendToTarget();
}
}
}
... ... ... ...
}
进入 JobHandler 方法:
1.2.4.2 JobService.JobHandler
处理前面通过 Binder 发送过来的 MSG_STOP_JOB:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45class JobHandler extends Handler {
JobHandler(Looper looper) {
super(looper);
}
public void handleMessage(Message msg) {
final JobParameters params = (JobParameters) msg.obj;
switch (msg.what) {
... ... ... ...
case MSG_STOP_JOB:
try {
// 这里是获得 JobService 的 onStopJob 的返回值!
boolean ret = JobService.this.onStopJob(params);
ackStopMessage(params, ret);
} catch (Exception e) {
Log.e(TAG, "Application unable to handle onStopJob.", e);
throw new RuntimeException(e);
}
break;
... ... ... ...
default:
Log.e(TAG, "Unrecognised message received.");
break;
}
}
... ... ... ...
private void ackStopMessage(JobParameters params, boolean reschedule) {
final IJobCallback callback = params.getCallback();
final int jobId = params.getJobId();
if (callback != null) {
try {
// 将被停止的 job 的 id 和 onStopJob 的返回值发给 JobServiceContext!
callback.acknowledgeStopMessage(jobId, reschedule);
} catch(RemoteException e) {
Log.e(TAG, "System unreachable for stopping job.");
}
} else {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Attempting to ack a job that has already been processed.");
}
}
}
}
JobService 的 onStopJob 的返回值如果为 true,那么,就表示 JobService 需要重新拉起他!前面我们分析的时候,知道,callback 就是 JobServiceContext
1.2.4.3 JSC.acknowledgeStopMessage
接着发送 MSG_CALLBACK 给 JobServiceHandler:1
2
3
4
5
6
7
8
public void acknowledgeStopMessage(int jobId, boolean reschedule) {
if (!verifyCallingUid()) {
return;
}
mCallbackHandler.obtainMessage(MSG_CALLBACK, jobId, reschedule ? 1 : 0)
.sendToTarget();
}
我们进入 JobServiceHandler 方法里面看看:
1.2.4.4 JSC.JobServiceHandler
1 | private class JobServiceHandler extends Handler { |
可以看到,最后会调用 JSH 的 closeAndCleanupJobH 方法:
1.2.4.5 JSH.closeAndCleanupJobH
如果 job 的状态已经不是 VERB_EXECUTING,那就清除资源,恢复初始化;这个方法很简单,就是将 JobServiceContext 中的属性值恢复初始化,表示没有任何 job 在运行!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34private void closeAndCleanupJobH(boolean reschedule) {
final JobStatus completedJob;
synchronized (mLock) {
if (mVerb == VERB_FINISHED) {
return;
}
completedJob = mRunningJob;
mJobPackageTracker.noteInactive(completedJob);
try {
mBatteryStats.noteJobFinish(mRunningJob.getBatteryName(),
mRunningJob.getSourceUid());
} catch (RemoteException e) {
// Whatever.
}
if (mWakeLock != null) {
mWakeLock.release();
}
mContext.unbindService(JobServiceContext.this); // 取消绑定 jobSerivce
mWakeLock = null;
mRunningJob = null; // mRunningJob 的值置为 null!
mParams = null; // JobParamters 置为 null
mVerb = VERB_FINISHED; // mVerb 的状态值为 VERB_FINISHED
mCancelled.set(false); // mCancelled 置为 false
service = null; // 应用的 JobService 代理对象置为 null
mAvailable = true; // mAvailable 置为 true,表示这个 JobService 可以分配给其他 job
}
removeOpTimeOut();
removeMessages(MSG_CALLBACK); // 清除处理过的 MSG
removeMessages(MSG_SERVICE_BOUND);
removeMessages(MSG_CANCEL);
removeMessages(MSG_SHUTDOWN_EXECUTION);
// 回调 JobSchedulerService 的 onJobCompleted 方法!
mCompletedListener.onJobCompleted(completedJob, reschedule);
}
恢复初始化,为下次做准备!
1.2.4.5.1 JSC.onServiceDisconnected
取消绑定 JobService 会调用 onServiceDisconnected1
2
3
4
5/** If the client service crashes we reschedule this job and clean up. */
public void onServiceDisconnected(ComponentName name) {
mCallbackHandler.obtainMessage(MSG_SHUTDOWN_EXECUTION).sendToTarget();
}
这里的会再回到 JobServiceHandler 中:1
2
3case MSG_SHUTDOWN_EXECUTION:
closeAndCleanupJobH(true /* needsReschedule */);
break;
做第二次 clean,防止第一次不成功,其实第一次 clean 成功的话,mVerb 的值为 VERB_FINISHED,第二次 clean 会自动退出的!
1.2.4.5.2 JSS.onJobCompleted
我们进入 JSS 的 onJobCompleted 的方法中:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public void onJobCompleted(JobStatus jobStatus, boolean needsReschedule) {
if (DEBUG) {
Slog.d(TAG, "Completed " + jobStatus + ", reschedule=" + needsReschedule);
}
// Do not write back immediately if this is a periodic job. The job may get lost if system
// shuts down before it is added back.
// 再次停止 track 这个 job,这里 stopTrackingJob 的返回值为 false!
if (!stopTrackingJob(jobStatus, null, !jobStatus.getJob().isPeriodic())) {
if (DEBUG) {
Slog.d(TAG, "Could not find job to remove. Was job removed while executing?");
}
// We still want to check for jobs to execute, because this job may have
// scheduled a new job under the same job id, and now we can run it.
// 发送 MSG_CHECK_JOB_GREEDY,继续执行其他的 job,然后直接 return
mHandler.obtainMessage(MSG_CHECK_JOB_GREEDY).sendToTarget();
return;
}
// Note: there is a small window of time in here where, when rescheduling a job,
// we will stop monitoring its content providers. This should be fixed by stopping
// the old job after scheduling the new one, but since we have no lock held here
// that may cause ordering problems if the app removes jobStatus while in here.
if (needsReschedule) {
JobStatus rescheduled = getRescheduleJobForFailure(jobStatus);
startTrackingJob(rescheduled, jobStatus);
} else if (jobStatus.getJob().isPeriodic()) {
JobStatus rescheduledPeriodic = getRescheduleJobForPeriodic(jobStatus);
startTrackingJob(rescheduledPeriodic, jobStatus);
}
reportActive();
mHandler.obtainMessage(MSG_CHECK_JOB_GREEDY).sendToTarget();
}
这里首先调用了 stopTrackingJob 将这个 job 从 JobStore 和 controller 中移除,因为之前已经移除过了,所以这个 stopTrackingJob 的返回值为 false1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20/**
* Called when we want to remove a JobStatus object that we've finished executing. Returns the
* object removed.
*/
private boolean stopTrackingJob(JobStatus jobStatus, JobStatus incomingJob,
boolean writeBack) {
synchronized (mLock) {
// Remove from store as well as controllers.
// 尝试从 JobStore 中移除这个 job,注意,在之前已经移除过了,所以,这里的 removed 为 false!
final boolean removed = mJobs.remove(jobStatus, writeBack);
if (removed && mReadyToRock) {
for (int i=0; i<mControllers.size(); i++) {
StateController controller = mControllers.get(i);
// 从 Controller 的跟踪队列中移除!
controller.maybeStopTrackingJobLocked(jobStatus, incomingJob, false);
}
}
return removed;
}
}
可以看出,对于用户主动 cancel 的任务,无论 onStopJob 的返回值是什么,都不会 reschedule 了!