从Android SystemServer开始

安卓的Framework层也就是zygote是从SystemServer开始的,所有重要的上层服务都集中在SystemServer这个进程中,这个进程的名字为app_process(64位为app_process64).这个进程的启动脚本示例如下:

init.zygote64.rc

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system
    socket usap_pool_primary stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    onrestart restart vendor.servicetracker-1-1
    writepid /dev/cpuset/foreground/tasks

可以看到,当我们这个进程被重启以后很多需要被依赖的本地进程需要被拉起来,这些restart的server都是以binder的服务端存在的本地服务,提供了例如音频camera等的基础服务功能,我们Framework只是作为客户端会去调用这些服务里的一些功能,然后framework再为上层应用提供接口,作为中间人统筹管理这些所有的硬件资源。

上面提到的app_process这个进程源码目录在frameworks/base/cmds/app_pro
cess它只是作为一个启动器的存在,只有一个源文件就是app_main.cpp它可以被编译成32以及64位的版本。

这里的main函数通过AppRuntime继承自AndroidRuntime来启动java的类。

if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    }
这里的zygote是通过参数来判断的,我们上面的rc文件中可以看到我们通过这个进程带的参数是

--zygote --start-system-server

启动systemserver是从这里开始的,当然这个进程也可以启动普通app,当后面启动应用的时候还需要这个进程来创建镜像。

具体的如何启动vm然后怎么加载的java类我们先不做探讨。

我们知道在启动zygote的时候是调用了ZygoteInit这个类来完成的,它同样有个main函数如下:

frameworks\base\core\java\com\android\internal\os\ZygoteInit.java

@UnsupportedAppUsage
    public static void main(String argv[]) {
        ZygoteServer zygoteServer = null;

。。。。。省略一部分

zygoteServer = new ZygoteServer(isPrimaryZygote);

if (startSystemServer) {
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);

// {@code r == null} in the parent (zygote) process, and {@code r != null} in the
                // child (system_server) process.
                if (r != null) {
                    r.run();
                    return;
                }
            }

这里可以看到通过forkSystemServer继续去创建

private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {

这个函数里有个参数列表比较重要

/* Hardcoded command line to start the system server */
        String args[] = {
                "--setuid=1000",
                "--setgid=1000",
                "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
                        + "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
                "--capabilities=" + capabilities + "," + capabilities,
                "--nice-name=system_server",
                "--runtime-args",
                "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
                "com.android.server.SystemServer",
        };

这里的setgroups限制了那些uid的访问权限。以及指定了我们的类com.android.server.SystemServer

然后通过Zygote这个类继续创建如下:

/* Request to fork the system server process */
            pid = Zygote.forkSystemServer(
                    parsedArgs.mUid, parsedArgs.mGid,
                    parsedArgs.mGids,
                    parsedArgs.mRuntimeFlags,
                    null,
                    parsedArgs.mPermittedCapabilities,
                    parsedArgs.mEffectiveCapabilities);

当我们第一次创建子进程成功的时候这个pid肯定返回的是0,到这我们的SystemServer就要被启动了,并被作为主进程存在。

frameworks\base\core\java\com\android\internal\os\Zygote.java

public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
            int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
        ZygoteHooks.preFork();
        // Resets nice priority for zygote process.
        resetNicePriority();
        int pid = nativeForkSystemServer(
                uid, gid, gids, runtimeFlags, rlimits,
                permittedCapabilities, effectiveCapabilities);
        // Enable tracing as soon as we enter the system_server.
        if (pid == 0) {
            Trace.setTracingEnabled(true, runtimeFlags);
        }
        ZygoteHooks.postForkCommon();
        return pid;
    }

这里的nativeForkSystemServer就到了c++的底层程序了属于linux的编程,很容易就可以创建子进程。

这样我们就可以继续分析SystemServer。

SystemServer可以开始了,去到它的main函数。

frameworks\base\services\java\com\android\server\SystemServer.java

/**
     * The main entry point from zygote.
     */
    public static void main(String[] args) {
        new SystemServer().run();
    }

这里也说了我们的main函数来自zygote,同时注意这里也定义了构造函数

