JobSchedulerService 的启动

前面一节介绍了JobScheduler的简单使用, 本节介绍JobSchedulerService的启动.

1 SystemServer 中的启动

frameworks/base/services/java/com/android/server/SystemServer.java 的 startOtherServices方法中:

  1. traceBeginAndSlog("StartJobScheduler");
  2. mSystemServiceManager.startService(JobSchedulerService.class);
  3. traceEnd();
  4. // 启动所有的服务的startBootPhase方法, 包括JobSchedulerService的
  5. traceBeginAndSlog("StartBootPhaseSystemServicesReady");
  6. mSystemServiceManager.startBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
  7. traceEnd();

mSystemServiceManager 是SystemServiceManager,只会创建一次,启动服务时, 就调用startService方法. 启动的Service都必须继承SystemServer.

  1. /**
  2. * Creates and starts a system service. The class must be a subclass of
  3. * {@link com.android.server.SystemService}.
  4. *
  5. * @param serviceClass A Java class that implements the SystemService interface.
  6. * @return The service instance, never null.
  7. * @throws RuntimeException if the service fails to start.
  8. */
  9. @SuppressWarnings("unchecked")
  10. public <T extends SystemService> T startService(Class<T> serviceClass) {
  11. try {
  12. final String name = serviceClass.getName();
  13. Slog.i(TAG, "Starting " + name);
  14. Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name);
  15. // Create the service. 确保是继承了SystemService
  16. if (!SystemService.class.isAssignableFrom(serviceClass)) {
  17. throw n:ew RuntimeException("Failed to create " + name
  18. + ": service must extend " + SystemService.class.getName());
  19. }
  20. final T service;
  21. try { // 通过反射, 创建服务
  22. Constructor<T> constructor = serviceClass.getConstructor(Context.class);
  23. service = constructor.newInstance(mContext);
  24. } catch (InstantiationException ex) {
  25. throw new RuntimeException("Failed to create service " + name
  26. + ": service could not be instantiated", ex);
  27. } catch (IllegalAccessException ex) {
  28. throw new RuntimeException("Failed to create service " + name
  29. + ": service must have a public constructor with a Context argument", ex);
  30. } catch (NoSuchMethodException ex) {
  31. throw new RuntimeException("Failed to create service " + name
  32. + ": service must have a public constructor with a Context argument", ex);
  33. } catch (InvocationTargetException ex) {
  34. throw new RuntimeException("Failed to create service " + name
  35. + ": service constructor threw an exception", ex);
  36. }
  37. startService(service); // 调用到下面的startServices(@NonNull final SystemService service)
  38. return service;
  39. } finally {
  40. Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
  41. }
  42. }
  43. public void startService(@NonNull final SystemService service) {
  44. // Register it. 注册服务
  45. mServices.add(service);
  46. // Start it.
  47. long time = SystemClock.elapsedRealtime();
  48. try {
  49. service.onStart();// 启动服务
  50. } catch (RuntimeException ex) {
  51. throw new RuntimeException("Failed to start service " + service.getClass().getName()
  52. + ": onStart threw an exception", ex);
  53. }
  54. warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
  55. }

对于具体的JobSchedulerService,创建服务就是调用JobSchedulerService的构造方法, service.onStart() 就是调用的JobSchedulerService.onStart().

2 JobSchedulerService 创建

2.1 JobSchedulerService 的构造器

