天天看點

Android framework源碼分析二 應用程序啟動流程源碼分析(Android8.0)概述

點選桌面圖示如何啟動的app Android8.0

  • 概述
    • 1:APP啟動的入口Launcher的分析
    • 2:APP的啟動在Activity中啟動過程
    • 3:APP的啟動在AMS中啟動過程
    • 4:Process、ZygoteProcess的啟動過程
      • 小插曲LocalSocket、LocalSocketAddress 和LocalServerSocket的關系
    • 5:Zygote完成建立APP程序的過程:ZygoteInit、ZygoteServer和ZygoteConnection
      • Native層調用Linux系統fork函數完成建立程序的過程
    • 6:應用的程序啟動後,啟動Activity 和關聯Context的過程。
    • 7:總結

概述

首先附上我的幾篇其它文章連結感興趣的可以看看,如果文章有異議的地方歡迎指出,共同進步,順便點贊謝謝!!!

Android studio編寫第一個NDK工程的過程詳解(附Demo下載下傳位址)

面試必備1:HashMap(JDK1.8)原理以及源碼分析

面試必備2:JDK1.8LinkedHashMap實作原理及源碼分析

Android事件分發機制原理及源碼分析

View事件的滑動沖突以及解決方案

Handler機制一篇文章深入分析Handler、Message、MessageQueue、Looper流程和源碼

Android三級緩存原理及用LruCache、DiskLruCache實作一個三級緩存的ImageLoader

本文是在上文Android framework 源碼分析之Activity啟動流程(android 8.0)的基礎上多應用程序建立、啟動以及程序啟動後啟動activity過程分析。中間涉及Launcher、AMS、Binder、Process、LocalSocket、Zygote、fork等知識。

上一篇文章中對Activity的啟動流程做了詳細的分析,在第三部分的Step13中ActivityStackSupervisor類的

startSpecificActivityLocked

方法中分析到如果activity所在程序已經啟動的情況,今天就來分析一下程序未啟動的情況,即App的啟動流程。

其實app的啟動最後也是通過調用Activity的startActivity方法,最終走到上圖中AMS的

startProcessLocked

方法,在

startProcessLocked

先去啟動App所在的程序,啟動這個程序的過程牽扯了:

Zygote

程序和

system_server

程序,在這個過程中所有跨進城都離不開Binder機制。

1:APP啟動的入口Launcher的分析

Android 系統啟動後已經啟動了 Zygote,ServiceManager,SystemServer 等系統程序;ServiceManager 程序中完成了 Binder 初始化;SystemServer 程序中 ActivityManagerService,WindowManagerService,PackageManagerService 等系統服務在 ServiceManager 中已經注冊;最後啟動了 Launcher 桌面應用。

Launcher本神就是一個應用,被系統啟動,這裡不詳細分析分析Launcher的源碼,我們從點選桌面上的圖示入手分析,即啟動APP的入口

Step1: Launcher中條目的點選監聽的onClick方法開始:

/**
     * Launches the intent referred by the clicked shortcut.
     * 啟動被單擊的快捷方式引用的意圖
     */
    public void onClick(View v) {
          ....代碼
        Object tag = v.getTag();
        if (tag instanceof ShortcutInfo) {
            onClickAppShortcut(v);
        } else if (tag instanceof FolderInfo) {
            if (v instanceof FolderIcon) {
                onClickFolderIcon(v);
            }
        } else if ((v instanceof PageIndicator) ||
                (v == mAllAppsButton && mAllAppsButton != null)) {
            onClickAllAppsButton(v);
        } else if (tag instanceof AppInfo) {//如果屬于AppInfo,裡面包含了啟動的APP的資訊
            //交給startAppShortcutOrInfoActivity 去處理
            startAppShortcutOrInfoActivity(v);
        } else if (tag instanceof LauncherAppWidgetInfo) {
            if (v instanceof PendingAppWidgetHostView) {
                onClickPendingWidget((PendingAppWidgetHostView) v);
            }
        }
    }
           

經過一些簡單校驗交給交給

startAppShortcutOrInfoActivity

去處理。

Step2: Launcher的

startAppShortcutOrInfoActivity

方法啟動APP:

private void startAppShortcutOrInfoActivity(View v) {
        ...省略部分代碼,主要是對intent進行校驗
        //交給startActivitySafely去啟動
        boolean success = startActivitySafely(v, intent, item);
        getUserEventDispatcher().logAppLaunch(v, intent); // TODO for discovered apps b/35802115
        if (success && v instanceof BubbleTextView) {
            mWaitingForResume = (BubbleTextView) v;
            mWaitingForResume.setStayPressed(true);
        }
    }
           

首先對intent進行校驗,最終将将啟動任務交給了

startActivitySafely

方法

Step3: Launcher的

startActivitySafely

方法啟動APP:

public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
        ...省略部分代碼
        try {
            if (Utilities.ATLEAST_MARSHMALLOW
                    && (item instanceof ShortcutInfo)
                    && (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
                    || item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
                    && !((ShortcutInfo) item).isPromise()) {
                //快捷啟動需要進行一些校驗
                startShortcutIntentSafely(intent, optsBundle, item);
            } else if (user == null || user.equals(Process.myUserHandle())) {
                // 最終執行父類Activity的startActivity方法
                startActivity(intent, optsBundle);
            }
            ...省略代碼
        return false;
    }
           

**小結:**這startActivitySafely方法中,最終将啟動任務交給了父類Activity的startActivity方法去啟動APP,自己在進入onPause狀态。自此APP的的啟動流程就進入了Activity的啟動流程,如果沒有看過請先閱讀我的第一篇文章Android framework 源碼分析之Activity啟動流程(android 8.0)

2:APP的啟動在Activity中啟動過程

在Activity中啟動過程在Android framework 源碼分析之Activity啟動流程(android 8.0)中已做了詳細分析,都是從Activity的startActivityForResult開始一直到上文Step12 都是一緻的在此不做分析,接下來我們着重看一下Step13

ActivityStackSupervisor

類的

startSpecificActivityLocked

方法

Step4: ActivityStackSupervisor的

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.getStack().setLaunchTime(r);
        if (app != null && app.thread != null) {
         //app程序已經在運作,直接去啟動
            try {
                if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                        || !"android".equals(r.info.packageName)) {
                    // Don't add this if it is a platform component that is marked
                    // to run in multiple processes, because this is actually
                    // part of the framework so doesn't make sense to track as a
                    // separate apk in the process.
                    //如果它是一個被标記為在多個程序中運作的平台元件,那麼不要添加它,因為它實際上是架構的一部分,是以在程序中作為單獨的apk進行跟蹤是沒有意義的
                    app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
                            mService.mProcessStats);
                }
                //重點:将activity的啟動工作轉交給realStartActivityLocked方法
                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting activity " + r.intent.getComponent().flattenToShortString(), e);
            }
            // If a dead object exception was thrown -- fall through to
            // restart the application.
        }
        // 如果程序為app 為null或者有異常,則AMS重新fork一個程序來起來,點選桌面啟動圖示如果該應用程序未啟動,走到這裡
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    }

           

分析:

startSpecificActivityLocked方法邏輯比較簡單,主要負責跟要啟動的Activity程序相關的工作,首先由AMS根據參數通過

getProcessRecordLocked

方法擷取目前APP程序的記錄ProcessRecord ,如果擷取到ProcessRecord即應用所在程序已經啟動,則執行

realStartActivityLocked

方法,否則應用程序未啟動,則交給AMS的

startProcessLocked

方法去啟動該程序。

至于方法裡if裡面

realStartActivityLocked

方法的内容已經在上文中分析了,接下來我們繼續分析else部分的邏輯,即APP的啟動。

3:APP的啟動在AMS中啟動過程

Step5: ActivityManagerService的

startProcessLocked

方法去啟動程序的邏輯分析:

final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags,
                                           String hostingType, ComponentName hostingName, boolean allowWhileBooting,
                                           boolean isolated, boolean keepIfLarge) {
         //調用它的重載方法,需要注意的是,加入一個參數叫做entryPoint,并且參數為null
        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表示目前需要啟動的app是不是一個獨立的程序,如果是獨立的話那就重新
        // 建立一個ProcessRecord,如果不是的話那就從正在運作的程序清單中找。
        if (!isolated) {
            //根據程序名和程序uid擷取程序對應的ProcessRecord,ProcessRecord封裝了正在運作的程序的完整資訊
            app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
            ....省略部分代碼
            //   這是一個獨立的程序或者在正在運作的清單中沒有找到相應的記錄
        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;
            }
            //一堆指派操作
            app.crashHandler = crashHandler;
            app.isolatedEntryPoint = entryPoint;
            app.isolatedEntryPointArgs = entryPointArgs;
            checkTime(startTime, "startProcess: done creating new process record");
        } else {
             // // 如果這是該程序中的一個新的package,那就添加到package清單
            // 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方法去建立程序,注意這個方法的傳回值boolean
        final boolean success = startProcessLocked(app, hostingType, hostingNameStr, abiOverride);
        checkTime(startTime, "startProcess: done starting proc!");
        return success ? app : null;
    }

           

**分析:這裡邏輯比較簡單, 這裡再次檢查是否已經有以process + uid命名的程序存在,如果我們首次啟動這個app,則app==null,是以,後面會建立一個ProcessRecord,并存儲存在成員變量mProcessNames中,最終即程序的啟動交給了startProcessLocked 方法,注意此方法的傳回值是boolean。

Step6: AMS的

boolean startProcessLocked

方法分析:

private final boolean startProcessLocked(ProcessRecord app,
            String hostingType, String hostingNameStr, String abiOverride) {
           //繼續調用重載方法傳入參數disableHiddenApiChecks    為false
        return startProcessLocked(app, hostingType, hostingNameStr,
                false /* disableHiddenApiChecks */, abiOverride);
    }
           

繼續分析重載方法

private final boolean startProcessLocked(ProcessRecord app, String hostingType,
                                             String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride) {

            ....省略部分代碼,這着重看流程
             //重點: 這裡給一開傳進來的entryPoint指派給"android.app.ActivityThread"後面通過它進行反射來調用ActivityThread 的main方法
            final String entryPoint = "android.app.ActivityThread";
            //最後交給重載方法startProcessLocked去完成啟動程序的工作
            return startProcessLocked(hostingType, hostingNameStr, entryPoint, app, uid, gids,
                    runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith,
                    startTime);
        } catch (RuntimeException e) {
            Slog.e(TAG, "Failure starting process " + app.processName, e);
            //異常時強制停止啟動
            forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false,
                    false, true, false, false, UserHandle.getUserId(app.userId), "start failure");
            return false;
        }
    }
           

繼續分析其重載方法:

private boolean startProcessLocked(String hostingType, String hostingNameStr, String entryPoint,
                                       ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
                                       String seInfo, String requiredAbi, String instructionSet, String invokeWith,
                                       long startTime) {
        //給ProcessRecord的一些屬性進行一波指派操作
        app.pendingStart = true;
        app.killedByAm = false;
        app.removed = false;
        app.killed = false;
        final long startSeq = app.startSeq = ++mProcStartSeqCounter;
        app.setStartParams(uid, hostingType, hostingNameStr, seInfo, startTime);
        if (mConstants.FLAG_PROCESS_START_ASYNC) {//異步時
            if (DEBUG_PROCESSES) Slog.i(TAG_PROCESSES,
                    "Posting procStart msg for " + app.toShortString());
            mProcStartHandler.post(() -> {
                try {
                      ...省略部分代碼
                    }
                    //最終調用startProcess去啟動
                    final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint,
                            app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo,
                            requiredAbi, instructionSet, invokeWith, app.startTime);
                    synchronized (ActivityManagerService.this) {
                        handleProcessStartedLocked(app, startResult, startSeq);
                    }
                } catch (RuntimeException e) {
                        //異常時強制停止啟動
                }
            });
            return true;
        } else {
            try {
                //最終調用startProcess去啟動
                final ProcessStartResult startResult = startProcess(hostingType, entryPoint, app,
                        uid, gids, runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet,
                        invokeWith, startTime);
                handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper,
                        startSeq, false);
            } catch (RuntimeException e) {
                //異常時強制停止啟動
            }
            return app.pid > 0;
        }
    }
           