public SystemServer() {
        // Check for factory test mode.
        mFactoryTestMode = FactoryTest.getMode();

/ Record process start information.
        // Note SYSPROP_START_COUNT will increment by *2* on a FDE device when it fully boots;
        // one for the password screen, second for the actual boot.
        mStartCount = SystemProperties.getInt(SYSPROP_START_COUNT, 0) + 1;
        mRuntimeStartElapsedTime = SystemClock.elapsedRealtime();
        mRuntimeStartUptime = SystemClock.uptimeMillis();

// Remember if it's runtime restart(when sys.boot_completed is already set) or reboot
        // We don't use "mStartCount > 1" here because it'll be wrong on a FDE device.
        // TODO: mRuntimeRestart will *not* be set to true if the proccess crashes before
        // sys.boot_completed is set. Fix it.
        mRuntimeRestart = "1".equals(SystemProperties.get("sys.boot_completed"));
    }
检查工厂模式,记录一些时间信息,判断是否为重启systemserver。

mian函数只调用了run函数

我们继续去看run都做了什么

函数有点长但是非常主要,所有的主要动作都在这里完成:

private void run() {
        try {

traceBeginAndSlog("InitBeforeStartServices");//开始记录事件及打印log

// Record the process start information in sys props.记录启动信息比如次数时间信息等
            SystemProperties.set(SYSPROP_START_COUNT, String.valueOf(mStartCount));
            SystemProperties.set(SYSPROP_START_ELAPSED, String.valueOf(mRuntimeStartElapsedTime));
            SystemProperties.set(SYSPROP_START_UPTIME, String.valueOf(mRuntimeStartUptime));

EventLog.writeEvent(EventLogTags.SYSTEM_SERVER_START,
                    mStartCount, mRuntimeStartUptime, mRuntimeStartElapsedTime);

//处理系统时间

// If a device's clock is before 1970 (before 0), a lot of
            // APIs crash dealing with negative numbers, notably
            // java.io.File#setLastModified, so instead we fake it and
            // hope that time from cell towers or NTP fixes it shortly.
            if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
                Slog.w(TAG, "System clock is before 1970; setting to 1970.");
                SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
            }

//处理时区
            // Default the timezone property to GMT if not set.
            //
            String timezoneProperty = SystemProperties.get("persist.sys.timezone");
            if (timezoneProperty == null || timezoneProperty.isEmpty()) {
                Slog.w(TAG, "Timezone not set; setting to GMT.");
                SystemProperties.set("persist.sys.timezone", "GMT");
            }

//处理系统语言

// If the system has "persist.sys.language" and friends set, replace them with
            // "persist.sys.locale". Note that the default locale at this point is calculated
            // using the "-Duser.locale" command line flag. That flag is usually populated by
            // AndroidRuntime using the same set of system properties, but only the system_server
            // and system apps are allowed to set them.
            //
            // NOTE: Most changes made here will need an equivalent change to
            // core/jni/AndroidRuntime.cpp
            if (!SystemProperties.get("persist.sys.language").isEmpty()) {
                final String languageTag = Locale.getDefault().toLanguageTag();

SystemProperties.set("persist.sys.locale", languageTag);
                SystemProperties.set("persist.sys.language", "");
                SystemProperties.set("persist.sys.country", "");
                SystemProperties.set("persist.sys.localevar", "");
            }

// The system server should never make non-oneway calls系统服务为了响应速度需要为异步非阻塞形式
            Binder.setWarnOnBlocking(true);
            // The system server should always load safe labels
            PackageItemInfo.forceSafeLabels();

// Default to FULL within the system server.
            SQLiteGlobal.sDefaultSyncMode = SQLiteGlobal.SYNC_MODE_FULL;

// Deactivate SQLiteCompatibilityWalFlags until settings provider is initialized
            SQLiteCompatibilityWalFlags.init(null);

// Here we go!检查这个log开始
            Slog.i(TAG, "Entered the Android system server!");
            int uptimeMillis = (int) SystemClock.elapsedRealtime();
            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, uptimeMillis);
            if (!mRuntimeRestart) {
                MetricsLogger.histogram(null, "boot_system_server_init", uptimeMillis);
            }

// In case the runtime switched since last boot (such as when
            // the old runtime was removed in an OTA), set the system
            // property so that it is in sync. We can | xq oqi't do this in
            // libnativehelper's JniInvocation::Init code where we already
            // had to fallback to a different runtime because it is
            // running as root and we need to be the system user to set
            // the property. http://b/11463182
            SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());

// Mmmmmm... more memory!
            VMRuntime.getRuntime().clearGrowthLimit();

// The system server has to run all of the time, so it needs to be
            // as efficient as possible with its memory usage.
            VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);

