性能優化(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解除服務綁定),這部分只能留給大家自己看了,如果認真看完上面的分析應該這部分不會太難,希望大家不要害怕看源碼哈,看懂了源碼,使用的時候就更有把握了有沒有。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容