分享

Android内核解读

 放松神经 2016-08-03

转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/19302593

前言

当长按手机的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源码)

zygote的启动过程

zygote是一个linux程序,其对应的可执行文件位于/system/bin/app_process,它在/init.rc中定义,如下

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 netd

可以发现,zygote创建了一个流式套接字(即采用TCP协议),并监听660端口,并且当zygote重启的时候需要对唤醒电源并重启Media、netd服务。下面看zygote的源码,其路径为frameworks\base\cmds\app_process\app_main.cpp中:

  1. int main(int argc, char* const argv[])  
  2. {  
  3. #ifdef __arm__  
  4.     /* 
  5.      * b/7188322 - Temporarily revert to the compat memory layout 
  6.      * to avoid breaking third party apps. 
  7.      * 
  8.      * THIS WILL GO AWAY IN A FUTURE ANDROID RELEASE. 
  9.      * 
  10.      * http://git./?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=7dbaa466 
  11.      * changes the kernel mapping from bottom up to top-down. 
  12.      * This breaks some programs which improperly embed 
  13.      * an out of date copy of Android's linker. 
  14.      */  
  15.     char value[PROPERTY_VALUE_MAX];  
  16.     property_get("ro.kernel.qemu", value, "");  
  17.     bool is_qemu = (strcmp(value, "1") == 0);  
  18.     if ((getenv("NO_ADDR_COMPAT_LAYOUT_FIXUP") == NULL) && !is_qemu) {  
  19.         int current = personality(0xFFFFFFFF);  
  20.         if ((current & ADDR_COMPAT_LAYOUT) == 0) {  
  21.             personality(current | ADDR_COMPAT_LAYOUT);  
  22.             setenv("NO_ADDR_COMPAT_LAYOUT_FIXUP", "1", 1);  
  23.             execv("/system/bin/app_process", argv);  
  24.             return -1;  
  25.         }  
  26.     }  
  27.     unsetenv("NO_ADDR_COMPAT_LAYOUT_FIXUP");  
  28. #endif  
  29.   
  30.     // These are global variables in ProcessState.cpp  
  31.     mArgC = argc;  
  32.     mArgV = argv;  
  33.   
  34.     mArgLen = 0;  
  35.     for (int i=0; i<argc; i++) {  
  36.         mArgLen += strlen(argv[i]) + 1;  
  37.     }  
  38.     mArgLen--;  
  39.     //注意,这里持有了一个AppRuntime对象,其继承自AndroidRuntime  
  40.     AppRuntime runtime;  
  41.     const char* argv0 = argv[0];  
  42.   
  43.     // Process command line arguments  
  44.     // ignore argv[0]  
  45.     argc--;  
  46.     argv++;  
  47.   
  48.     // Everything up to '--' or first non '-' arg goes to the vm  
  49.   
  50.     int i = runtime.addVmArguments(argc, argv);  
  51.   
  52.     // Parse runtime arguments.  Stop at first unrecognized option.  
  53.     bool zygote = false;  
  54.     bool startSystemServer = false;  
  55.     bool application = false;  
  56.     const char* parentDir = NULL;  
  57.     const char* niceName = NULL;  
  58.     const char* className = NULL;  
  59.     //这里是解析init.rc中定义的zygote的启动参数  
  60.     while (i < argc) {  
  61.         const char* arg = argv[i++];  
  62.         if (!parentDir) {  
  63.             parentDir = arg;  
  64.         } else if (strcmp(arg, "--zygote") == 0) {  
  65.             zygote = true;  
  66.             niceName = "zygote";  
  67.         } else if (strcmp(arg, "--start-system-server") == 0) {  
  68.             startSystemServer = true;  
  69.         } else if (strcmp(arg, "--application") == 0) {  
  70.             application = true;  
  71.         } else if (strncmp(arg, "--nice-name=", 12) == 0) {  
  72.             niceName = arg + 12;  
  73.         } else {  
  74.             className = arg;  
  75.             break;  
  76.         }  
  77.     }  
  78.   
  79.     if (niceName && *niceName) {  
  80.         setArgv0(argv0, niceName);  
  81.         set_process_name(niceName);  
  82.     }  
  83.   
  84.     runtime.mParentDir = parentDir;  
  85.   
  86.     if (zygote) {  
  87.         //从init.rc中的定义可以看出,zygote为true,startSystemServer也为true  
  88.         //最终这里会调用ZygoteInit的main方法  
  89.         runtime.start("com.android.internal.os.ZygoteInit",  
  90.                 startSystemServer ? "start-system-server" : "");  
  91.     } else if (className) {  
  92.         // Remainder of args get passed to startup class main()  
  93.         runtime.mClassName = className;  
  94.         runtime.mArgC = argc - i;  
  95.         runtime.mArgV = argv + i;  
  96.         runtime.start("com.android.internal.os.RuntimeInit",  
  97.                 application ? "application" : "tool");  
  98.     } else {  
  99.         fprintf(stderr, "Error: no class name or --zygote supplied.\n");  
  100.         app_usage();  
  101.         LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");  
  102.         return 10;  
  103.     }  
  104. }  