// Some devices rely on runtime fingerprint generation, so make sure
            // we've defined it before booting further.
            Build.ensureFingerprintProperty();

// Within the system server, it is an error to access Environment paths without
            // explicitly specifying a user.
            Environment.setUserRequired(true);

// Within the system server, any incoming Bundles should be defused
            // to avoid throwing BadParcelableException.
            BaseBundle.setShouldDefuse(true);

// Within the system server, when parceling exceptions, include the stack trace
            Parcel.setStackTraceParceling(true);

// Ensure binder calls into the system always run at foreground priority.
            BinderInternal.disableBackgroundScheduling(true);

// Increase the number of binder threads in system_server
            BinderInternal.setMaxThreads(sMaxBinderThreads);

// Prepare the main looper thread (this thread).准备主线程循环
            android.os.Process.setThreadPriority(
                    android.os.Process.THREAD_PRIORITY_FOREGROUND);
            android.os.Process.setCanSelfBackground(false);
            Looper.prepareMainLooper();
            Looper.getMainLooper().setSlowLogThresholdMs(
                    SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);

// Initialize native services.加载本地服务库
            System.loadLibrary("android_servers");

// Debug builds - allow heap profiling.
            if (Build.IS_DEBUGGABLE) {
                initZygoteChildHeapProfiling();
            }

// Check whether we failed to shut down last time we tried.
            // This call may not return.
            performPendingShutdown();

// Initialize the system context.创建系统上下文,为system相关服务使用
            createSystemContext();

// Create the system service manager.创建系统服务管理器后面所有的系统服务都是由他管理
            mSystemServiceManager = new SystemServiceManager(mSystemContext);
            mSystemServiceManager.setStartInfo(mRuntimeRestart,
                    mRuntimeStartElapsedTime, mRuntimeStartUptime);
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
            // Prepare the thread pool for init tasks that can be parallelized
            SystemServerInitThreadPool.get();
        } finally {
            traceEnd();  // InitBeforeStartServices
        }

// Start services.启动各种系统服务,由最重要到次重要
        try {
            traceBeginAndSlog("StartServices");
            startBootstrapServices();
            startCoreServices();
            startOtherServices();
            SystemServerInitThreadPool.shutdown();
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        } finally {
            traceEnd();
        }

StrictMode.initVmDefaults(null);

if (!mRuntimeRestart && !isFirstBootOrUpgrade()) {
            int uptimeMillis = (int) SystemClock.elapsedRealtime();
            MetricsLogger.histogram(null, "boot_system_server_ready", uptimeMillis);
            final int MAX_UPTIME_MILLIS = 60 * 1000;
            if (uptimeMillis > MAX_UPTIME_MILLIS) {
                Slog.wtf(SYSTEM_SERVER_TIMING_TAG,
                        "SystemServer init took too long. uptimeMillis=" + uptimeMillis);
            }
        }

// Diagnostic to ensure that the system is in a base healthy state. Done here as a common
        // non-zygote process.
        if (!VMRuntime.hasBootImageSpaces()) {
            Slog.wtf(TAG, "Runtime is not running with a boot image!");
        }

// Loop forever.开始消息循环队列等待处理系统消息,不允许退出系统服务的朱looper
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

到这里SystemServer就跑完了基本的系统服务也基本开机结束了。

做个简单的总结:

我们在内核启动后使用init启动了zygote,zygote是通过app_process这个bin执行文件实现的,这个进程只有一个main文件以及main函数,这个函数接收启动的参数,选择性启动zygote。这个进程调用了AndroidRuntime的库,继而可以使用java的虚拟环境,通过类名找到com.android.internal.os.RuntimeInit然后启动它,RuntimeInit的main函数会判断是否是启动系统服务(SystemServer),如果是则使用forkSystemServer函数去创建系统服务的子进程,在创建子进程之前添加了uid组管理等策略,并且将这些策略以及我们即将启动的系统服务类 "com.android.server.SystemServer"(SystemServer)等作为参数继续传递给com.android.internal.os.Zygote然后又调用了Zygote的 pid = Zygote.forkSystemServer函数继续去创建子进程。接下来通过本地服务去启动我们的SystemServer,然后就又开始了SystemServer的main以及run函数。具体本地如何fork子进程后续再探究。

然后我们继续细化SystemServer的服务启动流程。

