Android應用程序進程啟動過程-源碼分析

Android系統(tǒng)中戒幔,啟動一個app首先要保證該app所在的進程已經(jīng)被啟動射窒。本文就介紹下app進程搪柑,即應用程序進程的啟動過程裙椭。這里順便提一句,通常所說的啟動應用程序滓走,指的是其根Activity的啟動,和應用程序進程的啟動是兩個概念。

  • 了解Android系統(tǒng)啟動過程或者Zygote進程的同學都會知道鲤竹,應用程序進程的創(chuàng)建是通過Zygote進程fork其自身而產(chǎn)生的。①
  • 了解Activity的啟動過程的朋友昔榴,又知道在Activity的啟動過程中辛藻,會有一個檢查Activity所在進程是否已經(jīng)啟動,否則就會先創(chuàng)建并啟動其所在進程互订,再啟動Activity吱肌。②
    知道了上面兩個過程,再來理解app進程啟動過程仰禽,就相對容易了氮墨。先讓大家有個大概的流程認識:

在Android系統(tǒng)的啟動過程中,Zygote進程的Java框架層中創(chuàng)建一個Server端的Socket吐葵。這個Socket用來等待AMS發(fā)送請求规揪,讓Zygote進程創(chuàng)建新的app進程。Zygote進程接收到請求后温峭,通過fork自身創(chuàng)建app進程猛铅。

具體的創(chuàng)建和啟動過程步驟比較多,我們把上述過程分為兩個部分來分別講解诚镰。

AMS發(fā)送啟動app進程的請求

先來看一下AMS發(fā)送啟動app進程請求過程的時序圖


image.png

AMS如果想要啟動app進程奕坟,就需要向Zygote進程發(fā)送創(chuàng)建app進程的請求,AMS會通過調(diào)用startProcessLocked方法來開始這一過程清笨。下面展示相關(guān)的重要代碼

private final void startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
    ...
    try {
            ...
            //獲取要創(chuàng)建的app進程的用戶id
            int uid = app.uid;
            ...
            //對用戶組gids進行創(chuàng)建和賦值
            if (ArrayUtils.isEmpty(permGids)) {
                    gids = new int[3];
                } else {
                    gids = new int[permGids.length + 3];
                    System.arraycopy(permGids, 0, gids, 3, permGids.length);
                }
                gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
                gids[1] = UserHandle.getCacheAppGid(UserHandle.getAppId(uid));
                gids[2] = UserHandle.getUserGid(UserHandle.getUserId(uid));
            ...
            // Start the process.  It will either succeed and return a result containing
            // the PID of the new process, or else throw a RuntimeException.
            //這里的entryPoint的值就是app進程主線程的類名月杉。
            if (entryPoint == null) entryPoint = "android.app.ActivityThread";
            ...
            //調(diào)用Process.start方法,將上面得到的entryPoint抠艾,uid苛萎,gids傳進去
            startResult = Process.start(entryPoint,
                        app.processName, uid, uid, gids, debugFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, invokeWith, entryPointArgs);
}

關(guān)于uid、gid和進程
在Linux中,每個UID標識一個用戶腌歉,每個用戶又至少屬于一個組蛙酪,每個組都有一個唯一標識的GID。每個進程都擁有真實的用戶翘盖、組(UID桂塞、GID)。在Android系統(tǒng)中馍驯,一個用戶的UID表示一個app阁危。app在安裝時被分配了用戶UID,其在設備上存續(xù)期間汰瘫,用戶UID保持不變狂打。對于普通的用戶程序,GID和UID相同混弥。詳細介紹可以參考Android 安全機制(1)uid 趴乡、 gid 與 pid

entryPoint 希望讀者能夠留意這個變量值,它關(guān)系到app進程創(chuàng)建后的初始化過程蝗拿,后面會提到晾捏。

接下來查看Process的start方法,這里需要注意的是蛹磺,此處的Process類不是java/lang/Process.java的Process類粟瞬,而是android/os/Process.java的Process類

package android.os;
/**
 * Tools for managing OS processes.
 */
public class Process {
        ...
        public static final ProcessStartResult start(final String processClass,
                                  final String niceName,
                                  int uid, int gid, int[] gids,
                                  int runtimeFlags, int mountExternal,
                                  int targetSdkVersion,
                                  String seInfo,
                                  String abi,
                                  String instructionSet,
                                  String appDataDir,
                                  String invokeWith,
                                  String[] zygoteArgs) {
        return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                    runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
    }
        ...
}

一目了然,其內(nèi)部直接調(diào)用了ZygoteProcess的start方法

