1. 程式人生 > >Android 應用程序啟動流程

Android 應用程序啟動流程

我們知道啟動Activity時,在ActivityStackSupervisor.java中函式startSpecificActivityLocked裡面會判斷當前Activity所在application是否已經啟動,如果啟動,則直接建立Activity也即呼叫realStartActivityLocked,本篇討論需要啟動的Activity所屬的application沒有啟動的情況,此時就會通過AMS來呼叫startProcessLocked建立新程序。

AMS獲取請求

在ActivityStackSupervisor中分析完確定啟動新程序,就會操作權交給AMS來處理,如圖:         

          startSpecificActivityLocked分析是否要建立程序           
    void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        // Is this activity's application already running?
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);

        r.task.stack.setLaunchTime(r);

        if (app != null && app.thread != null) {
            try {
                ......
                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
                ......
            }

            ......
        }

        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    }
         mService.startProcessLocked進入AMS處理流程,最終會進入AMS內部私有函式private final void startProcessLocked(ProcessRecord app,
            String hostingType, String hostingNameStr),如下:
    private final void startProcessLocked(ProcessRecord app,
            String hostingType, String hostingNameStr) {
        ......

        try {
            ......

            // Start the process.  It will either succeed and return a result containing
            // the PID of the new process, or else throw a RuntimeException.
            Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
                    app.processName, uid, uid, gids, debugFlags, mountExternal,
                    app.info.targetSdkVersion, app.info.seinfo, null);

            ......

            if (app.persistent) {
                Watchdog.getInstance().processStarted(app.processName, startResult.pid);
            }

            ......
            }
        } catch (RuntimeException e) {
            // XXX do better error recovery.
            app.setPid(0);
            Slog.e(TAG, "Failure starting process " + app.processName, e);
        }
    }
       接著Process接手啟動應用主執行緒ActivityThread的任務
    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[] zygoteArgs) {
        try {
            return startViaZygote(processClass, niceName, uid, gid, gids,
                    debugFlags, mountExternal, targetSdkVersion, seInfo, zygoteArgs);
        } catch (ZygoteStartFailedEx ex) {
            Log.e(LOG_TAG,
                    "Starting VM process through Zygote failed");
            throw new RuntimeException(
                    "Starting VM process through Zygote failed", ex);
        }
    }
        然後,startViaZygote封裝相關資訊,向Zygote服務程序傳送啟動新應用程序的請求,並通過/dev/socket/zygote通道傳送請求資訊。
    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[] extraArgs)
                                  throws ZygoteStartFailedEx {
        synchronized(Process.class) {
            ArrayList<String> argsForZygote = new ArrayList<String>();

            // --runtime-init, --setuid=, --setgid=,
            // and --setgroups= must go first
            argsForZygote.add("--runtime-init");
            argsForZygote.add("--setuid=" + uid);
            argsForZygote.add("--setgid=" + gid);
            if ((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0) {
                argsForZygote.add("--enable-jni-logging");
            }
            if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) {
                argsForZygote.add("--enable-safemode");
            }
            if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) {
                argsForZygote.add("--enable-debugger");
            }
            if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) {
                argsForZygote.add("--enable-checkjni");
            }
            if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
                argsForZygote.add("--enable-assert");
            }
            if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER) {
                argsForZygote.add("--mount-external-multiuser");
            } else if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL) {
                argsForZygote.add("--mount-external-multiuser-all");
            }
            argsForZygote.add("--target-sdk-version=" + targetSdkVersion);

            //TODO optionally enable debuger
            //argsForZygote.add("--enable-debugger");

            // --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);
            }

            argsForZygote.add(processClass);

            if (extraArgs != null) {
                for (String arg : extraArgs) {
                    argsForZygote.add(arg);
                }
            }

            return zygoteSendArgsAndGetResult(argsForZygote);
        }
    }
       zygoteSendArgsAndGetResult傳送封裝的資訊並獲取返回結果
    private static ProcessStartResult zygoteSendArgsAndGetResult(ArrayList<String> args)
            throws ZygoteStartFailedEx {
        openZygoteSocketIfNeeded();

        try {
            /**
             * See com.android.internal.os.ZygoteInit.readArgumentList()
             * Presently the wire format to the zygote process is:
             * a) a count of arguments (argc, in essence)
             * b) a number of newline-separated argument strings equal to count
             *
             * After the zygote process reads these it will write the pid of
             * the child or -1 on failure, followed by boolean to
             * indicate whether a wrapper process was used.
             */

            sZygoteWriter.write(Integer.toString(args.size()));
            sZygoteWriter.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");
                }
                sZygoteWriter.write(arg);
                sZygoteWriter.newLine();
            }

            sZygoteWriter.flush();

            // Should there be a timeout on this?
            ProcessStartResult result = new ProcessStartResult();
            result.pid = sZygoteInputStream.readInt();
            if (result.pid < 0) {
                throw new ZygoteStartFailedEx("fork() failed");
            }
            result.usingWrapper = sZygoteInputStream.readBoolean();
            return result;
        } catch (IOException ex) {
            try {
                if (sZygoteSocket != null) {
                    sZygoteSocket.close();
                }
            } catch (IOException ex2) {
                // we're going to fail anyway
                Log.e(LOG_TAG,"I/O exception on routine close", ex2);
            }

            sZygoteSocket = null;

            throw new ZygoteStartFailedEx(ex);
        }
    }
        openZygoteSocketIfNeeded建立通訊需要使用的通道
    private static void openZygoteSocketIfNeeded() 
            throws ZygoteStartFailedEx {

        ......

        for (int retry = 0
                ; (sZygoteSocket == null) && (retry < (retryCount + 1))
                ; retry++ ) {

            ......

            try {
                sZygoteSocket = new LocalSocket();

                sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET, 
                        LocalSocketAddress.Namespace.RESERVED));

                sZygoteInputStream
                        = new DataInputStream(sZygoteSocket.getInputStream());

                sZygoteWriter =
                    new BufferedWriter(
                            new OutputStreamWriter(
                                    sZygoteSocket.getOutputStream()),
                            256);

                Log.i("Zygote", "Process: zygote socket opened");

                sPreviousZygoteOpenFailed = false;
                break;
            } catch (IOException ex) {
                if (sZygoteSocket != null) {
                    try {
                        sZygoteSocket.close();
                    } catch (IOException ex2) {
                        Log.e(LOG_TAG,"I/O exception on close after exception",
                                ex2);
                    }
                }

                sZygoteSocket = null;
            }
        }

        if (sZygoteSocket == null) {
            sPreviousZygoteOpenFailed = true;
            throw new ZygoteStartFailedEx("connect failed");                 
        }
    }
