启动流程
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(¤t_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函数。