分析:經過上面無論if還是else,最終将啟動程序的工作轉移到

startProcess

方法上

Step7: AMS的

startProcess

方法啟動分析:

private ProcessStartResult startProcess(String hostingType, String entryPoint,
            ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
            String seInfo, String requiredAbi, String instructionSet, String invokeWith,
            long startTime) {
        try {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                    app.processName);
            checkTime(startTime, "startProcess: asking zygote to start proc");
            final ProcessStartResult startResult;
            if (hostingType.equals("webview_service")) {
            //在最初ActivityStackSupervisor的startSpecificActivityLocked方法那可以看出傳入的hostingType  等于activity,是以if語句不執行
                startResult = startWebView(entryPoint,
                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, null,
                        new String[] {PROC_START_SEQ_IDENT + app.startSeq});
            } else {
                 //最終執行到這  這裡主要是調用Process.start接口來建立一個新的程序,成功後會傳回程序的pid         foui 否則就會抛出異常,  需要注意的是這個過程是一個阻塞過程, 還有傳入的entryPoint值就是上面傳入的android.app.ActivityThread
                startResult = Process.start(entryPoint,
                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, invokeWith,
                        new String[] {PROC_START_SEQ_IDENT + app.startSeq});
            }
            checkTime(startTime, "startProcess: returned from zygote!");
            return startResult;
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        }
    }
           

分析:

最後是通過

Process.start

來建立應用程序;原理是通過socket向Zygote程序發送建立新程序的請求;Zygote程序啟動後有一個

runSelectLoop

循環,當收到用戶端請求便會執行

ZygoteConnection.runOnce()

方法,再經過層層調用後fork出新的應用程序,建立新程序後将ActivityThread類加載到新程序,并反射調用ActivityThread.main()方法,就這樣建立程序的啟動app的任務就轉移到Process的

start

方法中。接下來我就來詳細分析這個流程。

4:Process、ZygoteProcess的啟動過程

Step8: **Process的

star

方法分析:

/**
 *  需要注意processClass參數就是上文提到entryPoint的值   android.app.ActivityThread
 */
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);
    }

           

這個方法的邏輯比較簡單主要是通過 ZygoteProcess的

start

方法建立新程序。

Step9: ZygoteProcess的

startProcess

方法分析:

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 {
            //最後交給startViaZygote方法去建立新程序
            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);
        }
    }
           

Step10: ZygoteProcess的

startViaZygote

方法建立程序的過程分析:

先大緻說明一下接下來的工作流程:在Process類的startViaZygote方法裡,會計算啟動應用程序用的各個參數,然後再調用zygoteSendArgsAndGetResult方法将這些參數通過socket發送給zygote程序,zygote程序會孵化出新的dalvik應用程序,然後告訴ActivityManagerService新啟動的程序的pid。接下來我們将詳細分析這一過程。

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>();
         ...省略部分代碼   主要是将程序相關的uid、gid等一系列資訊儲存到argsForZygote集合中
        synchronized(mLock) {
            //最終将建立程序的工作交過zygoteSendArgsAndGetResult方法
           //需要注意的是第一個參數是通過openZygoteSocketIfNeeded方法去建構的,幾下來就依次分析這兩個方法
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
        }
    }

           

分析:這個方法邏輯比較簡單,首先是将程序相關的資訊儲存到

argsForZygote

集合中,并将該集合作為參數,交給zygoteSendArgsAndGetResult方法去建立程序,需要注意的是第一個參數是通過openZygoteSocketIfNeeded方法去建構的。

Step11: ZygoteProcess的

openZygoteSocketIfNeeded

方法分析:

private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
        Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
        //   調用該方法時傳入的參數就是上面我們說 的abi了,也就是我們要啟動的目标程序到底是調用Zygote32來fork,還是調用Zygote64來fork
        if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
        //primaryZygoteState是否為空或者已經關閉
            try {   
            //調用ZygoteState.connect(mSocket),嘗試與Zygote程序建立socket連接配接
                primaryZygoteState = ZygoteState.connect(mSocket);
            } catch (IOException ioe) {
                throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
            }
            maybeSetApiBlacklistExemptions(primaryZygoteState, false);
            maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
        }
        //然後去比對abi
        if (primaryZygoteState.matches(abi)) {
        	//如果成功則傳回ZygoteState來啟動目标程序
            return primaryZygoteState;
        }
          
        // The primary zygote didn't match. Try the secondary.
        //  //當主zygote沒能比對成功,則采用第二個zygote,發起connect()操作,邏輯和上面一樣
        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);
        }
        //根據abi去比對
        if (secondaryZygoteState.matches(abi)) {
            return secondaryZygoteState;
        }
        //如果都比對失敗則直接抛出ABI
        throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
    }

           

分析:簡單總結一下

openZygoteSocketIfNeeded

,通過

ZygoteState.connect

方法嘗試與Zygote程序建立socket連接配接,傳回一個

ZygoteStatee

連接配接狀态,拿到這個ZygoteState連接配接狀态後就可以進行寫操作,而與之建立連接配接的Zygote程序會讀取到這個資訊。

