編輯:關於Android編程
zygote本身是一個Linux的Native應用程序,當init進程啟動完畢之後,通過init.rc文件啟動zygote並修改進程名字為zygote(frameworks/base/cmds/app_process/app_main.cpp文件)。它是一個deamon進程,啟動VM,加載class和resource等。之後唯一的任務就是監聽socket(/dev/socket/zygote這個是用來監聽的socket)並啟動application,所有APP的父進程皆為zygote進程。
zygote從”/dev/socket/zygote”監聽到APP啟動的請求之後,最終會fork()一個子進程。我們知道fork()會完全復制父進程(clone)到另外的一個用戶空間。當zygote進行fork之後,還需要創建新的Dalvik VM,還需要preload那些APP需要的class和resource。看起來像是zygote每次啟動一個APP的時候都要重新復制整塊的內存並重新加載class和resouce,但其實不然,這是因為Linux內核實現的Copy-On-Write(COW)。有Copy-On-Write,意味著在fork復制內存操作中,沒有內存是會被馬上拷貝的。而是在進程在改寫這段內存的時候,kernel會中斷這種寫操作並先做之前沒有做的復制操作。在zygote進行preload的class和resource都是只讀的文件,所以在啟動APP和運行APP的過程中,沒有class和resource是會被復制到另外的內存的,而是所有的APP都在用同一份class和resource,也就是zygote啟動的時候加載的那些。
1.設置init.xx.rc啟動運行相關service
//system/core/rootdir/init.zygotexx.rc //xx是64或者32,看平台 service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server class main socket zygote stream 660 root system //設置zygote相關的socket名字,權限等。會生成/dev/socket/zygote節點,權限如下: //srw-rw---- root system 2012-01-28 13:39 zygote onrestart write /sys/android_power/request_state wake //?? onrestart write /sys/power/state on //?? onrestart restart media onrestart restart netd onrestart restart loc_launcher
2.init進程讀到上面的service之後,會跑到/frameworks/base/cmds/app_process/app_main.cpp文件的main函數,並傳入參數。main函數主要做以下幾件事情
1)修改當前進程名字為zygote
if (!niceName.isEmpty()) { runtime.setArgv0(niceName.string()); set_process_name(niceName.string()); } //通過這個最終用prctl()系統調用修改當前進程的名字為zygo
2)調用AppRuntime.start函數!! 下面會繼續分析AppRuntime.start函數
AppRuntime.start函數做如下一些事情
1) startVm()初始化DVM
2) startReg()注冊JNI函數
3)
char* slashClassName = toSlashClassName(className); jclass startClass = env->FindClass(slashClassName); jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V"); env->CallStaticVoidMethod(startClass, startMeth, strArray) //加載"com.android.internal.os.ZygoteInit"類並調用其main函數。 //第一個java函數調用開始了~~
ZygoteInit.main函數主要做以下幾件事情
1.調用registerZygoteSocket函數創建了一個socket接口,用來和ActivityManagerService通訊
boolean startSystemServer = false; String socketName = "zygote"; registerZygoteSocket(socketName);
registerZygoteSocket()函數如下:
private static void registerZygoteSocket(String socketName) { if (sServerSocket == null) { int fileDesc; final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName; try { String env = System.getenv(fullSocketName); fileDesc = Integer.parseInt(env); } catch (RuntimeException ex) { throw new RuntimeException(fullSocketName + " unset or invalid", ex); } try { sServerSocket = new LocalServerSocket( createFileDescriptor(fileDesc)); } catch (IOException ex) { throw new RuntimeException( "Error binding to local socket '" + fileDesc + "'", ex); } } }
可以看到registerZygoteSocket()函數通過叫fullSocketName的環境變量得到env並轉換為文件描述符。
這個環境變量的名字可以從上面的函數中知道是”ANDROID_SOCKET_zygote”。這個環境變量是在哪裡設置的呢?
我們知道,系統啟動腳本文件system/core/rootdir/init.rc是由init進程來解釋執行的,而init進程的源代碼位於system/core/init目錄中,在init.c文件中,是由service_start函數來解釋init.rc文件中的service命令的。每一個service命令都會促使init進程調用fork函數來創建一個新的進程,在新的進程裡面,會分析裡面的socket選項,對於每一個socket選項,都會通過create_socket函數來在/dev/socket目錄下創建一個文件,在這個場景中,這個文件便是zygote了,然後得到的文件描述符通過publish_socket函數寫入到環境變量中去。publish_socke()函數中可以看到是如何設置環境變量的。
static void publish_socket(const char *name, int fd) { char key[64] = ANDROID_SOCKET_ENV_PREFIX; char val[64]; strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1, name, sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX)); snprintf(val, sizeof(val), "%d", fd); add_environment(key, val); /* make sure we don't close-on-exec */ fcntl(fd, F_SETFD, 0); }
因此,這裡就把上面得到的文件描述符寫入到以”ANDROID_SOCKET_zygote”為key值的環境變量中。又因為上面的ZygoteInit.registerZygoteSocket函數與這裡創建socket文件的create_socket函數是運行在同一個進程中,因此,上面的ZygoteInit.registerZygoteSocket函數可以直接使用這個文件描述符來創建一個Java層的LocalServerSocket對象。如果其它進程也需要打開這個/dev/socket/zygote文件來和Zygote進程進行通信,那就必須要通過文件名來連接這個LocalServerSocket了
2.預加載
static void preload() { Log.d(TAG, "begin preload"); preloadClasses(); preloadResources(); preloadOpenGL(); preloadSharedLibraries(); // Ask the WebViewFactory to do any initialization that must run in the zygote process, // for memory sharing purposes. WebViewFactory.prepareWebViewInZygote(); Log.d(TAG, "end preload"); }
3.調用startSystemServer函數來啟動SystemServer組件
private static boolean startSystemServer(String abiList, String socketName) throws MethodAndArgsCaller, RuntimeException { long capabilities = posixCapabilitiesAsBits( OsConstants.CAP_BLOCK_SUSPEND, OsConstants.CAP_KILL, OsConstants.CAP_NET_ADMIN, OsConstants.CAP_NET_BIND_SERVICE, OsConstants.CAP_NET_BROADCAST, OsConstants.CAP_NET_RAW, OsConstants.CAP_SYS_MODULE, OsConstants.CAP_SYS_NICE, OsConstants.CAP_SYS_RESOURCE, OsConstants.CAP_SYS_TIME, OsConstants.CAP_SYS_TTY_CONFIG ); /* Hardcoded command line to start the system server */ String args[] = {//SystemServer進程的uid,gid等等,,很多參數設置,需要仔細看看 "--setuid=1000", "--setgid=1000", //WTL_EDM_START // "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007", //Adds system to net_raw and net_admin (3004, 3005) //groups, so that system can use iptables. "-- setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3004,3005,3006,3007", //WTL_EDM_END "--capabilities=" + capabilities + "," + capabilities, "--runtime-init", "--nice-name=system_server", "com.android.server.SystemServer", }; ZygoteConnection.Arguments parsedArgs = null; int pid; try { //按照上面的參數賦值給parsedArgs parsedArgs = new ZygoteConnection.Arguments(args); ZygoteConnection.applyDebuggerSystemProperty(parsedArgs); ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs); //fork出來一個SystemServer進程 /* Request to fork the system server process */ pid = Zygote.forkSystemServer( parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, null, parsedArgs.permittedCapabilities, parsedArgs.effectiveCapabilities); } catch (IllegalArgumentException ex) { throw new RuntimeException(ex); } /* For child process */ if (pid == 0) { if (hasSecondZygote(abiList)) { waitForSecondaryZygote(socketName); } //SystemServer進程跑到這裡,開始跑handleSystemServerProcess()。 handleSystemServerProcess(parsedArgs); } return true; }
private static void handleSystemServerProcess( ZygoteConnection.Arguments parsedArgs) throws ZygoteInit.MethodAndArgsCaller { closeServerSocket(); // set umask to 0077 so new files and directories will default to owner-only permissions. Os.umask(S_IRWXG | S_IRWXO); if (parsedArgs.niceName != null) { Process.setArgV0(parsedArgs.niceName); } final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH"); if (systemServerClasspath != null) { performSystemServerDexOpt(systemServerClasspath); } if (parsedArgs.invokeWith != null) { String[] args = parsedArgs.remainingArgs; // If we have a non-null system server class path, we'll have to duplicate the // existing arguments and append the classpath to it. ART will handle the classpath // correctly when we exec a new process. if (systemServerClasspath != null) { String[] amendedArgs = new String[args.length + 2]; amendedArgs[0] = "-cp"; amendedArgs[1] = systemServerClasspath; System.arraycopy(parsedArgs.remainingArgs, 0, amendedArgs, 2, parsedArgs.remainingArgs.length); } WrapperInit.execApplication(parsedArgs.invokeWith, parsedArgs.niceName, parsedArgs.targetSdkVersion, null, args); } else { ClassLoader cl = null; if (systemServerClasspath != null) { cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader()); Thread.currentThread().setContextClassLoader(cl); } /* * Pass the remaining arguments to SystemServer. */ RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl); } /* should never reach here */ }
這裡重點是RuntimeInit.zygoteInit()函數
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller { if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote"); redirectLogStreams(); commonInit(); nativeZygoteInit(); applicationInit(targetSdkVersion, argv, classLoader); }
這個函數都是做一些初始化工作,其中nativeZygoteInit最終會調用到app_main.cpp中的onZygoteInit。
virtual void onZygoteInit() { // Re-enable tracing now that we're no longer in Zygote. atrace_set_tracing_enabled(true); spproc = ProcessState::self(); ALOGV("App process: starting thread pool.\n"); proc->startThreadPool(); }
applicationInit函數中的invokeStaticMain(args.startClass, args.startArgs, classLoader)最終會調用SystemServer.java中的main函數。ZygoteInit.java的startSystemServer()函數中,args參數的最後一個就是 “com.android.server.SystemServer”,所以最後調用的就是這個庫的main函數。
/** * The main entry point from zygote. * */ public static void main(String[] args) { new SystemServer().run(); }
這裡看到SystemServer啟動,但具體內容很多,需要後面再進行分析。
4.調用runSelectLoopMode函數進入一個無限循環在前面創建的socket接口上等待ActivityManagerService請求創建新的應用程序進程。
runSelectLoop()->ZygoteConnection.runOnce()函數負責接收command並啟動APP /*runSelectLoop()函數中,GC_LOOP_COUNT表示跑起來幾個APP之後調用一次gc()清理內存。 如果內存較小,可以適當調整這個值?*/
從這裡可以再進一步看看ActivityManagerService是怎麼組織參數發給zygote來啟動一個參數的。
這裡也涉及到安全等,需要仔細檢查一下。
//安全相關的 applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext); applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext); applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext); applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext); //需要設置的uid,gid等,, pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,parsedArgs.category, parsedArgs.accessInfo, parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet, parsedArgs.appDataDir);
至此,zygote進程的啟動分析就結束了,它會一直循環在這裡,等待其他進程請求它孵化出新的進程。
版本:1.0日期:2014.5.17 2014.6.1版權:© 2014 kince 轉載注明出處 在介紹SwitchButton之前,先來看一下系統Butt
這篇文章主要是練習了安卓listview的arrayadapter和baseadapter的簡單填充。1.arrayadapter填充布局: 代碼: pa
文本和輸入 使用文字服務添加便利功能,例如復制/粘貼和拼寫檢查到您的應用程序。您也可以開發自己的文字服務,提供自定義的輸入法,字典和拼寫檢查,你可以分發給用戶為應用程序。
最新消息,距離Nexus Player、SHIELD TV等少數Android TV電視發布近兩年後,Google終於推出了面向iOS平台的An