- 一、回调 StateChangedListener 接口
- 二、JobHandler 处理 ( 任务检查 )
- 三、maybeRunPendingJobsH 方法
- 四、assignJobsToContextsLocked 方法 ( 任务执行 )
- 五、JobSchedulerService 部分源码注释
推荐代码查看网站 :
-
https://www.androidos.net.cn/sourcecode ( 推荐 )
-
http://androidxref.com/
上一篇博客 【Android 电量优化】JobScheduler 相关源码分析 ( ConnectivityController 底层源码分析 | 构造函数 | 追踪任务更新 | 注册接收者监听连接变化 ) 中 ConnectivityController 最后调用了 mStateChangedListener 任务状态改变监听器接口的 onControllerStateChanged 方法 , 该接口实际上是 JobSchedulerService 类型的对象 ;
StateController 状态控制器创建时 , 会传入 mStateChangedListener , 该状态改变监听器就是 JobSchedulerService , 其实现了 StateChangedListener 接口 ; 如下代码中 , ConnectivityController 创建时 , 通过 get 方法设置了 JobSchedulerService 为状态监听器 ;
public final class JobSchedulerService extends com.android.server.SystemService
implements StateChangedListener, JobCompletedListener {
// ...
public JobSchedulerService(Context context) {
// ...
// 创建控制器集合
mControllers = new ArrayList();
// 网络连接控制器
mControllers.add(ConnectivityController.get(this));
// ...
}
// ...
}
在实现接口的 onControllerStateChanged 方法中 , 传递消息给 com.android.server.job.JobSchedulerService.JobHandler , 通知如下内容 : 一些控制器的状态发生了改变 , 以便去遍历集合并开启或停止相应的任务 ;
//
public final class JobSchedulerService extends com.android.server.SystemService
implements StateChangedListener, JobCompletedListener {
// ...
/**
* 实现的 StateChangedListener 接口方法
* 传递消息给 com.android.server.job.JobSchedulerService.JobHandler ,
* 通知如下内容 : 一些控制器的状态发生了改变 , 以便去遍历集合并开启或停止相应的任务
*/
@Override
public void onControllerStateChanged() {
// 发送了 Handler 信息
mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
}
// ...
}
二、JobHandler 处理 ( 任务检查 )
JobHandler 是定义在 JobSchedulerService 中的内部类 , 在该类中通过接收不同的 Message 信息 , 进行任务超时处理 , 任务检查 , 任务贪婪检查 , 任务停止 4 4 4 个操作 ;
构造函数 : 使用主线程的 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.SystemService
implements StateChangedListener, JobCompletedListener {
// ...
final JobHandler mHandler;
// ...
// JobHandler 内部类
private class JobHandler extends Handler {
// 构造函数 , 使用主线程的 context.getMainLooper() 作为参数
public JobHandler(Looper looper) {
super(looper);
}
@Override
public 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.SystemService
implements 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.SystemService
implements 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 mActiveServices = new ArrayList();
public JobSchedulerService(Context context) {
super(context);
// 创建 Handler
mHandler = new JobHandler(context.getMainLooper());
// 创建控制器集合
mControllers = new ArrayList();
// 网络连接控制器
mControllers.add(ConnectivityController.get(this));
// ...
}
/**
* 实现的 StateChangedListener 接口方法
* 传递消息给 com.android.server.job.JobSchedulerService.JobHandler ,
* 通知如下内容 : 一些控制器的状态发生了改变 , 以便去遍历集合并开启或停止相应的任务
*/
@Override
public void onControllerStateChanged() {
// 发送了 Handler 信息
mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
}
// JobHandler 内部类
private class JobHandler extends Handler {
// 构造函数 , 使用主线程的 context.getMainLooper() 作为参数
public JobHandler(Looper looper) {
super(looper);
}
@Override
public 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= JobInfo.PRIORITY_TOP_APP) {
numForeground++;
}
}
}
mJobPackageTracker.noteConcurrency(numActive, numForeground);
// 遍历 contextIdToJobMap 集合 , 从该集合中取出可执行任务并执行
for (int i=0; i
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?