性能优化(8.5)-JobScheduler的源码分析

主目录见::Android高级进阶知识(这是总目录索引)

 今天讲这篇文章主要是为了接上面一篇来讲的,如果大家不知道JobScheduler怎么使用的话,那么可以移步在Android Lollipop中使用JobScheduler,我们知道,Android系统中有几个重要的进程,init进程,Zygote进程,SystemServer进程,这些进程的启动流程分别为:

  • init进程->Zygote进程->SystemServer进程->各种应用进程

这里的Zygote进程是应用的根进程,其他进程都是包括SystemServer进程和各种应用进程都是Zygote中fork出来的,其中SystemServer主要是启动各种系统服务,比如:ActivityManagerServicePackageManagerServiceWindowManagerService以及JobScheduler等服务,JobScheduler作为系统服务,也是从SystemServer中启动的,所以我们先来看SystemServer的main方法,因为SystemServerZygote进程fork出来的时候会调用此方法:

  public static void main(String[] args) {
        new SystemServer().run();
    }

这里我们看到主要是调用SystemServer类的run方法,所以我们接下来看看:

 private void run() {
...
   // Start services.
        try {
            Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartServices");
            startBootstrapServices();
            startCoreServices();
            startOtherServices();
        } catch (Throwable ex) {
                 throw ex;
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        }
...
}

我们看到确实SystemServer中会启动各种服务,我们的JobScheduler服务是在方法startOtherServices()中通过SystemServiceManager类来启动的,我们来看看:

private void startOtherServices() {
...
  mSystemServiceManager.startService(JobSchedulerService.class);
...
}

我们看到确实是交给SystemServiceManager通过startService来启动JobSchedulerService服务,所以我们来看startService干了一些啥:

  @SuppressWarnings("unchecked")
    public <T extends SystemService> T startService(Class<T> serviceClass) {
        try {
//获取服务名称,我们这里就是JobSchedulerService
            final String name = serviceClass.getName();
.....
            // Create the service.
//这里判断参数serviceClass是否是SystemService的子类,不是的话就抛出错误
            if (!SystemService.class.isAssignableFrom(serviceClass)) {
                throw new RuntimeException("Failed to create " + name
                        + ": service must extend " + SystemService.class.getName());
            }
            final T service;
            try {
//获取serviceClass的一个参数为Context的构造函数
                Constructor<T> constructor = serviceClass.getConstructor(Context.class);
//实例化服务对象
                service = constructor.newInstance(mContext);
            } catch (Exception ex) {
              ......
            }

            // Register it.
//添加到服务的list中
            mServices.add(service);

            // Start it.
            try {
//然后调用服务的onStart方法
                service.onStart();
            } catch (RuntimeException ex) {
              ......
            }
            return service;
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        }
    }

我们看到这个方法里面会调用服务一个参数为Context的构造函数进行实例化,所以我们这里接下来看看JobSchedulerService的构造函数做了什么。

1.JobSchedulerService

因为实例化一个JobSchedulerService类的时候,会执行构造函数的代码:

public final class JobSchedulerService extends com.android.server.SystemService
        implements StateChangedListener, JobCompletedListener {
final JobHandler mHandler;//主要处理任务到期,任务检查,任务结束等消息
final Constants mConstants;//存放一些常量
final JobSchedulerStub mJobSchedulerStub;//Binder接口的代理类
 final JobStore mJobs;//里面维护了一个Job集合,从data/system/job/jobs.xml文件中读取的永久性任务
List<StateController> mControllers;//控制器集合
.....

 public JobSchedulerService(Context context) {
        super(context);
//初始化
        mHandler = new JobHandler(context.getMainLooper());
        mConstants = new Constants(mHandler);
        mJobSchedulerStub = new JobSchedulerStub();
        mJobs = JobStore.initAndGet(this);

        // Create the controllers.
        mControllers = new ArrayList<StateController>();
//网络连接情况控制器
        mControllers.add(ConnectivityController.get(this));
//执行时机控制器
        mControllers.add(TimeController.get(this));
//空闲状态控制器
        mControllers.add(IdleController.get(this));
//电量情况控制器
        mControllers.add(BatteryController.get(this));
//应用空闲状态控制器
        mControllers.add(AppIdleController.get(this));
//URIs内容变化控制器
        mControllers.add(ContentObserverController.get(this));
//设备空闲状态控制器
        mControllers.add(DeviceIdleJobsController.get(this));
    }
......
}