public final Process.ProcessStartResult start(final String processClass,
                                                  final String niceName,
                                                  int uid, int gid, int[] gids,
                                                  int runtimeFlags, int mountExternal,
                                                  int targetSdkVersion,
                                                  String seInfo,
                                                  String abi,
                                                  String instructionSet,
                                                  String appDataDir,
                                                  String invokeWith,
                                                  String[] zygoteArgs) {
        try {
            return startViaZygote(processClass, niceName, uid, gid, gids,
                    runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */,
                    zygoteArgs);
        } catch (ZygoteStartFailedEx ex) {
            Log.e(LOG_TAG,
                    "Starting VM process through Zygote failed");
            throw new RuntimeException(
                    "Starting VM process through Zygote failed", ex);
        }
    }

它又調(diào)用了startViaZygote方法

/**
* Starts a new process via the zygote mechanism.
*/
private Process.ProcessStartResult startViaZygote(final String processClass,
                                                      final String niceName,
                                                      final int uid, final int gid,
                                                      final int[] gids,
                                                      int runtimeFlags, int mountExternal,
                                                      int targetSdkVersion,
                                                      String seInfo,
                                                      String abi,
                                                      String instructionSet,
                                                      String appDataDir,
                                                      String invokeWith,
                                                      boolean startChildZygote,
                                                      String[] extraArgs)
                                                      throws ZygoteStartFailedEx {
        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);
        argsForZygote.add("--runtime-flags=" + runtimeFlags);
        if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
            argsForZygote.add("--mount-external-default");
        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
            argsForZygote.add("--mount-external-read");
        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
            argsForZygote.add("--mount-external-write");
        }
        argsForZygote.add("--target-sdk-version=" + targetSdkVersion);

        // --setgroups is a comma-separated list
        if (gids != null && gids.length > 0) {
            StringBuilder sb = new StringBuilder();
            sb.append("--setgroups=");

            int sz = gids.length;
            for (int i = 0; i < sz; i++) {
                if (i != 0) {
                    sb.append(',');
                }
                sb.append(gids[i]);
            }
            argsForZygote.add(sb.toString());
        }
        if (niceName != null) {
            argsForZygote.add("--nice-name=" + niceName);
        }
        if (seInfo != null) {
            argsForZygote.add("--seinfo=" + seInfo);
        }
        if (instructionSet != null) {
            argsForZygote.add("--instruction-set=" + instructionSet);
        }
        if (appDataDir != null) {
            argsForZygote.add("--app-data-dir=" + appDataDir);
        }
        if (invokeWith != null) {
            argsForZygote.add("--invoke-with");
            argsForZygote.add(invokeWith);
        }
        if (startChildZygote) {
            argsForZygote.add("--start-child-zygote");
        }
        argsForZygote.add(processClass);
        if (extraArgs != null) {
            for (String arg : extraArgs) {
                argsForZygote.add(arg);
            }
        }
        synchronized(mLock) {
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
        }
    }

這個方法前面一段是創(chuàng)建字符串列表argsForZygote萤捆,并將app進程的啟動參數(shù)放在argsForZygote中裙品。方法最后調(diào)用了zygoteSendArgsAndGetResult方法。需要注意的是zygoteSendArgsAndGetResult方法的第一個參數(shù)openZygoteSocketIfNeeded俗或,稍后會講到市怎。第二個參數(shù)就是argsForZygote。先看看zygoteSendArgsAndGetResult方法的代碼

/**
     * Sends an argument list to the zygote process, which starts a new child
     * and returns the child's pid. Please note: the present implementation
     * replaces newlines in the argument list with spaces.
     *
     * @throws ZygoteStartFailedEx if process start failed for any reason
     */
@GuardedBy("mLock")
    private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, ArrayList<String> args)
            throws ZygoteStartFailedEx {
        try {
            int sz = args.size();
            for (int i = 0; i < sz; i++) {
                if (args.get(i).indexOf('\n') >= 0) {
                    throw new ZygoteStartFailedEx("embedded newlines not allowed");
                }
            }
            ... 
            final BufferedWriter writer = zygoteState.writer;
            final DataInputStream inputStream = zygoteState.inputStream;

            writer.write(Integer.toString(args.size()));
            writer.newLine();

            for (int i = 0; i < sz; i++) {
                String arg = args.get(i);
                writer.write(arg);
                writer.newLine();
            }
            writer.flush();
            ...
            result.pid = inputStream.readInt();
            result.usingWrapper = inputStream.readBoolean();

            if (result.pid < 0) {
                throw new ZygoteStartFailedEx("fork() failed");
            }
            return result;
        } catch (IOException ex) {
            zygoteState.close();
            throw new ZygoteStartFailedEx(ex);
        }
    }

