热门标签 | 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注解的基本概念及其在现代Java开发中的应用。文章不仅介绍了如何创建和使用自定义注解,还详细讲解了如何利用反射机制解析注解,以及Java内建注解的使用场景。 ... [详细]
  • A题简单判断#includeusingnamespacestd;typedeflonglongll;intt;intmain(){cint;whil ... [详细]
  • Flutter 高德地图插件使用指南
    本文档详细介绍了如何在Flutter项目中集成和使用高德地图插件,包括安装、配置及基本使用方法。 ... [详细]
  • 本文章介绍了如何将阿拉伯数字形式的金额转换为中国传统的大写形式,适用于财务报告和正式文件中的金额表示。 ... [详细]
  • 本文详细介绍了如何在Android游戏中实现360°平滑触屏摇杆,包括摇杆的基本设计原理和具体实现步骤。 ... [详细]
  • 本文将详细介绍如何使用ViewPager实现多页面滑动切换,并探讨如何去掉其默认的左右切换动画效果。ViewPager是Android开发中常用的组件之一,用于实现屏幕间的内容切换。 ... [详细]
  • 深入浅出:Java面向对象编程
    本文详细介绍了Java语言的核心特性——面向对象编程。探讨了Java的基本概念、平台无关性、丰富的内置类库及安全性,同时深入解析了类加载器、垃圾回收机制以及基本数据类型和其包装类。 ... [详细]
  • 本文探讨了如何利用自定义URI方案和注册表编辑,在Windows操作系统中实现从Web浏览器启动本地应用程序的方法,同时强调了这一过程中的安全考虑。 ... [详细]
  • 探讨了一个关于Windows C++开发中遇到的乱码问题,特别是在处理宽字符时出现的情况。本文通过一个具体的示例——一个简单的窗口应用程序,展示了如何正确地使用宽字符以避免乱码。 ... [详细]
  • 本文介绍了一种利用迭代法解决特定方程问题的方法,特别是当给定函数f(x)在区间[x1, x2]内连续且f(x1)0时,存在一个x~使得f(x~)=0。通过逐步细化搜索范围,可以高效地找到方程的根。 ... [详细]
  • 设计模式笔记12:迭代器模式(Iterator Pattern) ... [详细]
  • 本文介绍了NHibernate中通过定义接口和实现类来管理会话工厂的方法,包括接口的优势、模型文件夹的结构以及具体的代码示例。 ... [详细]
  • 深入理解Hibernate延迟加载机制
    本文探讨了Hibernate框架中的延迟加载(懒加载)特性,分析其对程序性能的影响及实现原理,同时提供了具体的代码示例来说明如何配置和使用延迟加载。 ... [详细]
  • Linux双网卡绑定技术详解与实践
    本文详细介绍了如何在Linux系统中实现双网卡绑定,即将两块物理网卡合并为一个逻辑网卡,以提高网络性能和可靠性。文中不仅涵盖了基本的概念,还提供了具体的配置步骤和测试方法。 ... [详细]
  • 本文介绍了如何通过实现Runnable接口并利用静态代理模式来创建多线程程序。主要内容包括自定义类、代理类的设计以及它们如何共同实现Runnable接口。此外,还将探讨Callable接口作为另一种实现多线程的方法。 ... [详细]
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社区 版权所有