我们首先看到JobSchedulerService类实现了StateChangedListener接口,然后我们看到所有的控制器都是实现的StateController类。首先来看看这个接口和类:

public interface StateChangedListener {
//控制器调用这个方法来通知JobManager 该检查一个任务的状态了,因为这里JobSchedulerService 
//实现了这个接口,所以会调用JobSchedulerService里面这个方法的实现
    public void onControllerStateChanged();

//控制器调用这个方法通知JobManager ,应该马上执行任务了
    public void onRunJobNow(JobStatus jobStatus);
//设备的空闲状态发生改变调用这个方法
    public void onDeviceIdleStateChanged(boolean deviceIdle);
}

我们知道JobSchedulerService 实现了这个接口,所以调用这里的接口就会调用到JobSchedulerService 中的方法实现。

public abstract class StateController {
    protected static final boolean DEBUG = JobSchedulerService.DEBUG;
    protected final Context mContext;
    protected final Object mLock;
    protected final StateChangedListener mStateChangedListener;

    public StateController(StateChangedListener stateChangedListener, Context context,
            Object lock) {
        mStateChangedListener = stateChangedListener;
        mContext = context;
        mLock = lock;
    }

//添加需要监听的任务,同时在任务更新的时候也会调用
    public abstract void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob);

//可选实现,在任务执行前做准备
    public void prepareForExecutionLocked(JobStatus jobStatus) {
    }
//清除该任务,当任务被取消,或者完成的时候调用
    public abstract void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
            boolean forUpdate);
//当一个新任务被创建来重新执行之前失败的任务时调用
    public void rescheduleForFailure(JobStatus newJob, JobStatus failureToReschedule) {
    }

    public abstract void dumpControllerStateLocked(PrintWriter pw, int filterUid);
}

我们看到所有的控制器都是继承的这个抽象类,而且实现了里面的几个抽象方法。这里我们就挑一个控制器来看看实现,这里我们选择ConnectivityController控制器来看下流程。

2.ConnectivityController