Android源码阅读记录相关推荐

  1. Android源码阅读---init进程

    Android源码阅读-init进程 文章目录 Android源码阅读---init进程 1. 编译命令和进程入口 1. init 进程编译命令 2. main函数流程 2. 主函数处理流程 1. 创 ...

  2. Android源码阅读平台

    Android源码阅读平台 前言 链接 前言 ​ 记录Android源码阅读平台 链接 AndroidXRef:http://androidxref.com/ AndroidXRef-ng:https ...

  3. r8169驱动源码阅读记录

    r8169驱动源码阅读记录 初始化 发包 收包 源码地址:linux-4.19.90\drivers\net\ethernet\realtek\r8169.c 源码阅读环境:Windows 搭建 op ...

  4. android源码阅读笔记1-配置源码路径/阅读源码方法讨论

    开始之前 android studio中配置android源码路径 android studio中有源码的路径,你只需要打开SDK Manager下载源码然后重启android studio即可查看源 ...

  5. Android源码阅读工具AndroidXRef使用说明

    (62条消息) AndroidXRef使用说明_n_fly的博客-CSDN博客 http://www.aospxref.com AndroidXRef (81条消息) 官方版Android源码查看工具 ...

  6. Windows 10 下安装Ubuntu子系统 编译Android源码问题记录

    一.Ubuntu子系统安装 1.启用WSL Windows Subsystem for Linux(简称WSL)是一个在Windows 10\11上能够运行原生Linux二进制可执行文件(ELF格式) ...

  7. Android源码阅读-编译8

    Android8.0源码的下载就比较蛋疼了,因为我们只有通过VPN才能访问Google的一些东西,对于源码这东西,动不动几十个G的话,通过VPN来下载的话,肯定懵逼啊,所以我们得另辟途径.[清华大学开 ...

  8. Android源码阅读方法

    很多读者,尤其是初学者特别抗拒去看源码,这里我说明一下为什么要进行源码分析.其中包括下面一些好处: 学习Android源码有助于我们学习其中的设计模式.思想.架构. 熟悉整个源码的架构,有助于我们更加 ...

  9. Tomcat 源码阅读记录(1)

    使用Ant 工具进行编译打包. 源码对应关系: SourceCode TargetPackage /bin /bin /conf /conf /java /lib/* /Modules 依赖包 /re ...

  10. GUN Global + Vim及其插件 打造Android源码阅读器

    2019独角兽企业重金招聘Python工程师标准>>> 第一步安装GUN Global 建议使用源码安装,下载地址:http://tamacom.com/global/global- ...

最新文章

  1. 计算机仿真和vr的区别,AR对比VR有何不同?你能分清楚他们的区别么
  2. (八)数据结构之“树”
  3. linux数据库实例开机启动,linux下数据库实例开机自启动设置
  4. Nginx何防止流量攻击
  5. 173. Insertion Sort List【LintCode by java】
  6. rehat 出现GDB debuginfo-install 问题处理
  7. sqldeveloper 工具的使用——连接数据库的介绍
  8. layui表单验证,表单提交的若干个方法
  9. Promise、then()、catch()详解
  10. 服装吊牌如何在条码打印软件中制作?
  11. 将谷歌网盘的文件搬运到百度网盘
  12. 从「雄狮」到「瑶光」,奇瑞历史突破背后的十字路口
  13. python如何将字典数据存入excel
  14. Android调整Bitmap图片大小
  15. 数据处理(一)数据清洗
  16. 矩阵理论——直和与投影
  17. uniapp小程序获取手机号、获取用户信息
  18. Cocos creator 学习笔记(2)
  19. linux开源视频播放器_8个适用于Linux的开源音乐播放器
  20. python微博文本分析_微博评论挖掘之Bert实战应用案例-文本情感分类

热门文章

  1. 两篇关于区块链的最新综述论文被 IEEE ACCESS 接收
  2. 联想 计算机无线网络设置方法,联想g400如何打开无线_联想G400s笔记本电脑无线开关在哪-win7之家...
  3. Unreal Engine 4 问题:如何设置分辨率
  4. 如何获取excel 中的 某几个列的值
  5. 添加滑条进行图像叠加
  6. linux 6.7 远程端口,CentOS6.7安装vncserver及xrdp实现远程桌面
  7. python 拟合对数正态分布
  8. python对数正态分布函数_将对数正态分布的拟合PDF缩放到python中的histrogram
  9. android 拼音字母语音,拼音发音点读app
  10. Light OJ 1138