文章目录

  • 一、回调 StateChangedListener 接口
  • 二、JobHandler 处理 ( 任务检查 )
  • 三、maybeRunPendingJobsH 方法
  • 四、assignJobsToContextsLocked 方法 ( 任务执行 )
  • 五、JobSchedulerService 部分源码注释

推荐代码查看网站 :

  • https://www.androidos.net.cn/sourcecode ( 推荐 )

  • http://androidxref.com/

一、回调 StateChangedListener 接口


上一篇博客 【Android 电量优化】JobScheduler 相关源码分析 ( ConnectivityController 底层源码分析 | 构造函数 | 追踪任务更新 | 注册接收者监听连接变化 ) 中 ConnectivityController 最后调用了 mStateChangedListener 任务状态改变监听器接口的 onControllerStateChanged 方法 , 该接口实际上是 JobSchedulerService 类型的对象 ;

StateController 状态控制器创建时 , 会传入 mStateChangedListener , 该状态改变监听器就是 JobSchedulerService , 其实现了 StateChangedListener 接口 ; 如下代码中 , ConnectivityController 创建时 , 通过 get 方法设置了 JobSchedulerService 为状态监听器 ;

public final class JobSchedulerService extends com.android.server.SystemServiceimplements StateChangedListener, JobCompletedListener {// ... public JobSchedulerService(Context context) {// ...// 创建控制器集合mControllers = new ArrayList<StateController>();// 网络连接控制器mControllers.add(ConnectivityController.get(this));// ... }// ...
}

在实现接口的 onControllerStateChanged 方法中 , 传递消息给 com.android.server.job.JobSchedulerService.JobHandler , 通知如下内容 : 一些控制器的状态发生了改变 , 以便去遍历集合并开启或停止相应的任务 ;

//
public final class JobSchedulerService extends com.android.server.SystemServiceimplements StateChangedListener, JobCompletedListener {// .../*** 实现的 StateChangedListener 接口方法* 传递消息给 com.android.server.job.JobSchedulerService.JobHandler , * 通知如下内容 : 一些控制器的状态发生了改变 , 以便去遍历集合并开启或停止相应的任务*/@Overridepublic void onControllerStateChanged() {// 发送了 Handler 信息mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();}// ...
}

二、JobHandler 处理 ( 任务检查 )


JobHandler 是定义在 JobSchedulerService 中的内部类 , 在该类中通过接收不同的 Message 信息 , 进行任务超时处理 , 任务检查 , 任务贪婪检查 , 任务停止 444 个操作 ;

构造函数 : 使用主线程的 context.getMainLooper() 作为参数 ;

处理消息 : 根据不同的消息的 what 标识 , 进行不同的任务处理 ;

  • MSG_JOB_EXPIRED : 处理超时任务 , 首先 获取任务状态 , 任务状态可能是空的 , 这是控制器表示其状态的一种方式 , 所有已准备的任务应该马上被执行 ;

  • MSG_CHECK_JOB : 检查任务 , 查看任务执行是否满足条件 , 如果满足就启动任务 ; 如果当前正在执行任务 , 将本次准备好了的任务放入待执行队列中准备执行 ; 反之如果当前没有执行任务 , 检查任务集合 , 如果合适运行其中的一些工任务 ;

  • MSG_CHECK_JOB_GREEDY : 贪婪检查任务 , 不管当前有没有正在执行任务 , 都将本次准备好了的任务放入待执行队列中准备执行 ;

  • MSG_STOP_JOB : 停止正在执行的任务 ;

上述操作都是针对任务队列的 ;

maybeRunPendingJobsH 方法是真正执行任务的核心逻辑 ;

