Android應用進程的創建過程

基于Android 7.0源碼分析

以Launcher點擊應用啟動應用為例

ActivityManagerService(system_server)請求Zygote創建應用進程的過程

當運行應用時,如果應用進程還沒有創建,ActivityManagerService會請求Zygotefork進程,下面從ActivityManagerServicestartProcessLocked()開始分析。

final ProcessRecord startProcessLocked(String processName,
        ApplicationInfo info, boolean knownToBeDead, int intentFlags,
        String hostingType, ComponentName hostingName, boolean allowWhileBooting,
        boolean isolated, boolean keepIfLarge) {
    // keepIfLarge為true,knownToBeDead為true,intentFlags為0,allowWhileBooting為false
    // isolated為false
    return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
            hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
            null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
            null /* crashHandler */);
}

final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
        boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
        boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
        String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
    long startTime = SystemClock.elapsedRealtime();
    ProcessRecord app;
    // isolated通常為false,與安全相關
    if (!isolated) {
        // 查找ProcessRecord,非isolated進程,可以重用先前的ProcessRecord
        app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
        checkTime(startTime, "startProcess: after getProcessRecord");
        if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {
            // If we are in the background, then check to see if this process
            // is bad.  If so, we will just silently fail.
            // 檢查是否是經常crash的應用
            if (mAppErrors.isBadProcessLocked(info)) {
                if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid
                        + "/" + info.processName);
                return null;
            }
        } else {
            // When the user is explicitly starting a process, then clear its
            // crash count so that we won't make it bad until they see at
            // least one crash dialog again, and make the process good again
            // if it had been bad.
            if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid
                    + "/" + info.processName);
            // 清理進程crash信息
            mAppErrors.resetProcessCrashTimeLocked(info);
            if (mAppErrors.isBadProcessLocked(info)) {
                EventLog.writeEvent(EventLogTags.AM_PROC_GOOD,
                        UserHandle.getUserId(info.uid), info.uid,
                        info.processName);
                mAppErrors.clearBadProcessLocked(info);
                if (app != null) {
                    app.bad = false;
                }
            }
        }
    } else {
        // If this is an isolated process, it can't re-use an existing process.
        // isolated進程不能重用ProcessRecord
        app = null;
    }
    // app launch boost for big.little configurations
    // use cpusets to migrate freshly launched tasks to big cores
    // 對于大小核架構,使用cpuset,將前臺任務遷移到大核上
    nativeMigrateToBoost();
    mIsBoosted = true;
    mBoostStartTime = SystemClock.uptimeMillis();
    // 設置Boost超時取消
    Message msg = mHandler.obtainMessage(APP_BOOST_DEACTIVATE_MSG);
    mHandler.sendMessageDelayed(msg, APP_BOOST_MESSAGE_DELAY);
    ......
    if (app != null && app.pid > 0) {
        if ((!knownToBeDead && !app.killed) || app.thread == null) {
            // 應用進程已經運行或者即將運行
            // We already have the app running, or are waiting for it to
            // come up (we have a pid but not yet its thread), so keep it.
            if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App already running: " + app);
            // If this is a new package in the process, add the package to the list
            app.addPackage(info.packageName, info.versionCode, mProcessStats);
            checkTime(startTime, "startProcess: done, added package to proc");
            return app;
        }
        // An application record is attached to a previous process,
        // clean it up now.
        if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_PROCESSES, "App died: " + app);
        // ProcessRecord關聯到先前的進程,清理
        checkTime(startTime, "startProcess: bad proc running, killing");
        killProcessGroup(app.uid, app.pid);
        handleAppDiedLocked(app, true, true);
        checkTime(startTime, "startProcess: done killing old proc");
    }
    ......
    if (app == null) {
        checkTime(startTime, "startProcess: creating new process record");
        // 創建新的ProcessRecord
        app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
        if (app == null) {
            Slog.w(TAG, "Failed making new process record for "
                    + processName + "/" + info.uid + " isolated=" + isolated);
            return null;
        }
        // 設置crashHandler
        app.crashHandler = crashHandler;
        checkTime(startTime, "startProcess: done creating new process record");
    } else {
        // If this is a new package in the process, add the package to the list
        app.addPackage(info.packageName, info.versionCode, mProcessStats);
        checkTime(startTime, "startProcess: added package to existing proc");
    }
    ......
    // 系統尚未準備好,暫緩啟動進程,待啟動進程添加到mProcessesOnHold
    if (!mProcessesReady
            && !isAllowedWhileBooting(info)
            && !allowWhileBooting) {
        if (!mProcessesOnHold.contains(app)) {
            mProcessesOnHold.add(app);
        }
        if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES,
                "System not ready, putting on hold: " + app);
        checkTime(startTime, "startProcess: returning with proc on hold");
        return app;
    }
    checkTime(startTime, "startProcess: stepping in to startProcess");
    // 啟動應用進程
    startProcessLocked(
            app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
    checkTime(startTime, "startProcess: done starting proc!");
    return (app.pid != 0) ? app : null;
}
  • 注意ProcessRecord可被重用