其中“ZYGOTE_SOCKET”為"zygote",建立通道後,對應裝置檔案“/dev/socket/zygote”,接著就使用sZygoteWriter將資訊傳送給服務端,服務端接手到後就會建立新程序,最後通過sZygoteInputStream分別獲取pid(=sZygoteInputStream.readInt()),usingWrapper(= sZygoteInputStream.readBoolean())。

Zygote孵化子程序

以上Prcess向Zygote傳送啟動子程序的訊息後,Zygote守護程序就會開始建立子程序。

Zygote服務程序會監聽“/dev/socket/zygote”裝置檔案,一旦有讀寫動作,內部的輪詢函授runSelectLoop就會建立ZygoteConnection,並執行runOnce

    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;
        }

        if (args == null) {
            // EOF reached.
            closeSocket();
            return true;
        }

        /** the stderr of the most recent request, if avail */
        PrintStream newStderr = null;

        if (descriptors != null && descriptors.length >= 3) {
            newStderr = new PrintStream(
                    new FileOutputStream(descriptors[2]));
        }

        int pid = -1;
        FileDescriptor childPipeFd = null;
        FileDescriptor serverPipeFd = null;

        try {
            parsedArgs = new Arguments(args);

            applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext);
            applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext);
            applyCapabilitiesSecurityPolicy(parsedArgs, peer, peerSecurityContext);
            applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext);
            applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext);

            applyDebuggerSystemProperty(parsedArgs);
            applyInvokeWithSystemProperty(parsedArgs);

            int[][] rlimits = null;

            if (parsedArgs.rlimits != null) {
                rlimits = parsedArgs.rlimits.toArray(intArray2d);
            }

            if (parsedArgs.runtimeInit && parsedArgs.invokeWith != null) {
                FileDescriptor[] pipeFds = Libcore.os.pipe();
                childPipeFd = pipeFds[1];
                serverPipeFd = pipeFds[0];
                ZygoteInit.setCloseOnExec(serverPipeFd, true);
            }

            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                    parsedArgs.niceName);
        } catch (IOException ex) {
            logAndPrintError(newStderr, "Exception creating pipe", ex);
        } catch (ErrnoException ex) {
            logAndPrintError(newStderr, "Exception creating pipe", ex);
        } catch (IllegalArgumentException ex) {
            logAndPrintError(newStderr, "Invalid zygote arguments", ex);
        } catch (ZygoteSecurityException ex) {
            logAndPrintError(newStderr,
                    "Zygote security policy prevents request: ", ex);
        }

        try {
            if (pid == 0) {
                // in child
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;
                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
                IoUtils.closeQuietly(childPipeFd);
                childPipeFd = null;
                return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
            }
        } finally {
            IoUtils.closeQuietly(childPipeFd);
            IoUtils.closeQuietly(serverPipeFd);
        }
    }
