主目錄見::Android高級進階知識(這是總目錄索引)
?今天講這篇文章主要是為了接上面一篇來講的,如果大家不知道JobScheduler怎么使用的話,那么可以移步在Android Lollipop中使用JobScheduler,我們知道,Android系統中有幾個重要的進程,init進程,Zygote進程,SystemServer進程,這些進程的啟動流程分別為:
- init進程->Zygote進程->SystemServer進程->各種應用進程
這里的Zygote
進程是應用的根進程,其他進程都是包括SystemServer
進程和各種應用進程都是Zygote
中fork出來的,其中SystemServer
主要是啟動各種系統服務,比如:ActivityManagerService
,PackageManagerService
,WindowManagerService
以及JobScheduler
等服務,JobScheduler
作為系統服務,也是從SystemServer
中啟動的,所以我們先來看SystemServer
的main方法,因為SystemServer
被Zygote
進程fork出來的時候會調用此方法:
public static void main(String[] args) {
new SystemServer().run();
}
這里我們看到主要是調用SystemServer
類的run方法,所以我們接下來看看:
private void run() {
...
// Start services.
try {
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartServices");
startBootstrapServices();
startCoreServices();
startOtherServices();
} catch (Throwable ex) {
throw ex;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
...
}
我們看到確實SystemServer
中會啟動各種服務,我們的JobScheduler
服務是在方法startOtherServices()
中通過SystemServiceManager
類來啟動的,我們來看看:
private void startOtherServices() {
...
mSystemServiceManager.startService(JobSchedulerService.class);
...
}
我們看到確實是交給SystemServiceManager
通過startService
來啟動JobSchedulerService
服務,所以我們來看startService
干了一些啥:
@SuppressWarnings("unchecked")
public <T extends SystemService> T startService(Class<T> serviceClass) {
try {
//獲取服務名稱,我們這里就是JobSchedulerService
final String name = serviceClass.getName();
.....
// Create the service.
//這里判斷參數serviceClass是否是SystemService的子類,不是的話就拋出錯誤
if (!SystemService.class.isAssignableFrom(serviceClass)) {
throw new RuntimeException("Failed to create " + name
+ ": service must extend " + SystemService.class.getName());
}
final T service;
try {
//獲取serviceClass的一個參數為Context的構造函數
Constructor<T> constructor = serviceClass.getConstructor(Context.class);
//實例化服務對象
service = constructor.newInstance(mContext);
} catch (Exception ex) {
......
}
// Register it.
//添加到服務的list中
mServices.add(service);
// Start it.
try {
//然后調用服務的onStart方法
service.onStart();
} catch (RuntimeException ex) {
......
}
return service;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
我們看到這個方法里面會調用服務一個參數為Context的構造函數進行實例化,所以我們這里接下來看看JobSchedulerService的構造函數做了什么。
1.JobSchedulerService
因為實例化一個JobSchedulerService類的時候,會執行構造函數的代碼:
public final class JobSchedulerService extends com.android.server.SystemService
implements StateChangedListener, JobCompletedListener {
final JobHandler mHandler;//主要處理任務到期,任務檢查,任務結束等消息
final Constants mConstants;//存放一些常量
final JobSchedulerStub mJobSchedulerStub;//Binder接口的代理類
final JobStore mJobs;//里面維護了一個Job集合,從data/system/job/jobs.xml文件中讀取的永久性任務
List<StateController> mControllers;//控制器集合
.....
public JobSchedulerService(Context context) {
super(context);
//初始化
mHandler = new JobHandler(context.getMainLooper());
mConstants = new Constants(mHandler);
mJobSchedulerStub = new JobSchedulerStub();
mJobs = JobStore.initAndGet(this);
// Create the controllers.
mControllers = new ArrayList<StateController>();
//網絡連接情況控制器
mControllers.add(ConnectivityController.get(this));
//執行時機控制器
mControllers.add(TimeController.get(this));
//空閑狀態控制器
mControllers.add(IdleController.get(this));
//電量情況控制器
mControllers.add(BatteryController.get(this));
//應用空閑狀態控制器
mControllers.add(AppIdleController.get(this));
//URIs內容變化控制器
mControllers.add(ContentObserverController.get(this));
//設備空閑狀態控制器
mControllers.add(DeviceIdleJobsController.get(this));
}
......
}
我們首先看到JobSchedulerService
類實現了StateChangedListener
接口,然后我們看到所有的控制器都是實現的StateController
類。首先來看看這個接口和類:
public interface StateChangedListener {
//控制器調用這個方法來通知JobManager 該檢查一個任務的狀態了,因為這里JobSchedulerService
//實現了這個接口,所以會調用JobSchedulerService里面這個方法的實現
public void onControllerStateChanged();
//控制器調用這個方法通知JobManager ,應該馬上執行任務了
public void onRunJobNow(JobStatus jobStatus);
//設備的空閑狀態發生改變調用這個方法
public void onDeviceIdleStateChanged(boolean deviceIdle);
}
我們知道JobSchedulerService
實現了這個接口,所以調用這里的接口就會調用到JobSchedulerService
中的方法實現。
public abstract class StateController {
protected static final boolean DEBUG = JobSchedulerService.DEBUG;
protected final Context mContext;
protected final Object mLock;
protected final StateChangedListener mStateChangedListener;
public StateController(StateChangedListener stateChangedListener, Context context,
Object lock) {
mStateChangedListener = stateChangedListener;
mContext = context;
mLock = lock;
}
//添加需要監聽的任務,同時在任務更新的時候也會調用
public abstract void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob);
//可選實現,在任務執行前做準備
public void prepareForExecutionLocked(JobStatus jobStatus) {
}
//清除該任務,當任務被取消,或者完成的時候調用
public abstract void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
boolean forUpdate);
//當一個新任務被創建來重新執行之前失敗的任務時調用
public void rescheduleForFailure(JobStatus newJob, JobStatus failureToReschedule) {
}
public abstract void dumpControllerStateLocked(PrintWriter pw, int filterUid);
}
我們看到所有的控制器都是繼承的這個抽象類,而且實現了里面的幾個抽象方法。這里我們就挑一個控制器來看看實現,這里我們選擇ConnectivityController控制器來看下流程。
2.ConnectivityController
public class ConnectivityController extends StateController implements
ConnectivityManager.OnNetworkActiveListener {
private static final String TAG = "JobScheduler.Conn";
//網絡連接管理類,用于獲取活躍網絡信息
private final ConnectivityManager mConnManager;
//提供網絡策略管理服務
private final NetworkPolicyManager mNetPolicyManager;
//追蹤的任務的列表
@GuardedBy("mLock")
private final ArrayList<JobStatus> mTrackedJobs = new ArrayList<JobStatus>();
/** Singleton. */
private static ConnectivityController mSingleton;
private static Object sCreationLock = new Object();
//獲取控制類實例:單例
public static ConnectivityController get(JobSchedulerService jms) {
synchronized (sCreationLock) {
if (mSingleton == null) {
mSingleton = new ConnectivityController(jms, jms.getContext(), jms.getLock());
}
return mSingleton;
}
}
private ConnectivityController(StateChangedListener stateChangedListener, Context context,
Object lock) {
super(stateChangedListener, context, lock);
//獲取管理類實例
mConnManager = mContext.getSystemService(ConnectivityManager.class);
mNetPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
//注冊網絡廣播
final IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
mContext.registerReceiverAsUser(
mConnectivityReceiver, UserHandle.SYSTEM, intentFilter, null, null);
mNetPolicyManager.registerListener(mNetPolicyListener);
}
@Override
public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
//判斷是否有連接約束,是否有不按用量計費的約束,是否有不允許漫游的約束
//(這些可以通過JobInfo的builder方法設置)
if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()
|| jobStatus.hasNotRoamingConstraint()) {
//更新任務的約束
updateConstraintsSatisfied(jobStatus);
//將任務添加進追蹤列表
mTrackedJobs.add(jobStatus);
}
}
@Override
public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
boolean forUpdate) {
if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()
|| jobStatus.hasNotRoamingConstraint()) {
//從追蹤列表中刪除任務
mTrackedJobs.remove(jobStatus);
}
}
private boolean updateConstraintsSatisfied(JobStatus jobStatus) {
final boolean ignoreBlocked = (jobStatus.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
//獲取活躍網絡的信息
final NetworkInfo info = mConnManager.getActiveNetworkInfoForUid(jobStatus.getSourceUid(),
ignoreBlocked);
final boolean connected = (info != null) && info.isConnected();
final boolean unmetered = connected && !info.isMetered();
final boolean notRoaming = connected && !info.isRoaming();
boolean changed = false;
//更新任務的網絡相關標識
changed |= jobStatus.setConnectivityConstraintSatisfied(connected);
changed |= jobStatus.setUnmeteredConstraintSatisfied(unmetered);
changed |= jobStatus.setNotRoamingConstraintSatisfied(notRoaming);
return changed;
}
/**
* Update all jobs tracked by this controller.
*
* @param uid only update jobs belonging to this UID, or {@code -1} to
* update all tracked jobs.
*/
private void updateTrackedJobs(int uid) {
synchronized (mLock) {
boolean changed = false;
//遍歷任務追蹤列表
for (int i = 0; i < mTrackedJobs.size(); i++) {
final JobStatus js = mTrackedJobs.get(i);
if (uid == -1 || uid == js.getSourceUid()) {
//更新約束
changed |= updateConstraintsSatisfied(js);
}
}
// 如果changed為true,則調用監聽器(即JobSchedulerService)的onControllerStateChanged方法
if (changed) {
mStateChangedListener.onControllerStateChanged();
}
}
}
/**
* We know the network has just come up. We want to run any jobs that are ready.
*/
@Override
public synchronized void onNetworkActive() {
synchronized (mLock) {
for (int i = 0; i < mTrackedJobs.size(); i++) {
final JobStatus js = mTrackedJobs.get(i);
if (js.isReady()) {
if (DEBUG) {
Slog.d(TAG, "Running " + js + " due to network activity.");
}
//當網絡狀態良好,我們就可以遍歷追蹤列表取出任務,然后調用下面方法馬上執行
mStateChangedListener.onRunJobNow(js);
}
}
}
}
private BroadcastReceiver mConnectivityReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//接收到網絡廣播則更新追蹤的任務
updateTrackedJobs(-1);
}
};
private INetworkPolicyListener mNetPolicyListener = new INetworkPolicyListener.Stub() {
//網絡策略變化則回調這里的相應方法
@Override
public void onUidRulesChanged(int uid, int uidRules) {
updateTrackedJobs(uid);
}
@Override
public void onMeteredIfacesChanged(String[] meteredIfaces) {
updateTrackedJobs(-1);
}
@Override
public void onRestrictBackgroundChanged(boolean restrictBackground) {
updateTrackedJobs(-1);
}
@Override
public void onRestrictBackgroundWhitelistChanged(int uid, boolean whitelisted) {
updateTrackedJobs(uid);
}
@Override
public void onRestrictBackgroundBlacklistChanged(int uid, boolean blacklisted) {
updateTrackedJobs(uid);
}
};
@Override
public void dumpControllerStateLocked(PrintWriter pw, int filterUid) {
//dump出來追蹤的任務信息
pw.println("Connectivity.");
pw.print("Tracking ");
pw.print(mTrackedJobs.size());
pw.println(":");
for (int i = 0; i < mTrackedJobs.size(); i++) {
final JobStatus js = mTrackedJobs.get(i);
if (js.shouldDump(filterUid)) {
pw.print(" #");
js.printUniqueId(pw);
pw.print(" from ");
UserHandle.formatUid(pw, js.getSourceUid());
pw.print(": C="); pw.print(js.hasConnectivityConstraint());
pw.print(": UM="); pw.print(js.hasUnmeteredConstraint());
pw.print(": NR="); pw.println(js.hasNotRoamingConstraint());
}
}
}
}
我們看到這個網絡連接控制器里面邏輯明了,主要是注冊了網絡連接的廣播,同時注冊了網絡約束的監聽,所以在接收到廣播后會調用updateTrackedJobs
方法來更新每個任務的約束信息,同時會調用JobSchedulerService
的onControllerStateChanged方法來通知說約束任務的條件狀態發生改變,而且由于該控制器實現了ConnectivityManager.OnNetworkActiveListener
接口,所以網絡可用的時候會回調onNetworkActive()
方法,這個方法在網絡可用狀態的時候,馬上執行任務。所以我們接下來看JobSchedulerService
的onControllerStateChanged
方法和onNetworkActive()
方法。
3.onControllerStateChanged和onNetworkActive
@Override
public void onControllerStateChanged() {
mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
}
@Override
public void onRunJobNow(JobStatus jobStatus) {
mHandler.obtainMessage(MSG_JOB_EXPIRED, jobStatus).sendToTarget();
}
我們看到JobSchedulerService
的這兩個方法主要就是向Handler
發送了消息,分別是MSG_CHECK_JOB
和MSG_JOB_EXPIRED
類型的消息,所以邏輯實際是交給了Handler
執行了。這里的Handler是什么呢?其實這里的Handler就是JobHandler
,JobHandler
類是在JobSchedulerService
中被實例化的。所以我們可以來看看JobHandler
類。
4.JobHandler
因為這是個Handler
的對象,所以我們先來看他的handleMessage
方法:
@Override
public void handleMessage(Message message) {
synchronized (mLock) {
if (!mReadyToRock) {//未準備好執行任務直接return
return;
}
}
switch (message.what) {
case MSG_JOB_EXPIRED://任務到期執行消息
synchronized (mLock) {
//取出消息里的任務
JobStatus runNow = (JobStatus) message.obj;
//runNow不為空且等待列表中有這個任務,且任務集合中有這個任務
if (runNow != null && !mPendingJobs.contains(runNow)
&& mJobs.containsJob(runNow)) {
mJobPackageTracker.notePending(runNow);
//將當前任務加入等待執行的列表中
mPendingJobs.add(runNow);
}
//將任務集合中已經準備執行的任務加入等待執行列表,準備取消執行的任務取消
queueReadyJobsForExecutionLockedH();
}
break;
case MSG_CHECK_JOB:
synchronized (mLock) {
if (mReportedActive) {
//將任務集合中已經準備執行的任務加入等待執行列表,準備取消執行的任務取消
queueReadyJobsForExecutionLockedH();
} else {
//檢查任務集合,把準備好執行的任務添加到等待執行列表
maybeQueueReadyJobsForExecutionLockedH();
}
}
break;
case MSG_CHECK_JOB_GREEDY:
synchronized (mLock) {
//將任務集合中已經準備執行的任務加入等待執行列表,準備取消執行的任務取消
queueReadyJobsForExecutionLockedH();
}
break;
case MSG_STOP_JOB:
//如果任務在等待執行列表中則移除,如果正在執行則取消
cancelJobImpl((JobStatus)message.obj, null);
break;
}
//開始執行等待執行列表中的任務
maybeRunPendingJobsH();
// Don't remove JOB_EXPIRED in case one came along while processing the queue.
removeMessages(MSG_CHECK_JOB);
}
我們看到這個Handler執行四種消息類型,其中我們onControllerStateChanged
方法發送的MSG_CHECK_JOB
和onRunJobNow
方法的MSG_JOB_EXPIRED
消息分別對應上面的操作,其中有幾個關鍵方法queueReadyJobsForExecutionLockedH()
,maybeQueueReadyJobsForExecutionLockedH()
,maybeRunPendingJobsH()
,我們一一來看看,首先我們來看queueReadyJobsForExecutionLockedH()
方法:
private void queueReadyJobsForExecutionLockedH() {
if (DEBUG) {
Slog.d(TAG, "queuing all ready jobs for execution:");
}
noteJobsNonpending(mPendingJobs);
//清除等待執行列表中的任務
mPendingJobs.clear();
// 遍歷任務列表,循環判斷任務是否準備好執行 ,準備好了則加入準備執行列表中,不然約束條件為滿足則取消
mJobs.forEachJob(mReadyQueueFunctor);
//將準備執行的任務重新添加到待執行任務列表中
mReadyQueueFunctor.postProcess();
if (DEBUG) {
final int queuedJobs = mPendingJobs.size();
if (queuedJobs == 0) {
Slog.d(TAG, "No jobs pending.");
} else {
Slog.d(TAG, queuedJobs + " jobs queued.");
}
}
}
我們看到這個方法主要是把JobStore
(JobStore從磁盤中讀取任務map存放在mJobSet中,xml文件主要在data/system/job目錄下創建jobs.xml文件)中的準備執行的符合約束條件的任務添加等待執行的任務列表中。maybeQueueReadyJobsForExecutionLockedH()
方法也是類似,我們這里直接看另外一個maybeRunPendingJobsH()
方法,這個方法非常關鍵,前面已經有等待執行任務列表了,這個方法就是取出來任務執行的。
private void maybeRunPendingJobsH() {
synchronized (mLock) {
assignJobsToContextsLocked();
reportActive();
}
}
我們看到這個方法會調用另外一個方法assignJobsToContextsLocked()
來執行任務,然后這個方法又會調用mActiveServices.get(i).executeRunnableJob(pendingJob)
來執行任務,mActiveServices.get(i)獲取到的是JobServiceContext
對象,所以我們調用這個對象的executeRunnableJob()
方法。
5.JobServiceContext executeRunnableJob
boolean executeRunnableJob(JobStatus job) {
synchronized (mLock) {
//如果這個Context無效則返回
if (!mAvailable) {
return false;
}
mPreferredUid = NO_PREFERRED_UID;
mRunningJob = job;
//任務是否有最后期限約束且最近一次執行時間是否小于開機時間
final boolean isDeadlineExpired =
job.hasDeadlineConstraint() &&
(job.getLatestRunTimeElapsed() < SystemClock.elapsedRealtime());
.....
mParams = new JobParameters(this, job.getJobId(), job.getExtras(), isDeadlineExpired,
triggeredUris, triggeredAuthorities);
mExecutionStartTimeElapsed = SystemClock.elapsedRealtime();
mVerb = VERB_BINDING;
scheduleOpTimeOut();
// 用任務的服務的組件名創建Intent
final Intent intent = new Intent().setComponent(job.getServiceComponent());
//這里執行了服務的綁定操作(跟AMS進行交互啟動服務),意思就是
//把你任務中設置的服務啟動然后會回調ServiceConnection
//對象的onServiceConnected方法
boolean binding = mContext.bindServiceAsUser(intent, this,
Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND,
new UserHandle(job.getUserId()));
if (!binding) {
mRunningJob = null;
mParams = null;
mExecutionStartTimeElapsed = 0L;
mVerb = VERB_FINISHED;
removeOpTimeOut();
return false;
}
try {
mBatteryStats.noteJobStart(job.getBatteryName(), job.getSourceUid());
} catch (RemoteException e) {
// Whatever.
}
mJobPackageTracker.noteActive(job);
mAvailable = false;
return true;
}
}
我們看到這個方法會調用Context
中的bindServiceAsUser
方法進行服務的綁定操作,這里的服務綁定跟我們的bindService服務類似,具體流程可以看從framework分析AIDL生成文件這里的流程非常詳細,我們知道最終程序會回調onServiceConnected
方法,因為這個地方this就是JobServiceContext
對象,而且我們看到JobServiceContext
就是實現了ServiceConnection
:
public class JobServiceContext extends IJobCallback.Stub implements ServiceConnection {
....
}
所以我們知道,綁定完服務會回調JobServiceContext
中的onServiceConnected
方法:
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
JobStatus runningJob;
synchronized (mLock) {
runningJob = mRunningJob;
}
//正在執行的任務為空,或者正在執行的任務的服務名稱和綁定的服務的服務名稱不一致則取消執行
if (runningJob == null || !name.equals(runningJob.getServiceComponent())) {
mCallbackHandler.obtainMessage(MSG_SHUTDOWN_EXECUTION).sendToTarget();
return;
}
//獲取遠程的JobService的代理
this.service = IJobService.Stub.asInterface(service);
final PowerManager pm =
(PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
runningJob.getTag());
wl.setWorkSource(new WorkSource(runningJob.getSourceUid()));
wl.setReferenceCounted(false);
wl.acquire();
synchronized (mLock) {
if (mWakeLock != null) {
mWakeLock.release();
}
mWakeLock = wl;
}
// 向mCallbackHandler發送綁定服務成功的消息
mCallbackHandler.obtainMessage(MSG_SERVICE_BOUND).sendToTarget();
}
我們看到這里跟我們平常寫AIDL跨進程通訊的回調寫法差不多,方法最后還會向mCallbackHandler
發送一個MSG_SERVICE_BOUND
類型的消息。這個mCallbackHandler又是什么呢?這里其實是JobServiceHandler
對象,我們來看看JobServiceHandler
中的handleMessage
做了啥:
@Override
public void handleMessage(Message message) {
switch (message.what) {
case MSG_SERVICE_BOUND:
removeOpTimeOut();
handleServiceBoundH();
break;
......
}
我們看到這里調用了handleServiceBoundH()方法,這個方法我們也跟進來看看:
/** Start the job on the service. */
private void handleServiceBoundH() {
if (mVerb != VERB_BINDING) {
closeAndCleanupJobH(false /* reschedule */);
return;
}
if (mCancelled.get()) {
closeAndCleanupJobH(true /* reschedule */);
return;
}
try {
mVerb = VERB_STARTING;
scheduleOpTimeOut();
//我們知道這里service是IJobService對象,其實就是遠程JobService的代理,所以會調用到JobService的startJob方法
service.startJob(mParams);
} catch (RemoteException e) {
......
}
}
到這里,我們看到會調用到JobService中的startJob,我們猜想,到這里我們的服務就啟動完成了。
6.JobService startJob
static final class JobInterface extends IJobService.Stub {
final WeakReference<JobService> mService;
JobInterface(JobService service) {
mService = new WeakReference<>(service);
}
@Override
public void startJob(JobParameters jobParams) throws RemoteException {
JobService service = mService.get();
if (service != null) {
service.ensureHandler();
// 把jobParams封裝成一個消息
Message m = Message.obtain(service.mHandler, MSG_EXECUTE_JOB, jobParams);
//發送消息
m.sendToTarget();
}
}
.......
}
我們知道跨進程通訊的人都知道,遠程JobService代理
調用startJob
其實就是調用到遠程Binder
中的startJob
方法,在這個方法中,會發送一個消息類型為MSG_EXECUTE_JOB
的消息給Handler
,這里的Handler
就是JobService
服務中的JobHandler
,同樣我們來看看他的handleMessage
里面的處理:
@Override
public void handleMessage(Message msg) {
final JobParameters params = (JobParameters) msg.obj;
switch (msg.what) {
case MSG_EXECUTE_JOB:
try {
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;
.....
}
我們看到這個方法執行了JobService
中的onStartJob
方法,這個方法在我們自定義服務繼承JobService的時候會重寫這個方法。我們會在這個方法啟動我們的任務。
7.JobScheduler schedule
我們知道,使用方法里面除了啟動自定義的服務之外,還會把JobInfo.Builder
傳給JobScheduler
的schedule方法,如下所示:
JobScheduler tm = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
tm.schedule(builder.build());
同時我們記得,在最前面我們SystemServiceManager
通過startService
啟動JobSchedulerService
服務的時候,當實例化JobSchedulerService
的時候,我們會調用JobSchedulerService
的onStart
方法,我們先來看看這個onStart
方法做了什么:
@Override
public void onStart() {
publishLocalService(JobSchedulerInternal.class, new LocalService());
publishBinderService(Context.JOB_SCHEDULER_SERVICE, mJobSchedulerStub);
}
是不是一眼就明白了,我們這里publishBinderService()
方法綁定的JOB_SCHEDULER_SERVICE
服務就是 mJobSchedulerStub
,也就是JobSchedulerService
的內部類JobSchedulerStub
對象,所以我們這里的schedule
方法實際其實是JobSchedulerStub
中的:
@Override
public int schedule(JobInfo job) throws RemoteException {
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
.......
long ident = Binder.clearCallingIdentity();
try {
return JobSchedulerService.this.schedule(job, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
我們看到以上的方法又調用了JobSchedulerService
的schedule
方法:
public int schedule(JobInfo job, int uId) {
return scheduleAsPackage(job, uId, null, -1, null);
}
我們接著往下看scheduleAsPackage方法:
public int scheduleAsPackage(JobInfo job, int uId, String packageName, int userId,
String tag) {
JobStatus jobStatus = JobStatus.createFromJobInfo(job, uId, packageName, userId, tag);
....
JobStatus toCancel;
.....
//查找任務隊列中的任務
toCancel = mJobs.getJobByUidAndJobId(uId, job.getId());
if (toCancel != null) {
// 如果任務已經在等待隊列或已經在執行則從等待隊列中移除或取消任務的執行
cancelJobImpl(toCancel, jobStatus);
}
// 開始追蹤任務
startTrackingJob(jobStatus, toCancel);
}
// 向Handler發送檢查任務的消息
mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
return JobScheduler.RESULT_SUCCESS;
}
我們看到這個方法主要就是根據傳進來的JobInfo
來創建一個任務,然后查找這個任務是否已經存在,如果存在的話那么刪除,然后開始追蹤,向JobHandler
中發送一個檢查任務消息,將任務添加到等待執行的任務列表中,然后執行任務。
總結:整體的流程大體是寫完了,但是發現還有JobFinish()方法的源碼沒有寫(這個方法會調用到JobServiceContext里的JobFinish(),然后會調用unbindService解除服務綁定),這部分只能留給大家自己看了,如果認真看完上面的分析應該這部分不會太難,希望大家不要害怕看源碼哈,看懂了源碼,使用的時候就更有把握了有沒有。