目录

Android-SystemServer-系列专题篇四SystemServerInitThreadPool线程池管理

Android SystemServer 系列专题【篇四:SystemServerInitThreadPool线程池管理】

本篇重点介绍一下SystemServerInitThreadPool,顾名思义此类针对SystemServer进程的提供了一套ThreadPool线程池的统一标准方案,下面从源码和日志的角度来剖析一个这个类。

1、SystemServerInitThreadPool单例设计

SystemServerInitThreadPool的源码路径在frameworks/base/services/core/java/com/android/server,如下代码其构造方法被定义为private,且存在静态类sInstance,这是一种典型的单例设计模式。

那么为什么这里采用了单例的设计模式呢?从后文可以看出来SystemServer的各个子服务都会通过这个类来执行耗时任务,因此单例设计是最优选,并且对sInstance进行了加锁保证线程安全。

https://i-blog.csdnimg.cn/direct/40dc5d80873e4c14b696bdf5cd07589e.png

2、SystemServerInitThreadPool何时启动?

第一节介绍了构造方法被private修饰,那么何时被构造何时被启动呢?

接下来继续看看start方法,该方法被定义为static方法,方法内通过LOCK去进行实例化,因此是一个典型的单例模式。

https://i-blog.csdnimg.cn/direct/e6bcfa640d05441b91bb792c4a955f69.png

那么何时调用start方法呢?如下代码在SystemServer进程的主流程中,并且放到了startxxx之前,为什么要放在这里呢?因为后续的三部曲都需要使用该类去执行一些子线程的任务。

https://i-blog.csdnimg.cn/direct/38d6e51b8c9b4e62b52e9f10d368afcb.png

我们来看一下SystemServerInitThreadPool启动日志:可以看出来线程池的长度为8

https://i-blog.csdnimg.cn/direct/1553dbeaf0b24a41a5cabf1db2782e3b.png

https://i-blog.csdnimg.cn/direct/55ce7c5c0d9f4de0a25b738e085239e2.png

3、SystemServerInitThreadPool任务执行

继续看一下submit方法,改方法为静态方法,供其他XXXService进行调用,最后移交给submitTask方法来创建启动线程池。这里的mService就是构造方法中通过mSize创建的线程池。

https://i-blog.csdnimg.cn/direct/a7e4364f47e342aaa3e5f20de4288c04.png

接下来看看在开机过程中,有哪些服务在调用这个方法创建子任务呢?

https://i-blog.csdnimg.cn/direct/bb1c676ede764d359e40a4e69e4e4821.png

下面举几个submit的示例:

1)ReadingSystemConfig

https://i-blog.csdnimg.cn/direct/b41d0634b4be4cfea115452996154408.png

这里很奇怪的是第一个参数应该是Runnable接口,第二个参数是字符串用来进行描述,但是这里的第一个参数直接返回了SystemConfig的实例,且该类没有找到实现Runnable接口的地方?


//frameworks/base/core/java/com/android/server/SystemConfig.java 
public class SystemConfig {
    static final String TAG = "SystemConfig";
    static SystemConfig sInstance;
    public static SystemConfig getInstance() {
        if (!isSystemProcess()) {
            Slog.wtf(TAG, "SystemConfig is being accessed by a process other than " + "system_server.");
        }
        synchronized (SystemConfig.class) {
            if (sInstance == null) {
                sInstance = new SystemConfig();
            }
            return sInstance;
        }
    }
    SystemConfig() {
        TimingsTraceLog log = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
        log.traceBegin("readAllPermissions");
        TDSystemConfig.getInstance();// TINNO modified by guobing.xiong 20230208 LIBRA-400
        try {
            readAllPermissions();
            readPublicNativeLibrariesList();
        } finally {
            log.traceEnd();
        }
    }
    //....
}

这个案例直接传递了SystemConfig单例对象进去,此单例对象在构造函数中去做readAllPermissions文件处理,这是一个耗时任务,因此使用了子线程的方式。

2)prepareAppData

https://i-blog.csdnimg.cn/direct/f3ce7d91eb94465dbcc49274f0f369d6.png

如上代码这里也没有传递一个Runnable接口,而是直接传递一个代码块,其中代码块用{}包裹,第二个参数传递prepareAppData,即任务描述,即第一个参数的代码块将在子线程中执行。

3)StartNativeSensorService

https://i-blog.csdnimg.cn/direct/fa571a615aa54ac79f2c91883c10df3e.png

如上代码,启动native进程的服务,也通过了子线程的方式进行了启动,第二个参数直接把服务名传递了进去。

4、SystemServerInitThreadPool任务停止

https://i-blog.csdnimg.cn/direct/c8c5764494cb4f4a811f4eba9d2e9507.png

如上日志表示SystemServerInitThreadPool调用shutdown进行终止所有线程池,我们来看看这段代码逻辑:

https://i-blog.csdnimg.cn/direct/6bbc451be9b14310b64efb7b14a75dc3.png

由此可见在开机完成之后,会主动调用SystemServerInitThreadPool.shutdown方法用来停止线程池中的所有任务,从上面的日志可以看出来,这些任务并不是直接暴力停止的,而是等待他们自己执行完成,具体实现如下:

https://i-blog.csdnimg.cn/direct/cc552648fa624f04b47cf144e500802b.png

PS:注意此段日志表示开机完成,非系统请求关机的日志