说明:这句代码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:

  1. public static void main(String argv[]) {  
  2.     try {  
  3.         // Start profiling the zygote initialization.  
  4.         SamplingProfilerIntegration.start();  
  5.         //这里注册流式socket,以便于fork新的dalvik进程  
  6.         registerZygoteSocket();  
  7.         EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,  
  8.             SystemClock.uptimeMillis());  
  9.         //这里预先加载一些类和资源  
  10.         preload();  
  11.         EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,  
  12.             SystemClock.uptimeMillis());  
  13.   
  14.         // Finish profiling the zygote initialization.  
  15.         SamplingProfilerIntegration.writeZygoteSnapshot();  
  16.   
  17.         // Do an initial gc to clean up after startup  
  18.         gc();  
  19.   
  20.         // Disable tracing so that forked processes do not inherit stale tracing tags from  
  21.         // Zygote.  
  22.         Trace.setTracingEnabled(false);  
  23.   
  24.         // If requested, start system server directly from Zygote  
  25.         if (argv.length != 2) {  
  26.             throw new RuntimeException(argv[0] + USAGE_STRING);  
  27.         }  
  28.   
  29.         if (argv[1].equals("start-system-server")) {  
  30.             //启动SystemServer,zygote通过SystemServer和上层服务进行交互  
  31.             startSystemServer();  
  32.         } else if (!argv[1].equals("")) {  
  33.             throw new RuntimeException(argv[0] + USAGE_STRING);  
  34.         }  
  35.   
  36.         Log.i(TAG, "Accepting command socket connections");  
  37.         //通过Select方式监听端口,即异步读取消息,死循环,没有消息则一直阻塞在那里  
  38.         runSelectLoop();  
  39.   
  40.         closeServerSocket();  
  41.     } catch (MethodAndArgsCaller caller) {  
  42.         caller.run();  
  43.     } catch (RuntimeException ex) {  
  44.         Log.e(TAG, "Zygote died with exception", ex);  
  45.         closeServerSocket();  
  46.         throw ex;  
  47.     }  
  48. }  

下面看一下runSelectLoop方法,看看它是如何fork产生一个新的进程的:

  1. /** 
  2.  * Runs the zygote process's select loop. Accepts new connections as 
  3.  * they happen, and reads commands from connections one spawn-request's 
  4.  * worth at a time. 
  5.  * 
  6.  * @throws MethodAndArgsCaller in a child process when a main() should 
  7.  * be executed. 
  8.  */  
  9. private static void runSelectLoop() throws MethodAndArgsCaller {  
  10.     ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();  
  11.     ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();  
  12.     FileDescriptor[] fdArray = new FileDescriptor[4];  
  13.   
  14.     fds.add(sServerSocket.getFileDescriptor());  
  15.     peers.add(null);  
  16.   
  17.     int loopCount = GC_LOOP_COUNT;  
  18.     //死循环,没有消息则一直阻塞在这里  
  19.     while (true) {  
  20.         int index;  
  21.   
  22.         /* 
  23.          * Call gc() before we block in select(). 
  24.          * It's work that has to be done anyway, and it's better 
  25.          * to avoid making every child do it.  It will also 
  26.          * madvise() any free memory as a side-effect. 
  27.          * 
  28.          * Don't call it every time, because walking the entire 
  29.          * heap is a lot of overhead to free a few hundred bytes. 
  30.          */  
  31.         if (loopCount <= 0) {  
  32.             gc();  
  33.             loopCount = GC_LOOP_COUNT;  
  34.         } else {  
  35.             loopCount--;  
  36.         }  
  37.   
  38.   
  39.         try {  
  40.             fdArray = fds.toArray(fdArray);  
  41.             //通过select()函数来读取新的socket消息,其返回值有<0、0、>0三种  
  42.             //分别代表:发生异常、继续读取新消息、首先处理当前消息  
  43.             index = selectReadable(fdArray);  
  44.         } catch (IOException ex) {  
  45.             throw new RuntimeException("Error in select()", ex);  
  46.         }  
  47.   
  48.         if (index < 0) {  
  49.             throw new RuntimeException("Error in select()");  
  50.         } else if (index == 0) {  
  51.             //构造一个ZygoteConnection对象,并将其加入到peers列表中  
  52.             ZygoteConnection newPeer = acceptCommandPeer();  
  53.             peers.add(newPeer);  
  54.             fds.add(newPeer.getFileDesciptor());  
  55.         } else {  
  56.             boolean done;  
  57.             //这里处理当前socket消息,ZygoteConnection的runOnce会被调用,一个新的dalvik进程会被创建  
  58.             done = peers.get(index).runOnce();  
  59.   
  60.             if (done) {  
  61.                 //处理完了以后删除此socket消息  
  62.                 peers.remove(index);  
  63.                 fds.remove(index);  
  64.             }  
  65.         }  
  66.     }  
  67. }  

