• 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。
  • 相关阅读:
    实战:第十六章:判断Mysql库中是否存在某表
    Tomcat:第五章:Tomcat 部署脚本编写
    MySQL数据库:第十七章:Explain详解
    实战:第十五章:摸爬滚打这些年的心路历程
    Tomcat:第三章:Tomcat各组件
    聊一聊保持登录状态的几种方法
    使用restassured框架优雅实现接口测试断言
    自动化脚本无法处理验证码?Python图片识别库Tesseract实战
    2022年了,你还不会HttpRunner吗?
    java设计模式之组合模式
  • 原文地址:https://www.cnblogs.com/softwarelanguagebs/p/9531562.html
Copyright © 2020-2023  润新知