下面繼續看startProcessLocked()實現

private final void startProcessLocked(ProcessRecord app, String hostingType,
        String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
    long startTime = SystemClock.elapsedRealtime();
    if (app.pid > 0 && app.pid != MY_PID) {
        // 重用的ProcessRecord,pid > 0
        checkTime(startTime, "startProcess: removing from pids map");
        // 從pids map中移除,移除進程啟動超時消息
        synchronized (mPidsSelfLocked) {
            mPidsSelfLocked.remove(app.pid);
            mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
        }
        checkTime(startTime, "startProcess: done removing from pids map");
        // pid置0
        app.setPid(0);
    }
    mProcessesOnHold.remove(app);
    ......
    try {
        try {
            // 獲取userId,通常為0
            final int userId = UserHandle.getUserId(app.uid);
            // 檢查應用的package狀態
            AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);
        } catch (RemoteException e) {
            throw e.rethrowAsRuntimeException();
        }
        ......
        int debugFlags = 0;
        if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
            // 應用可調式
            debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
            // Also turn on CheckJNI for debuggable apps. It's quite
            // awkward to turn on otherwise.
            debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
        }
        // Run the app in safe mode if its manifest requests so or the
        // system is booted in safe mode.
        if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 ||
            mSafeMode == true) {
            // 運行在安全模式
            debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
        }
        ......
        // abiOverride為null使用app的primaryCpuAbi
        String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;
        if (requiredAbi == null) {
            // 如果requiredAbi為null,使用系統支持的CPUABI列表中的第一個
            requiredAbi = Build.SUPPORTED_ABIS[0];
        }
        String instructionSet = null;
        if (app.info.primaryCpuAbi != null) {
            // 查找CPUABI對應的指令集
            // armeabi => arm
            // armeabi-v7a => arm
            // arm64-v8a => arm64
            instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi);
        }
        // 進程所屬額外的group ids
        app.gids = gids;
        app.requiredAbi = requiredAbi;
        app.instructionSet = instructionSet;
        ......
        boolean isActivityProcess = (entryPoint == null);
        // 設置進程入口,通常為"android.app.ActivityThread"
        if (entryPoint == null) entryPoint = "android.app.ActivityThread";
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                app.processName);
        checkTime(startTime, "startProcess: asking zygote to start proc");
        // 請求Zygote fork進程并等待Zygote發送進程啟動結果
        Process.ProcessStartResult startResult = Process.start(entryPoint,
                app.processName, uid, uid, gids, debugFlags, mountExternal,
                app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                app.info.dataDir, entryPointArgs);
        checkTime(startTime, "startProcess: returned from zygote!");
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

        if (app.isolated) {
            mBatteryStatsService.addIsolatedUid(app.uid, app.info.uid);
        }
        // 通知BatteryStatsService進程啟動
        mBatteryStatsService.noteProcessStart(app.processName, app.info.uid);
        checkTime(startTime, "startProcess: done updating battery stats");
        // AM_PROC_START事件log
        EventLog.writeEvent(EventLogTags.AM_PROC_START,
                UserHandle.getUserId(uid), startResult.pid, uid,
                app.processName, hostingType,
                hostingNameStr != null ? hostingNameStr : "");
        ......
        if (app.persistent) {
            // 記錄Phone進程的pid
            Watchdog.getInstance().processStarted(app.processName, startResult.pid);
        }
        ......
        // 設置ProcessRecord新進程信息
        app.setPid(startResult.pid);
        app.usingWrapper = startResult.usingWrapper;
        app.removed = false;
        app.killed = false;
        app.killedByAm = false;
        checkTime(startTime, "startProcess: starting to update pids map");
        synchronized (mPidsSelfLocked) {
            this.mPidsSelfLocked.put(startResult.pid, app);
            if (isActivityProcess) {
                // 設置應用進程attach到ActivityManagerService的超時檢測
                Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
                msg.obj = app;
                mHandler.sendMessageDelayed(msg, startResult.usingWrapper
                        ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
            }
        }
        ......
    }
}

