深入Android S(12.0) 探索 Android Framework 之 SystemServer 进程启动详解

深入学习 Android Framework

第三:深入Android S(12.0) 探索 Android Framework 之 SystemServer 进程启动详解


文章目录

  • 深入学习 Android Framework
  • 前言
  • 一、Android 系统的启动流程
    • 1. 流程图
    • 2. 启动流程概述
  • 二、源码详解
    • 1. 时序图
    • 2. 源代码
      • 1、ZygoteInit # main()
      • 2、ZygoteInit # forkSystemServer()
        • 2.1、Zygote # forkSystemServer()
          • 2.1.1、Zygote # nativeForkSystemServer()
          • 2.1.2、Zygote # ForkCommon()
          • 2.1.3、Zygote # SpecializeCommon()
        • 2.2、ZygoteInit # handleSystemServerProcess()
        • 2.3 ZygoteInit # zygoteInit()
          • 2.3.1 ZygoteInit # nativeZygoteInit()
          • 2.3.2 app_main # main()
          • 2.3.3 RuntimeInit # applicationInit()
          • 2.3.4 RuntimeInit # findStaticMain()
          • 2.3.5 MethodAndArgsCaller # run()
      • 3 SystemServer # main()
        • 3.1 SystemServer # performPendingShutdown()
        • 3.2 SystemServer # createSystemContext()
        • 3.3 SystemServiceManager
        • 3.4 SystemServer # startBootstrapServices()
        • 3.5 SystemServer # startCoreServices()
        • 3.5 SystemServer # startOtherServices()
  • 三、SystemServer 启动的服务及其作用
    • 1、引导服务
    • 2、核心服务
    • 3、其他服务
  • 总结


前言

Zygote 的纸面意思 “受精卵”,由他孵化出 Android 系统的其他进程。SystemServer 和其他所有 Dalivik 虚拟机进程都是由 Zygote 经过 fork 复制而来。SystemServer 作为 Zygote 进程 fork 出的第一个进程,其进程名为:system_server。其承载着整个 Framework 的核心服务,如创建并启动 ActivityManagerService、PowerManagerService、DisplayManagerService、PackageManagerService、WindowManagerService、LauncherAppsService、InputManagerService 等 90 多个核心系统服务。接下来一起深入学习一下 SystemServer 进程的创建与启动流程。


一、Android 系统的启动流程

1. 流程图

Android系统启动流程图

2. 启动流程概述

结合上面的流程图,先概述一下 Android 系统的总体启动流程:

  1. Android 系统按下电源键开机时,系统的引导芯片代码将从预定义的地方 ( 在ROM ) 开始执行,并去加载引导程序 BootLoaderRAM 中,然后执行 BootLoader
  2. 引导程序是 Android 系统被拉起来之前的一个程序,其作用是把 Android 系统拉起运行,也就是把 Linux 内核启动起来。
  3. 当 Linux 内核启动后会初始化各种软硬件环境、加载驱动程序、挂载根文件系统等,待到加载工作准备完毕后,开始加载一些特定的程序(进程),第一个加载的是 init 进程init 进程Linux 系统中用户空间的第一个进程,进程号固定位 1
  4. 内核启动后,在用户空间启动 init 进程,并调用 init 的 main() 方法。其作用有:创建目录、挂载分区;解析 init.rc 配置文件;启动解析 init.rc 配置文件获取到的服务(如:Zygote进程ServiceManager等);守护解析后启动的服务;
  5. 创建启动 Zygote 进程,首先会创建一个 Java 虚拟机实例,然后注册所有 Framework 相关的系统 JNI 接口,为 Java 世界做好准备。通过 JNI 调用进入 Java 世界,并调用 ZygoteInit.main() 方法,给 Zygote 注册 Socket 用于进程间通信,同时预加载一些常用的 Java 类库和系统资源(如:system/etc/preloaded-c]asses 文件中的类、drawable和 color 资源、opengl 等),执行 gc() 清理内存,为 fork 子进程做好准备。然后 fork 出子进程,并在子进程中初始化 SystemServer 进程,初始化的过程中启动 Android 系统所有的 Service 服务(其中包括输入系统服务 IMS);
  6. Zygote 进程启动后,在后台持续监听 Socket 等待新的应用启动请求,并且监听 SystemServer 的 SIGHID 信号,如果 SystemServer 挂掉,立即 kill 掉 Zygote 自己,然后 init 会重启 Zygote,再启动 SystemServer,使系统恢复正常(如果不能重新起来,将会导致手机重启)。
  7. ActivityManagerService 以后简称 AMS 执行 startService() 启动服务,并调用其 systemReady() 方法后,寻找系统的 “Startup” Application,并向 Zygote 发送请求,Zygote fork 出 “Startup” Application,也就是启动 Launcher 应用,然后将已经安装的应用程序图标显示到桌面上,完成 Android 系统启动。

二、源码详解

接下来,就让我们深入 Android 系统源码,通过源码来详细的分析学习 SystemServer 的启动流程。首先看一下 SystemServer 进程启动的时序图,即先总览全局,再深入细节,便于理解代码。

1. 时序图

Zygote 启动 SystemServer 时序图

2. 源代码

在分析 Zygote 进程启动流程中可知, system_server 进程是在 ZygoteInit # main() 函数进入循环等待之前启动的,进入代码一探究竟

1、ZygoteInit # main()

xref: /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

public class ZygoteInit {
	......
	@UnsupportedAppUsage
    public static void main(String[] argv) {
        ZygoteServer zygoteServer = null;
        ......
        Runnable caller;
        try {
            ...... // 解析传入参数
            zygoteServer = new ZygoteServer(isPrimaryZygote);
            if (startSystemServer) {
            	// fork 出 system_server 进程
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
                // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
                // child (system_server) process.
                // 如果返回值 r 为空则是在父进程,即 Zygote 进程,如果 r 不为空则是在子进程,即 system_server 进程
                if (r != null) {
                    r.run(); // 启动 SystemServer,调用 SystemServer # main() 方法,即入口函数
                    return; // 在Android 8.0之前是通过抛异常的方式来启动,这里是直接return出去,用来清空栈,提高栈帧利用率
                }
            }
            ......
            // 开启 loop 循环,在后台持续监听 client socket 发来的消息,等待新的应用启动请求
            caller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with fatal exception", ex);
            throw ex;
        } finally {
            if (zygoteServer != null) {
                zygoteServer.closeServerSocket();
            }
        }
        // 若fork出系统进程,则加入到列表,然后继续阻塞等待;若 fork 出子进程,则退出loop循环,返回创建的应用子进程,并执行子进程的启动。
        if (caller != null) {
            caller.run();
        }
    }
    ......
}

首先解析传入参数,新建 ZygoteServer 实例对象,然后调用 ZygoteInit # forkSystemServer() 方法来 fork 出 system_server 进程,如果返回值 Runnable r 不为空则是在子进程,即通过 fork 复制出的 system_server 进程,随后调用 Runnable # run() 方法启动 SystemServer,调用 SystemServer # main() 方法,即入口函数。之后开启 Loop 循环,在后台持续监听 client socket 发来的消息,等待新的应用启动请求,如果 fork 出系统进程,则加入到列表,然后继续阻塞等待;如果 fork 出子进程,则退出 Loop 循环,返回创建的应用子进程,并执行子进程的启动。继续跟进源码去查看一下

2、ZygoteInit # forkSystemServer()

xref: /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

public class ZygoteInit {
	......
    // 准备参数,然后 fork 出 system_server 进程
    // 返回一个 Runnable 并提供进入子进程 system_server 的入口点,如果返回空则是在父进程,即 Zygote 进程
	private static Runnable forkSystemServer(String abiList, String socketName,
                                             ZygoteServer zygoteServer) {
        ......
        // 创建 args 数组,保存 system_server 启动的参数,uid 和 gid 都为 1000
        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,3011", // 拥有的用户组权限
                "--capabilities=" + capabilities + "," + capabilities,
                "--nice-name=system_server", // 进程名为 system_server
                "--runtime-args",
                "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
                "com.android.server.SystemServer", // 启动的类名为:com.android.server.SystemServer
        };
        ZygoteArguments parsedArgs = null;
        int pid;
        try { // 按 ZygoteArguments 的格式解析封装上面保存的参数
            parsedArgs = new ZygoteArguments(args);
            Zygote.applyDebuggerSystemProperty(parsedArgs);
            Zygote.applyInvokeWithSystemProperty(parsedArgs);
            ......
            // fork 出系统服务进程 system_server
            pid = Zygote.forkSystemServer(
                    parsedArgs.mUid, parsedArgs.mGid,
                    parsedArgs.mGids,
                    parsedArgs.mRuntimeFlags,
                    null,
                    parsedArgs.mPermittedCapabilities,
                    parsedArgs.mEffectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }
        if (pid == 0) { // 进入子进程 system_server 进程
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName); // 需等待第二个 Zygote 创建完成
            }
            zygoteServer.closeServerSocket(); // fork 时会copy socket,Zygote 原有的 socket 需要关闭
            return handleSystemServerProcess(parsedArgs); // system_server 进程处理自己的工作
        }
        return null;
    }
    ......
}