readArgumentList獲取引數列表,也即startViaZygote中封裝的引數列表,接著呼叫Zygote的forkAndSpecialize,在到JNI層的nativeForkAndSpecialize,

forkAndSpecializeCommon,在到核心的fork函式,完成程序的建立,後面呼叫handleChildProc,handleParentProc對父子程序做相關處理。

    private boolean handleParentProc(int pid,
            FileDescriptor[] descriptors, FileDescriptor pipeFd, Arguments parsedArgs) {

        if (pid > 0) {
            setChildPgid(pid);
        }

        if (descriptors != null) {
            for (FileDescriptor fd: descriptors) {
                IoUtils.closeQuietly(fd);
            }
        }

        boolean usingWrapper = false;
        if (pipeFd != null && pid > 0) {
            DataInputStream is = new DataInputStream(new FileInputStream(pipeFd));
            int innerPid = -1;
            try {
                innerPid = is.readInt();
            } catch (IOException ex) {
                Log.w(TAG, "Error reading pid from wrapped process, child may have died", ex);
            } finally {
                try {
                    is.close();
                } catch (IOException ex) {
                }
            }

            // Ensure that the pid reported by the wrapped process is either the
            // child process that we forked, or a descendant of it.
            if (innerPid > 0) {
                int parentPid = innerPid;
                while (parentPid > 0 && parentPid != pid) {
                    parentPid = Process.getParentPid(parentPid);
                }
                if (parentPid > 0) {
                    Log.i(TAG, "Wrapped process has pid " + innerPid);
                    pid = innerPid;
                    usingWrapper = true;
                } else {
                    Log.w(TAG, "Wrapped process reported a pid that is not a child of "
                            + "the process that we forked: childPid=" + pid
                            + " innerPid=" + innerPid);
                }
            }
        }

        try {
            mSocketOutStream.writeInt(pid);
            mSocketOutStream.writeBoolean(usingWrapper);
        } catch (IOException ex) {
            Log.e(TAG, "Error reading from command socket", ex);
            return true;
        }

        return false;
    }