public class ConnectivityController extends StateController implements
        ConnectivityManager.OnNetworkActiveListener {
    private static final String TAG = "JobScheduler.Conn";
//网络连接管理类,用于获取活跃网络信息
    private final ConnectivityManager mConnManager;
//提供网络策略管理服务
    private final NetworkPolicyManager mNetPolicyManager;

//追踪的任务的列表
    @GuardedBy("mLock")
    private final ArrayList<JobStatus> mTrackedJobs = new ArrayList<JobStatus>();

    /** Singleton. */
    private static ConnectivityController mSingleton;
    private static Object sCreationLock = new Object();

//获取控制类实例:单例
    public static ConnectivityController get(JobSchedulerService jms) {
        synchronized (sCreationLock) {
            if (mSingleton == null) {
                mSingleton = new ConnectivityController(jms, jms.getContext(), jms.getLock());
            }
            return mSingleton;
        }
    }

    private ConnectivityController(StateChangedListener stateChangedListener, Context context,
            Object lock) {
        super(stateChangedListener, context, lock);
//获取管理类实例
        mConnManager = mContext.getSystemService(ConnectivityManager.class);
        mNetPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
//注册网络广播
        final IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
        mContext.registerReceiverAsUser(
                mConnectivityReceiver, UserHandle.SYSTEM, intentFilter, null, null);

        mNetPolicyManager.registerListener(mNetPolicyListener);
    }

    @Override
    public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
//判断是否有连接约束,是否有不按用量计费的约束,是否有不允许漫游的约束
//(这些可以通过JobInfo的builder方法设置)
        if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()
                || jobStatus.hasNotRoamingConstraint()) {
//更新任务的约束
            updateConstraintsSatisfied(jobStatus);
//将任务添加进追踪列表
            mTrackedJobs.add(jobStatus);
        }
    }

    @Override
    public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
            boolean forUpdate) {
        if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()
                || jobStatus.hasNotRoamingConstraint()) {
//从追踪列表中删除任务
            mTrackedJobs.remove(jobStatus);
        }
    }

    private boolean updateConstraintsSatisfied(JobStatus jobStatus) {
        final boolean ignoreBlocked = (jobStatus.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
//获取活跃网络的信息
        final NetworkInfo info = mConnManager.getActiveNetworkInfoForUid(jobStatus.getSourceUid(),
                ignoreBlocked);
        final boolean connected = (info != null) && info.isConnected();
        final boolean unmetered = connected && !info.isMetered();
        final boolean notRoaming = connected && !info.isRoaming();

        boolean changed = false;
//更新任务的网络相关标识
        changed |= jobStatus.setConnectivityConstraintSatisfied(connected);
        changed |= jobStatus.setUnmeteredConstraintSatisfied(unmetered);
        changed |= jobStatus.setNotRoamingConstraintSatisfied(notRoaming);
        return changed;
    }

    /**
     * Update all jobs tracked by this controller.
     *
     * @param uid only update jobs belonging to this UID, or {@code -1} to
     *            update all tracked jobs.
     */
    private void updateTrackedJobs(int uid) {
        synchronized (mLock) {
            boolean changed = false;
//遍历任务追踪列表
            for (int i = 0; i < mTrackedJobs.size(); i++) {
                final JobStatus js = mTrackedJobs.get(i);
                if (uid == -1 || uid == js.getSourceUid()) {
//更新约束
                    changed |= updateConstraintsSatisfied(js);
                }
            }
 // 如果changed为true,则调用监听器(即JobSchedulerService)的onControllerStateChanged方法  
            if (changed) {
                mStateChangedListener.onControllerStateChanged();
            }
        }
    }

    /**
     * We know the network has just come up. We want to run any jobs that are ready.
     */
    @Override
    public synchronized void onNetworkActive() {
        synchronized (mLock) {
            for (int i = 0; i < mTrackedJobs.size(); i++) {
                final JobStatus js = mTrackedJobs.get(i);
                if (js.isReady()) {
                    if (DEBUG) {
                        Slog.d(TAG, "Running " + js + " due to network activity.");
                    }
//当网络状态良好,我们就可以遍历追踪列表取出任务,然后调用下面方法马上执行
                    mStateChangedListener.onRunJobNow(js);
                }
            }
        }
    }

    private BroadcastReceiver mConnectivityReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
//接收到网络广播则更新追踪的任务
            updateTrackedJobs(-1);
        }
    };

    private INetworkPolicyListener mNetPolicyListener = new INetworkPolicyListener.Stub() {
//网络策略变化则回调这里的相应方法
        @Override
        public void onUidRulesChanged(int uid, int uidRules) {
            updateTrackedJobs(uid);
        }

        @Override
        public void onMeteredIfacesChanged(String[] meteredIfaces) {
            updateTrackedJobs(-1);
        }

        @Override
        public void onRestrictBackgroundChanged(boolean restrictBackground) {
            updateTrackedJobs(-1);
        }

        @Override
        public void onRestrictBackgroundWhitelistChanged(int uid, boolean whitelisted) {
            updateTrackedJobs(uid);
        }

        @Override
        public void onRestrictBackgroundBlacklistChanged(int uid, boolean blacklisted) {
            updateTrackedJobs(uid);
        }
    };

    @Override
    public void dumpControllerStateLocked(PrintWriter pw, int filterUid) {
//dump出来追踪的任务信息
        pw.println("Connectivity.");
        pw.print("Tracking ");
        pw.print(mTrackedJobs.size());
        pw.println(":");
        for (int i = 0; i < mTrackedJobs.size(); i++) {
            final JobStatus js = mTrackedJobs.get(i);
            if (js.shouldDump(filterUid)) {
                pw.print("  #");
                js.printUniqueId(pw);
                pw.print(" from ");
                UserHandle.formatUid(pw, js.getSourceUid());
                pw.print(": C="); pw.print(js.hasConnectivityConstraint());
                pw.print(": UM="); pw.print(js.hasUnmeteredConstraint());
                pw.print(": NR="); pw.println(js.hasNotRoamingConstraint());
            }
        }
    }
}

我们看到这个网络连接控制器里面逻辑明了,主要是注册了网络连接的广播,同时注册了网络约束的监听,所以在接收到广播后会调用updateTrackedJobs方法来更新每个任务的约束信息,同时会调用JobSchedulerService的onControllerStateChanged方法来通知说约束任务的条件状态发生改变,而且由于该控制器实现了ConnectivityManager.OnNetworkActiveListener 接口,所以网络可用的时候会回调onNetworkActive()方法,这个方法在网络可用状态的时候,马上执行任务。所以我们接下来看JobSchedulerServiceonControllerStateChanged方法和onNetworkActive()方法。