先来分析JobSchedulerService的构造方法:

  1. /**
  2. * Initializes the system service.
  3. * <p>
  4. * Subclasses must define a single argument constructor that accepts the context
  5. * and passes it to super.
  6. * </p>
  7. *
  8. * @param context The system server context.
  9. */
  10. public JobSchedulerService(Context context) {
  11. super(context);
  12. mLocalPM = LocalServices.getService(PackageManagerInternal.class);
  13. mActivityManagerInternal = Preconditions.checkNotNull(
  14. LocalServices.getService(ActivityManagerInternal.class));
  15. // 创建主线程looper
  16. mHandler = new JobHandler(context.getMainLooper());
  17. // 初始化JobSchedulerService 里使用到的常量
  18. mConstants = new Constants();
  19. // 继承ContentObserver类,通过实现onChange方法监听数据库的变化
  20. mConstantsObserver = new ConstantsObserver(mHandler);
  21. // 创建binder服务端
  22. mJobSchedulerStub = new JobSchedulerStub();
  23. // Set up the app standby bucketing tracker
  24. // android P 添加的新功能---应用待机分组
  25. mStandbyTracker = new StandbyTracker();
  26. mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
  27. mUsageStats.addAppIdleStateChangeListener(mStandbyTracker);
  28. // The job store needs to call back
  29. publishLocalService(JobSchedulerInternal.class, new LocalService());
  30. // Initialize the job store and set up any persisted jobs
  31. // 初始化 JobStore
  32. mJobs = JobStore.initAndGet(this);
  33. // Create the controllers.
  34. // 8 个 controller用于监听广播, job就是依据设备的电量,网络等状态变化触发的
  35. mControllers = new ArrayList<StateController>();
  36. mControllers.add(new ConnectivityController(this));
  37. mControllers.add(new TimeController(this));
  38. mControllers.add(new IdleController(this));
  39. mBatteryController = new BatteryController(this);
  40. mControllers.add(mBatteryController);
  41. mStorageController = new StorageController(this);
  42. mControllers.add(mStorageController);
  43. mControllers.add(new BackgroundJobsController(this));
  44. mControllers.add(new ContentObserverController(this));
  45. mDeviceIdleJobsController = new DeviceIdleJobsController(this);
  46. mControllers.add(mDeviceIdleJobsController);
  47. // If the job store determined that it can't yet reschedule persisted jobs,
  48. // we need to start watching the clock.
  49. if (!mJobs.jobTimesInflatedValid()) {
  50. Slog.w(TAG, "!!! RTC not yet good; tracking time updates for job scheduling");
  51. context.registerReceiver(mTimeSetReceiver, new IntentFilter(Intent.ACTION_TIME_CHANGED));
  52. }
  53. mPowerControllerHelper = new PowerControllerHelper();
  54. }

2.2 JobHandler 创建

  1. final private class JobHandler extends Handler {
  2. public JobHandler(Looper looper) {
  3. super(looper); // 说明JobHandler是使用了system_server进程主线程的looper
  4. }
  5. @Override
  6. public void handleMessage(Message message) {
  7. synchronized (mLock) {
  8. if (!mReadyToRock) {
  9. return;
  10. }
  11. switch (message.what) {
  12. case MSG_JOB_EXPIRED: {
  13. JobStatus runNow = (JobStatus) message.obj;
  14. // runNow can be null, which is a controller's way of indicating that its
  15. // state is such that all ready jobs should be run immediately.
  16. if (runNow != null && isReadyToBeExecutedLocked(runNow)) {
  17. mJobPackageTracker.notePending(runNow);
  18. addOrderedItem(mPendingJobs, runNow, mEnqueueTimeComparator);
  19. } else {
  20. queueReadyJobsForExecutionLocked();
  21. }
  22. } break;
  23. case MSG_CHECK_JOB:
  24. if (mReportedActive) {
  25. // if jobs are currently being run, queue all ready jobs for execution.
  26. queueReadyJobsForExecutionLocked();
  27. } else {
  28. // Check the list of jobs and run some of them if we feel inclined.
  29. maybeQueueReadyJobsForExecutionLocked();
  30. }
  31. break;
  32. .....// 好多case,不一一列出
  33. }
  34. maybeRunPendingJobsLocked();
  35. // Don't remove JOB_EXPIRED in case one came along while processing the queue.
  36. removeMessages(MSG_CHECK_JOB);
  37. }
  38. }
  39. }

2.3 JobSchedulerStub binder 服务端创建

  1. /**
  2. * Binder stub trampoline implementation
  3. */
  4. // 实现了 IJobScheduler 的 binder 服务端
  5. final class JobSchedulerStub extends IJobScheduler.Stub {
  6. ......
  7. }

2.4 应用待机分组

专门的文章来分析

2.5 初始化JobStore

frameworks/baseservices/core/java/com/android/server/job/JobStore.java .

2.5.1 创建JobStore

  1. /** Used by the {@link JobSchedulerService} to instantiate the JobStore. */
  2. static JobStore initAndGet(JobSchedulerService jobManagerService) {
  3. synchronized (sSingletonLock) {
  4. if (sSingleton == null) {
  5. sSingleton = new JobStore(jobManagerService.getContext(),
  6. jobManagerService.getLock(), Environment.getDataDirectory());
  7. }
  8. return sSingleton;
  9. }
  10. }