public final class JobSchedulerService extends com.android.server.SystemServiceimplements StateChangedListener, JobCompletedListener {// ...final JobHandler mHandler;// ... // JobHandler 内部类private class JobHandler extends Handler {// 构造函数 , 使用主线程的 context.getMainLooper() 作为参数public JobHandler(Looper looper) {super(looper);}@Overridepublic void handleMessage(Message message) {synchronized (mLock) {if (!mReadyToRock) {return;}}// 根据 message.what 处理消息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();// 移除 MSG_CHECK_JOB 任务  // JOB_EXPIRED 异步任务不能移除 , 防止处理队列时 JOB_EXPIRED 类型消息到达removeMessages(MSG_CHECK_JOB);}}

三、maybeRunPendingJobsH 方法


maybeRunPendingJobsH 方法中 , 根据可用的执行上下文 , 协调等待队列中的任务 ; 控制器可以强制将任务放入等待队列中 , 即使该任务已经在运行中 ; 在这里我们可以决定是否真正地执行该操作 ;

assignJobsToContextsLocked 方法中 , 启动任务 ;

public final class JobSchedulerService extends com.android.server.SystemServiceimplements StateChangedListener, JobCompletedListener {// ... /*** 根据可用的执行上下文 , 协调等待队列中的任务 ; * 控制器可以强制将任务放入等待队列中 , 即使该任务已经在运行中 ; * 在这里我们可以决定是否真正地执行该操作 ; */private void maybeRunPendingJobsH() {synchronized (mLock) {if (DEBUG) {Slog.d(TAG, "pending queue: " + mPendingJobs.size() + " jobs.");}// 在该函数中启动任务 assignJobsToContextsLocked();reportActive();}}// ...
}

四、assignJobsToContextsLocked 方法 ( 任务执行 )


assignJobsToContextsLocked 方法作用 : 从等待队列中获取任务 , 并在可用的上下文中执行它们 , 如果当前没有可用的上下文 , 执行高优先级任务 , 取代执行低优先级任务 ;

assignJobsToContextsLocked 方法代码逻辑 :

  • 获取可执行任务数 : 获取内存等级 , 根据内存等级确定最大的激活任务数 , 不同的可用内存等级 , 有不同的任务数 , 内存容量高 , 可同时执行的任务多 ;

  • 记录任务 : 使用 JobStatus[] contextIdToJobMap 记录可执行任务 ;

  • 获取任务 : 开始遍历 mPendingJobs 待执行任务集合 , 如果获取到可执行任务 , 放入 contextIdToJobMap 集合中 ;