下面看Processstart()方法

public static final ProcessStartResult start(final String processClass,
                              final String niceName,
                              int uid, int gid, int[] gids,
                              int debugFlags, int mountExternal,
                              int targetSdkVersion,
                              String seInfo,
                              String abi,
                              String instructionSet,
                              String appDataDir,
                              String[] zygoteArgs) {
    try {
        return startViaZygote(processClass, niceName, uid, gid, gids,
                debugFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, zygoteArgs);
    } catch (ZygoteStartFailedEx ex) {
        Log.e(LOG_TAG,
                "Starting VM process through Zygote failed");
        throw new RuntimeException(
                "Starting VM process through Zygote failed", ex);
    }
}
  • processClass 進程入口類名
  • niceName 進程名
  • uid 進程uid
  • gid 進程group id(通常等于uid)
  • gids 進程所屬額外的group ids
  • debugFlags 進程調試標志位
  • targetSdkVersion 應用目標sdk
  • seInfo 進程的SELinux信息
  • abi 進程運行的abi
  • instructionSet 進程運行的指令集
  • appDataDir 應用的數據路徑(/data/user/0/xxx)

下面看startViaZygote()的實現

private static ProcessStartResult startViaZygote(final String processClass,
                              final String niceName,
                              final int uid, final int gid,
                              final int[] gids,
                              int debugFlags, int mountExternal,
                              int targetSdkVersion,
                              String seInfo,
                              String abi,
                              String instructionSet,
                              String appDataDir,
                              String[] extraArgs)
                              throws ZygoteStartFailedEx {
    synchronized(Process.class) {
        // 通過ArrayList傳遞啟動參數給Zygote
        ArrayList<String> argsForZygote = new ArrayList<String>();
        // --runtime-args, --setuid=, --setgid=,
        // and --setgroups= must go first
        argsForZygote.add("--runtime-args");
        argsForZygote.add("--setuid=" + uid);
        argsForZygote.add("--setgid=" + gid);
        ......
        return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
    }
}

// 如果還沒有創建Socket,創建Socket用于與Zygote通信
// ZygoteState用于管理與Zygote通信的狀態
// 通常在arm64系統中,通常primaryZygoteState與secondaryZygoteState分別對應
// 進程Zygote64與Zygote(取決于*.rc文件配置)
private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
    // 如果primaryZygoteState沒有創建或已經關閉,創建它
    if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
        try {
            primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);
        } catch (IOException ioe) {
            throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
        }
    }
    // 檢查abi是否匹配primaryZygoteState
    if (primaryZygoteState.matches(abi)) {
        return primaryZygoteState;
    }
    // The primary zygote didn't match. Try the secondary.
    if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
        try {
        secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET);
        } catch (IOException ioe) {
            throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
        }
    }
    // 檢查abi是否匹配secondaryZygoteState
    if (secondaryZygoteState.matches(abi)) {
        return secondaryZygoteState;
    }
    throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
}