ZygoteInit # forkSystemServer() 方法主要执行了以下几个任务:

  1. 创建 args 数组,保存 system_server 启动的参数,然后调用 Zygote # forkSystemServer()方法 fork 出 system_server 进程。
  2. 如果系统初始化了 SecondaryZygote,则需等待第二个 zygote 创建完成。
  3. 由于 fork 的过程会拷贝 socket,因此在 fork 出 system_server 进程后,需要关闭从 zygote 进程复制过来的 socket 连接。
  4. 最后调用 ZygoteInit # handleSystemServerProcess() 方法处理 system_server 进程的初始化过程。
2.1、Zygote # forkSystemServer()

xref: /frameworks/base/core/java/com/android/internal/os/Zygote.java

public class Zygote {
	......
	static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
                                int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
        ZygoteHooks.preFork();
        // 调用 native 层的方法来fork system_server 进程
        int pid = nativeForkSystemServer(
                uid, gid, gids, runtimeFlags, rlimits,
                permittedCapabilities, effectiveCapabilities);
        // 当前线程的优先级设置为新应用程序的默认值
        Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
        ZygoteHooks.postForkCommon();
        return pid;
    }
    
     private static native int nativeForkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
             int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);
    ......
}

调用 native 层方法 nativeForkSystemServer() 来 fork 出 system_server 进程,最终通过 JNI 调用到 native 层的:com_android_internal_os_Zygote_nativeForkSystemServer() 方法,该方法在 com_android_internal_os_Zygote.cpp 文件中,继续跟踪源码查看

2.1.1、Zygote # nativeForkSystemServer()

xref: /frameworks/base/core/jni/com_android_internal_os_Zygote.cpp

    static const JNINativeMethod gMethods[] = { // JIN 注册的映射关系
            ......
            {"nativeForkSystemServer", "(II[II[[IJJ)I", 
             (void*)com_android_internal_os_Zygote_nativeForkSystemServer},
            ......
    };
    ......
	static jint com_android_internal_os_Zygote_nativeForkSystemServer(
            JNIEnv*env, jclass, uid_t uid, gid_t gid, jintArray gids,
            jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities,
            jlong effective_capabilities) {
		......
		// 继续通过 ForkCommon 方法来进行 fork
        pid_t pid = zygote::ForkCommon (env, true,
                fds_to_close,
                fds_to_ignore,
                true);
        if (pid == 0) {
            // 进入子进程,由于 system_server 进程不需要数据隔离,所以不需要知道 pkg_data_info_list,因此传 nullptr
            SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, permitted_capabilities,
                    effective_capabilities, MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true,
                    false, nullptr, nullptr, /* is_top_app= */ false,
                    /* pkg_data_info_list */ nullptr,
                    /* allowlisted_data_info_list */ nullptr, false, false);
        } else if (pid > 0) { // 继续进入父进程,即 Zygote 进程
            // Zygote 进程检查子进程是否已经死亡
            ALOGI("System server process %d has been created", pid); // system_server 进程已创建
            gSystemServerPid = pid;	// 将子进程 system_server 的 pid 存在 Zygote 进程的全局变量中
            // 有轻微的窗口提示表明系统服务进程已经挂掉,但因为还未发布该进程的 pid,因此没有注意到,所以在这里重新检查以确保其正常
            int status;
            // 函数使用详解见下面的引用介绍,通过 waitpid 函数获取状态发生变化的子进程 pid,设置 options 标志为 WNOHANG,即非阻塞
            // 如果 pid 指定的子进程没有结束,则立即返回 0,而非阻塞等待;如果结束了,则返回该子进程的进程号,即 pid
            if (waitpid(pid, & status,WNOHANG) ==pid){
            	// 当 system_server 进程死亡后,重启 Zygote 进程
                ALOGE("System server process %d has died. Restarting Zygote!", pid);
                RuntimeAbort(env, __LINE__, "System server process has died. Restarting Zygote!");
            }
			......
        }
        return pid;
    }
    ......

方法中继续调用 Zygote :: ForkCommon() 方法来 fork 出 system_server 进程,同时根据 Zygote :: ForkCommon() 方法返回的进程 pid 进行判断,如果 pid > 0 则继续进入父进程,即 Zygote 进程;如果 pid = 0 表示 system_server 子进程创建成功,进入 system_server 进程,继续调用 SpecializeCommon() 方法。

2.1.2、Zygote # ForkCommon()

xref: /frameworks/base/core/jni/com_android_internal_os_Zygote.cpp

	pid_t zygote::ForkCommon(JNIEnv*env, bool is_system_server,
                            const std::vector<int>&fds_to_close,
                            const std::vector<int>&fds_to_ignore,
                            bool is_priority_fork,
                            bool purge) {
		// 注册子进程信号监听器 SigChldHandler,监听子进程的死亡,当子进程死亡后,会产生一个信号,Zygote 进程收到
		// 该信号后就会调用 SigChldHandler() 函数进行处理
        SetSignalHandlers();
		......
		// 通过 Linux 的 fork() 系统调用创建一个新的进程,即创建当前进程的一个副本,使得两个进程在执行相同的代码
		// 但是在不同的内存空间中运行
        pid_t pid = fork();
        if (pid == 0) {	// 子进程,这里指 system_server 进程
            if (is_priority_fork) { // 根据条件设置进程优先级
                setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX);
            } else {
                setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MIN);
            }
            // 预先设置进程的一些属性,如设置 M_SET_ZYGOTE_CHILD 表示自己不是 Zygote 进程 等
            PreApplicationInit();
            // 关闭并清除文件描述符
	        DetachDescriptors(env, fds_to_close, fail_fn);
            ......
        } else {
            ALOGD("Forked child process %d", pid);
        }
		......
        return pid;
    }

分析代码可知,首先通过 SetSignalHandlers() 方法注册子进程信号监听器 SigChldHandler,用来监听子进程的死亡,当子进程死亡后,会产生一个信号,Zygote 进程收到该信号后就会调用 SigChldHandler() 方法进行处理。需要注意的是:Zygote 的信号监听器,关注的是 Zygote fork 出的所有的子进程,而不只是 system_server 进程(每次创建一个新的进程时,Zygote 都会注册对应的监听器)。

然后通过 Linux 的 fork() 系统调用创建一个新的进程,即创建当前进程的一个副本,使得两个进程在执行相同的代码,但是在不同的内存空间中运行。其中的拷贝复制过程,这里不再详述,感兴趣的童鞋可以去查一些 Linux 相关的资料。

2.1.3、Zygote # SpecializeCommon()

xref: /frameworks/base/core/jni/com_android_internal_os_Zygote.cpp

	static void SpecializeCommon(JNIEnv*env, uid_t uid, gid_t gid, jintArray gids, jint runtime_flags,
                                 jobjectArray rlimits, jlong permitted_capabilities,
                                 jlong effective_capabilities, jint mount_external,
                                 jstring managed_se_info, jstring managed_nice_name,
                                 bool is_system_server, bool is_child_zygote,
                                 jstring managed_instruction_set, jstring managed_app_data_dir,
                                 bool is_top_app, jobjectArray pkg_data_info_list,
                                 jobjectArray allowlisted_data_info_list, bool mount_data_dirs,
                                 bool mount_storage_dirs) {
        const char*process_name = is_system_server ? "system_server" : "zygote"; // 进程名
		......
        if (!is_system_server && getuid() == 0) {
        	// 对于非 system_server 子进程,则需创建进程组 group
            const int rc = createProcessGroup(uid, getpid());
            if (rc == -EROFS) {
                ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?");
            } else if (rc != 0) {
                ALOGE("createProcessGroup(%d, %d) failed: %s", uid, /* pid= */ 0, strerror(-rc));
            }
        }
        SetGids(env, gids, is_child_zygote, fail_fn); // 设置进程 group
        SetRLimits(env, rlimits, fail_fn);	// 设置资源 limit

        if (need_pre_initialize_native_bridge) {
            android::PreInitializeNativeBridge (app_data_dir.has_value() ? app_data_dir.value().c_str()
                    : nullptr,
                    instruction_set.value().c_str());
        }

        if (is_system_server) {
            // 如果是 system_server 则预加载 system_server 的类加载器,并绑定 system_server selinux 域
            env -> CallStaticObjectMethod(gZygoteInitClass, gGetOrCreateSystemServerClassLoader);
            if (env -> ExceptionCheck()) {
                env -> ExceptionClear();
            }
        }
		......
        const char*se_info_ptr = se_info.has_value() ? se_info.value().c_str() : nullptr;
        const char*nice_name_ptr = nice_name.has_value() ? nice_name.value().c_str() : nullptr;
		// selinux 上线文环境 context
        if (selinux_android_setcontext(uid, is_system_server, se_info_ptr, nice_name_ptr) == -1) {
            fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
                    is_system_server, se_info_ptr, nice_name_ptr));
        }
        // 设置线程名为: system_server,方便调试
        if (nice_name.has_value()) {
            SetThreadName(nice_name.value());
        } else if (is_system_server) {
            SetThreadName("system_server");
        }
		......
        if (is_system_server) {
        	// 调用对应 Zygote.java 的 callPostForkSystemServerHooks() 方法
            env -> CallStaticVoidMethod(gZygoteClass, gCallPostForkSystemServerHooks, runtime_flags);
            if (env -> ExceptionCheck()) {
                fail_fn("Error calling post fork system server hooks.");
            }
            // TODO(b/117874058): Remove hardcoded label here.
            static const char*kSystemServerLabel = "u:r:system_server:s0";
            if (selinux_android_setcon(kSystemServerLabel) != 0) {
                fail_fn(CREATE_ERROR("selinux_android_setcon(%s)", kSystemServerLabel));
            }
        }
		......
        env -> CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags,
                is_system_server, is_child_zygote, managed_instruction_set);
        // 进程优先级设置为默认值
        setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_DEFAULT);
        ......
    }
    ......