Step12: ZygoteProcess的靜态内部類ZygoteState的

connect

方法分析:

public static class ZygoteState {
        final LocalSocket socket;
        final DataInputStream inputStream;
        final BufferedWriter writer;
        final List<String> abiList;
        boolean mClosed;
        private ZygoteState(LocalSocket socket, DataInputStream inputStream,
                            BufferedWriter writer, List<String> abiList) {
            this.socket = socket;
            this.inputStream = inputStream;
            this.writer = writer;
            this.abiList = abiList;
        }
        
       //重點:傳進來本地Socket的位址
        public static ZygoteState connect(LocalSocketAddress address) throws IOException {
            DataInputStream zygoteInputStream = null;
            BufferedWriter zygoteWriter = null;
            //傳說中的Socket
            final LocalSocket zygoteSocket = new LocalSocket();
            try {
                //建立LocalSocket 連接配接,根據位址LocalSocketAddress 
                zygoteSocket.connect(address);
                //指向zygoteSocket輸入
                zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
                //指向zygoteSocket輸出
                zygoteWriter = new BufferedWriter(new OutputStreamWriter(zygoteSocket.getOutputStream()), 256);
            } catch (IOException ex) {
                try {
                    zygoteSocket.close();
                } catch (IOException ignore) {
                }
                throw ex;
            }
            //擷取zygote 程序支援的 ABI類标Application Binary Interface
            String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
            Log.i("Zygote", "Process: zygote socket " + address.getNamespace() + "/"
                    + address.getName() + " opened, supported ABIS: " + abiListString);
            //通過socket  輸入  輸出   abi 清單建立 ZygoteState
            return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
                    Arrays.asList(abiListString.split(",")));
        }
        boolean matches(String abi) {
            return abiList.contains(abi);
        }
        public void close() {
            try {
                socket.close();
            } catch (IOException ex) {
                Log.e(LOG_TAG,"I/O exception on routine close", ex);
            }
            mClosed = true;
        }
        boolean isClosed() {
            return mClosed;
        }
    }
           

分析:ZygoteState内部類的主要作:表示和Zygote程序的連接配接狀态,裡面有幾個成員變量存儲LocalSocket ,以及指向LocalSocket的輸入、輸出流等。而裡面的

connect

方法就是初始化這些變量,建立并傳回ZygoteState。這裡需要簡單分析一下LocalSocket和connect方法的參數LocalSocketAddress 。

小插曲LocalSocket、LocalSocketAddress 和LocalServerSocket的關系

這裡隻是簡單看一下遠離流程以及它們之間的關系,至于他們的詳細源碼就不一一貼出分析了。

LocalSocketAddress 就是LocalSocket的位址看看它的初始化過程:

1:

public static ZygoteState connect(LocalSocketAddress address)

方法中傳進來的

LocalSocketAddress

就是ZygotePrecess的成員變量,初始化是在構造器中,如下圖:

Android framework源碼分析二 應用程式啟動流程源碼分析(Android8.0)概述

2:接下來再看看ZygotePrecess構造器中的參數是什麼:ZygotePrecess構造器在Precess中調用

Android framework源碼分析二 應用程式啟動流程源碼分析(Android8.0)概述

接下來再說說LocalSocket和LocalServerSocket的關系:他門倆個之間的關系類似于Socket程式設計中:Socekt和ServerSocket的關系

平時用到的Socket,Socket通常是為了友善**兩台不同的機器之間的通信,**它封裝了TCP/IP協定,向外提供一些API簡化了網絡通信過程,可以實作不同層面,不同應用,跨程序跨網絡的通信;一般由Socket(client)和ServerSocket(Server)組成通信雙方。

而Android中的LocalSocket是基于UNIX-domain Socket的,UNIX-domain Socket是在Socket的基礎上衍生出來的一種IPC通信機制,**是以LocalSocket解決的是同一台主機上不同程序間互相通信的問題。其相對于網絡通信使用的socket不需要經過網絡協定棧,不需要打包拆包、計算校驗,自然的執行效率也高。**與binder機制作用一樣,都在Android系統中作為IPC通信手段被廣泛使用;一般由LocalSocket(Client)和LocalServerSocket(Server)組成通信雙方。

那麼在本文中AMS所在的system-server程序就充當了Client,zygote程序充當Server,因為zygote程序在建立的時候會在ZygoteInit.main方法中調用ZygoteInit.registerZygoteSocket方法,會執行個體化一個LocalServerSocket,并且在ZygoteInit.runSelectLoop方法中不停的擷取用戶端的請求。

關于LocalSocket、LocalSocketAddress 和LocalServerSocket分析先到這裡,詳細源碼我就不在這裡粘出了,接下我們繼續回到ZygoteProcess的

zygoteSendArgsAndGetResult

方法,通過LocalSocket發送參數給Zygote程序。

Step13: ZygoteProcess的

zygoteSendArgsAndGetResult

方法分析:

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

            /**
             * See com.android.internal.os.SystemZygoteInit.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.
             */
             //通過連接配接狀态 擷取輸入輸出流
            final BufferedWriter writer = zygoteState.writer;
            final DataInputStream inputStream = zygoteState.inputStream;
			//将參數通過Socket寫出去,至于從哪裡讀,請看上面的英文注解,至于讀取将在ZygoteInit類中找
            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();
            // Should there be a timeout on this?
            // 建立程序啟動結果類,把建立的結果例如程序pid等指派給這個結果類,用來傳回
            Process.ProcessStartResult result = new Process.ProcessStartResult();

            // Always read the entire result from the input stream to avoid leaving
            // bytes in the stream for future process starts to accidentally stumble
            // upon.
            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

