热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

JobScheduler5.0源码分析

0.JobScheduler执行代码mJobScheduler(JobScheduler)getSystemService(Context.JOB_SCHEDULER_SERVICE);




0.JobScheduler执行代码
mJobScheduler=(JobScheduler)getSystemService(Context.JOB_SCHEDULER_SERVICE);
mJobInfo=new JobInfo.Builder(i,mComponentName).setMinimumLatency(5*1000).build();
mJobScheduler.schedule(mJobInfo);

这里写图片描述


1.创建服务

1.1 SystemServer代码



上图提到,我们可以从zygote进程孵化一个新的系统服务进程,也叫做SystemServer。这里我们可以先找到main函数,看下他是如何创建一系列的系统子服务的:



/**
* The main entry point from zygote.
*/
public static void main(String[] args) {
new SystemServer().run();
}

private void run() {

//启动服务
try {
startBootstrapServices();
startCoreServices();
startOtherServices();//启动系统级服务
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
}
}

private void startOtherServices() {

mSystemServiceManager.startService(JobSchedulerService.class);

}

1.2 SystemServiceManager代码



上一节我们看到JobSchedulerService远程服务已经被启动了,如何启动呢,实际上是通过反射JobSchedulerService该类并调用该类的构造器初始化的:



public  T startService(Class serviceClass) {
final String name = serviceClass.getName();

final T service;
try {
Constructor cOnstructor= serviceClass.getConstructor(Context.class);
service = constructor.newInstance(mContext);
} catch (InstantiationException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service could not be instantiated", ex);
}

mServices.add(service);

return service;
}

1.3 JobSchedulerService远程服务代码



接下来我们看看他们是如何初始化:



public class JobSchedulerService extends com.android.server.SystemService
implements StateChangedListener, JobCompletedListener {

public JobSchedulerService(Context context) {
super(context);
// 初始化所有的控制器(每个JobInfo都会创建一系列的约束,必须免费的网络,系统空闲,时间 电量约束等等)
mCOntrollers= new ArrayList();
mControllers.add(ConnectivityController.get(this));
mControllers.add(TimeController.get(this));
mControllers.add(IdleController.get(this));
mControllers.add(BatteryController.get(this));

//操作任务逻辑的处理器
mHandler = new JobHandler(context.getMainLooper());
//远程服务的代理对象 很重要 至此!!!进程一服务端我们已经分析完毕
mJobSchedulerStub = new JobSchedulerStub();
// 读取任务进度的持久化文件 /system/job/jobs.xml
mJobs = JobStore.initAndGet(this);
}

}

2.关联服务

还记得我们调用代码的顺序吗,当我们获取服务后,我们会调用如下代码:



mJobScheduler.schedule(mJobInfo);   


此刻通过进程二服务端的图你会发现,JobScheduer是一个抽象类,而它还有一个子类实现。当我们调用schedule方法的时候,子类通过代理调用了服务端的schedule():



public abstract class JobScheduler {}

public class JobSchedulerImpl extends JobScheduler {

IJobScheduler mBinder;

/* package */ JobSchedulerImpl(IJobScheduler binder) {
mBinder = binder;
}

@Override
public int schedule(JobInfo job) {
try {
return mBinder.schedule(job);
} catch (RemoteException e) {
return JobScheduler.RESULT_FAILURE;
}
}

...

}


回到进程一服务端查看JobSchedulerStub代理是如何处理的:



@Override
public int schedule(JobInfo job) throws RemoteException {

...
try {
//调用JobSchedulerService的schedule(job, uid)
return JobSchedulerService.this.schedule(job, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}

public class JobSchedulerService{

public int schedule(JobInfo job, int uId) {
//1.封装任务为JobStatus
JobStatus jobStatus = new JobStatus(job, uId);
//2.如果之前任务已经存在 替换
cancelJob(uId, job.getId());
//3.开始跟踪任务 我们之前说过 JobInfo会携带各种约束,这里根据各种约束开始跟踪任务,会调用到约束的maybeStartTrackingJob()。
startTrackingJob(jobStatus);
//4.检查是否需要马上执行任务。
mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
return JobScheduler.RESULT_SUCCESS;
}
}

3.触发任务回调

之前我们提到,在创建JobInfo必须设置约束才可以。那么服务端也创建了一些列控制器来跟踪任务的状态。这个我们在JobScheduler创建的时候已经提过了。他们有个共同的父类StateController。



public abstract class StateController {
//开始跟踪任务
public abstract void maybeStartTrackingJob(JobStatus jobStatus);
//结束跟踪任务
public abstract void maybeStopTrackingJob(JobStatus jobStatus);

public abstract void dumpControllerState(PrintWriter pw);

}


以第一个子类ConnectivityController为例他是通过get静态方式初始化的:



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);
// Register connectivity changed BR.
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
mContext.registerReceiverAsUser(
mConnectivityChangedReceiver, UserHandle.ALL, intentFilter, null, null);
ConnectivityService cs =
(ConnectivityService)ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
if (cs != null) {
if (cs.getActiveNetworkInfo() != null) {
mNetworkCOnnected= cs.getActiveNetworkInfo().isConnected();
}
mNetworkUnmetered = mNetworkConnected && !cs.isActiveNetworkMetered();
}
}

}


上面的代码完成了如下几件事:




  1. 传入当前的StateChangedListener状态改变监听器,并且JobSchedulerService已经实现了该监听器。也就是说如果网络改变了可以通过该监听器回调给JobSchedulerService。

  2. 注册了一个叫做ConnectivityChangedReceiver广播接收者。当网络改变的时候就会调用该方法。

    class ConnectivityChangedReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

    final String action = intent.getAction();
    if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {

    //获取网络的类型...
    if (activeNetwork == null) {
    ...
    updateTrackedJobs(userid);
    } else if (activeNetwork.getType() == networkType) {
    ...
    updateTrackedJobs(userid);
    }
    }
    }
    };

    private void updateTrackedJobs(int userId) {
    synchronized (mTrackedJobs) {
    //... 如果网络改变了 则通过监听器告诉JobSchedulerService
    if (changed) {
    mStateChangedListener.onControllerStateChanged();
    }
    }
    }



我们看下当某个条件触发。JobSchedulerService是如何处理的:



@Override
public void onControllerStateChanged() {
mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
}

private class JobHandler extends Handler {
...
@Override
public void handleMessage(Message message) {
...
switch (message.what) {
case MSG_JOB_EXPIRED:
synchronized (mJobs) {
JobStatus runNow = (JobStatus) message.obj;
...
if (runNow != null && !mPendingJobs.contains(runNow)
&& mJobs.containsJob(runNow)) {
mPendingJobs.add(runNow);
}
queueReadyJobsForExecutionLockedH();
}
break;
case MSG_CHECK_JOB:
...
maybeQueueReadyJobsForExecutionLockedH();
break;
}
maybeRunPendingJobsH();
removeMessages(MSG_CHECK_JOB);
}

}


上面的代码主要执行三个有效的方法:




  1. maybeQueueReadyJobsForExecutionLockedH();//将任务添加到任务待执行列表中

  2. maybeRunPendingJobsH();//将待执行任务列表中的任务执行

  3. removeMessages(MSG_CHECK_JOB);移除当前任务



maybeRunPendingJobsH()是如何关联我们熟悉的JobService的?



private void maybeRunPendingJobsH() {
synchronized (mJobs) {
Iterator it = mPendingJobs.iterator();
while (it.hasNext()) {
//1.拿到等待执行的任务
JobStatus nextPending = it.next();
...
//2.从执行列表中移除当前任务
if (!availableContext.executeRunnableJob(nextPending)) {
if (DEBUG) {
Slog.d(TAG, "Error executing " + nextPending);
}
//3.从待运行的列表中移除
mJobs.remove(nextPending);
}
it.remove();
}
}
}


JobServiceContext是如何执行executeRunnableJob(nextPending)去执行任务的,代码如下:



boolean executeRunnableJob(JobStatus job) {
//构建任务参数
mParams = new JobParameters(this, job.getJobId(), job.getExtras(),
!job.isConstraintsSatisfied());
//绑定我们当初在JobInfo中传入的服务对象。
boolean binding = mContext.bindServiceAsUser(intent, this,
Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND,
new UserHandle(job.getUserId()));
}