对新创建的 system_server 进程进行配置,如进程名、进程 group 、资源 limit、预加载 system_server 的类加载器,并绑定 system_server selinux 域,最后设置进程优先级为默认值。

2.2、ZygoteInit # handleSystemServerProcess()

xref: /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

public class ZygoteInit {
	......
    private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {
        Os.umask(S_IRWXG | S_IRWXO); // 为用户文件创建权限掩码
        if (parsedArgs.mNiceName != null) {
            Process.setArgV0(parsedArgs.mNiceName); // 设置进程名为 system_server
        }
        // 加载指定路径下的 SystemServer 文件
        final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
        if (systemServerClasspath != null) {
        	// 路径不为空则加载执行 dex 优化操作,其内部工作是通过 AIDL 通信将命令参数传给 Installd 来完成的
            performSystemServerDexOpt(systemServerClasspath); 
            // Capturing profiles is only supported for debug or eng builds since selinux normally prevents it.
            if (shouldProfileSystemServer() && (Build.IS_USERDEBUG || Build.IS_ENG)) {
                try {
                    Log.d(TAG, "Preparing system server profile");
                    prepareSystemServerProfile(systemServerClasspath); // 加载 SystemServer 属性配置文件
                } catch (Exception e) {
                    Log.wtf(TAG, "Failed to set up system server profile", e);
                }
            }
        }

        if (parsedArgs.mInvokeWith != null) {
            String[] args = parsedArgs.mRemainingArgs;
            // 如果 SystemServer 类路径不为空,则需将其拼接到前面封装的 ZygoteArguments 的后面
            if (systemServerClasspath != null) { 
                String[] amendedArgs = new String[args.length + 2];
                amendedArgs[0] = "-cp";
                amendedArgs[1] = systemServerClasspath;
                System.arraycopy(args, 0, amendedArgs, 2, args.length);
                args = amendedArgs;
            }
			// 调用 WrapperInit # execApplication 方法使用包装器命令启动并执行运行时应用程序进程
            WrapperInit.execApplication(parsedArgs.mInvokeWith,
                    parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
                    VMRuntime.getCurrentInstructionSet(), null, args);
            throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");
        } else {
        	// 构建获取 SystemServer 类加载器,并设置给当前的线程
            ClassLoader cl = getOrCreateSystemServerClassLoader();
            if (cl != null) {
                Thread.currentThread().setContextClassLoader(cl);
            }
            // 将剩余参数交给 ZygoteInit.zygoteInit() 方法完成 SystemServer 进程的初始化
            return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
                    parsedArgs.mDisabledCompatChanges,
                    parsedArgs.mRemainingArgs, cl);
        }
    }
    ......
}

首先,为用户文件创建权限掩码,并设置进程名为:system_server。然后,加载指定路径下的 SystemServer 文件,并执行 dex 优化操作。最后构建获取 SystemServer 类加载器并设置给当前的线程,最后将剩余参数交给 ZygoteInit # zygoteInit() 方法完成 SystemServer 进程的初始化。

2.3 ZygoteInit # zygoteInit()

xref: /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

public class ZygoteInit {
	......
    public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
            String[] argv, ClassLoader classLoader) {
        if (RuntimeInit.DEBUG) {
            Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
        }
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
        RuntimeInit.redirectLogStreams(); // 重定向 log 日志输出
		// 进程初始化配置,如设置异常捕获 Handler、时区、重置 LogManager 等等
        RuntimeInit.commonInit();
        // native 层初始化 -- 打开/dev/binder 驱动,映射内核的地址空间,创建 binder 线程用于 IPC 通信
        ZygoteInit.nativeZygoteInit();
        return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
                classLoader);
    }
    ......
    private static native void nativeZygoteInit();
}

方法流程如下:

  1. 日志流重定向,将系统输出和系统错误重定向到 Android 日志。
  2. 进程初始化配置,如设置异常捕获 Handler、时区、重置 LogManager 等等。
  3. native 层初始化,打开 /dev/binder 驱动,映射内核的地址空间,创建 binder 线程用于 IPC 通信。
  4. 调用 RuntimeInit # applicationInit() 方法,返回创建的 Runnable 对象。
2.3.1 ZygoteInit # nativeZygoteInit()

ZygoteInit # nativeZygoteInit() 方法,通过 JNI 调用到 native 层的:com_android_internal_os_ZygoteInit_nativeZygoteInit() 方法,该方法在 AndroidRuntime.cpp 文件中,跟踪源码查看

	......
	static AndroidRuntime* gCurRuntime = NULL;
	......
    static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv*env, jobject clazz) {
    	// gCurRuntime 在 AndroidRuntime.cpp 中定义并赋值的,但其实现是在其子类 AppRuntime 类中
        gCurRuntime -> onZygoteInit();
    }
    ......
    int register_com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv*env) {
        const JNINativeMethod methods[] = {
            {"nativeZygoteInit", "()V",
               ( void*)com_android_internal_os_ZygoteInit_nativeZygoteInit },
        };
        return jniRegisterNativeMethods(env, "com/android/internal/os/ZygoteInit",
                methods, NELEM(methods));
    }
    ......
    AndroidRuntime::AndroidRuntime(char*argBlockStart, const size_t argBlockLength) :
            mExitWithoutCleanup(false),
            mArgBlockStart(argBlockStart),
            mArgBlockLength(argBlockLength) {
        init_android_graphics();
        // Pre-allocate enough space to hold a fair number of options.
        mOptions.setCapacity(20);
        assert (gCurRuntime == NULL);        // one per process
        gCurRuntime = this;
    }
    ......

在方法中继续调用 gCurRuntime :: onZygoteInit() 方法,可以看到 gCurRuntime 是 AndroidRuntime 类型的指针,并且在 AndroidRuntime 的构造方法中将自身 this 赋值给 gCurRuntime,即 AndroidRuntime 初始化时将 gCurRuntime 指向对象自身,那么 AndroidRuntime 是在何时初始化的呢?

2.3.2 app_main # main()

我们知道,app_main.cpp 的 main() 函数是 App 进程的主入口,启动解释的运行时,然后启动应用程序,进到源码中查看
xref: /frameworks/base/cmds/app_process/app_main.cpp

 	class AppRuntime : public AndroidRuntime 
 	{
    public:
        AppRuntime( char*argBlockStart, const size_t argBlockLength)
                  :AndroidRuntime(argBlockStart, argBlockLength)
                , mClass(NULL)
        {
        }
        ......
        virtual void onZygoteInit ()
        {	// 获取进程唯一实例,内部首先判断是否变量为NULL,非NULL则直接返回,反之才会调用其构造函数创建ProcessState实例
            // 因此同一进程有且只有一个 ProcessState 实例
            sp<ProcessState> proc = ProcessState::self ();
            ALOGV("App process: starting thread pool.\n");
            // 启动 Binder 线程池,方法内部继续调用 spawnPooledThread() 函数真正去启动线程池
            proc -> startThreadPool(); 
        }
		......
        String8 mClassName;
        Vector<String8> mArgs;
        jclass mClass;
    };
    ......
    int main(int argc, char*const argv[]) {
        ......
        // 创建 AppRuntime
        AppRuntime runtime (argv[0], computeArgBlockSize(argc, argv));
        ......
        if (!niceName.isEmpty()) {
            runtime.setArgv0(niceName.string(), true /* setProcName */);
        }

        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.");
        }
    }

在 app_main.cpp 的 main() 函数中创建了 AppRuntime,继续查看可知 AppRuntime 是 AndroidRuntime 的子类,在初始化过程中,构建 AppRuntime 的同时调用 AndroidRuntime 的构造函数来进行初始化,并将自身 this 赋值给 gCurRuntime。