zygoteSendArgsAndGetResult方法的主要作用就是將傳入的app進程的啟動參數(shù)argsForZygote寫入到zygoteState中辛慰,zygoteState是ZygoteProcess的靜態(tài)內(nèi)部類区匠,用于表示與Zygote進程的通信狀態(tài)。現(xiàn)在再回過頭去看帅腌,startViaZygote的return語句驰弄,我們可以知道,這個zygoteState對象是openZygoteSocketIfNeeded方法返回的速客。

/**
     * Tries to open socket to Zygote process if not already open. If
     * already open, does nothing.  May block and retry.  Requires that mLock be held.
     */
    @GuardedBy("mLock")
    private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
        Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
        if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
            try {
                primaryZygoteState = ZygoteState.connect(mSocket);
            } catch (IOException ioe) {
                throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
            }
            maybeSetApiBlacklistExemptions(primaryZygoteState, false);
             maybeSetHiddenApiAccessLogSampleRate(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(mSecondarySocket);
            } catch (IOException ioe) {
                throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
            }
            maybeSetApiBlacklistExemptions(secondaryZygoteState, false);        maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
        }
        if (secondaryZygoteState.matches(abi)) {
            return secondaryZygoteState;
        }
        throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
    }

在Zygote進程啟動過程中戚篙,Zygote的main方法中會創(chuàng)建name為"zygote"的Server端Socket。在上面的代碼中溺职,我們也看到了調(diào)用ZygoteState的connect方法岔擂。這個方法就是用來和Zygote進程建立Socket連接的位喂。其中的mSocket,是一個LocalSocketAddress對象乱灵,表示和Zygote進程通信的Socket名稱塑崖。在這里指的就是Zygote進程里的Socket名稱。
我們再來看看ZygoteState類痛倚,就能更容易理解這個Socket通信過程规婆。

public static class ZygoteState {
        final LocalSocket socket;
        final DataInputStream inputStream;
        final BufferedWriter writer;
        final List<String> abiList;
        ...
        public static ZygoteState connect(LocalSocketAddress address) throws IOException {
            DataInputStream zygoteInputStream = null;
            BufferedWriter zygoteWriter = null;
            final LocalSocket zygoteSocket = new LocalSocket();

            try {
                zygoteSocket.connect(address);

                zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());

                zygoteWriter = new BufferedWriter(new OutputStreamWriter(
                        zygoteSocket.getOutputStream()), 256);
            } catch (IOException ex) {
                try {
                    zygoteSocket.close();
                } catch (IOException ignore) {
                }

                throw ex;
            }

            String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
            Log.i("Zygote", "Process: zygote socket " + address.getNamespace() + "/"
                    + address.getName() + " opened, supported ABIS: " + abiListString);

            return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
                    Arrays.asList(abiListString.split(",")));
        }
        ...
}

可以看到在ZygoteState的connect方法里面,調(diào)用了LocalSocket的connect方法状原。而這個LocalSocket就是Android里面的Socket實現(xiàn)聋呢,和java里面的Socket類一樣苗踪,實現(xiàn)了Closeable接口颠区。
至此,我們已經(jīng)可以看出通铲,AMS和Zygote進程建立Socket連接的過程和基于Java的Socket連接過程是很相似的毕莱。

Zygote接收請求并創(chuàng)建app進程

同樣,我們先看一下這部分的時序圖
image.png

我們先從颅夺,Zygote進程啟動過程中會創(chuàng)建一個Server端的Socket朋截,這個Socket用來等待AMS發(fā)送請求講起。
這個過程是在ZygoteInit的main方法中執(zhí)行的吧黄。

