国外作品集网站,郑州seo网络推广,石家庄官网设计及搭建,wordpress h5制作插件Android系统启动系列 Android系统启动系列----init进程Android系统启动系列----Zygote进程引言 在开发app的过程中#xff0c;是不是会有疑问#xff1a; java程序的运行不是从main方法开始么#xff0c;怎么app入口是Application的onCreate方法#xff1f;那java的运行环境… Android系统启动系列 Android系统启动系列----init进程Android系统启动系列----Zygote进程引言 在开发app的过程中是不是会有疑问 java程序的运行不是从main方法开始么怎么app入口是Application的onCreate方法那java的运行环境虚拟机Dalvik VM和ART又是什么时候创建的又是由谁创建的安卓是Linux内核那内核创建后系统又做了什么初始化了整个安卓环境当我们的手机或者安卓系统设备按下电源按键的时候系统都做什么当按下电源的那一刻都发生了啥 今天的分析都是基于Android 6.0系统的分析。 第一步启动电源 当电源按下引导芯片代码开始从预定义的地方固化在ROM开始执行。加载引导程序到RAM然后执行。 第二步执行引导程序Boot Loader 通常在运行Android系统之前会先执行Boot Loader引导程序它不属于Android系统常见的引导程序有redboot、uboot、qi bootloader等等。或者自行开发引导程序它是针对特定主板和芯片的OEM制造厂商或者运营商在加锁的时候就对这个引导程序做修改比如魅族就是修改了引导程序所以刷不了机。 第三步内核 Android内核与桌面linux内核启动的方式差不多。内核启动时设置缓存、被保护存储器、计划列表加载驱动。当内核完成系统设置它首先在系统文件中寻找”init”文件然后启动root进程或者系统的第一个进程。 第四步执行init进程 init进程是Android系统启动的第一个用户空间进程init进程主要做两个事情。第一挂载目录如挂载了/sys /dev /proc 等目录。第二解析执行init.rc脚本文件。 系统编译刷入手机后init的进程保存在/system/core/bin目录中对应程序的源代码入口是/system/core/init/init.cpp。 int main(int argc, char** argv) {if (!is_first_stage) {// Indicate that booting is in progress to background fw loaders, etc.close(open(/dev/.booting, O_WRONLY | O_CREAT | O_CLOEXEC, 0000));// 初始化属性服务property_init();// If arguments are passed both on the command line and in DT,// properties set in DT always have priority over the command-line ones.process_kernel_dt();process_kernel_cmdline();// Propogate the kernel variables to internal variables// used by init as well as the current required properties.export_kernel_boot_props();}........// 开始属性服务start_property_service();// 初始化“init.rc”配置文件解析器init_parse_config_file(/init.rc);action_for_each_trigger(early-init, action_add_queue_tail);........
}
复制代码主要看init.rc脚本文件的解析在说解析前先来了解下配置脚本的内容这是一个内建的脚本语言也叫Android初始化语言有自己的语法结构大概介绍下 Android初始化语言由四大类型的声明组成即Actions动作、Commands命令、Services服务、以及Options选项。 Action动作动作是以命令流程命名的有一个触发器决定动作是否发生。 on early-init# Set init and its forked childrens oom_adj.write /proc/1/oom_score_adj -1000# Set the security context of /adb_keys if present.restorecon /adb_keysstart ueventdon initsysclktz 0# Backward compatibility.symlink /system/etc /etcsymlink /sys/kernel/debug /d# Link /vendor to /system/vendor for devices without a vendor partition.symlink /system/vendor /vendor# Create cgroup mount point for cpu accountingmkdir /acctmount cgroup none /acct cpuacctmkdir /acct/uid
复制代码以上脚本中on early-init、on init就是 Action类型的语句语法格式为 on trigger [ trigger]* //设置触发器 command command //动作触发之后要执行的命令
复制代码Service服务服务是init进程启动的程序、当服务退出时init进程会视情况重启服务语法格式为 service name pathname [ argument ]* //service的名字执行程序路径传递参数 option //option是service的修饰词影响什么时候、如何启动services option ...
复制代码下面是默认的init.rc文件主要的事件及其服务。 Action/Service描述on early-init设置init进程以及它创建的子进程的优先级设置init进程的安全环境on init设置全局环境为cpu accounting创建cgroup(资源控制)挂载点on fs挂载mtd分区on post-fs改变系统目录的访问权限on post-fs-data改变/data目录以及它的子目录的访问权限on-boot基本网络的初始化内存管理等等service servicemanager启动系统管理器管理所有的本地服务比如位置、音频、Shared preference等等…service zygote启动zygote进程通常在这个阶段我们可以在屏幕上看到“Android logo”字样或者图标。 我们重点来看看zygote进程相关的属性配置它是独立的一个rc文件在/system/core/rootdir/init.zygote32.rc service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-serverclass mainsocket zygote stream 660 root systemonrestart write /sys/android_power/request_state wakeonrestart write /sys/power/state ononrestart restart mediaonrestart restart netdwritepid /dev/cpuset/foreground/tasks
复制代码执行zygote程序其实是通过执行app_process程序然后传入xzygote等等参数实现的。先找到app_process程序的源码所在地/frameworks/base/cmds/app_process/app_main.cpp 直接看程序的main函数 int main(int argc, char* const argv[])
{if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) 0) {// Older kernels dont understand PR_SET_NO_NEW_PRIVS and return// EINVAL. Dont die on such kernels.if (errno ! EINVAL) {LOG_ALWAYS_FATAL(PR_SET_NO_NEW_PRIVS failed: %s, strerror(errno));return 12;}}AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));// Process command line arguments// ignore argv[0]argc--;argv;int i;for (i 0; i argc; i) {if (argv[i][0] ! -) {break;}if (argv[i][1] - argv[i][2] 0) {i; // Skip --.break;}runtime.addOption(strdup(argv[i]));}// Parse runtime arguments. Stop at first unrecognized option.bool zygote false;bool startSystemServer false;bool application false;String8 niceName;String8 className;i; // Skip unused parent dir argument.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;}}VectorString8 args;if (!className.isEmpty()) {args.add(application ? String8(application) : String8(tool));runtime.setClassNameAndArgs(className, argc - i, argv i);} else {// Were in zygote mode.maybeCreateDalvikCache();if (startSystemServer) {args.add(String8(start-system-server));}char prop[PROP_VALUE_MAX];if (property_get(ABI_LIST_PROPERTY, prop, NULL) 0) {LOG_ALWAYS_FATAL(app_process: Unable to determine ABI list from property %s.,ABI_LIST_PROPERTY);return 11;}String8 abiFlag(--abi-list);abiFlag.append(prop);args.add(abiFlag);// In zygote mode, pass all remaining arguments to the zygote// main() method.for (; i argc; i) {args.add(String8(argv[i]));}}if (!niceName.isEmpty()) {runtime.setArgv0(niceName.string());set_process_name(niceName.string());}// 如果参数是--zygote那么runtime.start执行zygote进程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.);return 10;}
}
复制代码上面就是通过app_process进程启动zygote进程的入口执行启动zygote的程序的在java层的/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java接下来我们看看runtime.start(com.android.internal.os.ZygoteInit, args, zygote)都干了啥。 runtime是AppRuntime类的对象start函数在其父类AndroidRuntime中声明和实现。AndroidRuntime是不是很熟悉了Android的运行时通常app异常的时候这玩意是不是总伴随你左右。原来这玩意这么早就启动在监控系统的一举一动了。 /** Start the Android runtime. This involves starting the virtual machine* and calling the static void main(String[] args) method in the class* named by className.** Passes the main function two arguments, the class name and the specified* options string.*/
void AndroidRuntime::start(const char* className, const VectorString8 options, bool zygote)
{....../* start the virtual machine */JniInvocation jni_invocation;jni_invocation.Init(NULL);JNIEnv* env;if (startVm(mJavaVM, env, zygote) ! 0) { // 1return;}onVmCreated(env); // 2/** Register android functions.*/if (startReg(env) 0) {ALOGE(Unable to register all android natives\n);return;}/** We want to call main() with a String array with arguments in it.* At present we have two arguments, the class name and an option string.* Create an array to hold them.*/jclass stringClass;jobjectArray strArray;jstring classNameStr;stringClass env-FindClass(java/lang/String);assert(stringClass ! NULL);strArray env-NewObjectArray(options.size() 1, stringClass, NULL);assert(strArray ! NULL);classNameStr env-NewStringUTF(className);assert(classNameStr ! NULL);env-SetObjectArrayElement(strArray, 0, classNameStr); for (size_t i 0; i options.size(); i) {jstring optionsStr env-NewStringUTF(options.itemAt(i).string());assert(optionsStr ! NULL);env-SetObjectArrayElement(strArray, i 1, optionsStr);}/** 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); // 3if (startClass NULL) {ALOGE(JavaVM unable to locate class %s\n, slashClassName);/* keep going */} else {jmethodID startMeth env-GetStaticMethodID(startClass, main,([Ljava/lang/String;)V); // 4if (startMeth NULL) {ALOGE(JavaVM unable to find main() in %s\n, className);/* keep going */} else {env-CallStaticVoidMethod(startClass, startMeth, strArray); // 5#if 0if (env-ExceptionCheck())threadExitUncaughtException(env);
#endif}}......
}
复制代码注释1startVm顾名思义启动虚拟机在此启动java虚拟机当然这个是运行zygote进程的虚拟机也就回答了文章最开始引言问题虚拟机由app_process的AndroidRuntime创建。注释2虚拟机创建后的回调处理主要是创建一些资源。注释3className就是app_process中传入的参数“com.android.internal.os.ZygoteInit”因为ZygoteInit是java层的所以需要使用jni来找到ZygoteInit.classstartClass就是ZygoteInit.class注释4通过jni的GetStaticMethodID函数获取到ZygoteInit.java的静态main方法的类似于反射的Mehod对象引用。注释5最后通过JNI的CallStaticVoidMethod函数类似于java反射的invoke方法调用了4中获取的main方法的Method引用。 如果对JNI不熟的可以看看JNI系列入门文章如上就是Zygote进程的启动方式。 总结 手机按下电源后加载引导程序到内存中。执行引导程序启动内核设置缓存、被保护存储器、计划列表加载驱动查找/system/core/bin中init程序文件。启动init程序挂载/sys /dev /proc等等目录加载和解析init.rc脚本。在加载init.rc脚本的时候启动app_process进程。在app_process进程中根据init.zygote32.rc脚本配置的参数启动zygote进程。最终zygote进程的执行即ZygoteInit.java文件main方法的执行是由AndroidRuntime通过JNI的方式调用main方法执行的。在这之前启动了Dalvik VM或者ART虚拟机。 Android系统启动系列 Android系统启动系列----init进程Android系统启动系列----Zygote进程