因此经过分析可知,上一小节的 gCurRuntime 指向的就是 AppRuntime 对象,也即调用的是 AppRuntime # onZygoteInit() 方法,其方法内首先通过 ProcessState::self () 方法获取进程唯一实例,然后调用 ProcessState::startThreadPool() 方法启动 Binder 线程池,进而 SystemServer 进程就可以使用 Binder 与其他进程进行通信。

ProcessState: 继承自RefBase,其在同一进程内是唯一的,主要用于初始化 Binder 设备( 即打开 binder 设备文件/dev/binder节点) ,并将设备文件映射到进程的地址空间。Binder 线程池中的每一个线程都可以通过它与 Binder 驱动程序建立连接。简言之,其主要工作是调用 open() 函数打开 /dev/binder 驱动设备,再利用 mmap() 映射内核的地址空间, 将 Binder 驱动fd 赋值 ProcessState 对象中的变量 mDriverFD,用于交互操作。

2.3.3 RuntimeInit # applicationInit()

xref: /frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

public class RuntimeInit {
	......
	private static final native void nativeSetExitWithoutCleanup(boolean exitWithoutCleanup);
	......
	protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
            String[] argv, ClassLoader classLoader) {
        // true 代表应用程序退出时不调用 AppRuntime.onExit(),否则会在退出前调用,将导致剩余的运行线程在进程实际退出之前崩溃
        nativeSetExitWithoutCleanup(true);

        VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
        VMRuntime.getRuntime().setDisabledCompatChanges(disabledCompatChanges);
		// 解析参数
        final Arguments args = new Arguments(argv);
        // The end of of the RuntimeInit event (see #zygoteInit).
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        // 余下的参数传给即将要启动的类的静态 main 方法
        return findStaticMain(args.startClass, args.startArgs, classLoader);
    }
	......
}

首先调用 native 层的 nativeSetExitWithoutCleanup() 方法,且入参为 true,true 表示应用程序退出时不调用 AppRuntime.onExit() 方法,否则将会在退出前调用,导致剩余的运行线程在进程实际退出之前崩溃。然后解析参数,并继续调用 RuntimeInit # findStaticMain() 方法,将参数传给即将要启动的类的静态 main() 方法。

2.3.4 RuntimeInit # findStaticMain()

xref: /frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

public class RuntimeInit {
	......
	protected static Runnable findStaticMain(String className, String[] argv,
            ClassLoader classLoader) {
        Class<?> cl;
        try { // 通过反射机制得到 SystemServer 类
            cl = Class.forName(className, true, classLoader);
        } catch (ClassNotFoundException ex) {
            throw new RuntimeException("Missing class when invoking static main " + className, ex);
        }
        Method m;
        try { // 获取 SystemServer # main() 方法
            m = cl.getMethod("main", new Class[]{String[].class});
        } catch (NoSuchMethodException ex) {
            throw new RuntimeException("Missing static main on " + className, ex);
        } catch (SecurityException ex) {
            throw new RuntimeException("Problem getting static main on " + className, ex);
        }
		// 判断 main 方法是不是 public static 类型
        int modifiers = m.getModifiers();
        if (!(Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
            throw new RuntimeException("Main method is not public and static on " + className);
        }
        // 将获取的 Method 和参数封装成 MethodAndArgsCaller 对象返回,MethodAndArgsCaller 实现了 Runnable 接口
        return new MethodAndArgsCaller(m, argv);
    }
	......
}

首先,此处启动的类名为 fork 子进程时保存到 args 数组中的:com.android.server.SystemServer,并通过反射机制得到 SystemServer 类,然后通过 Class # getMethod() 方法获取 SystemServer 类的 main() 方法,再通过 Method # getModifiers() 方法获取方法的权限修饰,如果不是 public static 类型的则抛出异常,最后将获取的 Method 和参数封装成 MethodAndArgsCaller 对象返回,即返回到 1 ZygoteInit # main() 这节中 ZygoteInit # main() 方法中 forkSystemServer() 方法返回的 Runnable r,如果 r!=null 会调用这个 Runnable # run() 方法。

2.3.5 MethodAndArgsCaller # run()

xref: /frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

public class RuntimeInit {
	......
	 static class MethodAndArgsCaller implements Runnable {
        // 待反射调用的方法
        private final Method mMethod;
		// 待反射调用方法的参数数组
        private final String[] mArgs;
        public MethodAndArgsCaller(Method method, String[] args) {
            mMethod = method;
            mArgs = args;
        }
        public void run() {
            try { // 通过反射机制调用的是 SystemServer # main() 方法并传入传递过来的参数
                mMethod.invoke(null, new Object[]{mArgs});
            } catch (IllegalAccessException ex) {
                throw new RuntimeException(ex);
            } catch (InvocationTargetException ex) {
                Throwable cause = ex.getCause();
                if (cause instanceof RuntimeException) {
                    throw (RuntimeException) cause;
                } else if (cause instanceof Error) {
                    throw (Error) cause;
                }
                throw new RuntimeException(ex);
            }
        }
    }
}

MethodAndArgsCaller # run() 方法中使用了 invoke 反射调用,通过反射机制调用的是 SystemServer # main() 方法并传入传递过来的参数,至此 SystemServer 的 main() 方法得以执行,继续查看源码

3 SystemServer # main()

xref: /frameworks/base/services/java/com/android/server/SystemServer.java

public final class SystemServer implements Dumpable {
	......
	// Zygote 启动 SystemServer 的主要入口
    public static void main(String[] args) {
    	// 初始 SystemServer 对象,再调用其 run() 方法
        new SystemServer().run();
    }
    ......
    private void run() {
        TimingsTraceAndSlog t = new TimingsTraceAndSlog();
        try {
            t.traceBegin("InitBeforeStartServices");
            // 记录进程启动的信息
            SystemProperties.set(SYSPROP_START_COUNT, String.valueOf(mStartCount));
            ......
            // 如果未设置,则将时区属性默认为GMT
            String timezoneProperty = SystemProperties.get("persist.sys.timezone");
            if (!isValidTimeZoneId(timezoneProperty)) {
                Slog.w(TAG, "persist.sys.timezone is not valid (" + timezoneProperty + "); setting to GMT.");
                SystemProperties.set("persist.sys.timezone", "GMT");
            }
			......
            // 设置虚拟机的库文件,在 Android6.0 上用的是 libart.so
            SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());
            // 清除 vm 内存增长上限,由于启动过程需要较多的虚拟机内存空间
            VMRuntime.getRuntime().clearGrowthLimit();
            // 针对部分设备依赖于运行时就产生指纹信息,因此需在开机完成前定义好
            Build.ensureFingerprintProperty();
            // 在 system_server 中,访问环境路径前,需要明确地指定用户
            Environment.setUserRequired(true);
            // 在 system_server 中,需对传入的 bundle 进行解压缩,以避免抛出 BadParcelableException 异常
            BaseBundle.setShouldDefuse(true);
            // 在 system_server 中,当对异常进行打包时,应包括堆栈跟踪
            Parcel.setStackTraceParceling(true);
            // Ensure binder calls into the system always run at foreground priority.
            // 确保当前系统进程的 binder 调用,总是以前台优先级运行
            BinderInternal.disableBackgroundScheduling(true);
            // 在 system server 中,增加 binder 线程的数量,最大值为 31
            BinderInternal.setMaxThreads(sMaxBinderThreads);
            // 为主 Looper thread 做准备
            android.os.Process.setThreadPriority(
                    android.os.Process.THREAD_PRIORITY_FOREGROUND);
            android.os.Process.setCanSelfBackground(false);
            Looper.prepareMainLooper(); // 创建消息 Looper
            Looper.getMainLooper().setSlowLogThresholdMs(
                    SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
            SystemServiceRegistry.sEnableServiceNotFoundWtf = true;
            // 加载 android_servers.so 库,该库包含的源码在frameworks/base/services/目录下
            System.loadLibrary("android_servers");
            initZygoteChildHeapProfiling();
            // debug 模式下,构建并生成一个线程来监视 fd 泄漏
            if (Build.IS_DEBUGGABLE) {
                spawnFdLeakCheckThread();
            }
            // 检测上次关机过程是否失败,该方法可能不会返回
            performPendingShutdown();
            // 初始化系统上下文
            createSystemContext();
            // 调用每个进程主线模块初始化
            ActivityThread.initializeMainlineModules();
            // 设置转储服务
            ServiceManager.addService("system_server_dumper", mDumper);
            mDumper.addDumpable(this);
            // 创建系统服务管理 SystemServiceManager,对系统服务进行创建、启动和生命周期管理
            mSystemServiceManager = new SystemServiceManager(mSystemContext);
            mSystemServiceManager.setStartInfo(mRuntimeRestart,
                    mRuntimeStartElapsedTime, mRuntimeStartUptime);
            mDumper.addDumpable(mSystemServiceManager);
			// 将 mSystemServiceManager 添加到本地服务的成员 sLocalServiceObjects 中
			// LocalServices 通过用静态 Map 变量 sLocalServiceObjects,来保存以服务类名为key,以具体服务对象为value的Map结构
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
            // 为可以并行化的 init 任务准备线程池
            SystemServerInitThreadPool tp = SystemServerInitThreadPool.start();
            mDumper.addDumpable(tp);
            // 为 system server 加载预安装的系统字体,以便 WMS 等服务可以开始使用Typeface。
            // 注意,字体不仅用于文本渲染,还用于某些文本操作(例如textutils . makesafeforpresentation())
            if (Typeface.ENABLE_LAZY_TYPEFACE_INITIALIZATION) {
                Typeface.loadPreinstalledSystemFontMap();
            }
            // 如果这是一个可调试的构建并且设置了系统属性,则附加 JVMTI 代理
            if (Build.IS_DEBUGGABLE) {
                ......
            }
        } finally {
            t.traceEnd();  // InitBeforeStartServices
        }
        // 设置默认的应用 WTF Handler
        RuntimeInit.setDefaultApplicationWtfHandler(SystemServer::handleEarlySystemWtf);
        try { // 启动服务
            t.traceBegin("StartServices");
            startBootstrapServices(t); // 启动引导服务
            startCoreServices(t); // 启动核心服务
            startOtherServices(t); // 启动其他服务
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        } finally {
            t.traceEnd(); // StartServices
        }
        StrictMode.initVmDefaults(null); // 为当前的虚拟机初始化 VmPolicy
		......// 省略记录和日志输出等
        // 开启 Looper 循环,一直循环执行
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
    ......
}

作为 SystemServer 的入口方法,SystemServer # main() 方法很简单,初始 SystemServer 对象并调用其 run() 方法,配置属性、启动服务等任务都在 SystemServer # run() 方法中,这个方法很长,其主要执行了以下任务:

  1. 记录进程启动的信息,配置各种属性信息,然后创建当前线程 Looper 对象,通过 System # loadLibrary() 方法加载静态库 android_servers.so;
  2. 调用 SystemServer # performPendingShutdown() 方法,检测上次关机过程是否失败;
  3. 调用 SystemServer # createSystemContext() 方法创建并初始化系统上下文;
  4. 创建 SystemServiceManager 对象,用来管理系统服务 (SystemService) 的创建、启动和其他生命周期事件的;
  5. 创建服务初始化线程池 SystemServerInitThreadPool,为可以并行化的 init 任务准备线程池,使得系统服务的初始化过程可并行;
  6. 启动引导服务、核心服务以及其他服务;
  7. 通过 Looper # loop() 方法开启循环,等待消息队列 MessageQueue 中的消息到来,则马上进入执行状态。
3.1 SystemServer # performPendingShutdown()

xref: /frameworks/base/services/java/com/android/server/SystemServer.java

public final class SystemServer implements Dumpable {
	......
	private void performPendingShutdown() {
		// 读取系统属性配置 ShutdownThread.SHUTDOWN_ACTION_PROPERTY
        final String shutdownAction = SystemProperties.get(
                ShutdownThread.SHUTDOWN_ACTION_PROPERTY, "");
        if (shutdownAction != null && shutdownAction.length() > 0) {
            boolean reboot = (shutdownAction.charAt(0) == '1');
            final String reason;
            if (shutdownAction.length() > 1) {
                reason = shutdownAction.substring(1, shutdownAction.length());
            } else {
                reason = null;
            }
			// 重启保护,如果需重启恢复以更新应用,应确保在需要时正确执行uncrypt,且如果'/cache/recovery/block.map'没被创建则停止重启
            if (reason != null && reason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) {
                File packageFile = new File(UNCRYPT_PACKAGE_FILE);
                if (packageFile.exists()) {
                    String filename = null;
                    try {
                        filename = FileUtils.readTextFile(packageFile, 0, null);
                    } catch (IOException e) {
                        Slog.e(TAG, "Error reading uncrypt package file", e);
                    }
                    if (filename != null && filename.startsWith("/data")) {
                        if (!new File(BLOCK_MAP_FILE).exists()) {
                            Slog.e(TAG, "Can't find block map file, uncrypt failed or " +
                                    "unexpected runtime restart?");
                            return;
                        }
                    }
                }
            }
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    synchronized (this) { 
                    	// 当"sys.shutdown.requested"值为 1 时,则会重启,值不为空时,且不为 1 时,则会关机
                        ShutdownThread.rebootOrShutdown(null, reboot, reason);
                    }
                }
            };
            // ShutdownThread 必须运行在一个能够显示 UI 的 Looper 上,即 UI 主线程上启动 ShutdownThread 的rebootOrShutdown
            Message msg = Message.obtain(UiThread.getHandler(), runnable);
            msg.setAsynchronous(true);
            UiThread.getHandler().sendMessage(msg);
        }
    }
	......
}

读取系统属性配置 ShutdownThread.SHUTDOWN_ACTION_PROPERTY,如果获取到的值为 1 时,则会重启;值不为空且不为 1 时,则会关机。

注意ShutdownThread 必须运行在一个能够显示 UI 的 Looper 上,即 UI 主线程上。

3.2 SystemServer # createSystemContext()

xref: /frameworks/base/services/java/com/android/server/SystemServer.java

public final class SystemServer implements Dumpable {
	......
	private void createSystemContext() {
		// 创建获取 system_server 进程的上下文信息,并设置默认主题
        ActivityThread activityThread = ActivityThread.systemMain();
        mSystemContext = activityThread.getSystemContext();
        mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);
		// 创建获取 SystemUi 的上下文信息并设置默认主题
        final Context systemUiContext = activityThread.getSystemUiContext();
        systemUiContext.setTheme(DEFAULT_SYSTEM_THEME);
    }
	......
}

首先在 ActivityThread # systemMain() 方法中创建获取 ActivityThread 实例对象,然后调用 ActivityThread # attach() 方法,过程中会创建 InstrumentationContextImplApplication 等实例对象。ActivityThread # getSystemContext() 方法中通过 ContextImpl # createSystemContext() 方法创建 system_server 进程的上下文信息等,然后再给上下文设置默认主题信息,具体代码比较易懂,感兴趣的同学自行跟踪查看代码。

3.3 SystemServiceManager

xref: /frameworks/base/services/core/java/com/android/server/SystemServiceManager.java

public final class SystemServiceManager implements Dumpable {
	......
	private final Context mContext;
	// Services that should receive lifecycle events.
    private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();
    ......
    SystemServiceManager(Context context) {
    	mContext = context;
    }
    // 启动 Service,入参为待启动的服务类名,返回服务的实例
    public SystemService startService(String className) {
    	// 内部通过反射调用获取到待启动服务的类
        final Class<SystemService> serviceClass = loadClassFromLoader(className,
                this.getClass().getClassLoader());
        return startService(serviceClass); // 启动获取到的待启动服务类
    }
    ......
    public <T extends SystemService> T startService(Class<T> serviceClass) {
        try {
            ......// 创建待启动服务类的实例对象
            final T service;
            try {
                Constructor<T> constructor = serviceClass.getConstructor(Context.class);
                service = constructor.newInstance(mContext);
            } catch (InstantiationException ex) {
            	...... // 异常捕获并抛出
            }
            startService(service); // 启动服务类
            return service;
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        }
    }
   public void startService(@NonNull final SystemService service) {
        mServices.add(service); // 将启动的服务注册到已启动的服务列表中
        long time = SystemClock.elapsedRealtime();
        try {
            service.onStart(); // 服务启动后,回调其 Service # onStart() 方法
        } catch (RuntimeException ex) {
            throw new RuntimeException("Failed to start service " + service.getClass().getName()
                    + ": onStart threw an exception", ex);
        }
        warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
    }
    ......
}

SystemServiceManager 是用来管理系统服务 (SystemService) 的创建、启动和其他生命周期事件的。其内部的 mServices 用来存储启动的 Service 的列表,回调 services 的 onStart() 和 onBootPhase() 生命周期时都需要遍历该 List。

3.4 SystemServer # startBootstrapServices()

xref: /frameworks/base/services/java/com/android/server/SystemServer.java

public final class SystemServer implements Dumpable {
	......
	private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
        t.traceBegin("startBootstrapServices");
        // 启动 Watchdog 监控启动引导服务时是否会死锁
        t.traceBegin("StartWatchdog");
        final Watchdog watchdog = Watchdog.getInstance();
        watchdog.start();
        t.traceEnd();
        ...... // 平台配套服务由 AMS、PMS 以及将来可能的其他服务使用
        t.traceBegin("PlatformCompat");
        PlatformCompat platformCompat = new PlatformCompat(mSystemContext);
        ServiceManager.addService(Context.PLATFORM_COMPAT_SERVICE, platformCompat);
        ServiceManager.addService(Context.PLATFORM_COMPAT_NATIVE_SERVICE,
                new PlatformCompatNative(platformCompat));
        AppCompatCallbacks.install(new long[0]);
        t.traceEnd();

