android---JobScheduler调度器过程(JobSchedulerService的启动过程)

 

JobSchedulerService启动过程,最主要工作是从jobs.xml文件收集所有的jobs,放入到JobStore的成员变量mJobSet,转成jobinfo。

 

JobScheduler服务启动

2.1 startOtherServices

[-> SystemServer.java]

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

该方法先初始化JSS,然后再调用其onStart()方法。

 

2.2 JobSchedulerService

[-> JobSchedulerService.java]

JobSchedulerService {
    List<StateController> mControllers;
    final JobHandler mHandler;
    final JobSchedulerStub mJobSchedulerStub;
    final JobStore mJobs;
    ...

    public JobSchedulerService(Context context) {
        super(context);
        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));

        //创建主线程的looper[见小节2.3]
        mHandler = new JobHandler(context.getMainLooper());
        //创建binder服务端[见小节2.4]
        mJobSchedulerStub = new JobSchedulerStub();
        //[见小节2.5]
        mJobs = JobStore.initAndGet(this);
    }

    public void onStart() {
        publishBinderService(Context.JOB_SCHEDULER_SERVICE, mJobSchedulerStub);
    }
}

创建了5个不同的StateController,分别添加到mControllers。

类型说明
ConnectivityController 注册监听网络连接状态的广播
TimeController 注册监听job时间到期的广播
IdleController 注册监听屏幕亮/灭,dream进入/退出,状态改变的广播
BatteryController 注册监听电池是否充电,电量状态的广播
AppIdleController 监听app是否空闲

state_controller

接下来,以ConnectivityController为例,说一说相应Controller的创建过程, 其他Controller也基本类似.

 

 

2.2.1 ConnectivityController

[-> ConnectivityController.java]

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);
        //注册监听网络连接状态的广播,且采用BackgroundThread线程
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        mContext.registerReceiverAsUser(
                mConnectivityChangedReceiver, UserHandle.ALL, intentFilter, null,
                BackgroundThread.getHandler());
        ConnectivityService cs =
                (ConnectivityService)ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
        if (cs != null) {
            if (cs.getActiveNetworkInfo() != null) {
                mNetworkConnected = cs.getActiveNetworkInfo().isConnected();
            }
            mNetworkUnmetered = mNetworkConnected && !cs.isActiveNetworkMetered();
        }
    }
}

当监听到CONNECTIVITY_ACTION广播,onReceive方法的执行位于“android.bg”线程。

 

 

2.3 JSS.JobHandler

[-> JobSchedulerService.java ::JobHandler]

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

    public JobHandler(Looper looper) {
        super(looper);
    }

    public void handleMessage(Message message) {
        synchronized (mJobs) {
            //当系统启动到phase 600,则mReadyToRock=true.
            if (!mReadyToRock) {
                return;
            }
        }
        switch (message.what) {
            case MSG_JOB_EXPIRED: ...
            case MSG_CHECK_JOB: ...
        }
        maybeRunPendingJobsH();
        removeMessages(MSG_CHECK_JOB);
    }

JobHandler采用的是system_server进程的主线程Looper,也就是该过程运行在主线程。

 

 

2.4 JobSchedulerStub

[-> JobSchedulerService.java ::JobSchedulerStub]

final class JobSchedulerStub extends IJobScheduler.Stub {
    ...
}

JobSchedulerStub作为实现接口IJobScheduler的binder服务端。

 

 

2.5 JS.initAndGet

[-> JobStore.java]

static JobStore initAndGet(JobSchedulerService jobManagerService) {
    synchronized (sSingletonLock) {
        if (sSingleton == null) {
            //[见小节2.6]
            sSingleton = new JobStore(jobManagerService.getContext(),
                    Environment.getDataDirectory());
        }
        return sSingleton;
    }
}

2.6 创建JobStore

[-> JobStore.java]