方法,通過上一步中的連接配接狀态擷取輸出流,将建立程序的參數通過Socket發送給給Zygote程序,通知Zygote去建立程序,并傳回結果。Zygote程序是在系統啟動初始化的,Zygote在啟動之後開啟了socket 監聽功能,監聽需要建立 Process 的請求,關于zygote程序什麼時候開啟這個socket的需要去看Zygote的源碼。

這裡為止,建立APP程序的工作交給了Zygote程序去完成。

5:Zygote完成建立APP程序的過程:ZygoteInit、ZygoteServer和ZygoteConnection

Zygote程序是在Android系統啟動時就會完成Zygote的啟動,在Android系統中,所有的應用程式程序以及系統服務程序SystemServer都是由Zygote程序孕育(fork)出來的,關于Zygote的啟動以後我會單獨寫一篇文章去分析,在這裡我将詳細分析一下Zygote程序作為服務端什麼時候開啟的Socket監聽,完成程序的建立過并将程序pid傳回的過程,而這個過程與

ZygoteInit、ZygoteServer和ZygoteConnection

三個類密切相關。

Zygote程序啟動的時候會調用ZygoteInit的main方法接下我将從它入手。

Step14: ZygoteInit的

main

方法分析:

public static void main(String argv[]) {
        ZygoteServer zygoteServer = new ZygoteServer();
        //...省略部分代碼
        try {
            //...省略部分代碼
            if (abiList == null) {
                throw new RuntimeException("No ABI list supplied.");
            }
            //為Zygote注冊socket監聽 :LocalServerSocket,具源碼很簡單,就不在下面粘貼了,感興趣和可以自己查閱
            zygoteServer.registerServerSocketFromEnv(socketName);
            //...省略部分代碼
            //初始化Zygote程序 非重點
            Zygote.nativeSecurityInit();

            //...省略部分代碼

            // The select loop returns early in the child process after a fork and
            // loops forever in the zygote.
            //進入循環模式,通過zygoteServer擷取用戶端Socket連接配接并處理
            caller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            throw ex;
        } finally {
            zygoteServer.closeServerSocket();
        }
        // We're in the child process and have exited the select loop. Proceed to execute the
        // command.
        if (caller != null) {
            caller.run();
        }
    }
           

分析:在 ZygoteInit的

main

方法中為通過

zygoteServer.registerServerSocketFromEnv

方法為Zygote注冊

socket

監聽

LocalServerSocket

;并開啟循環,通過zygoteServer的

runSelectLoop(abiList)

方法擷取用戶端Socket連接配接并處理。至于注冊

socket

監聽

LocalServerSocket

的過程比較簡單就不在這裡分析了,接下來着重分析

runSelectLoop(abiList)

擷取用戶端Socket連接配接并處理的過程。

Step15: ZygoteServer的

runSelectLoop

方法分析:

Runnable runSelectLoop(String abiList) {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
        // sServerSocket是socket通信中的服務端,即zygote程序。儲存到fds[0]
        fds.add(mServerSocket.getFileDescriptor());
        peers.add(null);
        //開啟循環
        while (true) {
            // ...省略部分源碼
            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);
                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;
                }
                // 即fds[0],代表的是sServerSocket,則意味着有用戶端連接配接請求;
                // 則建立ZygoteConnection對象,并添加到peers
                if (i == 0) {
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    fds.add(newPeer.getFileDesciptor());
                } else {
                    //i>0,則代表通過socket接收來自對端的資料,并執行相應操作
                    try {
                        //通過processOneCommand去處理用戶端發來的Socket請求
                        ZygoteConnection connection = peers.get(i);
                        final Runnable command = connection.processOneCommand(this);

                        if (mIsForkChild) {
                            //Set by the child process, immediately after a call to {@code Zygote.forkAndSpecialize}.
                            //由子程序設定,後立即調用Zygote.forkAndSpecialize
                            if (command == null) {
                                throw new IllegalStateException("command == null");
                            }
                            return command;
                        } else {
                            // We're in the server - we should never have any commands to run.
                            if (command != null) {
                                throw new IllegalStateException("command != null");
                            }
                            // We don't know whether the remote side of the socket was closed or
                            // not until we attempt to read from it from processOneCommand. This shows up as
                            // a regular POLLIN event in our regular processing loop.
                            if (connection.isClosedByPeer()) {
                                connection.closeSocket();
                                peers.remove(i);
                                fds.remove(i);
                            }
                        }
                    } catch (Exception e) {
                         //...省略異常資訊的處理
                        }
                    } finally {
                        // Reset the child flag, in the event that the child process is a child-
                        // zygote. The flag will not be consulted this loop pass after the Runnable
                        // is returned.
                        mIsForkChild = false;
                    }
                }
            }
        }
    }
           

繼續分析ZygoteConnection 的

connection.processOneCommand(this)

方法如何處理用戶端發送來的請求

Step16: ZygoteConnection的

processOneCommand

方法分析:

/**
     * Reads one start command from the command socket. If successful, a child is  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) {
        String args[];
        Arguments parsedArgs = null;
        FileDescriptor[] descriptors;
        try {
            //讀取上文提到client端發送來建立程序需要的參數清單
            args = readArgumentList();
            descriptors = mSocket.getAncillaryFileDescriptors();
        } catch (IOException ex) {
            throw new IllegalStateException("IOException on command socket", ex);
        }
        // readArgumentList returns null only when it has reached EOF with no available
        // data to read. This will only happen when the remote socket has disconnected.
        //readArgumentList隻有在到達EOF且沒有可用資料可讀時才傳回null。這隻會在用戶端斷開連接配接時發生。
        if (args == null) {
            isEof = true;
            return null;
        }
        int pid = -1;
        FileDescriptor childPipeFd = null;
        FileDescriptor serverPipeFd = null;
        //将從用戶端讀取來的參數封裝成 Arguments對象
        parsedArgs = new Arguments(args);

        //... 省略部分代碼

        fd = null;
        //通過Zygote程序的forkAndSpecialize方法去建立程序,并傳回程序的pid
        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 {
            //Zygote 建立程序完成後  将分成一下兩種情況處理
            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.   目前傳回的是父程序 ,Zygote程序
                IoUtils.closeQuietly(childPipeFd);
                childPipeFd = null;
                //父程序處理
                handleParentProc(pid, descriptors, serverPipeFd);
                return null;
            }
        } finally {
            IoUtils.closeQuietly(childPipeFd);
            IoUtils.closeQuietly(serverPipeFd);
        }
    }
           

分析:

processOneCommand

方法首先讀取用戶端發送過來的參數清單,并将這些參數清單封裝成

Arguments

對象,并交給

Zygote.forkAndSpecialize

去完成程序的建立工作,并傳回目标程序的pid,再往下就是根據pid==0說明目前傳回的是子程序,交給

handleChildProc

方法去處理;否則傳回的是父程序交給

handleParentProc

去處理。

Step17: Zygote的

forkAndSpecialize

方法分析:

public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
                                        int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
                                        int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir) {
        //調用preFork方法做一些準備工作
        //這個方法的主要目的是停止zygote程序的四個daemon子線程,分别是ReferenceQueueDaemon,FinalizerDaemon,FinalizerWatchdogDaemon,HeapTaskDaemon;
        //直到zygote是是單線程,以便于提高fork效率;
        VM_HOOKS.preFork();
        // Resets nice priority for zygote process.
        resetNicePriority();
        //重點是調用這個native方法去建立程序傳回程序的pid,這個過程經過JNI完成的
        int pid = nativeForkAndSpecialize(
                uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
                fdsToIgnore, startChildZygote, instructionSet, appDataDir);
        // Enable tracing as soon as possible for the child process.
        if (pid == 0) {
            Trace.setTracingEnabled(true, runtimeFlags);

            // Note that this event ends at the end of handleChildProc,
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
        }
        VM_HOOKS.postForkCommon();
        return pid;
    }

    //nativie  接口 它的實作完成程序的建立工作
    native private static int nativeForkAndSpecialize(int uid, int gid, int[] gids,int runtimeFlags,int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir);

           

分析:

forkAndSpecialize

方法邏輯比較簡單首先通過VM_HOOKS.preFork()為建立程序做一些準備工作,然後調用native方法

nativeForkAndSpecialize

去完成具體建立程序的工作。

Native層調用Linux系統fork函數完成建立程序的過程

接下來看看native方法

nativeForkAndSpecialize

的實作,此方法的實作是在

com_android_internal_os_Zygote.cpp

檔案中,目錄路徑為:

frameworks\base\core\jni\com_android_internal_os_Zygote.cpp

Step18: native的

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,
        jintArray fdsToIgnore,
        jstring instructionSet, jstring appDataDir) {
    jlong capabilities = 0;
    if (multiuser_get_app_id(uid) == AID_BLUETOOTH) {
      capabilities |= (1LL << CAP_WAKE_ALARM);
      capabilities |= (1LL << CAP_NET_RAW);
      capabilities |= (1LL << CAP_NET_BIND_SERVICE);
      capabilities |= (1LL << CAP_SYS_NICE);
    }
    // Grant CAP_BLOCK_SUSPEND to processes that belong to GID "wakelock"
    bool gid_wakelock_found = false;
    if (gid == AID_WAKELOCK) {
      gid_wakelock_found = true;
    } else if (gids != NULL) {
      jsize gids_num = env->GetArrayLength(gids);
      ScopedIntArrayRO ar(env, gids);
      if (ar.get() == NULL) {
        RuntimeAbort(env, __LINE__, "Bad gids array");
      }
      for (int i = 0; i < gids_num; i++) {
        if (ar[i] == AID_WAKELOCK) {
          gid_wakelock_found = true;
          break;
        }
      }
    }
    if (gid_wakelock_found) {
      capabilities |= (1LL << CAP_BLOCK_SUSPEND);
    }
   //最終将建立程序的工作交給ForkAndSpecializeCommon方法去完成
    return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags,
            rlimits, capabilities, capabilities, mount_external, se_info,
            se_name, false, fdsToClose, fdsToIgnore, instructionSet, appDataDir);
}
           

Step19: native的

ForkAndSpecializeCommon

方法:

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,
                                         jintArray fdsToIgnore,
                                         jstring instructionSet, jstring dataDir) {
        //設定子程序的signal信号處理函數
        SetSigChldHandler();
        sigset_t sigchld;
        sigemptyset( & sigchld);
        sigaddset( & sigchld, SIGCHLD);

        //...  省略部分代碼

        // 重點:fork是Linux的系統函數,是真正執行複制程序的工作,因為Zygote程序的權限很高,
        // fork方法會一模一樣的複制Zygote作為我們要建立的目标程序,這樣的話就會導緻目标應用程序也有很高的權限去操作各種檔案
        // fork出來的程序就是我們要啟動的程序,接下來我們要為目标程序設定一系列的屬性
        pid_t pid = fork();

        if (pid == 0) {//進入子程序
            // The child process.
            gMallocLeakZygoteChild = 1;
            // Set the jemalloc decay time to 1.
            mallopt(M_DECAY_TIME, 1);
            // Clean up any descriptors which must be closed immediately
            //關閉并清除檔案描述符
            DetachDescriptors(env, fdsToClose);

            //...  省略部分代碼

            if (!is_system_server) {
                //對于非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));
                    }
                }
            }
            //下面為目标程序的屬性指派
            //設定group
            SetGids(env, javaGids);
            //設定排程政策
            SetRLimits(env, javaRlimits);

            if (use_native_bridge) {
                ScopedUtfChars isa_string (env, instructionSet);
                ScopedUtfChars data_dir (env, dataDir);
                android::PreInitializeNativeBridge (data_dir.c_str(), isa_string.c_str());
            }
            //設定目标程序的gid
            int rc = setresgid(gid, gid, gid);
            if (rc == -1) {
                ALOGE("setresgid(%d) failed: %s", gid, strerror(errno));
                RuntimeAbort(env, __LINE__, "setresgid failed");
            }
            //設定目标程序的uid
            rc = setresuid(uid, uid, uid);
            if (rc == -1) {
                ALOGE("setresuid(%d) failed: %s", uid, strerror(errno));
                RuntimeAbort(env, __LINE__, "setresuid failed");
            }

            if (NeedsNoRandomizeWorkaround()) {
                // 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, permittedCapabilities);
            //為目标程序設定排程政策
            SetSchedulerPolicy(env);

            //...  省略部分代碼
            //在Zygote子程序中,設定信号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 進入父程序,即Zygote程序
    
            // We blocked SIGCHLD prior to a fork, we unblock it here.
            if (sigprocmask(SIG_UNBLOCK, & sigchld,nullptr) ==-1){
                ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno));
                RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_UNBLOCK, { SIGCHLD }) failed.");
            }
        }
        return pid;
    }

           

分析:

ForkAndSpecializeCommon

方法最核心的就是

pid_t pid = fork()

,通過Linux的fork機制複制Zygote程序作為要啟動的目标程序,接下來在為複制的目标程序的屬性指派,最後傳回目标程序的pid。到這裡就回到Step16: ZygoteConnection中

processOneCommand

方法建立程序後子程序(即目标程序)的處理流程,即

handleChildProc

方法;看下圖:

Android framework源碼分析二 應用程式啟動流程源碼分析(Android8.0)概述

Step20: ZygoteConnection的

handleChildProc

方法:

private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
                                     FileDescriptor pipeFd, boolean isZygote) {
        /**
         * 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();
        if (descriptors != null) {
            try {
                Os.dup2(descriptors[0], STDIN_FILENO);
                Os.dup2(descriptors[1], STDOUT_FILENO);
                Os.dup2(descriptors[2], STDERR_FILENO);

                for (FileDescriptor fd: descriptors) {
                    IoUtils.closeQuietly(fd);
                }
            } catch (ErrnoException ex) {
                Log.e(TAG, "Error reopening stdio", ex);
            }
        }

        if (parsedArgs.niceName != null) {
            //設定程序名
            Process.setArgV0(parsedArgs.niceName);
        }

        // End of the postFork event.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        //應用程序首次啟動時,parsedArgs.invokeWith參數為空,是以執行else
        if (parsedArgs.invokeWith != null) {
            WrapperInit.execApplication(parsedArgs.invokeWith,
                    parsedArgs.niceName, parsedArgs.targetSdkVersion,
                    VMRuntime.getCurrentInstructionSet(),
                    pipeFd, parsedArgs.remainingArgs);

            // Should not get here.
            throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
        } else {
            /**
             * isZygote  :whether this new child process is itself a new Zygote
             * isZygote來自上面的parsedArgs中的startChildZygote屬性---》 parsedArgs = new Arguments(args);
             * args上面分析過是從用戶端發來的參數---》去用戶端發送參數那看:
             *     可以追蹤到ZygotePrecess類的startViaZygote方法:再startViaZygote方法中的參數  boolean startChildZygote  
             *     傳進來 是 false
             * 是以:這裡  isZygote 為false  !isZygote 為true
             */
            if (!isZygote) {
                //是以會執行這裡
                return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
                        null /* classLoader */);
            } else {
                //啟動一個子的Zygote
                return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
                        parsedArgs.remainingArgs, null /* classLoader */);
            }
        }
    }
           

