Android 8.0系統啓動流程_Zygote(二)

本系列主要介紹Android系統啓動過程當中涉及到的init、Zygote、SystemServerLauncher。 文本分析的源碼時基於Android8.0源碼。java

Zygote(孵化器),系統中DVM、ART、應用程序進程和SystemServer進程都是由Zygote建立,其中SystemServer是應用層開發常常碰到的,由於應用層APP的進程是經過SystemServer進程建立出來的。android

1、Zygote啓動腳本

Android 8.0系統啓動流程_init(一)中講解到了init啓動Zygote的過程,init.cpp經過解析init.rc中配置信息,該過程稱之爲Zygote的啓動腳本,其流程包括以下:數組

  1. 引入init.zygote.xx.rc:在Android 8.0系統啓動流程_init(一)中init函數解析部分,講解了init.rc配置文件的五種語法格式,其中包括爲了擴展配置配置文件而引入的import語句,自Android8.0後,init.rc文件被分紅了四種格式,經過import語句引入,以下所示
import /init.${ro.zygote}.rc
複製代碼
  1. 自Android5.0後,開始支持64位程序,經過系統的ro.zygote屬性來控制使用不一樣的Zygote啓動腳本,啓動不一樣的腳本文件(四種中的一種),解析文件中init.zygote.xx.rc中service語句,以下所示:
\system\core\rootdir\init.zygote32.rc
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    ....
    writepid /dev/cpuset/foreground/tasks
複製代碼
\system\core\rootdir\init.zygote32_64.rc
service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    class main
    priority -20
    user root
    group root readproc
    .....
    writepid /dev/cpuset/foreground/tasks

service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
    class main
    priority -20
    user root
    group root readproc
    socket zygote_secondary stream 660 root system
    onrestart restart zygote
    writepid /dev/cpuset/foreground/tasks

複製代碼

以上是init.zygote32.rc、init.zygote32_64.rc的部分源碼,其餘兩種init.zygote64.rc和init.zygote64_32.rc基本相似,腳本文件主要解析以下:bash

  • service:在init.rc經過「service」說明該語句是service,啓動一個service進程;
  • zygote:進程名稱爲zygote;
  • /system/bin:經過應用程序/system/bin/app_process來啓動它,這也驗證了zygote剛開始時不叫zygote,而是app_procress,Zygote進程啓動後,Linux系統將其更改成zygote;
  • --zygote、--start--system--server:啓動Zygote的參數,後續app_main.cpp中main函數中判斷使用;
  • -socket-name=zygote:創建socket的名稱爲zygote;
  • class main:將Zygote聲明爲主要服務,在init啓動Zygote中,ForEachServiceInClass函數就是經過查找classname爲main的Zygote進程;
  • socket xxx:表示須要爲此服務建立一個socket;
  • onrestart xxx:當Zygote服務重啓時,須要執行的命令

2、Zygote進程啓動過程介紹

Zygote進程啓動時序圖
下面經過Zygote進程的時序圖,按照時序運行涉及到的類,來進行分析。

2.1 app_main.cpp

Android 8.0系統啓動流程_init(一)中第四部分講到init啓動Zygote的流程知道最終調用到frameworks\base\cmds\app_process\app_main.cpp下的main方法,以下所示:app

frameworks\base\cmds\app_process\app_main.cpp

int main(int argc, char* const argv[])
{
 while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;//若是當前運行Zygote進程中,則變量zygote設置爲true
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;//若是當前運行SystemServer進程中,則變量startSystemServer 設置爲true
        } else if (strcmp(arg, "--application") == 0) {
            application = true;//當前爲應用的進程,則變量 application設置爲true
        }
 ..
    }
if (zygote) {//若是運行在Zygote中,則啓動該進程
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } 
}
複製代碼

源碼分析以下:socket

  • 判斷當前進程:Zyogte及其子進程都是經過fork自身來建立子進程的,這樣Zygote及其子進程均可以進入app_main.cpp的main函數中,此時須要經過argd的參數來區分是當前運行的是那個進程?在main函數源碼解析中有以下注釋,若是是以「--」或不是以「-」開頭的arg則進入該函數中,以此做爲簡單的判斷。

Everything up to '--' or first non '-' arg goes to the vm. ... // --zygote : Start in zygote mode // --start-system-server : Start the system server. // --application : Start in application (stand alone, non zygote) mode. // --nice-name : The nice name for this process.ide

經過判斷arg中是否包含「--zygote」、「--start-system-server」、「--application」或其餘參數,來判斷當前運行的是那種進程。函數

  • 啓動進程: 若是變量zygote爲true,則會調用以下方法,啓動Zygote進程。
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
複製代碼

2.2 AndroidRuntime.cpp

\frameworks\base\core\jni\AndroidRuntime.cpp
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{
	...
	/* 1 start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    onVmCreated(env);

    /** 2 Register android functions.*/
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }
}
...
//3 獲取類名信息
classNameStr = env->NewStringUTF(className);
...
//4 className的「.」轉爲「/」
char* slashClassName = toSlashClassName(className != NULL ? className : "");
//5 找到ZygoteInit
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
    //6.找到ZygoteInit的main方法
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
        //7. 經過JNI調用ZygoteInit的main方法,因爲當前是在Native中,ZygoteInit是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");
複製代碼

源碼分析:oop

  • 啓動準備:在註釋1和2中,經過startVm建立Java虛擬機和startReg爲Java虛擬機註冊JNI方法;
  • 找到ZygoteInit類:在註釋三、四、5和6將com.android.os.ZygoteInit轉爲com/android/os/ZygoteInit並賦值給slashClassName,經過slashClassName找到ZygoteInit的main方法;
  • 調用ZygoteInit類:找到該類後,經過註釋7的JNI方法調用ZygoteInit的main方法,進入Java層的運行環境中。

