Android應用程序啓動過程(一)——進程建立

app進程建立

在這張簡圖中能夠看到,從Launcher點擊圖標啓動進程涉及到了3個角色。 其中Launcher是發起請求進程(caller),AMS接收到Launcher的請求並處理,若是要啓動的Activity的進程不存在,則經過本地套接字鏈接到Zygote,向Zygote發起建立進程的請求。Zygote接收該請求並fork出app進程。java

整個過程涉及到的細節比較多,咱們這裏只關注核心部分,分紅幾個小節來講。linux

1. Zygote

Zygote是android系統中的一個重要的守護進程,它的主要做用是:
① 建立VM實例、預加載類和資源等。
② 啓動systemserver。
③ 建立本地套接字,等待AMS的fork請求,完成app進程的建立工做。android

下面咱們簡單看下它的源碼:數據結構

// frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, const char* const argv[])
{
    AppRuntime runtime;
    ...
    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", 
                     startSystemServer ? "start-system-server" : "");
    }
    ...
}

AppRuntime的start()函數繼承自基類AndroidRuntime,即上述代碼將跳到app

// frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const char* options) {
    ...
    JNIEnv* env;
    // 啓動虛擬機
    if (startVm(&mJavaVM, &env) != 0) {
        return;
    }
    // 註冊android須要的jni函數
    if (startReg(env) < 0) {
        LOGE("Unable to register all android natives\n");
        return;
    }
    ...
    // className是com.android.internal.os.ZygoteInit
    char* slashClassName = toSlashClassName(className);
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        LOGE("JavaVM unable to locate class '%s'\n", slashClassName);
    } else {
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            LOGE("JavaVM unable to find main() in '%s'\n", className);
        } else {
            // 調用ZygoteInit的main(String[])方法
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
        }
    }
    free(slashClassName);
    ...
}

好了,到這一步,虛擬機已經啓動起來了,開始加載並運行主類(ZygoteInit)的main()函數了。socket

// frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
    try {
        // 建立本地套接字
        registerZygoteSocket();
        // 預加載類和資源等
        preload();
        ...
        if (argv[1].equals("start-system-server")) {
            // 啓動system server進程
            startSystemServer();
        } else if (!argv[1].equals("")) {
            throw new RuntimeException(argv[0] + USAGE_STRING);
        }
        ...
        // 建立一個本地套接字,等待客戶端的請求
        runSelectLoopMode();
        closeServerSocket();
    } catch (MethodAndArgsCaller caller) {
        // fork()出來的子進程最終會走到這
        // 在這個裏面經過反射調用對應主類(即ActivityThread)的main()方法
        caller.run();
    } catch (RuntimeException ex) {
        closeServerSocket();
        throw ex;
    }
}
private static void runSelectLoopMode() throws MethodAndArgsCaller {
    // fds--peers 每一項是一一對應的,即<文件描述符,已創建的鏈接>構成一個二元組
    ArrayList<FileDescriptor> fds = new ArrayList();
    ArrayList<ZygoteConnection> peers = new ArrayList();
    FileDescriptor[] fdArray = new FileDescriptor[4];

    // 第一個二元組是<socket監聽描述符,null>
    fds.add(sServerSocket.getFileDescriptor());
    peers.add(null);

    while (true) {
        ...
        try {
            fdArray = fds.toArray(fdArray);
            // native方法,使用了select io多路複用機制
            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) { 
            // index爲0的是socket監聽描述符,selectReadable()返回0表示來了個新鏈接
            ZygoteConnection newPeer = acceptCommandPeer();
            // 將創建好的新鏈接的二元組添加到集合中
            peers.add(newPeer);
            fds.add(newPeer.getFileDesciptor());
        } else {
            // index>0表示已鏈接描述符有收到數據了
            boolean done;
            // 讓對應的鏈接來處理數據
            done = peers.get(index).runOnce();

            if (done) {
                peers.remove(index);
                fds.remove(index);
            }
        }
    }
}

到這一步,Zygote的大致啓動流程咱們已經分析完了。關於Zygote如何建立app進程,咱們放到後面AMS那塊再說。函數

2. AMS