public static void main(String argv[]) {
        ...
        String socketName = "zygote";
        ...
        zygoteServer.registerServerSocketFromEnv(socketName);
        if (!enableLazyPreload) {
                bootTimingsTraceLog.traceBegin("ZygotePreload");
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                    SystemClock.uptimeMillis());
                //預加載資源
                preload(bootTimingsTraceLog);
          ...
          //創(chuàng)建SystemServer進程
          if (startSystemServer) {
                Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
          ...
          // The select loop returns early in the child process after a fork and
            // loops forever in the zygote.
            //等待AMS的請求
            caller = zygoteServer.runSelectLoop(abiList);
          ...  
}

這段代碼中部服,首先通過registerServerSocketFromEnv方法創(chuàng)建了一個Server段的Socket,這個name為"zygote"的Socket用來等待AMS請求Zygote拗慨,以創(chuàng)建新的app進程廓八。最后調(diào)用zygoteServer的runSelectLoop方法來等待或者說監(jiān)聽AMS請求創(chuàng)建新的app進程。接下來看看zygoteServer的runSelectLoop方法

/**
     * 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.
     */
    Runnable runSelectLoop(String abiList) {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
        ...
        while (true) {
            StructPollfd[] pollFds = new StructPollfd[fds.size()];
            for (int i = 0; i < pollFds.length; ++i) {
            ...
            ZygoteConnection connection = peers.get(i);
                        final Runnable command = connection.processOneCommand(this);
            ...
}

runSelectLoop方法中赵抢,通過一個while(true)的循環(huán)剧蹂,不停的遍歷ArrayList<ZygoteConnection>類型的peers列表,執(zhí)行其中每個ZygoteConnection對象的processOneCommand方法烦却。我們接著看ZygoteConnection的processOneCommand方法

/**
     * Reads one start command from the command socket. If successful, a child is forked and a
     * {@code Runnable} that calls the childs main method (or equivalent) is returned in the child
     * process. {@code null} is always returned in the parent process (the zygote).
     *
     * If the client closes the socket, an {@code EOF} condition is set, which callers can test
     * for by calling {@code ZygoteConnection.isClosedByPeer}.
     */
    Runnable processOneCommand(ZygoteServer zygoteServer) {
        ...
        //讀取app進程的啟動參數(shù)
        args = readArgumentList();
        ...
        parsedArgs = new Arguments(args);
        ...
        pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
                parsedArgs.instructionSet, parsedArgs.appDataDir);
       try {
            //當前代碼是在子進程中執(zhí)行的
            if (pid == 0) {
                // in child
                zygoteServer.setForkChild();

                zygoteServer.closeServerSocket();
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;

                return handleChildProc(parsedArgs, descriptors, childPipeFd,
                        parsedArgs.startChildZygote);
            } else {
                // In the parent. A pid < 0 indicates a failure and will be handled in
                // handleParentProc.
                IoUtils.closeQuietly(childPipeFd);
                childPipeFd = null;
                handleParentProc(pid, descriptors, serverPipeFd);
                return null;
            }
        } finally {
            IoUtils.closeQuietly(childPipeFd);
            IoUtils.closeQuietly(serverPipeFd);
        }
    }

上面這段代碼中宠叼,首先調(diào)用readArgumentList方法獲取app進程的啟動參數(shù),并封裝到Arguments類型的parsedArgs參數(shù)中其爵,然后會調(diào)用Zygote的forkAndSpecialize方法來創(chuàng)建app進程冒冬,參數(shù)就是parsedArgs中的app進程啟動參數(shù),然后返回pid摩渺。forkAndSpecialize方法主要是通過fork當前進程简烤,也就是Zygote進程來創(chuàng)建一個子進程的。如果pid為0证逻,那接下去的代碼就是在新創(chuàng)建的子進程中執(zhí)行乐埠。這時會調(diào)用handleChildProc來處理App進程抗斤。

   /**
     * Handles post-fork setup of child proc, closing sockets as appropriate,
     * reopen stdio as appropriate, and ultimately throwing MethodAndArgsCaller
     * if successful or returning if failed.
     */
private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
            FileDescriptor pipeFd, boolean isZygote) {
        //關(guān)閉LocalSocket
        closeSocket();
        ...
        if (!isZygote) {
                return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
                        null /* classLoader */);
        ...
}

在handleChildProc方法中,需要重點關(guān)注的代碼就是調(diào)用了ZygoteInit的zogoteInit方法丈咐。

/**
     * The main function called when started through the zygote process. This
     * could be unified with main(), if the native code in nativeFinishInit()
     * were rationalized with Zygote startup.
     *
     */
    public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
        if (RuntimeInit.DEBUG) {
            Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
        }

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
        RuntimeInit.redirectLogStreams();

        RuntimeInit.commonInit();
        //創(chuàng)建Binder線程池
        ZygoteInit.nativeZygoteInit();
        return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }

zygoteInit方法最后調(diào)用了RuntimeInit的applicationInit方法瑞眼。下面是applicationInit方法的代碼

protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) {
        nativeSetExitWithoutCleanup(true);
        VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
        VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
        final Arguments args = new Arguments(argv);
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        // Remaining arguments are passed to the start class's static main
        return findStaticMain(args.startClass, args.startArgs, classLoader);
    }

RuntimeInit的ApplicationInit方法最后調(diào)用了findStaticMain方法,