分析:

handleChildProc

這個方法邏輯比較簡單,注釋也标注的很清楚,最後交給了

ZygoteInit的zygoteInit

方法去處理。

Step21: ZygoteInit的

zygoteInit

方法分析:

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");
        ///把标準輸出和标準錯誤重定向給log.i和log.e
        RuntimeInit.redirectLogStreams();
		//針對日志和異常處理進行初始化
        RuntimeInit.commonInit();
        //這裡的作用是在新程序中引入Binder,也就說通過nativeZygoteInit以後,新的程序就可以使用Binder程序通信了。
        ZygoteInit.nativeZygoteInit();
        //初始化我們的應用程序。重點
        return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }
           

**分析:**最後就是調用RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader)來初始化我們的應用程式。繼續往下看。

Step22: RuntimeInit的

applicationInit

方法分析:

protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
                                              ClassLoader classLoader) {
        //如果應用程式調用System.exit(),則終止程序
        nativeSetExitWithoutCleanup(true);
        // We want to be fairly aggressive about heap utilization, to avoid
        // holding on to a lot of memory that isn't needed.
        //我們希望相當積極地處理堆使用率,以避免占用大量不需要的記憶體。
        VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
        VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
        //傳入的參數封裝成一個Arguments對象
        final Arguments args = new Arguments(argv);
        // The end of of the RuntimeInit event (see #zygoteInit).
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        // 會通過調用findStaticMain來調用args.startClass這個類的main()方法。
        // 在前面介紹socket的用戶端代碼時,在startProcessLocked()中傳入的這個類為"android.app.ActivityThread"。
        return findStaticMain(args.startClass, args.startArgs, classLoader);
    }

           

分析: 在applicationInit() 方法的最後,會通過調用

findStaticMain

來調用

args.startClass

這個類的

main()

方法。在前面介紹socket的用戶端代碼時,在

startProcessLocked()

中傳入的這個類為"

android.app.ActivityThread

"。是以接下來

findStaticMain()

的主要功能就是通過反射調用調用ActivityThread類的main()方法

Step23: RuntimeInit的

findStaticMain

方法分析:

protected static Runnable findStaticMain(String className, String[] argv, ClassLoader classLoader) {
        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();
        if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
            throw new RuntimeException(
                    "Main method is not public and static on " + className);
        }
        //交給 MethodAndArgsCaller去處理 ,8.0之前是通過抛出異常的形式反射調用main方法
        return new MethodAndArgsCaller(m, argv);
    }
           

再往下看,就是反射調用main

static class MethodAndArgsCaller implements Runnable {
        private final Method mMethod;
        private final String[] mArgs;
        public MethodAndArgsCaller(Method method, String[] args) {
            mMethod = method;
            mArgs = args;
        }
        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);
            }
        }
    }
           

Step24: ActivityThread的

Main

方法分析:

public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();

        // Set the reporter for event logging in libcore
        EventLogger.setReporter(new EventLoggingReporter());

        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        Process.setArgV0("<pre-initialized>");
        //初始化主線成的looper
        Looper.prepareMainLooper();

        // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
        // It will be in the format "seq=114"
        long startSeq = 0;
        if (args != null) {
            for (int i = args.length - 1; i >= 0; --i) {
                if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                    startSeq = Long.parseLong(
                            args[i].substring(PROC_START_SEQ_IDENT.length()));
                }
            }
        }
        ActivityThread thread = new ActivityThread();
        //重點  attach方法:
        thread.attach(false, startSeq);
        //初始化主線成的handler
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }
        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        //開啟消息循環
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
           

分析: ActivityThrad的

main

方法就是應用程式的入口,main方法執行表示應用程式的啟動,再往後面的的幾步分析主要是講應用程序啟動後,啟動Activity 和關聯Context等操作過程。下面簡單過一下啟動Activity的過程,至于詳細過程以及關聯Context操作以後将會專門寫一篇ActivityThrad的工作流程源碼分析中詳細介紹。

6:應用的程序啟動後,啟動Activity 和關聯Context的過程。

Step25: ActivityThread的

attach

方法分析:

private void attach(boolean system, long startSeq) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {
            ViewRootImpl.addFirstDrawHandler(new Runnable() {
                @Override
                public void run() {
                    ensureJitEnabled();
                }
            });
            android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                    UserHandle.myUserId());
            RuntimeInit.setApplicationObject(mAppThread.asBinder());
            //mgr 就是ActivityManagerService對象.   
            final IActivityManager mgr = ActivityManager.getService();
            try {
                 // 重點
                //通過Binder機制調用ActivityManagerService的attachApplication方法
                mgr.attachApplication(mAppThread, startSeq);

            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
            //...省略部分代碼
            ViewRootImpl.addConfigCallback(configChangedCallback);
        }
    }
           

分析:

attach

方法中,

mgr.attachApplication(mAppThread, startSeq)

是通過Binder機制回掉AMS的attachApplication方法,這一過程在上一篇文章Android framework 源碼分析之Activity啟動流程(android 8.0)中詳細分析過,如果不明白的可以查閱一下,這裡不在贅述。

Step26: AMS的

attachApplication

方法分析:

private final boolean attachApplicationLocked(IApplicationThread thread,
                                                  int pid, int callingUid, long startSeq) {

        ProcessRecord app;
        //...省略部分代碼

        //初始化資料
        app.makeActive(thread, mProcessStats);
        app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
        app.curSchedGroup = app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
        app.forcingToImportant = null;
        updateProcessForegroundLocked(app, false, false);
        app.hasShownUi = false;
        app.debugging = false;
        app.cached = false;
        app.killedByAm = false;
        app.killed = false;
 
        //....代碼

        // See if the top visible activity is waiting to run in this process...
        if (normalMode) {
            try {
                //重點: 調用mStackSupervisor.attachApplicationLocked(app)) 
                if (mStackSupervisor.attachApplicationLocked(app)) {
                    didSomething = true;
                }
            } catch (Exception e) {
                Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
                badApp = true;
            }
        }

        //...代碼
        return true;
    }
           

分析:

在AMS的

attachApplication

中,重點看這一句

mStackSupervisor.attachApplicationLocked

,将啟動和綁定工作交給了ActivityStackSupervisor的

attachApplicationLocked

方法去完成。

Step27: ActivityStackSupervisor的

attachApplicationLocked

方法分析:

boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
        final String processName = app.processName;
        boolean didSomething = false;
        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
                final ActivityStack stack = display.getChildAt(stackNdx);
                if (!isFocusedStack(stack)) {
                    continue;
                }
                stack.getAllRunningVisibleActivitiesLocked(mTmpActivityList);
                final ActivityRecord top = stack.topRunningActivityLocked();
                final int size = mTmpActivityList.size();
                for (int i = 0; i < size; i++) {
                    final ActivityRecord activity = mTmpActivityList.get(i);
                    if (activity.app == null && app.uid == activity.info.applicationInfo.uid
                            && processName.equals(activity.processName)) {
                        try {
                            //重點 ;realStartActivityLocked啟動acrivity
                            if (realStartActivityLocked(activity, app,
                                    top == activity /* andResume */, true /* checkConfig */)) {
                                didSomething = true;
                            }
                        } catch (RemoteException e) {
                            Slog.w(TAG, "Exception in new application when starting activity "
                                    + top.intent.getComponent().flattenToShortString(), e);
                            throw e;
                        }
                    }
                }
            }
        }
        if (!didSomething) {
            ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
        }
        return didSomething;
    }
           

分析: 在

attachApplicationLocked

方法中調用了

realStartActivityLocked

方法去完成啟動Activity工作,至于

realStartActivityLocked

的工作流程請閱讀上文Android framework 源碼分析之Activity啟動流程(android 8.0)的Step14-Step18。

7:總結

到此應用程序的啟動流程也分析完畢,如果文中有不對的地方歡迎請大家留言指出,共同進步,稍後根據這兩篇文章整理一張app啟動以及activity啟動流程總圖以便了解記憶。順便給點個贊謝謝祝,大家周末愉快!!!。

繼續閱讀