public class JobStore {
    final ArraySet<JobStatus> mJobSet;
    private final Handler mIoHandler = IoThread.getHandler();
    ...

    private JobStore(Context context, File dataDir) {
        mContext = context;
        mDirtyOperations = 0;

        File systemDir = new File(dataDir, "system");
        File jobDir = new File(systemDir, "job");
        jobDir.mkdirs();
        // 创建/data/system/job/jobs.xml
        mJobsFile = new AtomicFile(new File(jobDir, "jobs.xml"));
        mJobSet = new ArraySet<JobStatus>();
        //[见小节2.7.1]
        readJobMapFromDisk(mJobSet);
    }
}

该方法会创建job目录以及jobs.xml文件, 以及从文件中读取所有的JobStatus。

 

 

 

2.7 xml解析

2.7.1 ReadJobMapFromDiskRunnable

[-> JobStore.java]

private class ReadJobMapFromDiskRunnable implements Runnable {
    private final ArraySet<JobStatus> jobSet;

    ReadJobMapFromDiskRunnable(ArraySet<JobStatus> jobSet) {
        this.jobSet = jobSet;
    }

    public void run() {
        List<JobStatus> jobs;
        FileInputStream fis = mJobsFile.openRead();
        synchronized (JobStore.this) {
            jobs = readJobMapImpl(fis);  //[见小节2.7.2]
            if (jobs != null) {
                for (int i=0; i<jobs.size(); i++) {
                    this.jobSet.add(jobs.get(i));
                }
            }
        }
        fis.close();
    }
}

此处mJobsFile便是/data/system/job/jobs.xml。

 

 

2.7.2 readJobMapImpl

[-> JobStore.java]

private List<JobStatus> readJobMapImpl(FileInputStream fis)
         throws XmlPullParserException, IOException {
     XmlPullParser parser = Xml.newPullParser();
     parser.setInput(fis, StandardCharsets.UTF_8.name());
     ...

     String tagName = parser.getName();
     if ("job-info".equals(tagName)) {
         final List<JobStatus> jobs = new ArrayList<JobStatus>();
         ...
         eventType = parser.next();
         do {
             //读取每一个 <job/>
             if (eventType == XmlPullParser.START_TAG) {
                 tagName = parser.getName();
                 if ("job".equals(tagName)) {
                      //[见小节2.7.3]
                     JobStatus persistedJob = restoreJobFromXml(parser);
                     if (persistedJob != null) {
                         jobs.add(persistedJob);
                     }
                 }
             }
             eventType = parser.next();
         } while (eventType != XmlPullParser.END_DOCUMENT);
         return jobs;
     }
     return null;
 }

从文件jobs.xml中读取并创建JobStatus,然后添加到mJobSet.

 

 

2.7.3 restoreJobFromXml

[-> JobStore.java]

private JobStatus restoreJobFromXml(XmlPullParser parser) throws XmlPullParserException, IOException {
    JobInfo.Builder jobBuilder;
    int uid;
    //创建用于获取jobInfo的Builder[见小节2.7.4]
    jobBuilder = buildBuilderFromXml(parser);
    jobBuilder.setPersisted(true);
    uid = Integer.valueOf(parser.getAttributeValue(null, "uid"));
    ...

    buildConstraintsFromXml(jobBuilder, parser); //读取常量
    //读取job执行的两个时间点:delay和deadline
    Pair<Long, Long> elapsedRuntimes = buildExecutionTimesFromXml(parser);
    ...
    //[见小节2.8]
    return new JobStatus(jobBuilder.build(), uid,
                elapsedRuntimes.first, elapsedRuntimes.second);
}

2.7.4 buildBuilderFromXml

[-> JobStore.java]

private JobInfo.Builder buildBuilderFromXml(XmlPullParser parser) throws NumberFormatException {
    int jobId = Integer.valueOf(parser.getAttributeValue(null, "jobid"));
    String packageName = parser.getAttributeValue(null, "package");
    String className = parser.getAttributeValue(null, "class");
    ComponentName cname = new ComponentName(packageName, className);
    //[见小节2.7.5]
    return new JobInfo.Builder(jobId, cname);
}

