Android 11(R)启动流程 初版

启动流程

bootloader会去启动android第一个进程Idle,pid为0,会对进程 内存管理等进行初始化。Idle还被称作swapper。Idle会去创建两个进程,一个是init,另外一个是kthread。 kthread会去启动内核,用户是由init进行启动。

init进程的启动

在内核common/init/main.c 的kernel_init函数中

cpp 复制代码
	if (execute_command) {
		ret = run_init_process(execute_command);
		if (!ret)
			return 0;
		panic("Requested init %s failed (error %d).",
		      execute_command, ret);
	}
	if (!try_to_run_init_process("/sbin/init") ||
	    !try_to_run_init_process("/etc/init") ||
	    !try_to_run_init_process("/bin/init") ||
	    !try_to_run_init_process("/bin/sh"))
		return 0;

可以看到这里启动了init进程。并且这个bin是在根目录下的。

cpp 复制代码
static int run_init_process(const char *init_filename)
{
	argv_init[0] = init_filename;
	pr_info("Run %s as init process\n", init_filename);
	return do_execve(getname_kernel(init_filename),
		(const char __user *const __user *)argv_init,
		(const char __user *const __user *)envp_init);
}

do_execve 是一个内核函数,用于执行用户空间的程序,最后会调用到__do_execve_file函数

cpp 复制代码
/* 参数解释
int fd:

文件描述符,用于指定要执行的文件。如果不使用文件描述符,可以传入 AT_FDCWD。
struct filename *filename:

文件名结构体,包含要执行的可执行文件的路径。
struct user_arg_ptr argv:

参数指针结构体,指向传递给新进程的命令行参数。
struct user_arg_ptr envp:

环境变量指针结构体,指向传递给新进程的环境变量。
int flags:

标志位,用于控制执行行为。
struct file *file:

文件结构体指针,指向要执行的文件。如果不通过文件描述符打开文件,可以传入 NULL。*/