ActivityManagerService,簡稱AMS。見名知意,它是用來管理Activity的系統服務。就像linux內核使用task_struct來管理進程同樣,AMS要管理Activity,它確定須要用某種數據結構來記錄當前系統上Activity的信息。oop

  • ActivityRecord 記錄每一個Activity的運行時信息
final class ActivityRecord extends IApplicationToken.Stub {
    final ActivityManagerService service;
    // 從AndroidManifest.xml解析出來的關於Activity的信息
    final ActivityInfo info;
    // 觸發生成這個ActivityRecord的Intent
    final Intent intent;
    // 當前activity所屬的任務棧
    TaskRecord task;
    // 當前Activity所屬進程的信息
    ProcessRecord app;
    ...
}
  • ProcessRecord 記錄當前正在運行的某個進程的完整信息
class ProcessRecord {
    // 進程名和進程id
    final String processName;
    int pid;
    // AMS經過該Binder接口向app進程發請求
    IApplicationThread thread;
    ...
}

Launcher向AMS發起startActivity請求後,AMS會作一系列處理,這裏咱們只關心下面2個要點:
① AMS會建立一個ActivityRecord對象來記錄該Activity的信息。
② 若是進程不存在,即對應的ProcessRecord對象不存在,則建立ProcessRecord來記錄要新建的進程的信息,並向Zygote請求建立新進程。進程建立成功後,在ProcessRecord中記錄下Zygote返回新進程的pid。ui

// frameworks/base/services/java/com/android/server/am/ActivityStack.java
final int startActivityLocked(IApplicationThread caller,
            Intent intent, String resolvedType,
            Uri[] grantedUriPermissions,
            int grantedMode, ActivityInfo aInfo, IBinder resultTo,
            String resultWho, int requestCode,
            int callingPid, int callingUid, boolean onlyIfNeeded,
            boolean componentSpecified, ActivityRecord[] outActivity) {
    ...
        // 建立即將要啓動的Activity的相關信息,並保存在r變量中
        ActivityRecord r = new ActivityRecord(mService, this, callerApp, callingUid,
                intent, resolvedType, aInfo, mService.mConfiguration,
                resultRecord, resultWho, requestCode, componentSpecified);
    ...
}
// frameworks/base/services/java/com/android/server/am/ActivityStack.java
private final void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
    // AMS維護了一個ProcessMap<ProcessRecord> mProcessNames,用來記錄經過AMS啓動並運行的app進程
    // 在這個map裏沒查到說明該app進程不存在
    ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid);
    ...
    if (app != null && app.thread != null) {
        // 應用進程存在,則啓動對應的Activity
        try {
            app.addPackage(r.info.packageName);
            realStartActivityLocked(r, app, andResume, checkConfig);
            return;
        } catch (RemoteException e) {
            Slog.w(TAG, "Exception when starting activity "
                        + r.intent.getComponent().flattenToShortString(), e);
        }
    }

    // 應用進程不存在,先建立進程
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0, "activity", r.intent.getComponent(), false);
}
// frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags,
            String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
    ...
    if (app == null) {
        // 建立一個ProcessRecord,用來記錄要啓動的進程的信息
        app = newProcessRecordLocked(null, info, processName);
        // 將ProcessRecord存入map中
        mProcessNames.put(processName, info.uid, app);
    }
    ...
    startProcessLocked(app, hostingType, hostingNameStr);
    ...
}

private final void startProcessLocked(ProcessRecord app,
            String hostingType, String hostingNameStr) {
    // 使用Process.start來啓動新進程
    Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
                    app.processName, uid, uid, gids, debugFlags,
                    app.info.targetSdkVersion, null);
   ...
   app.pid = startResult.pid; // 記錄新進程的pid
   ...
}
3. Zygote socket 鏈接的請求及響應