接着,我们还需要看下ZygoteConnection的runOnce方法,看看一个dalvik进程到底是如何产生的,我们知道每个apk都运行在一个独立的dalvik进程中,所以当启动一个apk的时候,zygote会孵化出一个新的进程,在这个进程中运行此apk。  在ZygoteConnection中,新进程是通过Zygote的静态方法forkAndSpecialize来产生的:

pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName);

具体的我们就不用多看了,内部肯定是通过linux系统的fork()函数来产生一个新进程的。当一个新的dalvik进程产生了以后,还需要做一些清场的工作,由于新进程是由zygote程序fork出来的,所以子进程具有zygote的一份拷贝,我们知道,zygote启动的时候创建了一个socket服务端,这个服务端只能有一个,由zygote孵化的子进程是不应该有的,所以子进程孵化出来以后,还必须关闭拷贝的socket服务端,这些操作在handleChildProc方法中完成:

  1. private void handleChildProc(Arguments parsedArgs,  
  2.         FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)  
  3.         throws ZygoteInit.MethodAndArgsCaller {  
  4.     //关闭本地和服务端(如果有)的socket  
  5.     closeSocket();  
  6.     ZygoteInit.closeServerSocket();  
  7.   
  8.     if (descriptors != null) {  
  9.         try {  
  10.             ZygoteInit.reopenStdio(descriptors[0],  
  11.                     descriptors[1], descriptors[2]);  
  12.   
  13.             for (FileDescriptor fd: descriptors) {  
  14.                 IoUtils.closeQuietly(fd);  
  15.             }  
  16.             newStderr = System.err;  
  17.         } catch (IOException ex) {  
  18.             Log.e(TAG, "Error reopening stdio", ex);  
  19.         }  
  20.     }  
  21.   
  22.     if (parsedArgs.niceName != null) {  
  23.         Process.setArgV0(parsedArgs.niceName);  
  24.     }  
  25.   
  26.     if (parsedArgs.runtimeInit) {  
  27.         if (parsedArgs.invokeWith != null) {  
  28.             WrapperInit.execApplication(parsedArgs.invokeWith,  
  29.                     parsedArgs.niceName, parsedArgs.targetSdkVersion,  
  30.                     pipeFd, parsedArgs.remainingArgs);  
  31.         } else {  
  32.             RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,  
  33.                     parsedArgs.remainingArgs);  
  34.         }  
  35.     } else {  
  36.         String className;  
  37.         try {  
  38.             className = parsedArgs.remainingArgs[0];  
  39.         } catch (ArrayIndexOutOfBoundsException ex) {  
  40.             logAndPrintError(newStderr,  
  41.                     "Missing required class name argument", null);  
  42.             return;  
  43.         }  
  44.   
  45.         String[] mainArgs = new String[parsedArgs.remainingArgs.length - 1];  
  46.         System.arraycopy(parsedArgs.remainingArgs, 1,  
  47.                 mainArgs, 0, mainArgs.length);  
  48.   
  49.         if (parsedArgs.invokeWith != null) {  
  50.             WrapperInit.execStandalone(parsedArgs.invokeWith,  
  51.                     parsedArgs.classpath, className, mainArgs);  
  52.         } else {  
  53.             ClassLoader cloader;  
  54.             if (parsedArgs.classpath != null) {  
  55.                 cloader = new PathClassLoader(parsedArgs.classpath,  
  56.                         ClassLoader.getSystemClassLoader());  
  57.             } else {  
  58.                 cloader = ClassLoader.getSystemClassLoader();  
  59.             }  
  60.   
  61.             try {  
  62.                 //这里子进程的main方法被调用,此时,子进程完全从zygote(母体)上脱离出来了  
  63.                 ZygoteInit.invokeStaticMain(cloader, className, mainArgs);  
  64.             } catch (RuntimeException ex) {  
  65.                 logAndPrintError(newStderr, "Error starting.", ex);  
  66.             }  
  67.         }  
  68.     }  
  69. }  