        // FileIntegrityService 响应来自应用程序和系统的请求。需在资源准备好之后,在应用程序(或系统中的第一个客户)运行之前运行
        t.traceBegin("StartFileIntegrityService");
        mSystemServiceManager.startService(FileIntegrityService.class);
        t.traceEnd();

        t.traceBegin("StartInstaller"); // 阻塞等待 Installd 服务启动完成且与其建立 socket 通道
        Installer installer = mSystemServiceManager.startService(Installer.class);
        t.traceEnd();

        // 在某些情况下,在启动应用程序后,需要访问设备标识符,因此要在 activity manager 之前注册
        t.traceBegin("DeviceIdentifiersPolicyService");
        mSystemServiceManager.startService(DeviceIdentifiersPolicyService.class);
        t.traceEnd();

        t.traceBegin("UriGrantsManagerService"); // 启动 Uri 授权管理服务
        mSystemServiceManager.startService(UriGrantsManagerService.Lifecycle.class);
        t.traceEnd();

        t.traceBegin("StartPowerStatsService"); // 启动 PowerStatsService 服务,用于功率统计
        mSystemServiceManager.startService(PowerStatsService.class);
        t.traceEnd();

        t.traceBegin("StartIStatsService");
        startIStatsService(); // 阻塞调用,启动 IStats 服务
        t.traceEnd();

        // 在 ActivityManager 之前启动 MemtrackProxyService 服务,以免调用 Memtrack::getMemory() 方法失败
        t.traceBegin("MemtrackProxyService");
        startMemtrackProxyService();
        t.traceEnd();

        // Activity manager 负责显示
        t.traceBegin("StartActivityManager"); // 启动 ActivityTaskManagerService 服务
		// ATMS 是 Android 10 中新增的,本来都是 ActivityManagerService 来管理
		// Google考虑到AMS职责太多、代码太庞大,所以单独拆出来ATMS用于管理Activity及其容器类如Task、Stack、Display等,分担部分职责
        ActivityTaskManagerService atm = mSystemServiceManager.startService(
                ActivityTaskManagerService.Lifecycle.class).getService();
        mActivityManagerService = ActivityManagerService.Lifecycle.startService(
                mSystemServiceManager, atm); // 启动 ActivityManagerService 服务
        mActivityManagerService.setSystemServiceManager(mSystemServiceManager); // AMS 设置 SystemServiceManager
        mActivityManagerService.setInstaller(installer); // AMS 设置 Installer
        mWindowManagerGlobalLock = atm.getGlobalLock(); // 获取 ATMS 的成员 mGlobalLock 赋值给 mWindowManagerGlobalLock
        t.traceEnd();

        // DataLoaderManagerService 数据加载器管理服务需要在包管理服务之前启动
        t.traceBegin("StartDataLoaderManagerService");
        mDataLoaderManagerService = mSystemServiceManager.startService(
                DataLoaderManagerService.class);
        t.traceEnd();

        // IncrementalService 服务需要在包管理服务之前启动
        t.traceBegin("StartIncrementalService");
        mIncrementalServiceHandle = startIncrementalService();
        t.traceEnd();

        // 因有其他业务需要用到,因此 PowerManagerService 电源管理服务要尽早启动
        t.traceBegin("StartPowerManager");
        mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
        t.traceEnd();

        t.traceBegin("StartThermalManager");
        mSystemServiceManager.startService(ThermalManagerService.class);
        t.traceEnd();

        t.traceBegin("StartHintManager");
        mSystemServiceManager.startService(HintManagerService.class);
        t.traceEnd();

        // 电源管理服务已经启动,Activity Manager 初始化电源管理特性
        t.traceBegin("InitPowerManagement");
        mActivityManagerService.initPowerManagement();
        t.traceEnd();

        // 启动恢复系统,以防需要重启
        t.traceBegin("StartRecoverySystemService");
        mSystemServiceManager.startService(RecoverySystemService.Lifecycle.class);
        t.traceEnd();

        // 已经启动并运行了操作系统的基本要素,但须注意,有可能会陷入运行时重启循环
        RescueParty.registerHealthObserver(mSystemContext);
        PackageWatchdog.getInstance(mSystemContext).noteBoot();

        t.traceBegin("StartLightsService"); // 启动 LightsService 服务,管理 LED 和显示
        mSystemServiceManager.startService(LightsService.class);
        t.traceEnd();

        t.traceBegin("StartSidekickService");
        if (SystemProperties.getBoolean("config.enable_sidekick_graphics", false)) {
            mSystemServiceManager.startService(WEAR_SIDEKICK_SERVICE_CLASS);
        }
        t.traceEnd();
        
        // 启动 DisplayManagerService 服务,需在包管理服务之前启动,用于提供显示
        t.traceBegin("StartDisplayManager");
        mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
        t.traceEnd();

        // 在初始化包管理服务之前,我们需要默认的显示
        t.traceBegin("WaitForDisplay");
        mSystemServiceManager.startBootPhase(t, SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
        t.traceEnd();
		......
        t.traceBegin("StartDomainVerificationService");
        DomainVerificationService domainVerificationService = new DomainVerificationService(
                mSystemContext, SystemConfig.getInstance(), platformCompat);
        mSystemServiceManager.startService(domainVerificationService);
        t.traceEnd();

        t.traceBegin("StartPackageManagerService");
        try { // 启动包管理服务 PackageManagerService
            Watchdog.getInstance().pauseWatchingCurrentThread("packagemanagermain");
            mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                    domainVerificationService, mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF,
                    mOnlyCore);
        } finally {
            Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain");
        }

        // 包管理服务已经启动,注册 dex load reporter 捕获系统服务加载的任何 dex 文件,这些 dex 文件将被后台dexoptservice优化
        SystemServerDexLoadReporter.configureSystemServerDexReporter(mPackageManagerService);

        mFirstBoot = mPackageManagerService.isFirstBoot(); // 是否第一次启动
        mPackageManager = mSystemContext.getPackageManager();
        t.traceEnd();
        if (!mRuntimeRestart && !isFirstBootOrUpgrade()) {
            FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
                    FrameworkStatsLog
                            .BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__PACKAGE_MANAGER_INIT_READY,
                    SystemClock.elapsedRealtime());
        }
        ......
        t.traceBegin("StartUserManagerService"); // 启动 UserManagerService 服务
        mSystemServiceManager.startService(UserManagerService.LifeCycle.class);
        t.traceEnd();

        t.traceBegin("InitAttributerCache");
        AttributeCache.init(mSystemContext); // 初始化用于缓存从包中获取的属性缓存
        t.traceEnd();

        // 为系统进程设置 Application 实例并开始
        t.traceBegin("SetSystemProcess");
        mActivityManagerService.setSystemProcess();
        t.traceEnd();

        // PackageReceiver 依赖于 Activity Service 服务来注册
        platformCompat.registerPackageReceiver(mSystemContext);

        // 使用 ActivityManager 实例完成 Watchdog 设置,并侦听重新启动
        // 只有在 ActivityManagerService 作为系统进程且正确启动后才能执行此操作
        t.traceBegin("InitWatchdog");
        watchdog.init(mSystemContext, mActivityManagerService);
        t.traceEnd();
        
        // DisplayManagerService 需要设置与显示调度相关的策略,因为setSystemProcess()会因为setProcessGroup而覆盖策略
        mDisplayManagerService.setupSchedulerPolicies();

        // 启动 OverlayManagerService 服务,用于管理叠加包
        t.traceBegin("StartOverlayManagerService");
        mSystemServiceManager.startService(new OverlayManagerService(mSystemContext));
        t.traceEnd();
		// 启动 SensorPrivacyService 服务,传感器有关如重力加速、光线等
        t.traceBegin("StartSensorPrivacyService");
        mSystemServiceManager.startService(new SensorPrivacyService(mSystemContext));
        t.traceEnd();

        if (SystemProperties.getInt("persist.sys.displayinset.top", 0) > 0) {
            // 更新 DisplayManagerService 服务
            mActivityManagerService.updateSystemUiContext();
            LocalServices.getService(DisplayManagerInternal.class).onOverlayChanged();
        }

        // 启动 SensorService 传感器服务,其需要访问包管理服务、应用ops服务和权限服务,因此我们在它们之后启动它
        t.traceBegin("StartSensorService"); 
        mSystemServiceManager.startService(SensorService.class);
        t.traceEnd();
        t.traceEnd(); // startBootstrapServices
    }
	......
}

代码比较长,方法中按序启动了很多的引导服务,有:Installer、ActivityTaskManagerService、ActivityManagerService、PowerManagerService、LightsService、DisplayManagerService、PackageManagerService、UserManagerService、OverlayManagerService 和 SensorService 等服务,具体可查看代码注释。