单例模式创建JobStore,看来在系统里面jobstore是唯一的,接着看JobStore的创建:

  1. /**
  2. * Construct the instance of the job store. This results in a blocking read from disk.
  3. */
  4. private JobStore(Context context, Object lock, File dataDir) {
  5. mLock = lock;
  6. mContext = context;
  7. mDirtyOperations = 0;
  8. // 在/data 目录下创建system目录
  9. File systemDir = new File(dataDir, "system");
  10. // 在/data/system目录下创建job目录
  11. File jobDir = new File(systemDir, "job");
  12. // /data/system/job目录创建完毕
  13. jobDir.mkdirs();
  14. // mJobsFile就是`/data/system/job/jobs.xml`
  15. mJobsFile = new AtomicFile(new File(jobDir, "jobs.xml"), "jobs");
  16. // 用于记录所有的 JobStatus对象
  17. mJobSet = new JobSet(); // 注意此处的mJobSet是JobStore这个类的变量
  18. // If the current RTC is earlier than the timestamp on our persisted jobs file,
  19. // we suspect that the RTC is uninitialized and so we cannot draw conclusions
  20. // about persisted job scheduling.
  21. //
  22. // Note that if the persisted jobs file does not exist, we proceed with the
  23. // assumption that the RTC is good. This is less work and is safe: if the
  24. // clock updates to sanity then we'll be saving the persisted jobs file in that
  25. // correct state, which is normal; or we'll wind up writing the jobs file with
  26. // an incorrect historical timestamp. That's fine; at worst we'll reboot with
  27. // a *correct* timestamp, see a bunch of overdue jobs, and run them; then
  28. // settle into normal operation.
  29. // 如果RTC的时间比我们在jobs.xml里面的时间戳好早,可能RTC没有被初始化,这样的情况下,执行持久化的job,可能会在RTC回复正常是,系统会抽风
  30. // 这里的mRtcGood为true则说明RTC正常
  31. mXmlTimestamp = mJobsFile.getLastModifiedTime();
  32. mRtcGood = (sSystemClock.millis() > mXmlTimestamp);
  33. // 详见2.5.2
  34. readJobMapFromDisk(mJobSet, mRtcGood);
  35. }

2.5.2 readJobMapFromDisk实现

readJobMapFromDisk(mJobSet, mRtcGood)的实现如下:

  1. @VisibleForTesting
  2. public void readJobMapFromDisk(JobSet jobSet, boolean rtcGood) {
  3. new ReadJobMapFromDiskRunnable(jobSet, rtcGood).run();// 实现了Runnable的run方法
  4. }