3.onControllerStateChanged和onNetworkActive

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

    @Override
    public void onRunJobNow(JobStatus jobStatus) {
        mHandler.obtainMessage(MSG_JOB_EXPIRED, jobStatus).sendToTarget();
    }

我们看到JobSchedulerService的这两个方法主要就是向Handler发送了消息,分别是MSG_CHECK_JOBMSG_JOB_EXPIRED类型的消息,所以逻辑实际是交给了Handler执行了。这里的Handler是什么呢?其实这里的Handler就是JobHandlerJobHandler类是在JobSchedulerService中被实例化的。所以我们可以来看看JobHandler类。

4.JobHandler

因为这是个Handler的对象,所以我们先来看他的handleMessage方法:

   @Override
        public void handleMessage(Message message) {
            synchronized (mLock) {
                if (!mReadyToRock) {//未准备好执行任务直接return
                    return;
                }
            }
            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();
            // Don't remove JOB_EXPIRED in case one came along while processing the queue.
            removeMessages(MSG_CHECK_JOB);
        }

我们看到这个Handler执行四种消息类型,其中我们onControllerStateChanged方法发送的MSG_CHECK_JOBonRunJobNow方法的MSG_JOB_EXPIRED消息分别对应上面的操作,其中有几个关键方法queueReadyJobsForExecutionLockedH(),maybeQueueReadyJobsForExecutionLockedH(),maybeRunPendingJobsH(),我们一一来看看,首先我们来看queueReadyJobsForExecutionLockedH()方法:

        private void queueReadyJobsForExecutionLockedH() {
            if (DEBUG) {
                Slog.d(TAG, "queuing all ready jobs for execution:");
            }
            noteJobsNonpending(mPendingJobs);
          //清除等待执行列表中的任务
            mPendingJobs.clear();
          // 遍历任务列表,循环判断任务是否准备好执行 ,准备好了则加入准备执行列表中,不然约束条件为满足则取消
            mJobs.forEachJob(mReadyQueueFunctor);
          //将准备执行的任务重新添加到待执行任务列表中
            mReadyQueueFunctor.postProcess();

            if (DEBUG) {
                final int queuedJobs = mPendingJobs.size();
                if (queuedJobs == 0) {
                    Slog.d(TAG, "No jobs pending.");
                } else {
                    Slog.d(TAG, queuedJobs + " jobs queued.");
                }
            }
        }

我们看到这个方法主要是把JobStoreJobStore从磁盘中读取任务map存放在mJobSet中,xml文件主要在data/system/job目录下创建jobs.xml文件)中的准备执行的符合约束条件的任务添加等待执行的任务列表中。maybeQueueReadyJobsForExecutionLockedH()方法也是类似,我们这里直接看另外一个maybeRunPendingJobsH()方法,这个方法非常关键,前面已经有等待执行任务列表了,这个方法就是取出来任务执行的。

 private void maybeRunPendingJobsH() {
            synchronized (mLock) {
                assignJobsToContextsLocked();
                reportActive();
            }
        }

我们看到这个方法会调用另外一个方法assignJobsToContextsLocked()来执行任务,然后这个方法又会调用mActiveServices.get(i).executeRunnableJob(pendingJob)来执行任务,mActiveServices.get(i)获取到的是JobServiceContext对象,所以我们调用这个对象的executeRunnableJob()方法。

