JobSchedulerService啟動過程,最主要工作是從jobs.xml文件收集所有的jobs,放入到JobStore的成員變量mJobSet,轉成jobinfo。
JobScheduler服務啟動
2.1 startOtherServices
[-> SystemServer.java]
private void startOtherServices() { ... mSystemServiceManager.startService(JobSchedulerService.class); ... }
該方法先初始化JSS,然后再調用其onStart()方法。
2.2 JobSchedulerService
[-> JobSchedulerService.java]
JobSchedulerService {
List<StateController> mControllers;
final JobHandler mHandler;
final JobSchedulerStub mJobSchedulerStub;
final JobStore mJobs;
...
public JobSchedulerService(Context context) { super(context); 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)); //創建主線程的looper[見小節2.3] mHandler = new JobHandler(context.getMainLooper()); //創建binder服務端[見小節2.4] mJobSchedulerStub = new JobSchedulerStub(); //[見小節2.5] mJobs = JobStore.initAndGet(this); } public void onStart() { publishBinderService(Context.JOB_SCHEDULER_SERVICE, mJobSchedulerStub); } }
創建了5個不同的StateController,分別添加到mControllers。
類型 | 說明 |
---|---|
ConnectivityController | 注冊監聽網絡連接狀態的廣播 |
TimeController | 注冊監聽job時間到期的廣播 |
IdleController | 注冊監聽屏幕亮/滅,dream進入/退出,狀態改變的廣播 |
BatteryController | 注冊監聽電池是否充電,電量狀態的廣播 |
AppIdleController | 監聽app是否空閑 |
接下來,以ConnectivityController為例,說一說相應Controller的創建過程, 其他Controller也基本類似.
2.2.1 ConnectivityController
[-> ConnectivityController.java]
public class ConnectivityController extends StateController implements ConnectivityManager.OnNetworkActiveListener { public static ConnectivityController get(JobSchedulerService jms) { synchronized (sCreationLock) { if (mSingleton == null) { //單例模式 mSingleton = new ConnectivityController(jms, jms.getContext()); } return mSingleton; } } private ConnectivityController(StateChangedListener stateChangedListener, Context context) { super(stateChangedListener, context); //注冊監聽網絡連接狀態的廣播,且采用BackgroundThread線程 IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); mContext.registerReceiverAsUser( mConnectivityChangedReceiver, UserHandle.ALL, intentFilter, null, BackgroundThread.getHandler()); ConnectivityService cs = (ConnectivityService)ServiceManager.getService(Context.CONNECTIVITY_SERVICE); if (cs != null) { if (cs.getActiveNetworkInfo() != null) { mNetworkConnected = cs.getActiveNetworkInfo().isConnected(); } mNetworkUnmetered = mNetworkConnected && !cs.isActiveNetworkMetered(); } } }
當監聽到CONNECTIVITY_ACTION廣播,onReceive方法的執行位於“android.bg”線程。
2.3 JSS.JobHandler
[-> JobSchedulerService.java ::JobHandler]
public class JobSchedulerService extends com.android.server.SystemService implements StateChangedListener, JobCompletedListener { private class JobHandler extends Handler { public JobHandler(Looper looper) { super(looper); } public void handleMessage(Message message) { synchronized (mJobs) { //當系統啟動到phase 600,則mReadyToRock=true. if (!mReadyToRock) { return; } } switch (message.what) { case MSG_JOB_EXPIRED: ... case MSG_CHECK_JOB: ... } maybeRunPendingJobsH(); removeMessages(MSG_CHECK_JOB); }
JobHandler采用的是system_server進程的主線程Looper,也就是該過程運行在主線程。
2.4 JobSchedulerStub
[-> JobSchedulerService.java ::JobSchedulerStub]
final class JobSchedulerStub extends IJobScheduler.Stub { ... }
JobSchedulerStub作為實現接口IJobScheduler的binder服務端。
2.5 JS.initAndGet
[-> JobStore.java]
static JobStore initAndGet(JobSchedulerService jobManagerService) { synchronized (sSingletonLock) { if (sSingleton == null) { //[見小節2.6] sSingleton = new JobStore(jobManagerService.getContext(), Environment.getDataDirectory()); } return sSingleton; } }
2.6 創建JobStore
[-> JobStore.java]
public class JobStore { final ArraySet<JobStatus> mJobSet; private final Handler mIoHandler = IoThread.getHandler(); ... private JobStore(Context context, File dataDir) { mContext = context; mDirtyOperations = 0; File systemDir = new File(dataDir, "system"); File jobDir = new File(systemDir, "job"); jobDir.mkdirs(); // 創建/data/system/job/jobs.xml mJobsFile = new AtomicFile(new File(jobDir, "jobs.xml")); mJobSet = new ArraySet<JobStatus>(); //[見小節2.7.1] readJobMapFromDisk(mJobSet); } }
該方法會創建job目錄以及jobs.xml文件, 以及從文件中讀取所有的JobStatus。
2.7 xml解析
2.7.1 ReadJobMapFromDiskRunnable
[-> JobStore.java]
private class ReadJobMapFromDiskRunnable implements Runnable { private final ArraySet<JobStatus> jobSet; ReadJobMapFromDiskRunnable(ArraySet<JobStatus> jobSet) { this.jobSet = jobSet; } public void run() { List<JobStatus> jobs; FileInputStream fis = mJobsFile.openRead(); synchronized (JobStore.this) { jobs = readJobMapImpl(fis); //[見小節2.7.2] if (jobs != null) { for (int i=0; i<jobs.size(); i++) { this.jobSet.add(jobs.get(i)); } } } fis.close(); } }
此處mJobsFile便是/data/system/job/jobs.xml。
2.7.2 readJobMapImpl
[-> JobStore.java]
private List<JobStatus> readJobMapImpl(FileInputStream fis) throws XmlPullParserException, IOException { XmlPullParser parser = Xml.newPullParser(); parser.setInput(fis, StandardCharsets.UTF_8.name()); ... String tagName = parser.getName(); if ("job-info".equals(tagName)) { final List<JobStatus> jobs = new ArrayList<JobStatus>(); ... eventType = parser.next(); do { //讀取每一個 <job/> if (eventType == XmlPullParser.START_TAG) { tagName = parser.getName(); if ("job".equals(tagName)) { //[見小節2.7.3] JobStatus persistedJob = restoreJobFromXml(parser); if (persistedJob != null) { jobs.add(persistedJob); } } } eventType = parser.next(); } while (eventType != XmlPullParser.END_DOCUMENT); return jobs; } return null; }
從文件jobs.xml中讀取並創建JobStatus,然后添加到mJobSet.
2.7.3 restoreJobFromXml
[-> JobStore.java]
private JobStatus restoreJobFromXml(XmlPullParser parser) throws XmlPullParserException, IOException { JobInfo.Builder jobBuilder; int uid; //創建用於獲取jobInfo的Builder[見小節2.7.4] jobBuilder = buildBuilderFromXml(parser); jobBuilder.setPersisted(true); uid = Integer.valueOf(parser.getAttributeValue(null, "uid")); ... buildConstraintsFromXml(jobBuilder, parser); //讀取常量 //讀取job執行的兩個時間點:delay和deadline Pair<Long, Long> elapsedRuntimes = buildExecutionTimesFromXml(parser); ... //[見小節2.8] return new JobStatus(jobBuilder.build(), uid, elapsedRuntimes.first, elapsedRuntimes.second); }
2.7.4 buildBuilderFromXml
[-> JobStore.java]
private JobInfo.Builder buildBuilderFromXml(XmlPullParser parser) throws NumberFormatException { int jobId = Integer.valueOf(parser.getAttributeValue(null, "jobid")); String packageName = parser.getAttributeValue(null, "package"); String className = parser.getAttributeValue(null, "class"); ComponentName cname = new ComponentName(packageName, className); //[見小節2.7.5] return new JobInfo.Builder(jobId, cname); }
創建的JobInfo對象,記錄着任務的jobid, package, class。
2.7.5 創建JobInfo
[-> JobInfo.java]
public class JobInfo implements Parcelable { public static final class Builder { public Builder(int jobId, ComponentName jobService) { mJobService = jobService; mJobId = jobId; } public JobInfo build() { mExtras = new PersistableBundle(mExtras); return new JobInfo(this); //創建JobInfo } } }
2.8 創建JobStatus
[-> JobStatus.java]
public JobStatus(JobInfo job, int uId, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) { this(job, uId, 0); this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis; this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis; } private JobStatus(JobInfo job, int uId, int numFailures) { this.job = job; this.uId = uId; this.name = job.getService().flattenToShortString(); this.tag = "*job*/" + this.name; this.numFailures = numFailures; }
JobStatus對象記錄着任務的jobId, ComponentName, uid以及標簽和失敗次數信息。
2.9 JSS.onBootPhase
public void onBootPhase(int phase) { if (PHASE_SYSTEM_SERVICES_READY == phase) { //階段500,則開始注冊package和use移除的廣播監聽 final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED); filter.addDataScheme("package"); getContext().registerReceiverAsUser( mBroadcastReceiver, UserHandle.ALL, filter, null, null); final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED); userFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); getContext().registerReceiverAsUser( mBroadcastReceiver, UserHandle.ALL, userFilter, null, null); mPowerManager = (PowerManager)getContext().getSystemService(Context.POWER_SERVICE); } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { synchronized (mJobs) { mReadyToRock = true; mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( BatteryStats.SERVICE_NAME)); for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) { //創建JobServiceContext對象 mActiveServices.add( new JobServiceContext(this, mBatteryStats, getContext().getMainLooper())); } ArraySet<JobStatus> jobs = mJobs.getJobs(); for (int i=0; i<jobs.size(); i++) { JobStatus job = jobs.valueAt(i); for (int controller=0; controller<mControllers.size(); controller++) { mControllers.get(controller).deviceIdleModeChanged(mDeviceIdleMode); mControllers.get(controller).maybeStartTrackingJob(job); } } //[見小節3.8] mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget(); } } }
對於低內存的設備,則只創建一個創建JobServiceContext對象;否則創建3個該對象。
2.9.1 創建JobServiceContext
[-> JobServiceContext.java]
JobServiceContext(JobSchedulerService service, IBatteryStats batteryStats, Looper looper) {
this(service.getContext(), batteryStats, service, looper); } JobServiceContext(Context context, IBatteryStats batteryStats, JobCompletedListener completedListener, Looper looper) { mContext = context; mBatteryStats = batteryStats; mCallbackHandler = new JobServiceHandler(looper); mCompletedListener = completedListener; mAvailable = true; }
此處的JobServiceHandler采用的是system_server進程的主線程。
2.10 小結
- JSS.JobHandler運行在system_server進程的主線程;
- JobServiceContext.JobServiceHandler運行在system_server進程的主線程;
- JobSchedulerStub作為實現接口IJobScheduler的binder服務端;
- JobStore:其成員變量mIoHandler運行在”android.io”線程;
- JobStatus:從/data/system/job/jobs.xml文件中讀取每個JobInfo,再解析成JobStatus對象,添加到mJobSet。