// 向Zygote進程(Zygote64/Zygote)發送參數列表,請求fork進程
private static ProcessStartResult zygoteSendArgsAndGetResult(
        ZygoteState zygoteState, ArrayList<String> args)
        throws ZygoteStartFailedEx {
    try {
        final BufferedWriter writer = zygoteState.writer;
        final DataInputStream inputStream = zygoteState.inputStream;
        // 向Zygote發送參數的數目以及參數字符串
        writer.write(Integer.toString(args.size()));
        writer.newLine();
        int sz = args.size();
        for (int i = 0; i < sz; i++) {
            String arg = args.get(i);
            if (arg.indexOf('\n') >= 0) {
                throw new ZygoteStartFailedEx(
                        "embedded newlines not allowed");
            }
            writer.write(arg);
            writer.newLine();
        }
        writer.flush();

        // 讀取Zygote發送結果,可能需要等待
        ProcessStartResult result = new ProcessStartResult();
        result.pid = inputStream.readInt();
        if (result.pid < 0) {
            throw new ZygoteStartFailedEx("fork() failed");
        }
        result.usingWrapper = inputStream.readBoolean();
        return result;
    } catch (IOException ex) {
        zygoteState.close();
        throw new ZygoteStartFailedEx(ex);
    }
}

下面看Zygote收到請求后,創建應用進程的過程。Zygote進程啟動后,會調用runSelectLoop()等待客戶端的連接請求,下面分析runSelectLoop()

public static void main(String argv[]) {
    // Mark zygote start. This ensures that thread creation will throw
    // an error.
    ZygoteHooks.startZygoteNoThreadCreation();
    try {
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygoteInit");
        ......
        // 運行runSelectLoop,等待客戶端連接
        runSelectLoop(abiList);
        closeServerSocket();
    } catch (MethodAndArgsCaller caller) {
        // 子進程中調用MethodAndArgsCaller的run方法
        caller.run();
    } catch (RuntimeException ex) {
        Log.e(TAG, "Zygote died with exception", ex);
        closeServerSocket();
        throw ex;
    }
}

private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
    ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
    ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
    fds.add(sServerSocket.getFileDescriptor());
    peers.add(null);

    while (true) {
        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 {
            // 監聽文件描述符集pollFds
            Os.poll(pollFds, -1);
        } catch (ErrnoException ex) {
            throw new RuntimeException("poll failed", ex);
        }
        for (int i = pollFds.length - 1; i >= 0; --i) {
            if ((pollFds[i].revents & POLLIN) == 0) {
                continue;
            }
            if (i == 0) {
                // 接收客戶端的連接請求,創建ZygoteConnection
                ZygoteConnection newPeer = acceptCommandPeer(abiList);
                peers.add(newPeer);
                fds.add(newPeer.getFileDesciptor());
            } else {
                // 讀取、處理客戶端請求
                ne = peers.get(i).runOnce();
                if (done) {
                    peers.remove(i);
                    fds.remove(i);
                }
            }
        }
    }
}