2.3 ZygoteInit.java

frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
public static void main(String argv[]) {
	...
	//1.新建一個ZygoteServer對象
	 ZygoteServer zygoteServer = new ZygoteServer();
	...
	//2.建立一個server端的socket,且名稱爲zygote
	zygoteServer.registerServerSocket(socketName);
 
  //3.預加載類和資源
  preload(bootTimingsTraceLog);
	...
	//4.啓動SystemServer進程
	  if (startSystemServer) {
                Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
                // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
                // child (system_server) process.
                if (r != null) {
                    r.run();
                    return;
                }
            }
	 Log.i(TAG, "Accepting command socket connections");

     //5.等待AMS請求
            caller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            throw ex;
        } finally {
            zygoteServer.closeServerSocket();
        }
	
 }
 ...
複製代碼

ZygoteInit的main方法主要作了以下幾件事: 一、建立一個name爲「zygote」的Socket服務端,用於等待AMS的請求Zygote來建立新的進程; 二、預加載類和資源,包括drawable、color、OpenGL和文本鏈接符資源等,保存到Resources一個全局靜態變量中,下次讀取系統資源的時候優先從靜態變量中查找; 三、啓動SystemServer進程; 四、經過runSelectLoop()方法,等待AMS的請求建立新的應用程序進程。源碼分析

1.registerServerSocket

frameworks\base\core\java\com\android\internal\os\ZygoteServer.java
void registerServerSocket(String socketName) {
        if (mServerSocket == null) {
            int fileDesc;
            //1.拼接Socket的名稱
            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
            try {
            //2.獲得Soket的環境變量值:ANDROID_SOCKET_zygote
                String env = System.getenv(fullSocketName);
                fileDesc = Integer.parseInt(env);
            } catch (RuntimeException ex) {
                throw new RuntimeException(fullSocketName + " unset or invalid", ex);
            }

            try {
            //3.經過fileDesc建立文件描述符:fd
                FileDescriptor fd = new FileDescriptor();
                fd.setInt$(fileDesc);
                //4.建立服務端的Socket
                mServerSocket = new LocalServerSocket(fd);
            } catch (IOException ex) {
                throw new RuntimeException(
                        "Error binding to local socket '" + fileDesc + "'", ex);
            }
        }
    }
複製代碼

2.預加載類和資源

frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
 static void preload(TimingsTraceLog bootTimingsTraceLog) {
     ...
     //1.預加載位於/system/etc/preloaded-classes文件中的類
        preloadClasses();
     ...
     2.預加載drawble和color的資源信息
        preloadResources();
      ...
      //3.經過JNI調用,預加載底層相關的資源
        nativePreloadAppProcessHALs();
      ...
      //4.預加載OpenGL資源
        preloadOpenGL();
       ...
       //5.預加載共享庫:"android","compiler_rt","jnigraphics"
        preloadSharedLibraries();
        //6.預加載文本鏈接符資源
        preloadTextResources();
      ...
      //7.zygote中,內存共享進程
        warmUpJcaProviders();
      ...
    }
複製代碼

3.啓動SystemServer進程

frameworks\base\core\java\com\android\internal\os\ZygoteServer.java
 private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
  ...
  //1.建立數組,保存啓動SystemServer的參數
        String args[] = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010",
            "--capabilities=" + capabilities + "," + capabilities,
            "--nice-name=system_server",
            "--runtime-args",
            "com.android.server.SystemServer",
        };
        ZygoteConnection.Arguments parsedArgs = null;

        int pid;

        try {
            parsedArgs = new ZygoteConnection.Arguments(args);
            ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
            ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

            /* Request to fork the system server process */
            //2.建立SystemServer進程
            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 */
        //3.若是pid爲0,表示運行在新的子進程中
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }
            zygoteServer.closeServerSocket();
            //4.處理SystemServer進程
            return handleSystemServerProcess(parsedArgs);
        }
        return null;
    }
複製代碼

4.runSelectLoop()

frameworks\base\core\java\com\android\internal\os\ZygoteServer.java
 /**
     * 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.
     * 運行在Zygote進程中,等待新的鏈接,並讀取請求數據
     */
    Runnable runSelectLoop(String abiList) {
		ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
		//1.將ServerSocket添加到集合中
        fds.add(mServerSocket.getFileDescriptor());
        peers.add(null);
        2.開啓死循環,不斷的等待AMS的請求
          while (true) {
          //3.經過遍歷fds存儲信息,添加至 pollFds數組中
            StructPollfd[] pollFds = new StructPollfd[fds.size()];
            for (int i = 0; i < pollFds.length; ++i) {
                pollFds[i] = new StructPollfd();
                pollFds[i].fd = fds.get(i);
                pollFds[i].events = (short) POLLIN;
            }
            try {
                Os.poll(pollFds, -1);
            } catch (ErrnoException ex) {
                throw new RuntimeException("poll failed", ex);
            }
            //4. 經過遍歷pollFds信息
            for (int i = pollFds.length - 1; i >= 0; --i) {
                if ((pollFds[i].revents & POLLIN) == 0) {
                    continue;
                }
                //5.若是pid爲0,代表已經鏈接socket,
			  if (i == 0) {
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    fds.add(newPeer.getFileDesciptor());
                }else{
                /6.若是不等於0 ,AMS向Zyogte進程建立一個新的進程的請求
						 ZygoteConnection connection = peers.get(i);
                        final Runnable command = connection.processOneCommand(this);
				}
                ... 
	}
複製代碼
相關文章
相關標籤/搜索