基于 Android 7.1.1 源码分析
前言
当任务完成时,应用需要手动调用 jobFinished 方法,这个方法是属于 JobService 的:1
2
3
4
5
6public final void jobFinished(JobParameters params, boolean needsReschedule) {
    ensureHandler();
    Message m = Message.obtain(mHandler, MSG_JOB_FINISHED, params);
    m.arg2 = needsReschedule ? 1 : 0;
    m.sendToTarget();
}
其实,参数很简单,这个消息 MSG_JOB_FINISHED 会发送到 JobHandler 中!
1 JS.JobHandler
进入 JobHandler 中来看看: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
32class JobHandler extends Handler {
    JobHandler(Looper looper) {
        super(looper);
    }
    
    public void handleMessage(Message msg) {
        final JobParameters params = (JobParameters) msg.obj;
        switch (msg.what) {
            ... ... ... ...
      
            case MSG_JOB_FINISHED:
                final boolean needsReschedule = (msg.arg2 == 1);
                // callback 是 JobServiceContext 
                IJobCallback callback = params.getCallback();
                if (callback != null) {
                    try {
                        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;
            default:
                Log.e(TAG, "Unrecognised message received.");
                break;
        }
    }
}
这里调用了 JObServiceContext 的 jobFinished 方法!
2 JSC.jobFinished
我们来看看 JobServiceContext 的 jobFinished 方法:1
2
3
4
5
6
7
8
9
public void jobFinished(int jobId, boolean reschedule) {
    if (!verifyCallingUid()) {
        return;
    }
    mCallbackHandler.obtainMessage(MSG_CALLBACK, jobId, reschedule ? 1 : 0)
            .sendToTarget();
}
这里先调用了 JobServiceContext 的 verifyCallingUid,校验 uid!1
2
3
4
5
6
7
8
9
10
11private boolean verifyCallingUid() {
    synchronized (mLock) {
        if (mRunningJob == null || Binder.getCallingUid() != mRunningJob.getUid()) {
            if (DEBUG) {
                Slog.d(TAG, "Stale callback received, ignoring.");
            }
            return false;
        }
        return true;
    }
}
接着发送了一个 MSG_CALLBACK 的消息给了 JobServiceHandler!
3 JSC.JobServiceHandler
接着进入了 JobServiceHandler,来看主要代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19case MSG_CALLBACK:
    if (DEBUG) {
        Slog.d(TAG, "MSG_CALLBACK of : " + mRunningJob
                + " v:" + VERB_STRINGS[mVerb]);
    }
    removeOpTimeOut();
    if (mVerb == VERB_STARTING) {
        final boolean workOngoing = message.arg2 == 1;
        handleStartedH(workOngoing);
    } else if (mVerb == VERB_EXECUTING || // 此时 mVerb 的状态为 VERB_EXECUTING
            mVerb == VERB_STOPPING) { 
        final boolean reschedule = message.arg2 == 1;
        handleFinishedH(reschedule);
    } else {
        if (DEBUG) {
            Slog.d(TAG, "Unrecognised callback: " + mRunningJob);
        }
    }
    break;
调用了 handleFinishedH:1
2
3
4
5
6
7
8
9
10
11private void handleFinishedH(boolean reschedule) {
    switch (mVerb) {
        case VERB_EXECUTING:
        case VERB_STOPPING:
            closeAndCleanupJobH(reschedule);
            break;
        default:
            Slog.e(TAG, "Got an execution complete message for a job that wasn't being" +
                    "executed. Was " + VERB_STRINGS[mVerb] + ".");
    }
}
这里就很简单了,调用了 closeAndCleanupJobH 来解除 bind 和将 JObServiceContext 恢复初始化,为下一次 bind 做准备!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    private 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);
            mWakeLock = null;
            mRunningJob = null;
            mParams = null;
            mVerb = VERB_FINISHED; // 状态变为 VERB_FINISHED
            mCancelled.set(false);
            service = null;
            mAvailable = true;
        }
        removeOpTimeOut();
        removeMessages(MSG_CALLBACK);
        removeMessages(MSG_SERVICE_BOUND);
        removeMessages(MSG_CANCEL);
        removeMessages(MSG_SHUTDOWN_EXECUTION);
        // 通知 JobSchedulerService,这个 job 已经 finished 了
        mCompletedListener.onJobCompleted(completedJob, reschedule);
    }
}
接着,进入了 JobSchedulerService 方法中:
4 JSS.onJobCompleted
调用了 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
33
34
public void onJobCompleted(JobStatus jobStatus, boolean needsReschedule) {
    if (DEBUG) {
        Slog.d(TAG, "Completed " + jobStatus + ", reschedule=" + needsReschedule);
    }
    // 停止 track job,会将 job 从 JobStore 中删除,如果不是周期性的 job,还要更新本地的 jobs.xml 文件!
    if (!stopTrackingJob(jobStatus, null, !jobStatus.getJob().isPeriodic())) {
        if (DEBUG) {
            Slog.d(TAG, "Could not find job to remove. Was job removed while executing?");
        }
        
        // 停止失败,说明 job 之前已经被移除,继续发起下一轮的执行!
        mHandler.obtainMessage(MSG_CHECK_JOB_GREEDY).sendToTarget();
        return;
    }
    
    // 停止成功
    if (needsReschedule) {// 需要 reschedule 这个 job,如果需要,就 startTrackingJob
        JobStatus rescheduled = getRescheduleJobForFailure(jobStatus);
        startTrackingJob(rescheduled, jobStatus);
        
    } else if (jobStatus.getJob().isPeriodic()) { // 如果不需要 reschedule,但是这个 job 是周期性的,也要 startTrackingJob
        JobStatus rescheduledPeriodic = getRescheduleJobForPeriodic(jobStatus);
        startTrackingJob(rescheduledPeriodic, jobStatus);
    }
    
    // 汇报 JSS 运行状态给 DeviceIdleController!
    reportActive();
    
    // 继续开始新一轮的 job 执行!
    mHandler.obtainMessage(MSG_CHECK_JOB_GREEDY).sendToTarget();
}
4.1 JSS.getRescheduleJobForFailure
这里调用了 getRescheduleJobForPeriodic 的方法: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 JobStatus getRescheduleJobForFailure(JobStatus failureToReschedule) {
    // 获得自开机后,经过的时间,包括深度睡眠的时间;
    final long elapsedNowMillis = SystemClock.elapsedRealtime();
    // 获得这个 jobFinished 的 jobStatus 对应的 JobInfo;
    final JobInfo job = failureToReschedule.getJob();
    final long initialBackoffMillis = job.getInitialBackoffMillis();
    final int backoffAttempts = failureToReschedule.getNumFailures() + 1;
    long delayMillis;
    switch (job.getBackoffPolicy()) {
        case JobInfo.BACKOFF_POLICY_LINEAR:
            delayMillis = initialBackoffMillis * backoffAttempts;
            break;
        case JobInfo.BACKOFF_POLICY_EXPONENTIAL:
            delayMillis =
                    (long) Math.scalb(initialBackoffMillis, backoffAttempts - 1);
            break;
        default:
            if (DEBUG) {
                Slog.v(TAG, "Unrecognised back-off policy, defaulting to exponential.");
            }
    }
    delayMillis =
            Math.min(delayMillis, JobInfo.MAX_BACKOFF_DELAY_MILLIS);
    JobStatus newJob = new JobStatus(failureToReschedule, elapsedNowMillis + delayMillis,
            JobStatus.NO_LATEST_RUNTIME, backoffAttempts);
    for (int ic=0; ic<mControllers.size(); ic++) {
        StateController controller = mControllers.get(ic);
        controller.rescheduleForFailure(newJob, failureToReschedule);
    }
    return newJob;
}
4.2 JSS.getRescheduleJobForPeriodic
| 1 | private JobStatus getRescheduleJobForPeriodic(JobStatus periodicToReschedule) { | 
