文章目录

  • 一、回调 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.SystemService        implements 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.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<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 ,      * 通知如下内容 : 一些控制器的状态发生了改变 , 以便去遍历集合并开启或停止相应的任务     */    @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<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

更多相关文章

  1. android强制横屏息屏后重新打开时会先显示竖屏
  2. 更改Android模拟器中的hosts文件
  3. 【转载】Android事件分发机制完全解析,带你从源码的角度彻底理解(
  4. Android(安卓)线程池相关知识
  5. Java(Android)线程池
  6. android phone电话调用流程
  7. android 后台长时间执行周期性定时任务 解决方案收集
  8. Java(Android)线程池
  9. 高级UI-事件传递

随机推荐

  1. Android硬件访问服务-Service
  2. Android中横竖屏、全屏、无标题设置
  3. 2010.11.27———android 展示网络上的图
  4. Android中的集中常用布局方式和按钮事件
  5. LayoutAnimation
  6. 在Android上执行Java程序
  7. zxing项目源码解读(2.3.0版本,Android部分)
  8. Android创建自定义键盘
  9. Android(安卓)Service小实践
  10. Android(安卓)JNI环境搭建及开发入门