static int __do_execve_file(int fd, struct filename *filename,
			    struct user_arg_ptr argv,
			    struct user_arg_ptr envp,
			    int flags, struct file *file)
{
	char *pathbuf = NULL;
	struct linux_binprm *bprm;
	struct files_struct *displaced;
	int retval;

    //检查 filename 是否为错误指针,如果是,则返回相应的错误码。

	if (IS_ERR(filename))
		return PTR_ERR(filename);

	/*
	 * We move the actual failure in case of RLIMIT_NPROC excess from
	 * set*uid() to execve() because too many poorly written programs
	 * don't check setuid() return code.  Here we additionally recheck
	 * whether NPROC limit is still exceeded.
	 */

    //检查当前用户的进程数是否超过了限制,如果超过了限制,则返回 -EAGAIN 错误码。
    //清除进程标志 PF_NPROC_EXCEEDED。

	if ((current->flags & PF_NPROC_EXCEEDED) &&
	    atomic_read(&current_user()->processes) > rlimit(RLIMIT_NPROC)) {
		retval = -EAGAIN;
		goto out_ret;
	}

	/* We're below the limit (still or again), so we don't want to make
	 * further execve() calls fail. */
	current->flags &= ~PF_NPROC_EXCEEDED;

    //调用 unshare_files 函数分离文件结构,以确保进程在执行期间独占文件描述符表
	retval = unshare_files(&displaced);
	if (retval)
		goto out_ret;

	retval = -ENOMEM;
    //分配并初始化 linux_binprm 结构体,该结构体用于存储进程执行所需的各种信息
	bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
	if (!bprm)
		goto out_files;

	retval = prepare_bprm_creds(bprm);
	if (retval)
		goto out_free;

    //调用 check_unsafe_exec 函数进行安全检查
	check_unsafe_exec(bprm);
	current->in_execve = 1;

    //如果没有提供文件指针,则使用 do_open_execat 函数根据文件描述符和文件名打开文件
	if (!file)
		file = do_open_execat(fd, filename, flags);
	retval = PTR_ERR(file);
	if (IS_ERR(file))
		goto out_unmark;

    /*准备执行环境:
    调用 sched_exec 函数设置调度相关信息。
    初始化 bprm 结构体中的文件和文件名信息。
    调用 bprm_mm_init 函数初始化进程的内存管理。
    调用 prepare_arg_pages 函数准备参数和环境变量的内存页。
    调用 prepare_binprm 函数准备可执行文件的二进制参数。*/

	sched_exec();

	bprm->file = file;
	if (!filename) {
		bprm->filename = "none";
	} else if (fd == AT_FDCWD || filename->name[0] == '/') {
		bprm->filename = filename->name;
	} else {
		if (filename->name[0] == '\0')
			pathbuf = kasprintf(GFP_KERNEL, "/dev/fd/%d", fd);
		else
			pathbuf = kasprintf(GFP_KERNEL, "/dev/fd/%d/%s",
					    fd, filename->name);
		if (!pathbuf) {
			retval = -ENOMEM;
			goto out_unmark;
		}
		/*
		 * Record that a name derived from an O_CLOEXEC fd will be
		 * inaccessible after exec. Relies on having exclusive access to
		 * current->files (due to unshare_files above).
		 */
		if (close_on_exec(fd, rcu_dereference_raw(current->files->fdt)))
			bprm->interp_flags |= BINPRM_FLAGS_PATH_INACCESSIBLE;
		bprm->filename = pathbuf;
	}
	bprm->interp = bprm->filename;

	retval = bprm_mm_init(bprm);
	if (retval)
		goto out_unmark;

	retval = prepare_arg_pages(bprm, argv, envp);
	if (retval < 0)
		goto out;

	retval = prepare_binprm(bprm);
	if (retval < 0)
		goto out;


    //复制参数和环境变量:

    //调用 copy_strings_kernel 函数复制文件名到用户栈。
    //调用 copy_strings 函数依次复制环境变量和命令行参数到用户栈

	retval = copy_strings_kernel(1, &bprm->filename, bprm);
	if (retval < 0)
		goto out;

	bprm->exec = bprm->p;
	retval = copy_strings(bprm->envc, envp, bprm);
	if (retval < 0)
		goto out;

	retval = copy_strings(bprm->argc, argv, bprm);
	if (retval < 0)
		goto out;

	/*
	 * When argv is empty, add an empty string ("") as argv[0] to
	 * ensure confused userspace programs that start processing
	 * from argv[1] won't end up walking envp. See also
	 * bprm_stack_limits().
	 */
	if (bprm->argc == 0) {
		const char *argv[] = { "", NULL };
		retval = copy_strings_kernel(1, argv, bprm);
		if (retval < 0)
			goto out;
		bprm->argc = 1;
	}

    //调用 exec_binprm 函数执行可执行文件
	retval = exec_binprm(bprm);
	if (retval < 0)
		goto out;

    //如果执行成功,清理各种临时数据结构,释放资源,并返回成功状态。
    //如果执行失败,进行错误处理,清理资源,并返回相应的错误码。
	/* execve succeeded */
	current->fs->in_exec = 0;
	current->in_execve = 0;
	rseq_execve(current);
	acct_update_integrals(current);
	task_numa_free(current, false);
	free_bprm(bprm);
	kfree(pathbuf);
	if (filename)
		putname(filename);
	if (displaced)
		put_files_struct(displaced);
	return retval;

out:
	if (bprm->mm) {
		acct_arg_size(bprm, 0);
		mmput(bprm->mm);
	}

out_unmark:
	current->fs->in_exec = 0;
	current->in_execve = 0;

out_free:
	free_bprm(bprm);
	kfree(pathbuf);

out_files:
	if (displaced)
		reset_files_struct(displaced);
out_ret:
	if (filename)
		putname(filename);
	return retval;
}

接下来就正式进入init的启动流程,init代码路径:system/core/init/main.cpp main函数代码较短,直接贴上来。

cpp 复制代码
int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
    __asan_set_error_report_callback(AsanReportCallback);
#endif

    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }

    if (argc > 1) {
        if (!strcmp(argv[1], "subcontext")) {
            android::base::InitLogging(argv, &android::base::KernelLogger);
            const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();

            return SubcontextMain(argc, argv, &function_map);
        }

        if (!strcmp(argv[1], "selinux_setup")) {
            return SetupSelinux(argv);
        }

        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv);
        }
    }

    return FirstStageMain(argc, argv);
}

FirstStageMain

在FirstStageMain中,主要是挂载文件目录,创建一些文件,做一些初始化等的阶段。

还包括初始化日志系统,将输入输出重定向。

最后,会去启动init 并且带一个selinux_setup

SelinuxInitialize

在SelinuxInitialize中会初始化一些安全策略