handleParentProc設定程序組,返回pid,usingWrapper的值。
    private void handleChildProc(Arguments parsedArgs,
            FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
            throws ZygoteInit.MethodAndArgsCaller {

        closeSocket();
        ZygoteInit.closeServerSocket();

        if (descriptors != null) {
            try {
                ZygoteInit.reopenStdio(descriptors[0],
                        descriptors[1], descriptors[2]);

                for (FileDescriptor fd: descriptors) {
                    IoUtils.closeQuietly(fd);
                }
                newStderr = System.err;
            } catch (IOException ex) {
                Log.e(TAG, "Error reopening stdio", ex);
            }
        }

        if (parsedArgs.niceName != null) {
            Process.setArgV0(parsedArgs.niceName);
        }

        if (parsedArgs.runtimeInit) {
            if (parsedArgs.invokeWith != null) {
                WrapperInit.execApplication(parsedArgs.invokeWith,
                        parsedArgs.niceName, parsedArgs.targetSdkVersion,
                        pipeFd, parsedArgs.remainingArgs);
            } else {
                RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
                        parsedArgs.remainingArgs);
            }
        } else {
            String className;
            try {
                className = parsedArgs.remainingArgs[0];
            } catch (ArrayIndexOutOfBoundsException ex) {
                logAndPrintError(newStderr,
                        "Missing required class name argument", null);
                return;
            }

            String[] mainArgs = new String[parsedArgs.remainingArgs.length - 1];
            System.arraycopy(parsedArgs.remainingArgs, 1,
                    mainArgs, 0, mainArgs.length);

            if (parsedArgs.invokeWith != null) {
                WrapperInit.execStandalone(parsedArgs.invokeWith,
                        parsedArgs.classpath, className, mainArgs);
            } else {
                ClassLoader cloader;
                if (parsedArgs.classpath != null) {
                    cloader = new PathClassLoader(parsedArgs.classpath,
                            ClassLoader.getSystemClassLoader());
                } else {
                    cloader = ClassLoader.getSystemClassLoader();
                }

                try {
                    ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
                } catch (RuntimeException ex) {
                    logAndPrintError(newStderr, "Error starting.", ex);
                }
            }
        }
    }
handleChildProc最主要的任務就調到ZygoteInit的invokeStaticMain方法,中間主要是使用放射方式構造ActivityThread類並呼叫main方法
    static void invokeStaticMain(ClassLoader loader,
            String className, String[] argv)
            throws ZygoteInit.MethodAndArgsCaller {
        Class<?> cl;

        try {
            cl = loader.loadClass(className);
        } 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.
         */
        throw new ZygoteInit.MethodAndArgsCaller(m, argv);
    }
調完ActivityThread.main方法之後,應用的程序的啟動也就完成了。Activity在主執行緒ActivityThread建立之後,程序空間就準備完畢,後續就call  onCreate,onResume來完成介面佈局。


相關推薦

Android 應用程序啟動流程

我們知道啟動Activity時,在ActivityStackSupervisor.java中函式startSpecificActivityLocked裡面會判斷當前Activity所在application是否已經啟動,如果啟動,則直接建立Activity也即呼叫realS

Android 應用程序啟動流程

閱讀的收益 討論的內容也就是一個應用程序是如何啟動的,私以為這一部分的內容頗為重要,即便不瞭解細節,也要知道其中的大體步驟。特別是針對我們應用開發者而言,理應瞭解我們的 App 是如何被啟動的,App 中的元件是如何被系統服務呼叫和組織的。 講應用程序啟動的文章不是很多,也

Android原始碼解析之(十一)-->應用程序啟動流程

本節主要是通過分析Activity的啟動過程介紹應用程式程序的啟動流程。關於Android的應用程序在android guide中有這樣的一段描述: By default, every application runs in its own Linu

Android程式入口ActivityThread和Android應用程式啟動流程詳解

          大家初學java時候都知道java的程式入口是從main方法進入,那麼Android是基於java編寫的,那Android的程式入口做了哪些操作呢?還有Android的應用程式到底是怎樣啟動的呢?我們一起來看一下. 首先附上ActivityThread.

Android APK打包安裝、應用程序啟動過程、Activity啟動流程

目錄 一、Android APK的構建過程 通過IDE可以生成可以在android裝置中安裝的apk檔案,Google官方提供的構建APK的過程流程圖如下: 打包APK流程總結如下: AAPT(Android Asset Packaging Tool)工

Android中system server程序啟動流程原始碼解析 系統服務啟動

system server 前言 System Server fork SystemServer SystemServer.main() SystemServer.createSystemContext SystemSe

Android雜談:systrace簡單檢視一個應用啟動流程

騰空.png systrace是用來檢視應用和系統執行狀態的工具,利用他可以分析一些效能問題。例如檢視應用是否卡頓,卡在那個方法了之類的問題。本文簡單抓一個瀏覽器啟動的systrace隨便看看吧。 一.啟動Andriod Device Monitor 連線

Android進階(二): 應用程序啟動過程

