转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/19302593java
当长按手机的power键,Android手机就会开机,那么Android系统的开机启动过程究竟是怎么样的呢,本文将要介绍这一过程。简单来讲,Android系统的开机启动过程大体是这样的:首先linux系统会启动一个叫作zygote(能够称为受精卵、母体)的linux程序,这个程序实际上就是android系统的内核,zygote启动的时候会创建socket服务端并加载大量的类和资源。接着zygote会孵化第一个dalvik进程SystemServer,在SystemServer中会建立一个socket客户端,后续AMS(ActivityManagerService)会经过此客户端和zygote通讯,zygote再根据请求孵化出新的dalvik进程即启动一个新的apk同时把新进程的socket链接关闭。SystemServer初始化完毕后会启动一个位于桟顶的activity,因为系统刚开机,因此task桟顶没有activity,因而接着它会发送一个隐式的intent(category:CATEGORY_HOME),也就是launcher了,即Android系统的桌面程序,launcher启动之后,咱们就能够经过桌面启动各类应用了,能够发现,launcher能够有多个,第三方应用只要加入launcher所须要的intent-filter便可。下面一一分析各个流程。(注:本文分析基于Android4.3源码)linux
zygote是一个linux程序,其对应的可执行文件位于/system/bin/app_process,它在/init.rc中定义,以下android
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netdgit
能够发现,zygote建立了一个流式套接字(即采用TCP协议),并监听660端口,而且当zygote重启的时候须要对唤醒电源并重启Media、netd服务。下面看zygote的源码,其路径为frameworks\base\cmds\app_process\app_main.cpp中:app
int main(int argc, char* const argv[]) { #ifdef __arm__ /* * b/7188322 - Temporarily revert to the compat memory layout * to avoid breaking third party apps. * * THIS WILL GO AWAY IN A FUTURE ANDROID RELEASE. * * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=7dbaa466 * changes the kernel mapping from bottom up to top-down. * This breaks some programs which improperly embed * an out of date copy of Android's linker. */ char value[PROPERTY_VALUE_MAX]; property_get("ro.kernel.qemu", value, ""); bool is_qemu = (strcmp(value, "1") == 0); if ((getenv("NO_ADDR_COMPAT_LAYOUT_FIXUP") == NULL) && !is_qemu) { int current = personality(0xFFFFFFFF); if ((current & ADDR_COMPAT_LAYOUT) == 0) { personality(current | ADDR_COMPAT_LAYOUT); setenv("NO_ADDR_COMPAT_LAYOUT_FIXUP", "1", 1); execv("/system/bin/app_process", argv); return -1; } } unsetenv("NO_ADDR_COMPAT_LAYOUT_FIXUP"); #endif // These are global variables in ProcessState.cpp mArgC = argc; mArgV = argv; mArgLen = 0; for (int i=0; i<argc; i++) { mArgLen += strlen(argv[i]) + 1; } mArgLen--; //注意,这里持有了一个AppRuntime对象,其继承自AndroidRuntime AppRuntime runtime; const char* argv0 = argv[0]; // Process command line arguments // ignore argv[0] argc--; argv++; // Everything up to '--' or first non '-' arg goes to the vm int i = runtime.addVmArguments(argc, argv); // Parse runtime arguments. Stop at first unrecognized option. bool zygote = false; bool startSystemServer = false; bool application = false; const char* parentDir = NULL; const char* niceName = NULL; const char* className = NULL; //这里是解析init.rc中定义的zygote的启动参数 while (i < argc) { const char* arg = argv[i++]; if (!parentDir) { parentDir = arg; } else if (strcmp(arg, "--zygote") == 0) { zygote = true; niceName = "zygote"; } 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 = arg + 12; } else { className = arg; break; } } if (niceName && *niceName) { setArgv0(argv0, niceName); set_process_name(niceName); } runtime.mParentDir = parentDir; if (zygote) { //从init.rc中的定义能够看出,zygote为true,startSystemServer也为true //最终这里会调用ZygoteInit的main方法 runtime.start("com.android.internal.os.ZygoteInit", startSystemServer ? "start-system-server" : ""); } else if (className) { // Remainder of args get passed to startup class main() runtime.mClassName = className; runtime.mArgC = argc - i; runtime.mArgV = argv + i; runtime.start("com.android.internal.os.RuntimeInit", application ? "application" : "tool"); } 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; } }
说明:这句代码runtime.start("com.android.internal.os.ZygoteInit", startSystemServer ? "start-system-server" : "")在AndroidRuntime中实现,其最终会调用ZygoteInit的main方法,请看env->CallStaticVoidMethod(startClass, startMeth, strArray);这里的startClass就是com.android.internal.os.ZygoteInit,而startMeth就是main,因此,咱们直接看ZygoteInit的main方法,代码路径为:frameworks\base\core\java\com\android\internal\os\ZygoteInit.java:less
public static void main(String argv[]) { try { // Start profiling the zygote initialization. SamplingProfilerIntegration.start(); //这里注册流式socket,以便于fork新的dalvik进程 registerZygoteSocket(); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, SystemClock.uptimeMillis()); //这里预先加载一些类和资源 preload(); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis()); // Finish profiling the zygote initialization. SamplingProfilerIntegration.writeZygoteSnapshot(); // Do an initial gc to clean up after startup gc(); // Disable tracing so that forked processes do not inherit stale tracing tags from // Zygote. Trace.setTracingEnabled(false); // If requested, start system server directly from Zygote if (argv.length != 2) { throw new RuntimeException(argv[0] + USAGE_STRING); } if (argv[1].equals("start-system-server")) { //启动SystemServer,zygote经过SystemServer和上层服务进行交互 startSystemServer(); } else if (!argv[1].equals("")) { throw new RuntimeException(argv[0] + USAGE_STRING); } Log.i(TAG, "Accepting command socket connections"); //经过Select方式监听端口,即异步读取消息,死循环,没有消息则一直阻塞在那里 runSelectLoop(); closeServerSocket(); } catch (MethodAndArgsCaller caller) { caller.run(); } catch (RuntimeException ex) { Log.e(TAG, "Zygote died with exception", ex); closeServerSocket(); throw ex; } }
下面看一下runSelectLoop方法,看看它是如何fork产生一个新的进程的:异步
/** * Runs the zygote process's select loop. Accepts new connections as * they happen, and reads commands from connections one spawn-request's * worth at a time. * * @throws MethodAndArgsCaller in a child process when a main() should * be executed. */ private static void runSelectLoop() throws MethodAndArgsCaller { ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>(); ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>(); FileDescriptor[] fdArray = new FileDescriptor[4]; fds.add(sServerSocket.getFileDescriptor()); peers.add(null); int loopCount = GC_LOOP_COUNT; //死循环,没有消息则一直阻塞在这里 while (true) { int index; /* * Call gc() before we block in select(). * It's work that has to be done anyway, and it's better * to avoid making every child do it. It will also * madvise() any free memory as a side-effect. * * Don't call it every time, because walking the entire * heap is a lot of overhead to free a few hundred bytes. */ if (loopCount <= 0) { gc(); loopCount = GC_LOOP_COUNT; } else { loopCount--; } try { fdArray = fds.toArray(fdArray); //经过select()函数来读取新的socket消息,其返回值有<0、0、>0三种 //分别表明:发生异常、继续读取新消息、首先处理当前消息 index = selectReadable(fdArray); } catch (IOException ex) { throw new RuntimeException("Error in select()", ex); } if (index < 0) { throw new RuntimeException("Error in select()"); } else if (index == 0) { //构造一个ZygoteConnection对象,并将其加入到peers列表中 ZygoteConnection newPeer = acceptCommandPeer(); peers.add(newPeer); fds.add(newPeer.getFileDesciptor()); } else { boolean done; //这里处理当前socket消息,ZygoteConnection的runOnce会被调用,一个新的dalvik进程会被建立 done = peers.get(index).runOnce(); if (done) { //处理完了之后删除此socket消息 peers.remove(index); fds.remove(index); } } } }
接着,咱们还须要看下ZygoteConnection的runOnce方法,看看一个dalvik进程究竟是如何产生的,咱们知道每一个apk都运行在一个独立的dalvik进程中,因此当启动一个apk的时候,zygote会孵化出一个新的进程,在这个进程中运行此apk。 在ZygoteConnection中,新进程是经过Zygote的静态方法forkAndSpecialize来产生的:socket
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName);ide
具体的咱们就不用多看了,内部确定是经过linux系统的fork()函数来产生一个新进程的。当一个新的dalvik进程产生了之后,还须要作一些清场的工做,因为新进程是由zygote程序fork出来的,因此子进程具备zygote的一份拷贝,咱们知道,zygote启动的时候建立了一个socket服务端,这个服务端只能有一个,由zygote孵化的子进程是不该该有的,因此子进程孵化出来之后,还必须关闭拷贝的socket服务端,这些操做在handleChildProc方法中完成:函数
private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr) throws ZygoteInit.MethodAndArgsCaller { //关闭本地和服务端(若是有)的socket closeSocket(); ZygoteInit.closeServerSocket(); if (descriptors != null) { try { ZygoteInit.reopenStdio(descriptors[0], descriptors[1], descriptors[2]); for (FileDescriptor fd: descriptors) { IoUtils.closeQuietly(fd); } newStderr = System.err; } catch (IOException ex) { Log.e(TAG, "Error reopening stdio", ex); } } if (parsedArgs.niceName != null) { Process.setArgV0(parsedArgs.niceName); } if (parsedArgs.runtimeInit) { if (parsedArgs.invokeWith != null) { WrapperInit.execApplication(parsedArgs.invokeWith, parsedArgs.niceName, parsedArgs.targetSdkVersion, pipeFd, parsedArgs.remainingArgs); } else { RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs); } } else { String className; try { className = parsedArgs.remainingArgs[0]; } catch (ArrayIndexOutOfBoundsException ex) { logAndPrintError(newStderr, "Missing required class name argument", null); return; } String[] mainArgs = new String[parsedArgs.remainingArgs.length - 1]; System.arraycopy(parsedArgs.remainingArgs, 1, mainArgs, 0, mainArgs.length); if (parsedArgs.invokeWith != null) { WrapperInit.execStandalone(parsedArgs.invokeWith, parsedArgs.classpath, className, mainArgs); } else { ClassLoader cloader; if (parsedArgs.classpath != null) { cloader = new PathClassLoader(parsedArgs.classpath, ClassLoader.getSystemClassLoader()); } else { cloader = ClassLoader.getSystemClassLoader(); } try { //这里子进程的main方法被调用,此时,子进程彻底从zygote(母体)上脱离出来了 ZygoteInit.invokeStaticMain(cloader, className, mainArgs); } catch (RuntimeException ex) { logAndPrintError(newStderr, "Error starting.", ex); } } } }
同时在ZygoteInit中会预先加载一些类和资源,具体代码在preload方法中:
static void preload() {SystemServer做为zygote孵化的第一个dalvik进程,其孵化过程在上面已经进行了描述,可是其和普通进程的启动略有不一样,普通进程由Zygote.forkAndSpecialize来启动,而SystemServer由Zygote.forkSystemServer来启动,其次是SystemServer内部多建立了一个socket客户端。关于SystemServer内部的本地socket客户端,本文前面已经说过,外围的Service都是经过SystemServer和zygote交互的,好比要启动一个apk,首先AMS会发起一个新进程的建立请求,在startProcessLocked方法中会调用Process的start方法,其内部会调用startViaZygote方法,而在startViaZygote内部会建立一个本地socket和zygote通讯,咱们要知道,AMS是在SystemServer进程中建立的,因此说在SystemServer中建立一个本地socket和zygote通讯是有道理的。SystemServer的一个很重要的做用是建立各类服务,包括你们常见的WindowManagerService 、AlarmManagerService、ActivityManagerService等,而后上层的各类manager经过binder和service进行交互,关于SystemServer建立各类服务的过程以及和binder的交互,请参考我以前写的一篇博客的其中一节,这里就不重复了:各类Manager和Binder服务的对应关系。
final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) { // Find the first activity that is not finishing. //找到桟顶的activity记录 ActivityRecord next = topRunningActivityLocked(null); // Remember how we'll process this pause/resume situation, and ensure // that the state is reset however we wind up proceeding. final boolean userLeaving = mUserLeaving; mUserLeaving = false; //因为系统刚启动,桟顶确定没有activity,因此next为null if (next == null) { // There are no more activities! Let's just start up the // Launcher... if (mMainStack) { ActivityOptions.abort(options); //程序执行到这里,桌面就会被调起来 return mService.startHomeActivityLocked(mCurrentUser); } } ...此处省略 }
最后看看桌面是如何被调起来的:
boolean startHomeActivityLocked(int userId) { if (mHeadless) { // Added because none of the other calls to ensureBootCompleted seem to fire // when running headless. ensureBootCompleted(); return false; } if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL && mTopAction == null) { // We are running in factory test mode, but unable to find // the factory test app, so just sit around displaying the // error message and don't try to start anything. return false; } Intent intent = new Intent( mTopAction, mTopData != null ? Uri.parse(mTopData) : null); intent.setComponent(mTopComponent); if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { //其实就是为intent加上CATEGORY_HOME这个Category,接着就发送隐式intent来调起全部知足条件的桌面 //这也是第三方桌面存在的价值 intent.addCategory(Intent.CATEGORY_HOME); } ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId); if (aInfo != null) { intent.setComponent(new ComponentName( aInfo.applicationInfo.packageName, aInfo.name)); // Don't do this if the home app is currently being // instrumented. aInfo = new ActivityInfo(aInfo); aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId); ProcessRecord app = getProcessRecordLocked(aInfo.processName, aInfo.applicationInfo.uid); if (app == null || app.instrumentationClass == null) { intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK); //这里启动桌面activity,到此为止,桌面被启动了,咱们就能够认为手机开机完成了 mMainStack.startActivityLocked(null, intent, null, aInfo, null, null, 0, 0, 0, null, 0, null, false, null); } } return true; }
到此为止,桌面已经启动了,也就意味着手机的开机启动过程已经完成,后续咱们就能够经过桌面来启动各个应用了,根据本文的介绍,咱们已经知道apk启动时dalvik进程的建立过程,关于单个activity的启动过程,请参看我以前写的另外一篇文章Android源码分析-Activity的启动过程。到此为止,本文结束了,相信你们对Android系统的开机启动过程应该有了一个感性的认识了。