selinux_setup之后会去second_stage

SecondStageMain

cpp 复制代码
PropertyInit();  初始化属性域

selinux初始化
// Now set up SELinux for second stage.
SelinuxSetupKernelLogging();
SelabelInitialize();
SelinuxRestoreContext();//恢复安全上下文


//处理子进程的终止信号,判断子进程有没有挂掉 (僵尸进程) 回收资源。
InstallSignalFdHandler(&epoll);
InstallInitNotifier(&epoll);
StartPropertyService(&property_fd);


//匹配命令和函数之间的关系,ls 等命令和函数的关系
const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
cpp 复制代码
/********************************/
//解析init.rc
LoadBootScripts(am, sm);
/********************************/
cpp 复制代码
static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
    Parser parser = CreateParser(action_manager, service_list);

    std::string bootscript = GetProperty("ro.boot.init_rc", "");
    if (bootscript.empty()) {
        parser.ParseConfig("/system/etc/init/hw/init.rc");
        if (!parser.ParseConfig("/system/etc/init")) {
            late_import_paths.emplace_back("/system/etc/init");
        }
        // late_import is available only in Q and earlier release. As we don't
        // have system_ext in those versions, skip late_import for system_ext.
        parser.ParseConfig("/system_ext/etc/init");
        if (!parser.ParseConfig("/product/etc/init")) {
            late_import_paths.emplace_back("/product/etc/init");
        }
        if (!parser.ParseConfig("/odm/etc/init")) {
            late_import_paths.emplace_back("/odm/etc/init");
        }
        if (!parser.ParseConfig("/vendor/etc/init")) {
            late_import_paths.emplace_back("/vendor/etc/init");
        }
    } else {
        parser.ParseConfig(bootscript);
    }
}

在LoadBootScripts中会去创建三种对应解释器

cpp 复制代码
Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {
    Parser parser;

    parser.AddSectionParser("service", std::make_unique<ServiceParser>(
                                               &service_list, GetSubcontext(), std::nullopt));
    parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, GetSubcontext()));
    parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));

    return parser;
}

init处理的重要事情

1.挂载文件

2.设置selinux

3.开启属性服务

4.解析init.rc

5.循环处理脚本 -》 启动zygote

6.循环等待

init.rc -》zygote

html 复制代码
# Now we can start zygote for devices with file based encryption
trigger zygote-start

这段 init.rc 脚本配置了在不同加密状态下启动 zygote 及其相关服务的逻辑。根据设备的加密状态(未加密、不支持加密或已加密)

init.rc解析时会导入import /system/etc/init/hw/init.${ro.zygote}.rc

这里大括号{}中的ro.zygote表示它会用 ro.zygote 系统属性的值来替换 ${ro.zygote}

所以这里是 import /system/etc/init/hw/init.zygote32.rc

init.zygote32.rc类似的文件有四个,对应32位系统,64位系统,还有主32次64或者主64的。这种会在32执行失败之后再执行64位的。

启动一个服务 zygote 后面是路径, 在后面是参数

zygote的作用之一是要进入java层,为Android启动运行时环境。

AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); -》class AppRuntime : public AndroidRuntime

app_main.cpp中 runtime.start("com.android.internal.os.ZygoteInit", args, zygote);去启动android运行时环境。

app_main.cpp runtime.start -》

AndroidRuntime.cpp AndroidRuntime::start -》

startVm 启动虚拟机-》

startReg 注册jni-》

env->CallStaticVoidMethod(startClass, startMeth, strArray);

启动com.android.internal.os.ZygoteInit -》ZygoteInit.java . main

AndroidRuntime 中包括对虚拟机一系列的初始化,这里包括heapsize的初始化为16M,

进程和虚拟机是什么关系

虚拟机实现了进程中内存管理的功能

注册jni

startReg-》

register_jni_procs-》

register_com_android_internal_os_RuntimeInit (env)

register_com_android_internal_os_ZygoteInit_nativeZygoteInit(env)

register_com_android_internal_os_......

Zygote的java启动

runtime.start("com.android.internal.os.ZygoteInit", args, zygote); -》

env->CallStaticVoidMethod(startClass, startMeth, strArray);-》

ZygoteInit.java main-》

preload(bootTimingsTraceLog);//加快进程的启动-》

zygoteServer = new ZygoteServer(isPrimaryZygote);-》

Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);// 启动systemserver进程-》