ReadJobMapFromDiskRunnable类的定义和run方法实现:

  1. /**
  2. * Runnable that reads list of persisted job from xml. This is run once at start up, so doesn't
  3. * need to go through {@link JobStore#add(com.android.server.job.controllers.JobStatus)}.
  4. */
  5. private final class ReadJobMapFromDiskRunnable implements Runnable {
  6. private final JobSet jobSet;
  7. private final boolean rtcGood;
  8. ReadJobMapFromDiskRunnable(JobSet jobSet, boolean rtcIsGood) {
  9. this.jobSet = jobSet;
  10. this.rtcGood = rtcIsGood;
  11. }
  12. @Override
  13. public void run() { // 开启线程执行操作, 看来可能是一个耗时的操作
  14. int numJobs = 0;
  15. int numSystemJobs = 0;
  16. int numSyncJobs = 0;
  17. try {
  18. List<JobStatus> jobs;
  19. // mJobsFile -- > `/data/system/job/jobs.xml`
  20. FileInputStream fis = mJobsFile.openRead();
  21. synchronized (mLock) {
  22. //
  23. jobs = readJobMapImpl(fis, rtcGood);
  24. if (jobs != null) {
  25. long now = sElapsedRealtimeClock.millis();
  26. IActivityManager am = ActivityManager.getService();
  27. for (int i=0; i<jobs.size(); i++) {
  28. // 读取jobs里面对应的JobStatus对象
  29. JobStatus js = jobs.get(i);
  30. js.prepareLocked(am);
  31. js.enqueueTime = now;
  32. // 将读取的JobStatus对象保存在jobSet中
  33. this.jobSet.add(js);
  34. numJobs++;
  35. if (js.getUid() == Process.SYSTEM_UID) {
  36. numSystemJobs++;
  37. if (isSyncJob(js)) {
  38. numSyncJobs++;
  39. }
  40. }
  41. }
  42. }
  43. }
  44. fis.close();
  45. } catch (FileNotFoundException e) {
  46. .........

先分析jobSet.add过程:jobSet由JobSet mJobSet 参数传参来的,这里就分析JobSet结构就行:

mJobSet 的定义方式:

  1. @VisibleForTesting // Key is the getUid() originator of the jobs in each sheaf
  2. final SparseArray<ArraySet<JobStatus>> mJobs;
  3. public JobSet() {
  4. mJobs = new SparseArray<ArraySet<JobStatus>>();
  5. mJobsPerSourceUid = new SparseArray<>();
  6. }
  7. public boolean add(JobStatus job) {
  8. final int uid = job.getUid();
  9. final int sourceUid = job.getSourceUid();
  10. ArraySet<JobStatus> jobs = mJobs.get(uid); // 查看有没有该uid的集合(ArraySet<JobStatus>)
  11. if (jobs == null) { // 该uid是第一次创建job,就重新创建
  12. jobs = new ArraySet<JobStatus>();
  13. mJobs.put(uid, jobs); // 并将ArraySet<JobStatus>添加到
  14. }
  15. ArraySet<JobStatus> jobsForSourceUid = mJobsPerSourceUid.get(sourceUid);
  16. if (jobsForSourceUid == null) {
  17. jobsForSourceUid = new ArraySet<>();
  18. mJobsPerSourceUid.put(sourceUid, jobsForSourceUid);
  19. }
  20. final boolean added = jobs.add(job);// 将job(JobStatus) 添加到ArraySet<JobStatus> 中
  21. final boolean addedInSource = jobsForSourceUid.add(job);
  22. if (added != addedInSource) {
  23. Slog.wtf(TAG, "mJobs and mJobsPerSourceUid mismatch; caller= " + added
  24. + " source= " + addedInSource);
  25. }
  26. return added || addedInSource;
  27. }

mJobsSparseArray<ArraySet<JobStatus>>类型, mJobs是所有应用的job的集合, ArraySet是同一个uid的job的集合. JobStatus是app定义的一个jobinfo的封装, 这个封装过程是在List<JobStatus> jobs = readJobMapImpl(fis, rtcGood), jobs保存一个个的JobStatus, 这些JobStatus是来自readJobMapImpl(fis, rtcGood),定义job是这样的:JobInfo jobInfo = new JobInfo.Builder,怎么就从JobInfo变成JobStatus类型??? 详见2.5.3 readJobMapImpl

2.5.3 readJobMapImpl实现

frameworks/base/services/core/java/com/android/server/job/JobStore.java

2.5.3.1 readJobMapImpl实现

这里的readJobMapImpl就是解析/data/system/job/jobs.xml, 那么这里给出jobs.xml的内容demo, 有助于帮助理解解析过程:

  1. <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
  2. <job-info version="0">
  3. <job jobid="10087" package="com.lq.tct.tctapplication" class="com.lq.tct.tctapplication.MyJobService" sourcePackageName="com.lq.tct.tctapplication" sourceUserId="0" uid="10174" priority="0" flags="0" lastSuccessfulRunTime="0" lastFailedRunTime="0">
  4. <constraints unmetered="true" charging="true" />
  5. <one-off deadline="1264103317926" delay="1264103270271" backoff-policy="0" initial-backoff="10000" />
  6. <extras />
  7. </job>
  8. <job jobid="1" package="com.tencent.mobileqq" class="com.tencent.mobileqq.msf.service.MSFAliveJobService" sourcePackageName="com.tencent.mobileqq" sourceUserId="0" uid="10163" priority="0" flags="0" lastSuccessfulRunTime="1262980997656" lastFailedRunTime="0">
  9. <constraints />
  10. <periodic period="900000" flex="900000" deadline="1262982797615" delay="1262981897615" />
  11. <extras />
  12. </job>
  13. .....
  14. </job-info>

好了, 下面的代码就是把上面的格式的xml,读取出来, 然后封装成 JobStatus , 最后装到List里面:

  1. private List<JobStatus> readJobMapImpl(FileInputStream fis, boolean rtcIsGood)
  2. throws XmlPullParserException, IOException {
  3. XmlPullParser parser = Xml.newPullParser();
  4. parser.setInput(fis, StandardCharsets.UTF_8.name());
  5. int eventType = parser.getEventType();
  6. ......
  7. String tagName = parser.getName();
  8. if ("job-info".equals(tagName)) { // job-info 是 jobsxml的开始标签, 说明开始解析了
  9. final List<JobStatus> jobs = new ArrayList<JobStatus>(); // 创建好存JobStatus的容器
  10. // Read in version info.
  11. try {// 读取jobs的版本号, 不符合就game over
  12. int version = Integer.parseInt(parser.getAttributeValue(null, "version"));
  13. if (version != JOBS_FILE_VERSION) {
  14. Slog.d(TAG, "Invalid version number, aborting jobs file read.");
  15. return null;
  16. }
  17. } catch (NumberFormatException e) {
  18. Slog.e(TAG, "Invalid version number, aborting jobs file read.");
  19. return null;
  20. }
  21. eventType = parser.next();
  22. do { // 一切检查都pass
  23. // Read each <job/>
  24. if (eventType == XmlPullParser.START_TAG) {
  25. tagName = parser.getName();
  26. // Start reading job.
  27. if ("job".equals(tagName)) {
  28. // 将一个job标签里的内容封装成一个JobStatus,从persistedJob名字也可以看出,这是从持久化文件jobs读取到的一个JobStatus
  29. // restoreJobFromXml无疑将成为重点,注意这个和RTC时间相关的变量还在参数列表中
  30. JobStatus persistedJob = restoreJobFromXml(rtcIsGood, parser);
  31. if (persistedJob != null) {
  32. if (DEBUG) {
  33. Slog.d(TAG, "Read out " + persistedJob);
  34. }
  35. jobs.add(persistedJob);
  36. } else {
  37. Slog.d(TAG, "Error reading job from file.");
  38. }
  39. }
  40. }
  41. eventType = parser.next();
  42. } while (eventType != XmlPullParser.END_DOCUMENT);
  43. return jobs;
  44. }
  45. return null; // 没有找到job-info标签,直接返回
  46. }
2.5.3.2 restoreJobFromXml实现

接着分析restoreJobFromXml的实现:

  1. // 作用就是解析一个job标签的内容, 封装成JobStatus
  2. private JobStatus restoreJobFromXml(boolean rtcIsGood, XmlPullParser parser)
  3. throws XmlPullParserException, IOException {
  4. JobInfo.Builder jobBuilder;
  5. int uid, sourceUserId;
  6. long lastSuccessfulRunTime;
  7. long lastFailedRunTime;
  8. int internalFlags = 0;
  9. // Read out job identifier attributes and priority.
  10. try {
  11. // 最终调用JobInfo.Builder构建JobInfo. 详见2.5.3.3
  12. jobBuilder = buildBuilderFromXml(parser);
  13. jobBuilder.setPersisted(true);
  14. // 依次解析uid,priority,flags等,并在jobBuilder调用setPriority设置,这就是在构建JobInfo呀!!!
  15. uid = Integer.parseInt(parser.getAttributeValue(null, "uid"));
  16. String val = parser.getAttributeValue(null, "priority");
  17. if (val != null) {
  18. jobBuilder.setPriority(Integer.parseInt(val));
  19. }
  20. ....
  21. }
  22. ......// 读取参数, 以及获取时间方面的参数
  23. // And now we're done
  24. JobSchedulerInternal service = LocalServices.getService(JobSchedulerInternal.class);
  25. // 获取sourcePackageName的应用待机分组的bucket, 由于不同的bucket在job的执行时间点上有不同的延迟
  26. final int appBucket = JobSchedulerService.standbyBucketForPackage(sourcePackageName,
  27. sourceUserId, elapsedNow);
  28. // 获得job的心跳
  29. long currentHeartbeat = service != null ? service.currentHeartbeat() : 0;
  30. // 关于job的所有信息都知道了, 创建JobStatus
  31. JobStatus js = new JobStatus(
  32. jobBuilder.build(), uid, sourcePackageName, sourceUserId,
  33. appBucket, currentHeartbeat, sourceTag,
  34. elapsedRuntimes.first, elapsedRuntimes.second,
  35. lastSuccessfulRunTime, lastFailedRunTime,
  36. (rtcIsGood) ? null : rtcRuntimes, internalFlags); // rtcIsGood 这个和RTC时间是否正常的标签,在这里的到了使用
  37. return js;
  38. }
2.5.3.3 buildBuilderFromXml实现

下面是buildBuilderFromXml的实现, 终于和JobInfo jobInfo = new JobInfo.Builder对应上了:

  1. private JobInfo.Builder buildBuilderFromXml(XmlPullParser parser) throws NumberFormatException {
  2. // Pull out required fields from <job> attributes.
  3. int jobId = Integer.parseInt(parser.getAttributeValue(null, "jobid"));
  4. String packageName = parser.getAttributeValue(null, "package");
  5. String className = parser.getAttributeValue(null, "class");
  6. ComponentName cname = new ComponentName(packageName, className);
  7. return new JobInfo.Builder(jobId, cname);
  8. }
2.5.3.4 JobStatus实现
  1. /**
  2. * Create a new JobStatus that was loaded from disk. We ignore the provided
  3. * {@link android.app.job.JobInfo} time criteria because we can load a persisted periodic job
  4. * from the {@link com.android.server.job.JobStore} and still want to respect its
  5. * wallclock runtime rather than resetting it on every boot.
  6. * We consider a freshly loaded job to no longer be in back-off, and the associated
  7. * standby bucket is whatever the OS thinks it should be at this moment.
  8. */
  9. // 注释中就说了,创建一个JobStatus从磁盘加载来的
  10. // 注意参数中的JobInfo job, 是由于`new JobStatus` 调用了`jobBuilder.build()`
  11. public JobStatus(JobInfo job, int callingUid, String sourcePkgName, int sourceUserId,
  12. int standbyBucket, long baseHeartbeat, String sourceTag,
  13. long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
  14. long lastSuccessfulRunTime, long lastFailedRunTime,
  15. Pair<Long, Long> persistedExecutionTimesUTC,
  16. int innerFlags) {
  17. this(job, callingUid, resolveTargetSdkVersion(job), sourcePkgName, sourceUserId,
  18. standbyBucket, baseHeartbeat,
  19. sourceTag, 0,
  20. earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
  21. lastSuccessfulRunTime, lastFailedRunTime, innerFlags);
  22. // Only during initial inflation do we record the UTC-timebase execution bounds
  23. // read from the persistent store. If we ever have to recreate the JobStatus on
  24. // the fly, it means we're rescheduling the job; and this means that the calculated
  25. // elapsed timebase bounds intrinsically become correct.
  26. this.mPersistedUtcTimes = persistedExecutionTimesUTC;
  27. if (persistedExecutionTimesUTC != null) {
  28. if (DEBUG) {
  29. Slog.i(TAG, "+ restored job with RTC times because of bad boot clock");
  30. }
  31. }
  32. }

从磁盘读取持久化的job, 就是JobStore的初始化过程,梳理一下:

  • /data/system/job/jobs.xml中解析job标签,构建成JobInfo
  • JobInfo封装成JobStatus
  • JobStatus被添加到ArraySet<JobStatus>集合,同一个uid的JobStatus都会被放到同一个ArraySet
  • 所有的ArraySet又会放到一个SparseArray<ArraySet<JobStatus>>集合. mJobs就是这个SparseArray<ArraySet<JobStatus>>.

创建完JobStore, 现在回到JobSchedulerService的构造函数里,接着分析.

2.6 controller 的创建

看下controller的构造方法:

  1. // Create the controllers.
  2. // 8 个 controller用于监听广播, job就是依据设备的电量,网络等状态变化触发的
  3. mControllers = new ArrayList<StateController>();
  4. mControllers.add(new ConnectivityController(this));
  5. mControllers.add(new TimeController(this));
  6. mControllers.add(new IdleController(this));
  7. // 这样构造BatteryController, 是由于mBatteryController 在其他地方还要使用
  8. mBatteryController = new BatteryController(this);
  9. mControllers.add(mBatteryController);
  10. mStorageController = new StorageController(this);
  11. mControllers.add(mStorageController);
  12. mControllers.add(new BackgroundJobsController(this));
  13. mControllers.add(new ContentObserverController(this));
  14. mDeviceIdleJobsController = new DeviceIdleJobsController(this);
  15. mControllers.add(mDeviceIdleJobsController);

各类controller用于检测, 设备的各种状态, 用于触发job的执行

3 JobSchedulerService.onStart()

  1. public void onStart() {
  2. publishBinderService(Context.JOB_SCHEDULER_SERVICE, mJobSchedulerStub);
  3. }

调用父类frameworks/base/services/core/java/com/android/server/SystemService.javapublishBinderService方法

  1. /**
  2. * Publish the service so it is accessible to other services and apps.
  3. *
  4. * @param name the name of the new service
  5. * @param service the service object
  6. */
  7. protected final void publishBinderService(String name, IBinder service) {
  8. publishBinderService(name, service, false);
  9. }
  10. /**
  11. * Publish the service so it is accessible to other services and apps.
  12. *
  13. * @param name the name of the new service
  14. * @param service the service object
  15. * @param allowIsolated set to true to allow isolated sandboxed processes
  16. * to access this service
  17. */
  18. protected final void publishBinderService(String name, IBinder service,
  19. boolean allowIsolated) {
  20. publishBinderService(name, service, allowIsolated, DUMP_FLAG_PRIORITY_DEFAULT);
  21. }
  22. /**
  23. * Publish the service so it is accessible to other services and apps.
  24. *
  25. * @param name the name of the new service
  26. * @param service the service object
  27. * @param allowIsolated set to true to allow isolated sandboxed processes
  28. * to access this service
  29. * @param dumpPriority supported dump priority levels as a bitmask
  30. */
  31. protected final void publishBinderService(String name, IBinder service,
  32. boolean allowIsolated, int dumpPriority) {
  33. ServiceManager.addService(name, service, allowIsolated, dumpPriority);
  34. }

最终就是调用了ServiceManager.addService, 注册binder服务.

4 JobSchedulerService.onBootPhase阶段

4.1 onBootPhase

  1. @Override
  2. public void onBootPhase(int phase) {
  3. if (PHASE_SYSTEM_SERVICES_READY == phase) {
  4. mConstantsObserver.start(getContext().getContentResolver());
  5. mAppStateTracker = Preconditions.checkNotNull(
  6. LocalServices.getService(AppStateTracker.class));
  7. setNextHeartbeatAlarm();
  8. // Register br for package removals and user removals.
  9. final IntentFilter filter = new IntentFilter();
  10. // 注册需要监听的监听广播
  11. filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
  12. filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
  13. filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
  14. filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
  15. filter.addDataScheme("package");
  16. getContext().registerReceiverAsUser(
  17. mBroadcastReceiver, UserHandle.ALL, filter, null, null);
  18. final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
  19. getContext().registerReceiverAsUser(
  20. mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
  21. try {
  22. ActivityManager.getService().registerUidObserver(mUidObserver,
  23. ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE
  24. | ActivityManager.UID_OBSERVER_IDLE | ActivityManager.UID_OBSERVER_ACTIVE,
  25. ActivityManager.PROCESS_STATE_UNKNOWN, null);
  26. } catch (RemoteException e) {
  27. // ignored; both services live in system_server
  28. }
  29. // Remove any jobs that are not associated with any of the current users.
  30. cancelJobsForNonExistentUsers();
  31. } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
  32. synchronized (mLock) {
  33. // Let's go!
  34. mReadyToRock = true;
  35. mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
  36. BatteryStats.SERVICE_NAME));
  37. mLocalDeviceIdleController
  38. = LocalServices.getService(DeviceIdleController.LocalService.class);
  39. // Create the "runners".
  40. for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
  41. mActiveServices.add( // 创建JobServiceContext
  42. new JobServiceContext(this, mBatteryStats, mJobPackageTracker,
  43. getContext().getMainLooper()));
  44. }
  45. // Attach jobs to their controllers.
  46. mJobs.forEachJob((job) -> {
  47. for (int controller = 0; controller < mControllers.size(); controller++) {
  48. final StateController sc = mControllers.get(controller);
  49. sc.maybeStartTrackingJobLocked(job, null);
  50. }
  51. });
  52. // GO GO GO! job的执行
  53. mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
  54. }
  55. }
  56. }

MAX_JOB_CONTEXTS_COUNT指同时执行的job数量, android p默认是16. 在android O上是区分低内存设备的.

4.2 JobServiceContext

  1. JobServiceContext(Context context, Object lock, IBatteryStats batteryStats,
  2. JobPackageTracker tracker, JobCompletedListener completedListener, Looper looper) {
  3. mContext = context;
  4. mLock = lock;
  5. mBatteryStats = batteryStats;
  6. mJobPackageTracker = tracker;
  7. mCallbackHandler = new JobServiceHandler(looper);
  8. mCompletedListener = completedListener;
  9. mAvailable = true;
  10. mVerb = VERB_FINISHED;
  11. mPreferredUid = NO_PREFERRED_UID;
  12. }

参考Blog