同时在ZygoteInit中会预先加载一些类和资源,具体代码在preload方法中:

    static void preload() {
        preloadClasses();
        preloadResources();
    }

SystemServer的创建

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服务的对应关系

系统桌面的启动

 当SystemServer创建各种服务完毕后,其中的一个服务ActivityManagerService由于也创建完成,所以其事件回调方法systemReady会被调用,这个方法很长,注意到在这个方法的倒数第二句是mMainStack.resumeTopActivityLocked(null),它的意思是将桟顶的activity复位,看它的代码
  1. final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {  
  2.     // Find the first activity that is not finishing.  
  3.     //找到桟顶的activity记录  
  4.     ActivityRecord next = topRunningActivityLocked(null);  
  5.   
  6.     // Remember how we'll process this pause/resume situation, and ensure  
  7.     // that the state is reset however we wind up proceeding.  
  8.     final boolean userLeaving = mUserLeaving;  
  9.     mUserLeaving = false;  
  10.     //由于系统刚启动,桟顶肯定没有activity,所以next为null  
  11.     if (next == null) {  
  12.         // There are no more activities!  Let's just start up the  
  13.         // Launcher...  
  14.         if (mMainStack) {  
  15.             ActivityOptions.abort(options);  
  16.             //程序执行到这里,桌面就会被调起来  
  17.             return mService.startHomeActivityLocked(mCurrentUser);  
  18.         }  
  19.     }  
  20.     ...此处省略  
  21. }  

最后看看桌面是如何被调起来的:

  1. boolean startHomeActivityLocked(int userId) {  
  2.     if (mHeadless) {  
  3.         // Added because none of the other calls to ensureBootCompleted seem to fire  
  4.         // when running headless.  
  5.         ensureBootCompleted();  
  6.         return false;  
  7.     }  
  8.   
  9.     if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL  
  10.             && mTopAction == null) {  
  11.         // We are running in factory test mode, but unable to find  
  12.         // the factory test app, so just sit around displaying the  
  13.         // error message and don't try to start anything.  
  14.         return false;  
  15.     }  
  16.     Intent intent = new Intent(  
  17.         mTopAction,  
  18.         mTopData != null ? Uri.parse(mTopData) : null);  
  19.     intent.setComponent(mTopComponent);  
  20.     if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {  
  21.         //其实就是为intent加上CATEGORY_HOME这个Category,接着就发送隐式intent来调起所有满足条件的桌面  
  22.         //这也是第三方桌面存在的价值  
  23.         intent.addCategory(Intent.CATEGORY_HOME);  
  24.     }  
  25.     ActivityInfo aInfo =  
  26.         resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);  
  27.     if (aInfo != null) {  
  28.         intent.setComponent(new ComponentName(  
  29.                 aInfo.applicationInfo.packageName, aInfo.name));  
  30.         // Don't do this if the home app is currently being  
  31.         // instrumented.  
  32.         aInfo = new ActivityInfo(aInfo);  
  33.         aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);  
  34.         ProcessRecord app = getProcessRecordLocked(aInfo.processName,  
  35.                 aInfo.applicationInfo.uid);  
  36.         if (app == null || app.instrumentationClass == null) {  
  37.             intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);  
  38.             //这里启动桌面activity,到此为止,桌面被启动了,我们就可以认为手机开机完成了  
  39.             mMainStack.startActivityLocked(null, intent, null, aInfo,  
  40.                     null, null, 0, 0, 0, null, 0, null, false, null);  
  41.         }  
  42.     }  
  43.   
  44.     return true;  
  45. }  

到此为止,桌面已经启动了,也就意味着手机的开机启动过程已经完成,后续我们就可以通过桌面来启动各个应用了,根据本文的介绍,我们已经知道apk启动时dalvik进程的创建过程,关于单个activity的启动过程,请参看我之前写的另一篇文章Android源码分析-Activity的启动过程。到此为止,本文结束了,相信大家对Android系统的开机启动过程应该有了一个感性的认识了。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多