3.5 SystemServer # startCoreServices()

xref: /frameworks/base/services/java/com/android/server/SystemServer.java

public final class SystemServer implements Dumpable {
	......
	private void startCoreServices(@NonNull TimingsTraceAndSlog t) {
        t.traceBegin("startCoreServices");

        // 启动 SystemConfigService 系统配置服务
        t.traceBegin("StartSystemConfigService");
        mSystemServiceManager.startService(SystemConfigService.class);
        t.traceEnd();

        t.traceBegin("StartBatteryService");
        // 启动 BatteryService 电池服务,用于统计电池电量,需结合 LightService
        mSystemServiceManager.startService(BatteryService.class);
        t.traceEnd();

        // 启动 UsageStatsService 服务,用于统计应用使用情况
        t.traceBegin("StartUsageService");
        mSystemServiceManager.startService(UsageStatsService.class);
        mActivityManagerService.setUsageStatsManager(
                LocalServices.getService(UsageStatsManagerInternal.class));
        t.traceEnd();

        // 启动 WebViewUpdateService 服务,用于观察可更新的 WebView 是否处于就绪状态,并监视更新安装
        if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
            t.traceBegin("StartWebViewUpdateService");
            mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class);
            t.traceEnd();
        }

        // 启动 CachedDeviceStateService 服务,用于追踪和缓存设备状态
        t.traceBegin("StartCachedDeviceStateService");
        mSystemServiceManager.startService(CachedDeviceStateService.class);
        t.traceEnd();

        // 启动 BinderCallsStatsService 服务,用于追踪在 binder 调用中花费的 cpu 时间
        t.traceBegin("StartBinderCallsStatsService");
        mSystemServiceManager.startService(BinderCallsStatsService.LifeCycle.class);
        t.traceEnd();

        // 启动 LooperStatsService 服务,用于追踪在处理程序中处理消息所花费的时间
        t.traceBegin("StartLooperStatsService");
        mSystemServiceManager.startService(LooperStatsService.Lifecycle.class);
        t.traceEnd();

        // 启动 RollbackManagerService 服务,用于管理 apk 安装包的回滚
        t.traceBegin("StartRollbackManagerService");
        mSystemServiceManager.startService(ROLLBACK_MANAGER_SERVICE_CLASS);
        t.traceEnd();

        // 启动 NativeTombstoneManagerService 服务,用于追踪 native tombstones
        t.traceBegin("StartNativeTombstoneManagerService");
        mSystemServiceManager.startService(NativeTombstoneManagerService.class);
        t.traceEnd();

        // 启动 BugreportManagerService 服务,用于捕获并报告 bug
        t.traceBegin("StartBugreportManagerService");
        mSystemServiceManager.startService(BugreportManagerService.class);
        t.traceEnd();

        // 启动 GPU 和 GPU 驱动服务,用于为 GPU 和 GPU 驱动程序提供服务
        t.traceBegin("GpuService");
        mSystemServiceManager.startService(GpuService.class);
        t.traceEnd();

        t.traceEnd(); // startCoreServices
    }
	......
}

该方法用于启动一些在启动引导服务过程中没有相互依赖的基本服务,如:SystemConfigService、BatteryService、BinderCallsStatsService、BugreportManagerService 等服务,这些服务很少或基本不依赖于别的服务。

3.5 SystemServer # startOtherServices()

xref: /frameworks/base/services/java/com/android/server/SystemServer.java