1.前言 最近一直在看 《Android進階解密》 的一本書,這本書編寫邏輯、流程都非常好,而且很容易看懂,非常推薦大家去看看(沒有收廣告費,單純覺得作者寫的很好)。 今天就將 應用程序啟動過程 總結一下(基於Android 8.0 系統)。 文章中例項&nbs

Android原始碼解析之(九)-->SystemServer程序啟動流程

上面一文中我們講過android系統中比較重要的幾個程序:init程序,Zygote程序,SystemServer程序已經各種應用程序,其中Zygote程序是整個android系統的根程序,包含SystemServer程序已經各種應用程序在內的程序都是通過Z

Android 7.0應用啟動流程分析

最近在為自己Moto G定製Rom,順便重新讀了一遍Android 7.0的相關原始碼,特此記錄當做筆記. 在開始正文之前,首先要明白冷啟動和熱啟動.所謂冷啟動就是啟動該應用時,後臺沒有該應用的程序,此時系統會建立一個程序分配給它(AMS通過Socket和Zy

android應用程式啟動詳情之程序相關

        當某個應用元件啟動且該應用沒有執行其他任何元件時,Android 系統會使用單個執行執行緒為應用啟動新的 Linux 程序。 預設情況下,同一應用的所有元件在相同的程序和執行緒(稱為“主”執行緒)中執行。 如果某個應用元件啟動且該應用已存在程序(因為存在

Android O: init程序啟動流程分析(階段三)

本篇部落格我們就來看看init程序啟動時,解析init.rc檔案相關的工作。 一、建立Parser並決定解析檔案 int main(int argc, char** argv) { .............. //定義Action中

關於Android應用程序漏洞的防護措施

android 應用程序 移動應用 開發者 目前,Android應用程序市場的發展速度飛快,不少開發者為了追求開發速度而忽視應用程序的安全。但由於Android系統的開源性及其Java編寫的特殊性,各類Android App經常被爆出漏洞,有的Android開發者只是對App進行

最優雅退出 Android 應用程序的 6 種方式

home鍵 應用 一點 container new 出棧 manage 而且 rec 一、容器式建立一個全局容器,把所有的Activity存儲起來,退出時循環遍歷finish所有Activity import java.util.ArrayList; impor

【苦讀官方文檔】2.Android應用程序基本原理概述

project 做出 系統默認 體驗 告訴 sta 執行過程 顏色 硬件配置 官方文檔原文地址 應用程序原理 Android應用程序是通過Java編程語言來寫。Android軟件開發工具把你的代碼和其它數據、資源文件一起編譯、打包成一個APK文件

Android應用程序中實現推送通知

xamarin android 幾乎每一個應用程序的一個重要特性是支持推送通知的能力。使用推送通知,您可以更新用戶,而不需要應用程序在任何時候運行或輪詢服務器, 避免潛在的電池電量不足。 隨著火力點雲信息的介紹(FCM),谷歌使得在Android應用程序中實現推送通知變

Android應用程序訪問linux驅動第一步:實現並測試Linux驅動

sizeof 屬性文件 rup sla 沒有 lov /dev/ art kmalloc 一直都想親自做一次使用android應用程序訪問Linux內核驅動的嘗試,但總是沒能做到。最近抽出時間,下決心重新嘗試一次。嘗試的開始當然是先寫一個Linux內核驅動了。 我希望

iOS 應用程序啟動時要做什麽

通過 有關 撤銷 任務 臨時 hone 分享 ext 後臺 當您的應用程序啟動(無論是在前臺或後臺),使用您的應用程序委托application:willFinishLaunchingWithOptions:和application:didFinishLaunchingWi

Android應用一般上架流程

blog 個人 con 地址 -m cal 截圖 click mil Android App上架所需文件 上架準備 ?App文件: 1.?安裝包 2.?應用商標:圖

C#使用Xamarin開發Android應用程序 -- 系列文章

android界面 百度 0.11 itl 利用 設備 android安裝 tor href Xamarin開發Android應用程序 利用Xamaria構建Android應用-公交發車信息屏 Xamarin版的C# SVG路徑解析器 C#使用Xamarin開發可移植