剛纔上面咱們沒有看到有關和Zygote socket相關的內容。這塊實際上是由ZygoteProcess類實現的。Process.start()通過幾層調用,來到ZygoteProcess.startViaZygote()`。this

Process.start()  
	--> ZygoteProcess.start() 
		--> ZygoteProcess.startViaZygote()
private Process.ProcessStartResult startViaZygote(...) {
    ... // 省略參數的組裝過程
    synchronized(mLock) {
        return zygoteSendArgsAndGetResult(
                openZygoteSocketIfNeeded(abi), // 創建socket鏈接
                argsForZygote); // argsForZygote是要發給Zygote的參數,ArrayList類型
}
private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, ArrayList<String> args)
            throws ZygoteStartFailedEx {
    ...
    // 寫入流
    final BufferedWriter writer = zygoteState.writer;
    // 讀取流
    final DataInputStream inputStream = zygoteState.inputStream;
    // 按照Zygote協議寫數據
    // 先寫入參數個數,格式:size\n
    writer.write(Integer.toString(args.size()));
    writer.newLine();
    // 寫參數,每一個參數的格式:arg\n
    for (int i = 0; i < sz; i++) {
          String arg = args.get(i);
          writer.write(arg);
          writer.newLine();
    }
    writer.flush();
    Process.ProcessStartResult result = new Process.ProcessStartResult();
    // 讀取Zygote返回回來的進程id
    result.pid = inputStream.readInt();
    if (result.pid < 0) { // 若是pid小於0,說明fork失敗了
       throw new ZygoteStartFailedEx("fork() failed");
    }
    return result;
}

ProcessProcess向Zygote發送請求和接收請求的大體流程咱們已經看過了。那Zygote那邊怎麼接收和處理請求的呢?

// frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
    try {
        // 讀取client經過socket發過來的數據
        args = readArgumentList();
        descriptors = mSocket.getAncillaryFileDescriptors();
    } catch (IOException ex) {
        Log.w(TAG, "IOException on command socket " + ex.getMessage());
        closeSocket();
        return true;
    }
    ...
    // 將獲取的數據解析成Arguments類型
    parsedArgs = new Arguments(args);
    ...
    // 建立APP進程
    pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids, parsedArgs.debugFlags, rlimits);
    if (pid == 0) {
        ...
        // 走子進程的處理邏輯
        handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
        ...
    } else {
        ...
        // 走父進程的處理邏輯
        return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
    }
}

此時進程已經建立好了,須要將子進程的pid經過socket傳回給AMS了。

// frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
private boolean handleParentProc(int pid,
            FileDescriptor[] descriptors, FileDescriptor pipeFd, Arguments parsedArgs) {
    ...
   try {
        // 將fork出來的進程pid傳給AMS
        mSocketOutStream.writeInt(pid);
        mSocketOutStream.writeBoolean(usingWrapper);
    } catch (IOException ex) {
        Log.e(TAG, "Error reading from command socket", ex);
        return true;
    }
    ...
}
4. ActivityThread的main方法的執行

上面的流程結束後,子進程已經成功建立,接下來子進程將進行自身的初始化,加載主類和執行main(String[])方法。

ZygoteConnection.handleChildProc() 
    --> RuntimeInit.zygoteInit()
        --> RuntimeInit.zygoteInitNative() 
        --> RuntimeInit.applicationInit()
            --> RuntimeInit.invokeStaticMain()
private static void invokeStaticMain(String className, String[] argv)
            throws ZygoteInit.MethodAndArgsCaller {
    Class<?> cl;
    // 加載主類(android.app.ActivityThread)
    cl = Class.forName(className); 
    Method m;
    // 獲取main(String[])方法
    m = cl.getMethod("main", new Class[] { String[].class });
    // 檢查main方法是不是public static的
    int modifiers = m.getModifiers();
    if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
        throw new RuntimeException(
                    "Main method is not public and static on " + className);
    }
    // 拋出異常,返回到ZygoteInit.main()的catch塊中繼續執行
    throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}

這段代碼的最後將反射獲得的Method對象和參數封裝成ZygoteInit.MethodAndArgsCaller異常並拋出,這個異常被ZygoteInit的main()方法捕獲。

// ZygoteInit.main()
catch (MethodAndArgsCaller caller) {
    // fork()出來的子進程最終會走到這
    // 在這個裏面經過反射調用對應類的main()方法
    caller.run();
}

// MethodAndArgsCaller.run()
public void run() {
    try {
        // 最終經過反射調用main()方法
        mMethod.invoke(null, new Object[] { mArgs });
    } catch (IllegalAccessException ex) {
        throw new RuntimeException(ex);
    } catch (InvocationTargetException ex) {
        throw new RuntimeException(ex);
    }
}

最終,app進程的ActivityThread類的main()方法開始執行。

相關文章
相關標籤/搜索