public final class SystemServer implements Dumpable {
	......
	private ContentResolver mContentResolver;
	......
	private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
        t.traceBegin("startOtherServices");
        final Context context = mSystemContext;
        WindowManagerService wm = null;
        ......
        InputManagerService inputManager = null;
        ......
        try {
        	......
            t.traceBegin("StartKeyAttestationApplicationIdProviderService");
            ServiceManager.addService("sec_key_att_app_id_provider",
                    new KeyAttestationApplicationIdProviderService(context));
            ......
            mContentResolver = context.getContentResolver(); // 获取 ContentResolver 实例对象
            ...... // 安装 ContentProvider
        	mActivityManagerService.getContentProviderHelper().installSystemProviders();
        	......
            t.traceBegin("StartInputManagerService"); // 启动 InputManagerService 服务
        	inputManager = new InputManagerService(context);
        	......
        	t.traceBegin("StartWindowManagerService"); // 启动 WindowManagerService 服务
        	mSystemServiceManager.startBootPhase(t, SystemService.PHASE_WAIT_FOR_SENSOR_SERVICE);
        	wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
                	new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
        	ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
                	DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
        	ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
                	/* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
        	t.traceBegin("SetWindowManagerService"); // ActivityManagerService 设置 WindowManagerService
        	mActivityManagerService.setWindowManager(wm);
			......
        } catch (Throwable e) {
        	......// 日志输出并抛出异常
        }
        ......
        t.traceBegin("MakeDisplayReady");
        try {
            wm.displayReady();
        } catch (Throwable e) {
            reportWtf("making display ready", e);
        }
        t.traceEnd();
        ......
        t.traceBegin("MakeInputManagerServiceReady");
        try {
            if (inputManagerF != null) {
                inputManagerF.systemRunning();
            }
        } catch (Throwable e) {
            reportWtf("Notifying InputManagerService running", e);
        }
        ......
        // 准备好上面启动过的服务,如 WMS、PMS、DMS等
        t.traceBegin("MakeWindowManagerServiceReady");
        try {
            wm.systemReady();
        } catch (Throwable e) {
            reportWtf("making Window Manager Service ready", e);
        }
        mActivityManagerService.systemReady(() -> {
        	Slog.i(TAG, "Making services ready");
        	
        }, t);
        ......
		t.traceEnd(); // startOtherServices
    }
	......
}

该方法代码太多,主要是启动一些非紧要和不需要立即启动的服务,如:CameraService、AlarmManagerService、InputManagerService、WindowManagerService、…、AndioServcie 等,然后准备好这些启动过的服务,等待后续客户端的调用。


三、SystemServer 启动的服务及其作用

在 system_server 进程启动中,将系统服务分为三大类:引导服务核心服务其他服务。下面简单的罗列下这些在 Android 系统中常见的服务及其作用。

1、引导服务

Installer :系统安装 APK 时的一个服务类,启动完成 Installer 服务之后才能启动其他的系统服务
ActivityManagerService :负责四大组件的启动、切换、调度
PowerManagerService :计算系统中与 Power 相关的计算,然后决策系统应该如何反应
LightsService :管理和显示背光 LED
DisplayManagerService :用来管理所有显示设备
UserManagerService :多用户模式管理
SensorService :为系统提供各种感应器服务
PackageManagerService :对 APK 进行安装、解析、删除、卸载等操作
等等

2、核心服务

DropBoxManagerService:用于生成和管理系统运行时的一些日志文件
BatteryService:管理电池相关的服务
UsageStatsService:收集用户使用每一个 App 的频率、使用时长
WebViewUpdateService:WebView 更新服务
等等

3、其他服务

CameraService:摄像头相关服务
AlarmManagerService:全局定时器管理服务
InputManagerService:管理输入事件
WindowManagerService:窗口管理服务
VrManagerService:VR模式管理服务
BluetoothService:蓝牙管理服务
LocationManagerService:定位管理服务,GPS、定位等
AndioServcie:音频相关管理服务
LockSettingsService:屏幕锁定服务,管理每个用户的相关锁屏信息
DeviceIdleController:Doze模式的主要驱动
DevicePolicyManagerService:提供一些系统级别的设置及属性
StatusBarManagerService:状态栏管理服务
ClipboardService:系统剪切板服务
NetworkManagementService:网络管理服务
TextServicesManagerService:文本服务,例如文本检查等
NetworkScoreService:网络评分服务
NetworkStatsService:网络状态服务
NetworkPolicyManagerService:网络策略服务
WifiP2pService:Wifi Direct服务
WifiService:Wifi服务
WifiScanningService:Wifi扫描服务
RttService:Wifi相关
EthernetService:以太网服务
ConnectivityService:网络连接管理服务
NsdService:网络发现服务
NotificationManagerService:通知栏管理服务
DeviceStorageMonitorService:磁盘空间状态检测服务
CountryDetectorService:检测用户国家
SearchManagerService:搜索管理服务
DropBoxManagerService:用于系统运行时日志的存储于管理
WallpaperManagerService:壁纸管理服务
AudioService:AudioFlinger的上层管理封装,主要是音量、音效、声道及铃声等的管理
DockObserver:如果系统有个座子,当手机装上或拔出这个座子的话,就得靠他来管理了
WiredAccessoryManager:监视手机和底座上的耳机
UsbService:USB服务
SerialService:串口服务
TwilightService:指出用户当前所在位置是否为晚上,被 UiModeManager 等用来调整夜间模式
BackupManagerService:备份服务
AppWidgetService:提供Widget的管理和相关服务
VoiceInteractionManagerService:语音交互管理服务
DiskStatsService:磁盘统计服务,供dumpsys使用
SamplingProfilerService:用于耗时统计等
NetworkTimeUpdateService:监视网络时间,当网络时间变化时更新本地时间。
CertBlacklister:提供一种机制更新SSL certificate blacklist
DreamManagerService:屏幕保护
PrintManagerService:打印服务
HdmiControlService:HDMI控制服务
FingerprintService:指纹服务
等等


总结

SystemServer 进程是 Zygote 启动后 fork 出的第一个进程,其本质是通过 Linux 的 fork() 系统调用来创建的。SystemServer 进程在启动过程中,先初始化系统变量、加载系统类库、创建 Context 上线文对象等。然后创建 SystemServiceManager 对象用于对系统的服务进程创建、启动和生命周期管理。之后通过 SystemServiceManager 启动系统中的引导服务、核心服务和其它服务。

注意SystemServer 在启动服务前,会尝试与 Zygote 建立 Socket 通信,通信成功后才去启动服务,且启动的服务都单独运行在SystemServer 的各自线程中,同属于 SystemServer 进程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/150798.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

opencv(1):创建和显示窗口, 读取保存图片

下载源码&#xff0c;方便查看 API 信息。 快速在源码文件夹中搜索相关 api. grep“namedWindow(*-Rn// 限定 .h 文件 grep“namedWindow(*-Rn|grep "\.h" vscode 语法检测有问题 一直有波浪线 打开 vscode, setting 界面&#xff0c;搜索 python 在 setting.json…

【Shell脚本12】Shell 输入/输出重定向

Shell 输入/输出重定向 大多数 UNIX 系统命令从你的终端接受输入并将所产生的输出发送回​​到您的终端。一个命令通常从一个叫标准输入的地方读取输入&#xff0c;默认情况下&#xff0c;这恰好是你的终端。同样&#xff0c;一个命令通常将其输出写入到标准输出&#xff0c;默…

Linux系统编程——进程中vfork函数

函数原型 pid_t vfork(void);//pid_t是无符号整型 所需头文件 #include <sys/types.h> #include <unistd.h> 功能 vfork() 函数和 fork() 函数一样都是在已有的进程中创建一个新的进程&#xff0c;但它们创建的子进程是有区别的。 返回值 成功子进程中返回 …

RK3588平台开发系列讲解(摄像头篇)USB摄像头驱动分析

🚀返回专栏总目录 文章目录 一. USB摄像头基本知识1.1 内部逻辑结构1.2 描述符实例解析二. UVC驱动框架2.1、设备枚举过程2.2、数据传输过程沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 USB摄像头驱动位于 drivers\media\usb\uvc\uvc_driver.c ,我们本篇重点看下…

rpmbuild 包名 version 操作系统信息部分来源 /etc/rpm/macros.dist

/etc/rpm/macros.dist openeuler bclinux src.rpm openssl-1.1.1f-13.oe1.src.rpm 打包名称结果 openeuler openssl-1.1.1f-13.aarch64.rpm bclinux openssl-1.1.1f-13.oe1.bclinux.aarch64.rpm 验证 修改openeuler配置文件macros.dist 重新在openeuler上执行rpmbuild…

opencv:从0到实现人脸识别

目录 opencv 人脸检查原理&#xff1a; 整体目录&#xff1a; 1.读取并展示图片 2.人脸检测 3.视频人脸检测 4.拍照保存 5 数据训练 6 人脸识别 opencv 人脸检查原理&#xff1a; OpenCV 中的人脸检测是基于哈尔特征分类器&#xff08;Haar Feature-based Cascade Cla…

EtherCAT从站EEPROM组成信息详解(1):字0-7ESC寄存器配置区

0 工具准备 1.EtherCAT从站EEPROM数据&#xff08;本文使用DE3E-556步进电机驱动器&#xff09;1 字0-字7ESC寄存器配置区组成信息详解 1.1 ESC寄存器配置区组成规范 对于EtherCAT从站来说&#xff0c;EEPROM的字0-字7组成的ESC寄存器配置区决定了从站上电后ESC能否正常工作…

【React】React-Redux基本使用

容器组件和 UI 组件 所有的 UI 组件都需要有一个容器组件包裹 容器组件来负责和 Redux 打交道&#xff0c;可以随意使用 Redux 的API UI 组件无任何 Redux API 容器组件用于处理逻辑&#xff0c;UI 组件只会负责渲染和交互&#xff0c;不处理逻辑 在我们的生产当中&#xff0…

C/C++最大质数 2021年9月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析

目录 C/C比n小的最大质数 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 C/C比n小的最大质数 2021年9月 C/C编程等级考试一级编程题 一、题目要求 1、编程实现 对于给定的n&#xff0c;求比n小的质数中…

零小时零信任:数据标记如何加速实施

现在是零信任的零小时。 虽然这个概念已经存在多年&#xff0c;但现在联邦政府实施它的时间已经紧迫。 拜登政府备忘录被誉为以战斗速度安全交付关键任务数据的解决方案&#xff0c;要求联邦机构在 2024 财年年底前实现具体的零信任安全目标。 此外&#xff0c;国防部正在努…

ClickHouse的数据类型

1 整型 固定长度的整型&#xff0c;包括有符号整型或无符号整型。 整型范围&#xff08;-2n-1~2n-1-1&#xff09;&#xff1a; Int8 - [-128 : 127] Int16 - [-32768 : 32767] Int32 - [-2147483648 : 2147483647] Int64 - [-9223372036854775808 : 9223372036854775807] 无符…

CSDN每日一题学习训练——Python版(输入起始和结束的正整数,求其两个正整数之间的偶数和、两数相加)

版本说明 当前版本号[20231115]。 版本修改说明20231115初版 目录 文章目录 版本说明目录输入起始和结束的正整数&#xff0c;求其两个正整数之间的偶数和。题目解题思路代码思路参考代码 两数相加题目解题思路代码思路参考代码 输入起始和结束的正整数&#xff0c;求其两个…

P6入门:项目初始化11-项目详情之计算Calculations

前言 使用项目详细信息查看和编辑有关所选项目的详细信息&#xff0c;在项目创建完成后&#xff0c;初始化项目是一项非常重要的工作&#xff0c;涉及需要设置的内容包括项目名&#xff0c;ID,责任人&#xff0c;日历&#xff0c;预算&#xff0c;资金&#xff0c;分类码等等&…

STM32与ZigBee技术在智能家居无线通信中的应用研究

一、引言 智能家居系统是利用物联网技术将家庭各种设备进行互联互通&#xff0c;实现智能化控制和管理的系统。在智能家居系统中&#xff0c;无线通信技术起着至关重要的作用&#xff0c;而STM32微控制器和ZigBee技术则是实现智能家居无线通信的关键技术。本文将对STM32与ZigB…

北邮22级信通院数电:Verilog-FPGA(9)第九周实验(4)实现寄存器74LS374

北邮22信通一枚~ 跟随课程进度更新北邮信通院数字系统设计的笔记、代码和文章 持续关注作者 迎接数电实验学习~ 获取更多文章&#xff0c;请访问专栏&#xff1a; 北邮22级信通院数电实验_青山如墨雨如画的博客-CSDN博客 目录 一.代码部分 1.1 reg_74LS374.v 1.2 reg_LS3…

VIVADO+FPGA调试记录

vivadoFPGA调试记录 vitis编译vivado导出的硬件平台&#xff0c;提示xxxx.h file cant find vitis编译vivado导出的硬件平台&#xff0c;提示’xxxx.h file cant find’ 此硬件平台中&#xff0c;包含有AXI接口类型的ip。在vitis编译硬件平台时&#xff0c;经常会报错&#xf…

Docker Compose详细教程(从入门到放弃)

对于现代应用来说&#xff0c;大多都是通过很多的微服务互相协同组成的一个完整应用。例如&#xff0c; 订单管理、用户管理、品类管理、缓存服务、数据库服务等&#xff0c;它们构成了一个电商平台的应 用。而部署和管理大量的服务容器是一件非常繁琐的事情。而 Docker Compos…

WordPress 媒体库文件夹管理插件 FileBird v5.5.4和谐版下载

FileBird是一款WordPress 按照文件夹管理方式的插件。 拖放界面 拖放功能现已成为现代软件和网站的标配。本机拖动事件&#xff08;包括仅在刀片中将文件移动到文件夹以及将文件夹移动到文件夹&#xff09;极大地减少了完成任务所需的点击次数。 一流设计的文件夹树展示 我们…

如何下载 Apache + PHP + Mysql 集成安装环境并结合内网穿透工具实现公网访问内网服务

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、Cpolar杂谈 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. WampServer下载安装二. WampServer启动三. 安装cpolar内网穿透3.1 注册账号…

2023年09月 Python(五级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试(1~6级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 阅读以下代码,程序输出结果正确的选项是?( ) def process_keywords(keywords_list):unique_keywords = list(set(keywords_list))