caller = zygoteServer.runSelectLoop(abiList);进入loop死循环,接收AMS传过来的消息

preload加载的时间

Zygote总结:

native:

1.初始化运行环境,创建jvm

2.注册jni

3.调用zygoteinit.main

java

1.预加载 -- 加快进程启动

2.socket 服务器

3.循环等待

Zygote fork SystemServer进程

SystemServer的主要工作是管理服务,AMS WMS都和SystemServer属于同一进程,这些服务都是在SystemServer运行起来的。

ZygoteInit.java

-》

Runnable r = forkSystemServer(abiList, socketName, zygoteServer);

-》

Zygote.forkSystemServer-》

Zygote.java nativeForkSystemServer

-》

com_android_internal_os_Zygote.cpp com_android_internal_os_Zygote_nativeForkSystemServer

-》

ForkAndSpecializeCommon-》

fork(); -》

pid == 0 handleSystemServerProcess-》

ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);

-》

RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);

-》

RuntimeInit.commonInit();//初始化运行环境

-》

ZygoteInit.nativeZygoteInit //启动binder,方法在androidRuntime.cpp中注册

-》

RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);//ActivityThread.main();

-》

findStaticMain //app启动流程也是走这里,因此这里不仅返回AMS通过socket传过来的ActivityThread、还有systemserver

-》cl.getMethod("main", new Class[] { String[].class });//通过反射拿到对应类的main方法的Method对象

-》MethodAndArgsCaller implements Runnable 封装成Runnable对象

-》

mMethod.invoke(null, new Object[] { mArgs }); 执行run时通过invoke函数执行类所对应的main函数

-》r.run();

SystemServer基本流程

main-》new SystemServer().run();-》

startBootstrapServices

startCoreServices

startOtherServices -》

createSystemContext //创建系统上下文

SystemServer如何管理服务

systemserver基本都通过mSystemServiceManager.startService 来启动服务,可以看出SystemServer是通过SystemServiceManager来管理service的,服务都必须封装systemservice类,

mActivityManagerService = mSystemServiceManager.startService(ActivityManagerService.Lifecycle.class).getService();

java 复制代码
mActivityManagerService = mSystemServiceManager.startService(ActivityManagerService.Lifecycle.class).getService();

public class ActivityManagerService extends IActivityManager.Stub

implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {

..............} 从这里看出ActivityManagerService 是一个binder。但是因为只能有一个父类,为了能够实现继承自systemservice的效果,ActivityManagerService 实现了一个静态内部类Lifecycle拓展自SystemService。

public static final class Lifecycle extends SystemService {.......}

java 复制代码
public Lifecycle(Context context) {
    super(context);
    mService = new ActivityManagerService(context);
}

并且mSystemServiceManager.startService传递的是类名,可以通过反射创建实例,通过实例调用service.onStart();可以调用到继承自SystemService 的Lifecycle里面的onStart函数。

public <T extends SystemService> T startService(Class<T> serviceClass) {}

在通过

ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated= */ true, DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);

或者

publishBinderService(Context.USER_SERVICE, mUms); 将服务注册到servicemanager里面去,尽管publishBinderService最后也是调用ServiceManager.addService函数。

相关推荐
VincentWei9519 分钟前
Compose:MutableState 和 mutableStateOf
android
小白跃升坊21 分钟前
基于1Panel的AI运维
linux·运维·人工智能·ai大模型·教学·ai agent
jian1105829 分钟前
Android studio配置flutter,mac Android studio 发现苹果手机设备
android·flutter·android studio
跃渊Yuey40 分钟前
【Linux】线程同步与互斥
linux·笔记
舰长11542 分钟前
linux 实现文件共享的实现方式比较
linux·服务器·网络
zmjjdank1ng1 小时前
Linux 输出重定向
linux·运维
路由侠内网穿透.1 小时前
本地部署智能家居集成解决方案 ESPHome 并实现外部访问( Linux 版本)
linux·运维·服务器·网络协议·智能家居
2501_940007891 小时前
Flutter for OpenHarmony三国杀攻略App实战 - 性能优化与最佳实践
android·flutter·性能优化
VekiSon1 小时前
Linux内核驱动——基础概念与开发环境搭建
linux·运维·服务器·c语言·arm开发
Rysxt_2 小时前
UniApp获取安卓系统权限教程
android·uni-app