绑定JobService服务后,实现了如下:




  1. onBind()被调用,返回代理对象

    public abstract class JobService extends Service {

    IJobService mBinder = new IJobService.Stub() {
    @Override
    public void startJob(JobParameters jobParams) {
    ensureHandler();
    Message m = Message.obtain(mHandler, MSG_EXECUTE_JOB, jobParams);
    m.sendToTarget();
    }
    @Override
    public void stopJob(JobParameters jobParams) {
    ensureHandler();
    Message m = Message.obtain(mHandler, MSG_STOP_JOB, jobParams);
    m.sendToTarget();
    }
    };

    public final IBinder onBind(Intent intent) {
    return mBinder.asBinder();
    }

    }


  2. JobServiceContext的onServiceConnected()被调用:

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
    //内部wake_lock锁在这里。。。
    mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mRunningJob.getTag());
    mWakeLock.setWorkSource(new WorkSource(mRunningJob.getUid()));
    mWakeLock.setReferenceCounted(false);
    mWakeLock.acquire();
    mCallbackHandler.obtainMessage(MSG_SERVICE_BOUND).sendToTarget();
    }


    private class JobServiceHandler extends Handler {

    @Override
    public void handleMessage(Message message) {
    //case MSG_SERVICE_BOUND:
    handleServiceBoundH();
    }


    private void handleServiceBoundH() {
    ...
    //最最最...终启动了onStartJob();
    service.startJob(mParams);
    }

    }







推荐阅读
  • 本文介绍了Java并发库中的阻塞队列(BlockingQueue)及其典型应用场景。通过具体实例,展示了如何利用LinkedBlockingQueue实现线程间高效、安全的数据传递,并结合线程池和原子类优化性能。 ... [详细]
  • 本文详细介绍了Java中org.neo4j.helpers.collection.Iterators.single()方法的功能、使用场景及代码示例,帮助开发者更好地理解和应用该方法。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • Explore a common issue encountered when implementing an OAuth 1.0a API, specifically the inability to encode null objects and how to resolve it. ... [详细]
  • 本文介绍如何使用Objective-C结合dispatch库进行并发编程,以提高素数计数任务的效率。通过对比纯C代码与引入并发机制后的代码,展示dispatch库的强大功能。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 本文介绍如何利用动态规划算法解决经典的0-1背包问题。通过具体实例和代码实现,详细解释了在给定容量的背包中选择若干物品以最大化总价值的过程。 ... [详细]
  • 主要用了2个类来实现的,话不多说,直接看运行结果,然后在奉上源代码1.Index.javaimportjava.awt.Color;im ... [详细]
  • 在前两篇文章中,我们探讨了 ControllerDescriptor 和 ActionDescriptor 这两个描述对象,分别对应控制器和操作方法。本文将基于 MVC3 源码进一步分析 ParameterDescriptor,即用于描述 Action 方法参数的对象,并详细介绍其工作原理。 ... [详细]
  • 本文深入探讨了 Java 中的 Serializable 接口,解释了其实现机制、用途及注意事项,帮助开发者更好地理解和使用序列化功能。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 将Web服务部署到Tomcat
    本文介绍了如何在JDeveloper 12c中创建一个Java项目,并将其打包为Web服务,然后部署到Tomcat服务器。内容涵盖从项目创建、编写Web服务代码、配置相关XML文件到最终的本地部署和验证。 ... [详细]
  • 本文详细介绍了如何构建一个高效的UI管理系统,集中处理UI页面的打开、关闭、层级管理和页面跳转等问题。通过UIManager统一管理外部切换逻辑,实现功能逻辑分散化和代码复用,支持多人协作开发。 ... [详细]
  • 本文详细介绍了Java中org.w3c.dom.Text类的splitText()方法,通过多个代码示例展示了其实际应用。该方法用于将文本节点在指定位置拆分为两个节点,并保持在文档树中。 ... [详细]
  • 本文详细介绍了 Apache Jena 库中的 Txn.executeWrite 方法,通过多个实际代码示例展示了其在不同场景下的应用,帮助开发者更好地理解和使用该方法。 ... [详细]
author-avatar
麦豪小仙
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有