创建的JobInfo对象,记录着任务的jobid, package, class。

 

 

2.7.5 创建JobInfo

[-> JobInfo.java]

public class JobInfo implements Parcelable {
    public static final class Builder {
        public Builder(int jobId, ComponentName jobService) {
             mJobService = jobService;
             mJobId = jobId;
        }
        public JobInfo build() {
            mExtras = new PersistableBundle(mExtras);
            return new JobInfo(this); //创建JobInfo
        }
    }
}

2.8 创建JobStatus

[-> JobStatus.java]

public JobStatus(JobInfo job, int uId, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) {
    this(job, uId, 0);

    this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
    this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
}

private JobStatus(JobInfo job, int uId, int numFailures) {
    this.job = job;
    this.uId = uId;
    this.name = job.getService().flattenToShortString();
    this.tag = "*job*/" + this.name;
    this.numFailures = numFailures;
}

JobStatus对象记录着任务的jobId, ComponentName, uid以及标签和失败次数信息。

 

 

2.9 JSS.onBootPhase

public void onBootPhase(int phase) {
    if (PHASE_SYSTEM_SERVICES_READY == phase) {
        //阶段500,则开始注册package和use移除的广播监听
        final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
        filter.addDataScheme("package");
        getContext().registerReceiverAsUser(
                mBroadcastReceiver, UserHandle.ALL, filter, null, null);
        final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
        userFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
        getContext().registerReceiverAsUser(
                mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
        mPowerManager = (PowerManager)getContext().getSystemService(Context.POWER_SERVICE);
    } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
        synchronized (mJobs) {
            mReadyToRock = true;
            mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
                    BatteryStats.SERVICE_NAME));
            for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
                //创建JobServiceContext对象
                mActiveServices.add(
                        new JobServiceContext(this, mBatteryStats,
                                getContext().getMainLooper()));
            }
            ArraySet<JobStatus> jobs = mJobs.getJobs();
            for (int i=0; i<jobs.size(); i++) {
                JobStatus job = jobs.valueAt(i);
                for (int controller=0; controller<mControllers.size(); controller++) {
                    mControllers.get(controller).deviceIdleModeChanged(mDeviceIdleMode);
                    mControllers.get(controller).maybeStartTrackingJob(job);
                }
            }
            //[见小节3.8]
            mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
        }
    }
}

对于低内存的设备,则只创建一个创建JobServiceContext对象;否则创建3个该对象。

 

 

2.9.1 创建JobServiceContext

[-> JobServiceContext.java]

JobServiceContext(JobSchedulerService service, IBatteryStats batteryStats, Looper looper) {
    this(service.getContext(), batteryStats, service, looper);
}

JobServiceContext(Context context, IBatteryStats batteryStats,
        JobCompletedListener completedListener, Looper looper) {
    mContext = context;
    mBatteryStats = batteryStats;
    mCallbackHandler = new JobServiceHandler(looper);
    mCompletedListener = completedListener;
    mAvailable = true;
}

此处的JobServiceHandler采用的是system_server进程的主线程。

 

 

2.10 小结

  1. JSS.JobHandler运行在system_server进程的主线程;
  2. JobServiceContext.JobServiceHandler运行在system_server进程的主线程;
  3. JobSchedulerStub作为实现接口IJobScheduler的binder服务端;
  4. JobStore:其成员变量mIoHandler运行在”android.io”线程;
  5. JobStatus:从/data/system/job/jobs.xml文件中读取每个JobInfo,再解析成JobStatus对象,添加到mJobSet。

 

posted @ 2018-08-24 18:38  JavAndroidJSql  阅读(2857)  评论(0编辑  收藏  举报