// 在子進程中會拋出ZygoteInit.MethodAndArgsCaller
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
    String args[];
    Arguments parsedArgs = null;
    FileDescriptor[] descriptors;
    try {
        // 讀取客戶端發送的參數列表
        args = readArgumentList();
        descriptors = mSocket.getAncillaryFileDescriptors();
    } catch (IOException ex) {
        Log.w(TAG, "IOException on command socket " + ex.getMessage());
        closeSocket();
        return true;
    }
    ......
    try {
        // 解析參數列表
        parsedArgs = new Arguments(args);
        if (parsedArgs.abiListQuery) {
            // 處理客戶端查詢abiList請求(客戶端socket創建時)
            return handleAbiListQuery();
        }
        ......
        // 安全檢查
        applyUidSecurityPolicy(parsedArgs, peer);
        applyInvokeWithSecurityPolicy(parsedArgs, peer);
        applyDebuggerSystemProperty(parsedArgs);
        applyInvokeWithSystemProperty(parsedArgs);
        ......
        // 避免子進程文件描述符泄露,需要關閉Zygote socket文件描述符
        int [] fdsToClose = { -1, -1 };
        FileDescriptor fd = mSocket.getFileDescriptor();
        if (fd != null) {
            fdsToClose[0] = fd.getInt$();
        }
        fd = ZygoteInit.getServerSocketFileDescriptor();
        if (fd != null) {
            fdsToClose[1] = fd.getInt$();
        }
        fd = null;
        // fork進程
        pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
                parsedArgs.appDataDir);
    }
    
    try {
        if (pid == 0) {
            // in child
            // 子進程中執行
            IoUtils.closeQuietly(serverPipeFd);
            serverPipeFd = null;
            // 處理子進程fork后的設置,見下一節
            handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
            // should never get here, the child is expected to either
            // throw ZygoteInit.MethodAndArgsCaller or exec().
            return true;
        } else {
            // in parent...pid of < 0 means failure
            // Zygote進程中執行
            IoUtils.closeQuietly(childPipeFd);
            childPipeFd = null;
            return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
        }
    } finally {
        IoUtils.closeQuietly(childPipeFd);
        IoUtils.closeQuietly(serverPipeFd);
    }
}

下面看forkAndSpecialize的實現

public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
      int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
      String instructionSet, String appDataDir) {
    // fork之前的準備工作
    VM_HOOKS.preFork();
    int pid = nativeForkAndSpecialize(
              uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
              instructionSet, appDataDir);
    // Enable tracing as soon as possible for the child process.
    if (pid == 0) {
        // 在子進程中使能trace
        Trace.setTracingEnabled(true);
        // Note that this event ends at the end of handleChildProc,
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
    }
    // fork之后的工作
    VM_HOOKS.postForkCommon();
    return pid;
}

public void preFork() {
    // 停止4個守護線程
    Daemons.stop();
    // 等待守護線程結束
    waitUntilAllThreadsStopped();
    // 整理heap,如果有zygote heap基本上沒有工作
    token = nativePreFork();
}

public static void stop() {
    HeapTaskDaemon.INSTANCE.stop();
    ReferenceQueueDaemon.INSTANCE.stop();
    FinalizerDaemon.INSTANCE.stop();
    FinalizerWatchdogDaemon.INSTANCE.stop();
}

public void postForkCommon() {
    // 啟動4個守護線程
    Daemons.start();
}

這里介紹下4個守護線程:

  • HeapTaskDaemon
    • 用于處理GC tasks,包括Heap裁減,Heap垃圾回收器切換,Heap GC
  • ReferenceQueueDaemon
    • 當Reference關聯的對象被GC回收時,GC將Reference添加到靜態鏈表(ReferenceQueue.unenqueued)中,ReferenceQueueDaemon負責將靜態鏈表中的Reference添加到關聯的ReferenceQueue中
  • FinalizerDaemon
    • 執行對象的finalize方法,對于FinalizerDaemon的執行過程以后討論
  • FinalizerWatchdogDaemon
    • 監視FinalizerDaemon

下面看nativeForkAndSpecialize的實現

static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
        JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
        jint debug_flags, jobjectArray rlimits,
        jint mount_external, jstring se_info, jstring se_name,
        jintArray fdsToClose, jstring instructionSet, jstring appDataDir) {
    jlong capabilities = 0;
    ......
    return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags,
            rlimits, capabilities, capabilities, mount_external, se_info,
            se_name, false, fdsToClose, instructionSet, appDataDir);
}

