Android完整的启动流程,能够理解为从按下开机键到用户最终看到Launcher的过程,这部分细节不少,力求了解大概流程,对关键细节掌握便可。本篇重点讲解从开机到建立Dalvik VM的过程,下篇分析从Zygote到最终Launcher的显示过程。java
介绍Android系统启动流程的文章不少,在正式介绍以前,咱们能够思考下,类比windows等PC系统的系统启动流程,Android系统的启动流程有何特别之处。linux
Android能够理解为构建于在Linux上的一个特殊“应用”,所以Android启动的流程除了kernel的启动部分以外,还有构建在它之上的Android运行环境的启动部分。本篇主要介绍Kernel启动到构建出Dalvik VM的过程。android
借用一张图:windows
当系统加电后,CPU复位会首先运行在ROM芯片内固化的一段指令(Boot ROM),这段指令会将BootLoader程序加载到内存中而且开始执行。缓存
BootLoader也叫“引导加载程序”,是个底层代码,包含一堆指令,主要分为两部分,安全
关于镜像文件,能够参考:source.android.com/devices/boo…网络
bootloader相关的源码见:android/platform/bootable/bootloader/legacy/usbloader app
通过这一步,Kernel的相关镜像已经加载到了物理内存的指定地址处,并创建了内核运行所需的基本环境。接下来BootLoade就将控制权交给了Kernel,内核开始执行。socket
android kernel的加载过程与Linux Kernel加载过程相似,随着内核启动,开始设置缓存、受保护内存、调度和加载驱动程序。当完成这些设置后,便会启动指定 /system/core/init 第一个用户进程init。ide
相比Linux Kernel,Android Kernel新增了一些特性:
init进程是Android系统的第一个用户进程,能够说是root进程,它主要有两个职责:
以android 10源码为例,init进程的启动主要分为几个阶段:
//init进程入口
/init/main.cpp int main(int argc, char** argv) {
f (argc > 1) {
if (!strcmp(argv[1], "subcontext")) {
android::base::InitLogging(argv, &android::base::KernelLogger);
const BuiltinFunctionMap function_map;
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);
}
//第一阶段
/init/first_stage_init.cpp int FirstStagetMain(int argc, char** argv) {
//主要是建立挂载相关文件目录
CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"));
CHECKCALL(mkdir("/dev/pts", 0755));
CHECKCALL(mkdir("/dev/socket", 0755));
CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL));
#define MAKE_STR(x) __STRING(x)
CHECKCALL(mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC)));
...
//------------执行selinux_setup-->main.cpp
const char* path = "/system/bin/init";
const char* args[] = {path, "selinux_setup", nullptr};
execv(path, const_cast<char**>(args));
...
}
//创建安全机制
/init/selinux.cpp: 执行一些安全策略
/ This function initializes SELinux then execs init to run in the init SELinux context.
int SetupSelinux(char** argv) {
// Set up SELinux, loading the SELinux policy.
SelinuxSetupKernelLogging();
SelinuxInitialize();
//--------------进入second_stage main.cpp
const char* path = "/system/bin/init";
const char* args[] = {path, "second_stage", nullptr};
execv(path, const_cast<char**>(args));
}
//第二阶段
/init/init.cpp int SecondStageMain(int argc, char** argv) {
//初始化日志系统
InitKernelLogging(argv);
//初始化属性域
property_init();
//装载子进程信号处理:为了防止僵尸子进程没法回收
InstallSignalFdHandler(&epoll);
//开启属性服务
StartPropertyService(&epoll);
//加载脚本
ActionManager& am = ActionManager::GetInstance();
ServiceList& sm = ServiceList::GetInstance();
//加载解析init.rc脚本
LoadBootScripts(am, sm);
...
}
//解析init.rc文件
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("/init.rc");
}
...
}
复制代码
init.rc是个配置文件,具体语法能够参考: android.googlesource.com/platform/sy…
在手机目录下也能够找到针对32位和64位的rc文件:
这里不分析init.rc文件的细节,解析init.rc后主要完成了如下几件事情:
经过解析init.rc,从init进程fork出Zygote, 而且指定启动入口在app_main.cpp
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
复制代码
//----Zygote进程入口-----
/frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[]){
//构造AppRuntime
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
argc--;
argv++;
//while循环拼接参数:根据init.rc中的配置,这里zygote=true
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
niceName.setTo(arg + 12);
} else if (strncmp(arg, "--", 2) != 0) {
className.setTo(arg);
break;
} else {
--i;
break;
}
}
//根据前面init.rc指定传入参数,
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.");
}
}
//AndroidRuntime 继承自 AppRuntime
/frameworks/base/core/jni/AndroidRuntime.cpp
AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :
mExitWithoutCleanup(false),
mArgBlockStart(argBlockStart),
mArgBlockLength(argBlockLength)
{
//初始化绘制引擎skia
SkGraphics::Init();
// 虚拟机参数
mOptions.setCapacity(20);
//一个进程gCurRuntime只能初始化一次
assert(gCurRuntime == NULL); // one per process
gCurRuntime = this;
}
void AndroidRuntime::start(const char className, const Vector <String8> & options, bool zygote)
{
...
/* start the virtual machine */
//初始化JNI
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv env;
//启动VM
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
//建立成功调用
onVmCreated(env);
/*
* 注册预约义的JNI
*/
if (startReg(env) < 0) {
return;
}
/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
//入口类
char slashClassName = toSlashClassName(className);
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
} else {
//找到入口方法, ZygoteInit.main()
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
} else {
//Native调用Java,至此进入Java
env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
free(slashClassName);
ALOGD("Shutting down VM\n");
if (mJavaVM->DetachCurrentThread() != JNI_OK)
ALOGW("Warning: unable to detach main thread\n");
if (mJavaVM->DestroyJavaVM() != 0)
ALOGW("Warning: VM did not shut down cleanly\n");
}
复制代码
小结:init经过解析init.rc后fork出Zygote进程,以后Zygote在其main中处理完一堆参数后,初始化出一个AndroidRuntime对象,在构造AndroidRuntime对象时就会初始化Skia绘制引擎,而后调用start建立Dalvik(ART)虚拟机,注册上层须要的JNI函数,找到并调用Java层入口类ZygoteInit.main()。至此,进入了Java世界。
Android Kernel启动过程与大多数系统启动相似,从Boot ROM(PC BIOS)--> BootLoader-->Kernel 自启-->第一个进程(init);只不过android Kernel相比Linux,多了一些Ashmem、Binder驱动之类的,同时须要为构建Android上层环境作准备,所以init在解析init.rc文件的配置过程当中,会启动一些守护服务,同时fork出Zygote进程,Zygote做为链接Kernel与上层世界的桥梁,这里建立处了Dalvik(ART) VM,注册好JNI方法,经过Native调用并加载ZygoteInit.main(),进入了真正的Java世界。
下篇继续分析从ZygoteInit.mai()到Launcher界面的显示。