/**
     * Invokes a static "main(argv[]) method on class "className".
     * Converts various failing exceptions into RuntimeExceptions, with
     * the assumption that they will then cause the VM instance to exit.
     */
    protected static Runnable findStaticMain(String className, String[] argv,
            ClassLoader classLoader) {
        Class<?> cl;

        try {
            cl = Class.forName(className, true, classLoader);
        } catch (ClassNotFoundException ex) {
            throw new RuntimeException(
                    "Missing class when invoking static main " + className,
                    ex);
        }

        Method m;
        try {
            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();
        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.
         */
        return new MethodAndArgsCaller(m, argv);
    }

源碼中給出的注釋棵逊,findStaticMain方法的工作是伤疙,根據(jù)類名className,調(diào)用其指定類的main方法辆影。這個className指的就是本文開頭提到過的android.app.ActivityThread徒像。所以findStaticMain方法的實際作用就是調(diào)用進程中的ActivityThread類的main方法。
然后蛙讥,看到上面代碼的最后一行锯蛀,創(chuàng)建了一個MethodAndArgsCaller對象并返回。MethodAndArgsCaller實現(xiàn)了Runnable接口次慢,是一個可執(zhí)行的任務旁涤。到這里,我們要根據(jù)方法調(diào)用往回看迫像,最終會看到MethodAndArgsCaller對象的run方法是在ZygoteInit的main方法里面

public static void main(String argv[]) {
        ...
        caller = zygoteServer.runSelectLoop(abiList);
        ...
        // We're in the child process and have exited the select loop. Proceed to execute the
        // command.
        if (caller != null) {
            caller.run();
        }
}

接下來劈愚,我們來看看MethodAndArgsCaller的run方法

public void run() {
            try {
                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);
            }
        }

這里的mMethod方法就是ActivityThrea的main方法,調(diào)用mMethod的invoke方法后闻妓,ActivityThread的main方法就會被動態(tài)調(diào)用菌羽,app進程就進入了ActivityThread的main方法中,講到這里由缆,app進程的啟動過程就算完成了注祖。

總結(jié)

本文主要從源碼分析的角度,介紹app進程的啟動過程犁功,這對于理解應用程序的啟動機制以及相關(guān)的優(yōu)化方面氓轰,都是很有意義的。面試的時候浸卦,也會經(jīng)常被問到署鸡。個人認為其中比較重要的幾個關(guān)鍵點是:

  • AMS與Zygote進程之間的Socket通信,傳遞app進程的啟動參數(shù)
  • Zygote進程通過fork自身限嫌,創(chuàng)建app進程
  • app進程的初始化靴庆,創(chuàng)建Binder線程池,啟動ActivityThread線程

本文參考:
《Android進階解密》第三章
Android 安全機制(1)uid 怒医、 gid 與 pid

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末炉抒,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子稚叹,更是在濱河造成了極大的恐慌焰薄,老刑警劉巖拿诸,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異塞茅,居然都是意外死亡亩码,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進店門野瘦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來描沟,“玉大人,你說我怎么就攤上這事鞭光±袅” “怎么了?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵惰许,是天一觀的道長席覆。 經(jīng)常有香客問我,道長啡省,這世上最難降的妖魔是什么娜睛? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮卦睹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘方库。我一直安慰自己结序,他們只是感情好,可當我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布纵潦。 她就那樣靜靜地躺著徐鹤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪邀层。 梳的紋絲不亂的頭發(fā)上返敬,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天,我揣著相機與錄音寥院,去河邊找鬼劲赠。 笑死,一個胖子當著我的面吹牛秸谢,可吹牛的內(nèi)容都是我干的凛澎。 我是一名探鬼主播,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼估蹄,長吁一口氣:“原來是場噩夢啊……” “哼塑煎!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起臭蚁,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤最铁,失蹤者是張志新(化名)和其女友劉穎讯赏,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體冷尉,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡待逞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了网严。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片识樱。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖震束,靈堂內(nèi)的尸體忽然破棺而出怜庸,到底是詐尸還是另有隱情,我是刑警寧澤垢村,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布割疾,位于F島的核電站,受9級特大地震影響嘉栓,放射性物質(zhì)發(fā)生泄漏宏榕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一侵佃、第九天 我趴在偏房一處隱蔽的房頂上張望麻昼。 院中可真熱鬧,春花似錦馋辈、人聲如沸抚芦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽叉抡。三九已至,卻和暖如春答毫,著一層夾襖步出監(jiān)牢的瞬間褥民,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工洗搂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留消返,地道東北人。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓蚕脏,卻偏偏與公主長得像侦副,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子驼鞭,可洞房花燭夜當晚...
    茶點故事閱讀 45,507評論 2 359

推薦閱讀更多精彩內(nèi)容