5.JobServiceContext executeRunnableJob

 boolean executeRunnableJob(JobStatus job) {
        synchronized (mLock) {
            //如果这个Context无效则返回
            if (!mAvailable) {
                return false;
            }

            mPreferredUid = NO_PREFERRED_UID;

            mRunningJob = job;
            //任务是否有最后期限约束且最近一次执行时间是否小于开机时间
            final boolean isDeadlineExpired =
                    job.hasDeadlineConstraint() &&
                            (job.getLatestRunTimeElapsed() < SystemClock.elapsedRealtime());
   .....
            mParams = new JobParameters(this, job.getJobId(), job.getExtras(), isDeadlineExpired,
                    triggeredUris, triggeredAuthorities);
            mExecutionStartTimeElapsed = SystemClock.elapsedRealtime();

            mVerb = VERB_BINDING;
            scheduleOpTimeOut();
            // 用任务的服务的组件名创建Intent 
            final Intent intent = new Intent().setComponent(job.getServiceComponent());
            //这里执行了服务的绑定操作(跟AMS进行交互启动服务),意思就是
            //把你任务中设置的服务启动然后会回调ServiceConnection
            //对象的onServiceConnected方法
            boolean binding = mContext.bindServiceAsUser(intent, this,
                    Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND,
                    new UserHandle(job.getUserId()));
            if (!binding) {
                mRunningJob = null;
                mParams = null;
                mExecutionStartTimeElapsed = 0L;
                mVerb = VERB_FINISHED;
                removeOpTimeOut();
                return false;
            }
            try {
                mBatteryStats.noteJobStart(job.getBatteryName(), job.getSourceUid());
            } catch (RemoteException e) {
                // Whatever.
            }
            mJobPackageTracker.noteActive(job);
            mAvailable = false;
            return true;
        }
    }

我们看到这个方法会调用Context中的bindServiceAsUser方法进行服务的绑定操作,这里的服务绑定跟我们的bindService服务类似,具体流程可以看从framework分析AIDL生成文件这里的流程非常详细,我们知道最终程序会回调onServiceConnected方法,因为这个地方this就是JobServiceContext对象,而且我们看到JobServiceContext就是实现了ServiceConnection

public class JobServiceContext extends IJobCallback.Stub implements ServiceConnection {
....
}

所以我们知道,绑定完服务会回调JobServiceContext中的onServiceConnected方法:

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        JobStatus runningJob;
        synchronized (mLock) {
            runningJob = mRunningJob;
        }
//正在执行的任务为空,或者正在执行的任务的服务名称和绑定的服务的服务名称不一致则取消执行
        if (runningJob == null || !name.equals(runningJob.getServiceComponent())) {
            mCallbackHandler.obtainMessage(MSG_SHUTDOWN_EXECUTION).sendToTarget();
            return;
        }
//获取远程的JobService的代理
        this.service = IJobService.Stub.asInterface(service);
        final PowerManager pm =
                (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
        PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                runningJob.getTag());
        wl.setWorkSource(new WorkSource(runningJob.getSourceUid()));
        wl.setReferenceCounted(false);
        wl.acquire();
        synchronized (mLock) {
            if (mWakeLock != null) {
                mWakeLock.release();
            }
            mWakeLock = wl;
        }
// 向mCallbackHandler发送绑定服务成功的消息  
        mCallbackHandler.obtainMessage(MSG_SERVICE_BOUND).sendToTarget();
    }