  • 执行任务 : 遍历 contextIdToJobMap 集合 , 从该集合中取出可执行任务并执行 ;

执行任务方法 : 使用 mActiveServices.get(i).executeRunnableJob(pendingJob) 方法执行任务 , mActiveServices 集合元素类型是 JobServiceContext , 调用该 JobServiceContext 类对象的 executeRunnableJob 方法 , 传入 pendingJob 待执行任务 , 即可执行该任务 ;

五、JobSchedulerService 部分源码注释


public final class JobSchedulerService extends com.android.server.SystemServiceimplements StateChangedListener, JobCompletedListener {/** 任务的主要集合. */final JobStore mJobs;final JobHandler mHandler;/*** 该数组实际存储了 mActiveServices 数组状态 .* 该数组第 i 个索引存储了第 i 个 JobServiceContext 的任务 . * 我们会操作该数组 , 直到我们已经知道了哪些任务应该在哪些 JobServiceContext 上执行 .*/JobStatus[] mTmpAssignContextIdToJobMap = new JobStatus[MAX_JOB_CONTEXTS_COUNT];/*** 追踪那些已经激活或者等待执行额任务对应的服务 . * 对应的索引由 JobStatus.getServiceToken() 方法提供 .*/final List<JobServiceContext> mActiveServices = new ArrayList<>();public JobSchedulerService(Context context) {super(context);// 创建 Handler mHandler = new JobHandler(context.getMainLooper());// 创建控制器集合mControllers = new ArrayList<StateController>();// 网络连接控制器mControllers.add(ConnectivityController.get(this));// ... }/*** 实现的 StateChangedListener 接口方法* 传递消息给 com.android.server.job.JobSchedulerService.JobHandler , * 通知如下内容 : 一些控制器的状态发生了改变 , 以便去遍历集合并开启或停止相应的任务*/@Overridepublic void onControllerStateChanged() {// 发送了 Handler 信息mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();}// JobHandler 内部类private class JobHandler extends Handler {// 构造函数 , 使用主线程的 context.getMainLooper() 作为参数public JobHandler(Looper looper) {super(looper);}@Overridepublic void handleMessage(Message message) {synchronized (mLock) {if (!mReadyToRock) {return;}}// 根据 message.what 处理消息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();// 移除 MSG_CHECK_JOB 任务  // JOB_EXPIRED 异步任务不能移除 , 防止处理队列时 JOB_EXPIRED 类型消息到达removeMessages(MSG_CHECK_JOB);}// 设置状态变化 , 将满足条件的任务放入 mPendingJobs 集合中 private void maybeQueueReadyJobsForExecutionLockedH() {if (DEBUG) Slog.d(TAG, "Maybe queuing ready jobs...");noteJobsNonpending(mPendingJobs);mPendingJobs.clear();mJobs.forEachJob(mMaybeQueueFunctor);mMaybeQueueFunctor.postProcess();}/*** 根据可用的执行上下文 , 协调等待队列中的任务 ; * 控制器可以强制将任务放入等待队列中 , 即使该任务已经在运行中 ; * 在这里我们可以决定是否真正地执行该操作 ; */private void maybeRunPendingJobsH() {synchronized (mLock) {if (DEBUG) {Slog.d(TAG, "pending queue: " + mPendingJobs.size() + " jobs.");}// 在该函数中启动任务 assignJobsToContextsLocked();reportActive();}}/*** 从等待队列中获取任务 , 并在可用的上下文中执行它们 ; * 如果当前没有可用的上下文 ; * 这里的上下文指的是四大组件或者 Application ; * 执行高优先级任务 , 取代执行低优先级任务 ; */private void assignJobsToContextsLocked() {if (DEBUG) {Slog.d(TAG, printPendingQueue());}// 获取内存等级int memLevel;try {memLevel = ActivityManagerNative.getDefault().getMemoryTrimLevel();} catch (RemoteException e) {memLevel = ProcessStats.ADJ_MEM_FACTOR_NORMAL;}// 根据内存等级确定最大的激活任务数 // 不同的可用内存等级 , 有不同的任务数 , 内存容量高 , 可同时执行的任务多 switch (memLevel) {case ProcessStats.ADJ_MEM_FACTOR_MODERATE:mMaxActiveJobs = mConstants.BG_MODERATE_JOB_COUNT;break;case ProcessStats.ADJ_MEM_FACTOR_LOW:mMaxActiveJobs = mConstants.BG_LOW_JOB_COUNT;break;case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:mMaxActiveJobs = mConstants.BG_CRITICAL_JOB_COUNT;break;default:mMaxActiveJobs = mConstants.BG_NORMAL_JOB_COUNT;break;}// 用于记录可执行任务 , JobStatus[] contextIdToJobMap = mTmpAssignContextIdToJobMap;// ... // 开始遍历 mPendingJobs 待执行任务集合 // 启动任务 for (int i=0; i<mPendingJobs.size(); i++) {// 获取一个待执行任务 JobStatus nextPending = mPendingJobs.get(i);// 如果当前任务正在执行 , 处理下一个任务int jobRunningContext = findJobContextIdFromMap(nextPending, contextIdToJobMap);if (jobRunningContext != -1) {continue;}// 进行一系列判断 ... if (minPriorityContextId != -1) {// 获取到可执行任务 , 放入 contextIdToJobMap 集合中contextIdToJobMap[minPriorityContextId] = nextPending;act[minPriorityContextId] = true;numActive++;if (priority >= JobInfo.PRIORITY_TOP_APP) {numForeground++;}}}mJobPackageTracker.noteConcurrency(numActive, numForeground);// 遍历 contextIdToJobMap 集合 , 从该集合中取出可执行任务并执行for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) {boolean preservePreferredUid = false;if (act[i]) {JobStatus js = mActiveServices.get(i).getRunningJob();if (js != null) {// ... } else {// 取出要执行的任务final JobStatus pendingJob = contextIdToJobMap[i];// ...// executeRunnableJob 方法用于正式执行任务 // mActiveServices 集合元素类型是 JobServiceContext // 调用的 executeRunnableJob 方法定义在 JobServiceContext 中 if (!mActiveServices.get(i).executeRunnableJob(pendingJob)) {Slog.d(TAG, "Error executing " + pendingJob);}if (mPendingJobs.remove(pendingJob)) {mJobPackageTracker.noteNonpending(pendingJob);}}}if (!preservePreferredUid) {mActiveServices.get(i).clearPreferredUid();}}}}

该代码路径为 /frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java , 点击链接可跳转查看完整源码 ;

本篇博客涉及到的源码 :

  • /frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java

【Android 电量优化】JobScheduler 相关源码分析 ( JobSchedulerService 源码分析 | 任务检查 | 任务执行 )相关推荐

  1. 【Android 电量优化】JobScheduler 源码分析 ( JobServiceContext 源码分析 | 闭环操作总结 | 用户提交任务 | 广播接收者接受相关广播触发任务执行 )★

    文章目录 一.JobServiceContext 引入 二.JobServiceContext 源码分析 三.用户在应用层如何使用 JobScheduler 四.用户提交任务 五.广播接收者监听广播触 ...

  2. 【Android 电量优化】JobScheduler 相关源码分析 ( ConnectivityController 底层源码分析 | 构造函数 | 追踪任务更新 | 注册接收者监听连接变化 )