static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
                                     jint debug_flags, jobjectArray javaRlimits,
                                     jlong permittedCapabilities, jlong effectiveCapabilities,
                                     jint mount_external,
                                     jstring java_se_info, jstring java_se_name,
                                     bool is_system_server, jintArray fdsToClose,
                                     jstring instructionSet, jstring dataDir) {

  SetSigChldHandler();
  ......
  // fork進程
  pid_t pid = fork();

  if (pid == 0) {
    // 子進程
    // The child process.
    gMallocLeakZygoteChild = 1;

    // Clean up any descriptors which must be closed immediately
    // 關閉繼承自zygote的socket文件描述符
    DetachDescriptors(env, fdsToClose);
    ......
    if (!is_system_server) {
        // 創建進程組
        int rc = createProcessGroup(uid, getpid());
        if (rc != 0) {
            if (rc == -EROFS) {
                ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?");
            } else {
                ALOGE("createProcessGroup(%d, %d) failed: %s", uid, pid, strerror(-rc));
            }
        }
    }
    // 設置進程所屬額外的groups
    SetGids(env, javaGids);
    // 設置資源限制
    SetRLimits(env, javaRlimits);

    // 通常不使用native bridge
    // native bridge用于運行帶有與系統不同的處理器架構native庫的應用
    if (use_native_bridge) {
      ScopedUtfChars isa_string(env, instructionSet);
      ScopedUtfChars data_dir(env, dataDir);
      android::PreInitializeNativeBridge(data_dir.c_str(), isa_string.c_str());
    }

    // 設置real GID/effective GID/saved set-user-ID GID
    int rc = setresgid(gid, gid, gid);
    if (rc == -1) {
      ALOGE("setresgid(%d) failed: %s", gid, strerror(errno));
      RuntimeAbort(env, __LINE__, "setresgid failed");
    }
    // 設置real UID/effective UID/saved set-user-ID UID
    rc = setresuid(uid, uid, uid);
    if (rc == -1) {
      ALOGE("setresuid(%d) failed: %s", uid, strerror(errno));
      RuntimeAbort(env, __LINE__, "setresuid failed");
    }

    if (NeedsNoRandomizeWorkaround()) {
        // 針對低版本kernel,彌補ASLR(地址空間布局隨機化)的缺失
        // Work around ARM kernel ASLR lossage (http://b/5817320).
        int old_personality = personality(0xffffffff);
        int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);
        if (new_personality == -1) {
            ALOGW("personality(%d) failed: %s", new_personality, strerror(errno));
        }
    }
    // 設置權限
    SetCapabilities(env, permittedCapabilities, effectiveCapabilities);
    // 設置調度策略(SP_DEFAULT)
    SetSchedulerPolicy(env);
    ......
    // 設置Selinux策略
    rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
    ......
    if (se_info_c_str != NULL) {
      // 設置進程名
      SetThreadName(se_name_c_str);
    }

    delete se_info;
    delete se_name;
    // 取消SIGCHLD信號處理
    UnsetSigChldHandler();
    // 調用Zygote的callPostForkChildHooks方法
    env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,
                              is_system_server, instructionSet);
    if (env->ExceptionCheck()) {
      RuntimeAbort(env, __LINE__, "Error calling post fork hooks.");
    }
  } else if (pid > 0) {
    // the parent process

#ifdef ENABLE_SCHED_BOOST
    // unset scheduler knob
    SetForkLoad(false);
#endif

  }
  return pid;
}

下面看ZygotecallPostForkChildHooks的實現

private static void callPostForkChildHooks(int debugFlags, boolean isSystemServer,
        String instructionSet) {
    VM_HOOKS.postForkChild(debugFlags, isSystemServer, instructionSet);
}

public void postForkChild(int debugFlags, boolean isSystemServer, String instructionSet) {
    // 在Zygote fork之后的子進程中調用
    nativePostForkChild(token, debugFlags, isSystemServer, instructionSet);
    Math.setRandomSeedInternal(System.currentTimeMillis());
}

nativePostForkChild()是個native方法,下面看它的實現。