我们看到这里跟我们平常写AIDL跨进程通讯的回调写法差不多,方法最后还会向mCallbackHandler发送一个MSG_SERVICE_BOUND类型的消息。这个mCallbackHandler又是什么呢?这里其实是JobServiceHandler对象,我们来看看JobServiceHandler中的handleMessage做了啥:

  @Override
        public void handleMessage(Message message) {
            switch (message.what) {
                case MSG_SERVICE_BOUND:
                    removeOpTimeOut();
                    handleServiceBoundH();
                    break;
......
}

我们看到这里调用了handleServiceBoundH()方法,这个方法我们也跟进来看看:

        /** Start the job on the service. */
        private void handleServiceBoundH() {
            if (mVerb != VERB_BINDING) {
                closeAndCleanupJobH(false /* reschedule */);
                return;
            }
            if (mCancelled.get()) {
                closeAndCleanupJobH(true /* reschedule */);
                return;
            }
            try {
                mVerb = VERB_STARTING;
                scheduleOpTimeOut();
//我们知道这里service是IJobService对象,其实就是远程JobService的代理,所以会调用到JobService的startJob方法
                service.startJob(mParams);
            } catch (RemoteException e) {
         ......
            }
        }

到这里,我们看到会调用到JobService中的startJob,我们猜想,到这里我们的服务就启动完成了。

6.JobService startJob

 static final class JobInterface extends IJobService.Stub {
        final WeakReference<JobService> mService;

        JobInterface(JobService service) {
            mService = new WeakReference<>(service);
        }

        @Override
        public void startJob(JobParameters jobParams) throws RemoteException {
            JobService service = mService.get();
            if (service != null) {
                service.ensureHandler();
// 把jobParams封装成一个消息 
                Message m = Message.obtain(service.mHandler, MSG_EXECUTE_JOB, jobParams);
//发送消息
                m.sendToTarget();
            }
        }
.......
}

我们知道跨进程通讯的人都知道,远程JobService代理调用startJob其实就是调用到远程Binder中的startJob方法,在这个方法中,会发送一个消息类型为MSG_EXECUTE_JOB的消息给Handler,这里的Handler就是JobService服务中的JobHandler,同样我们来看看他的handleMessage里面的处理:

  @Override
        public void handleMessage(Message msg) {
            final JobParameters params = (JobParameters) msg.obj;
            switch (msg.what) {
                case MSG_EXECUTE_JOB:
                    try {
                        boolean workOngoing = JobService.this.onStartJob(params);
                        ackStartMessage(params, workOngoing);
                    } catch (Exception e) {
                        Log.e(TAG, "Error while executing job: " + params.getJobId());
                        throw new RuntimeException(e);
                    }
                    break;
.....
}

我们看到这个方法执行了JobService中的onStartJob方法,这个方法在我们自定义服务继承JobService的时候会重写这个方法。我们会在这个方法启动我们的任务。

7.JobScheduler schedule

我们知道,使用方法里面除了启动自定义的服务之外,还会把JobInfo.Builder传给JobScheduler的schedule方法,如下所示:

JobScheduler tm = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
 tm.schedule(builder.build());

同时我们记得,在最前面我们SystemServiceManager 通过startService启动JobSchedulerService服务的时候,当实例化JobSchedulerService的时候,我们会调用JobSchedulerServiceonStart方法,我们先来看看这个onStart方法做了什么:

  @Override
    public void onStart() {
        publishLocalService(JobSchedulerInternal.class, new LocalService());
        publishBinderService(Context.JOB_SCHEDULER_SERVICE, mJobSchedulerStub);
    }

是不是一眼就明白了,我们这里publishBinderService()方法绑定的JOB_SCHEDULER_SERVICE服务就是 mJobSchedulerStub,也就是JobSchedulerService的内部类JobSchedulerStub对象,所以我们这里的schedule方法实际其实是JobSchedulerStub中的:

        @Override
        public int schedule(JobInfo job) throws RemoteException {
            final int pid = Binder.getCallingPid();
            final int uid = Binder.getCallingUid();
.......

            long ident = Binder.clearCallingIdentity();
            try {
                return JobSchedulerService.this.schedule(job, uid);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }

我们看到以上的方法又调用了JobSchedulerServiceschedule方法:

   public int schedule(JobInfo job, int uId) {
        return scheduleAsPackage(job, uId, null, -1, null);
    }

我们接着往下看scheduleAsPackage方法:

    public int scheduleAsPackage(JobInfo job, int uId, String packageName, int userId,
            String tag) {
        JobStatus jobStatus = JobStatus.createFromJobInfo(job, uId, packageName, userId, tag);
   ....
        JobStatus toCancel;
  .....
//查找任务队列中的任务
            toCancel = mJobs.getJobByUidAndJobId(uId, job.getId());
            if (toCancel != null) {
// 如果任务已经在等待队列或已经在执行则从等待队列中移除或取消任务的执行  
                cancelJobImpl(toCancel, jobStatus);
            }
 // 开始追踪任务  
            startTrackingJob(jobStatus, toCancel);
        }
 // 向Handler发送检查任务的消息  
        mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
        return JobScheduler.RESULT_SUCCESS;
    }

我们看到这个方法主要就是根据传进来的JobInfo来创建一个任务,然后查找这个任务是否已经存在,如果存在的话那么删除,然后开始追踪,向JobHandler中发送一个检查任务消息,将任务添加到等待执行的任务列表中,然后执行任务。

总结:整体的流程大体是写完了,但是发现还有JobFinish()方法的源码没有写(这个方法会调用到JobServiceContext里的JobFinish(),然后会调用unbindService解除服务绑定),这部分只能留给大家自己看了,如果认真看完上面的分析应该这部分不会太难,希望大家不要害怕看源码哈,看懂了源码,使用的时候就更有把握了有没有。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容