    文章目录 一.ConnectivityController 连接控制器引入 二.ConnectivityController 构造方法解析 ( 注册接收者 ) 三.mConnectivityRecei ...

  3. 【Android 电量优化】JobScheduler 相关源码分析 ( JobSchedulerService 源码分析 | Android 源码在线网址推荐 )

    文章目录 一.JobScheduler 提交任务 schedule 方法源码分析 二.schedule(JobInfo job, int uId) 方法 三.scheduleAsPackage 方法 ...

  4. 【Android 电量优化】电量优化 ( Battery Historian 环境要求 | 电量分析报告 | 电量优化三原则 | 电量优化注意事项 )

    文章目录 一.Battery Historian 环境要求 二.上传电量报告 三.Battery Historian 电量分析报告 四.电量优化三原则 五.电量优化注意事项 参考 Google 官方文 ...

  5. 【Android 电量优化】电量优化 ( 获取电量分析报告 | 阿里云服务器搭建 Battery Historian | 上传并生成分析报告 )

    文章目录 一.Battery Historian 搭建环境 二.获取 Android 手机电量报告 1.重置电量状态 2.开启获取 WeakLock 信息 3.获取手机电量报告 三.阿里云服务器搭建 ...

  6. 【Android 电量优化】电量优化 ( 使用 AlarmManager 保持 CPU 唤醒 )

    文章目录 一.AlarmManager 简介 二.使用 AlarmManager 保持 CPU 唤醒流程 ( 省电操作 ) 三.使用 WeakLock 保持 CPU 唤醒 代码示例 1.Service ...

  7. 【Android 电量优化】电量优化 ( JobScheduler | JobService | AsyncTask )

    文章目录 一.JobScheduler 使用流程 二.AsyncTask 简介 三.JobScheduler 开发流程 四.JobScheduler 代码示例 1.JobScheduleManager ...

  8. Android电量优化

    最近领导老是反映说我们的APP耗电要比以前厉害一些,排在耗电量的首位,上黑名单了,需要进行电量优化!经过一段时间的研究,自己做了一部分的总结! 电量优化的工具battery-historien bat ...

  9. 详解Android电量优化

    目录 写在前面 一.电量优化介绍及方案选择 1.1.如何正确认识电量优化 1.2.耗电量测试方案 二.Battery Historian实战分析 三.电量辅助监控实战 3.1.获取运行时能耗 3.2. ...

最新文章

  1. 一起谈.NET技术,微软PDC10:大牛谈ASP.NET和C#技术走向
  2. 试求由a,b,c三个字母组成的n位符号串中不出现aa图像的符号串的数目
  3. 为衣服添加NFC功能:挥下袖子就能安全支付,打开车门坐进去就能启动汽车|Nature子刊...
  4. Java 7中的Try-with-resources
  5. 从民宅到独栋大厦 我们搬家啦!
  6. middleware generic错误处理机制
  7. 单片机串口发送数据很慢?这种方法帮助你提高!
  8. 在windows storage server 2008上创建iscsi磁盘
  9. java shark_JAVA项目开发笔记(3)Shark部分: Shark API | 学步园
  10. sql多语句表值函数_构造一个特殊的多语句表函数来检查SQL Server的运行状况
  11. Mac配置腾讯云服务器SSH秘钥免登陆
  12. HenCoder Android 开发进阶:自定义 View 1-4 Canvas 对绘制的辅助 clipXXX() 和 Matrix
  13. 通过安卓模拟器使直播软件obs的0粉丝用户开播
  14. 安装 opencv-python 出现Command “python setup.py egg_info“ failed with error code 1 in /tmp/pip-build-npa
  15. Adobe Bridge 2021最新中文版来了!!!!
  16. 岁寒,然后知松柏之后凋也。关于后凋的解释
  17. Python~~~有料才能 有派
  18. PCA Whitening ZCA Whitening
  19. 软件测试用例分析和用例设计
  20. poj3666序列对应——DP

热门文章

  1. 微软发布 Mobile Express for Microsoft Dynamics CRM 4.0
  2. 人的一生奋斗史Rational Rose 版
  3. RabbitMQ 官方NET教程(二)【工作队列】
  4. 开始逆向objc基础准备(一)简单认识一下arm32,以及与x86汇编指令类比
  5. DataGridView的单元格控制只能输入数字
  6. day26-3 模拟ssh远程执行命令
  7. 连接MySQL的10060错误:Can't connect to MySQL server on '*.*.*.*'(10060)
  8. javascript对象的几种创建方式
  9. Linux驱动入门篇(一):Hello, world
  10. BZOJ1935 园丁的烦恼