static void ZygoteHooks_nativePostForkChild(JNIEnv* env,
                                            jclass,
                                            jlong token,
                                            jint debug_flags,
                                            jboolean is_system_server,
                                            jstring instruction_set) {
  Thread* thread = reinterpret_cast<Thread*>(token);
  // Our system thread ID, etc, has changed so reset Thread state.
  thread->InitAfterFork();
  EnableDebugFeatures(debug_flags);
  ......
  if (instruction_set != nullptr && !is_system_server) {
    // 指令集不為空且非system_server  
    ScopedUtfChars isa_string(env, instruction_set);
    InstructionSet isa = GetInstructionSetFromString(isa_string.c_str());
    Runtime::NativeBridgeAction action = Runtime::NativeBridgeAction::kUnload;
    if (isa != kNone && isa != kRuntimeISA) {
      action = Runtime::NativeBridgeAction::kInitialize;
    }
    // 設置heap、創建Jit等
    Runtime::Current()->InitNonZygoteOrPostFork(
        env, is_system_server, action, isa_string.c_str());
  } else {
    Runtime::Current()->InitNonZygoteOrPostFork(
        env, is_system_server, Runtime::NativeBridgeAction::kUnload, nullptr);
  }
}

void Runtime::InitNonZygoteOrPostFork(
    JNIEnv* env, bool is_system_server, NativeBridgeAction action, const char* isa) {
  is_zygote_ = false;

  // 通常is_native_bridge_loaded_為false, See ro.dalvik.vm.native.bridge屬性
  if (is_native_bridge_loaded_) {
    switch (action) {
      case NativeBridgeAction::kUnload:
        UnloadNativeBridge();
        is_native_bridge_loaded_ = false;
        break;

      case NativeBridgeAction::kInitialize:
        InitializeNativeBridge(env, isa);
        break;
    }
  }

  // Create the thread pools.
  heap_->CreateThreadPool();
  // Reset the gc performance data at zygote fork so that the GCs
  // before fork aren't attributed to an app.
  // 重置GC性能數據
  heap_->ResetGcPerformanceInfo();

  if (!is_system_server &&
      !safe_mode_ &&
      (jit_options_->UseJitCompilation() || jit_options_->GetSaveProfilingInfo()) &&
      jit_.get() == nullptr) {
    // Note that when running ART standalone (not zygote, nor zygote fork),
    // the jit may have already been created.
    // 創建Jit
    CreateJit();
  }
  // 啟動Signal Catcher Thread
  StartSignalCatcher();

  // Start the JDWP thread. If the command-line debugger flags specified "suspend=y",
  // this will pause the runtime, so we probably want this to come last.
  Dbg::StartJdwp();
}

至此,應用進程基本創建完成,下面看應用進程創建后設置的過程。

應用進程創建后設置的過程

回到ZygoteConnectionrunOnce中,下面分析子進程fork后的設置,也就是handleChildProc的實現。

private void handleChildProc(Arguments parsedArgs,
        FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
        throws ZygoteInit.MethodAndArgsCaller {
    /**
     * By the time we get here, the native code has closed the two actual Zygote
     * socket connections, and substituted /dev/null in their place.  The LocalSocket
     * objects still need to be closed properly.
     */
    // 關閉與連接關聯的socket
    closeSocket();
    // 關閉清理Zygote socket
    ZygoteInit.closeServerSocket();
    ......
    // End of the postFork event.
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    // 這里invokeWith為null
    if (parsedArgs.invokeWith != null) {
        WrapperInit.execApplication(parsedArgs.invokeWith,
                parsedArgs.niceName, parsedArgs.targetSdkVersion,
                VMRuntime.getCurrentInstructionSet(),
                pipeFd, parsedArgs.remainingArgs);
    } else {
        RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
                parsedArgs.remainingArgs, null /* classLoader */);
    }
}

下面看RuntimeInitzygoteInit方法的實現

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
        throws ZygoteInit.MethodAndArgsCaller {
    if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
    // System.out重定向到Android log
    redirectLogStreams();
    // 設置未捕獲異常處理,Logger log寫入Android log等
    commonInit();
    // 支持Binder通信
    nativeZygoteInit();
    applicationInit(targetSdkVersion, argv, classLoader);
}

在Android應用中使用System.out以及Logger打印log,通過logcat也能看到。

下面看applicationInit的實現

private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
        throws ZygoteInit.MethodAndArgsCaller {
    // If the application calls System.exit(), terminate the process
    // immediately without running any shutdown hooks.  It is not possible to
    // shutdown an Android application gracefully.  Among other things, the
    // Android runtime shutdown hooks close the Binder driver, which can cause
    // leftover running threads to crash before the process actually exits.
    nativeSetExitWithoutCleanup(true);
    // We want to be fairly aggressive about heap utilization, to avoid
    // holding on to a lot of memory that isn't needed.
    // heap目標利用率設置
    VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
    VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
    final Arguments args;
    try {
        args = new Arguments(argv);
    } catch (IllegalArgumentException ex) {
        Slog.e(TAG, ex.getMessage());
        // let the process exit
        return;
    }
    // The end of of the RuntimeInit event (see #zygoteInit).
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    
    // Remaining arguments are passed to the start class's static main
    // 調用ActivityThread的main方法
    invokeStaticMain(args.startClass, args.startArgs, classLoader);
}

private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
        throws ZygoteInit.MethodAndArgsCaller {
    Class<?> cl;
    try {
        // 獲取ActivityThread類對象
        cl = Class.forName(className, true, classLoader);
    } catch (ClassNotFoundException ex) {
        throw new RuntimeException(
                "Missing class when invoking static main " + className,
                ex);
    }
    Method m;
    try {
        // ActivityThread的main方法
        m = cl.getMethod("main", new Class[] { String[].class });
    } catch (NoSuchMethodException ex) {
        throw new RuntimeException(
                "Missing static main on " + className, ex);
    } catch (SecurityException ex) {
        throw new RuntimeException(
                "Problem getting static main on " + className, ex);
    }
    int modifiers = m.getModifiers();
    // main方法必須是public static
    if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
        throw new RuntimeException(
                "Main method is not public and static on " + className);
    }
    /*
     * This throw gets caught in ZygoteInit.main(), which responds
     * by invoking the exception's run() method. This arrangement
     * clears up all the stack frames that were required in setting
     * up the process.
     */
    // 為了進程啟動時清理棧幀,拋出MethodAndArgsCaller,在ZygoteInit.main方法中捕獲處理
    throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}

回到ZygoteInitmain方法中。

public static void main(String argv[]) {
    // Mark zygote start. This ensures that thread creation will throw
    // an error.
    ZygoteHooks.startZygoteNoThreadCreation();
    try {
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygoteInit");
        ......
        runSelectLoop(abiList);
        closeServerSocket();
    } catch (MethodAndArgsCaller caller) {
        // 調用MethodAndArgsCaller的run方法
        caller.run();
    } catch (RuntimeException ex) {
        Log.e(TAG, "Zygote died with exception", ex);
        closeServerSocket();
        throw ex;
    }
}

public static class MethodAndArgsCaller extends Exception
        implements Runnable {
    ......
    public void run() {
        try {
            // 調用ActivityThread的main方法
            mMethod.invoke(null, new Object[] { mArgs });
        } catch (IllegalAccessException ex) {
            throw new RuntimeException(ex);
        } catch (InvocationTargetException ex) {
            Throwable cause = ex.getCause();
            if (cause instanceof RuntimeException) {
                throw (RuntimeException) cause;
            } else if (cause instanceof Error) {
                throw (Error) cause;
            }
            throw new RuntimeException(ex);
        }
    }
}

對于Android應用進程的啟動過程,這里分析到ActivityThreadmain方法,對于后續流程暫不討論。

小結

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,401評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,011評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,263評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,543評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,323評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,874評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,968評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,095評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,605評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,551評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,720評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,242評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,961評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,358評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,612評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,330評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,690評論 2 370

推薦閱讀更多精彩內容