Android 8.0系統原始碼分析–應用程序啟動過程分析

NO IMAGE

     說了說Binder。再看看Looper,睡到床上想想,接下來分析什麼呢?第一時間越入腦海的就是應用程序的啟動過程了。Android相比IOS是開放的(不能說開源,因為還是有些原始碼沒有對外,比如每個廠商的驅動等等),可以下載到基本上所有的原始碼,而且也提供了非常好的framework框架,現在的Android App到處都是,這些也是直接和使用者打交道的,那麼我們是否瞭解一個應用程序的啟動過程呢?在之前的面試和培訓中,我從身旁同事中瞭解的情況就是,相當大部分人都對我們應用程序的啟動還秀陌生。我們今天就來看看Android應用程序是怎麼樣從無到有啟動起來的。

     當我們在Launcher桌面上點選一個應用的圖示時,當然Launcher啟動之後,已經把桌面上每個圖示對應的資訊都封裝好了,使用者點選之後,Launcher程序就會通過Binder程序間通訊機制呼叫startActivity的方式去開啟目標程序的入口Activity,指令傳達到ActivityManagerService當中時,AMS會去檢測當有的應用程序是否已經啟動,如果沒有啟動,那麼就會先將當前的目標程序啟動起來,啟動目標程序是通過呼叫startProcessLocked方法來完成的,該方法的實現在ActivityManagerService類中,目錄路徑為frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java,startProcessLocked方法的原始碼如下:

    private final void startProcessLocked(ProcessRecord app,
String hostingType, String hostingNameStr) {
startProcessLocked(app, hostingType, hostingNameStr, null /* abiOverride */,
null /* entryPoint */, null /* entryPointArgs */);
}

     該方法就是直接呼叫另一個過載方法來實現在,該過載方法的原始碼如下:

private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
long startTime = SystemClock.elapsedRealtime();
if (app.pid > 0 && app.pid != MY_PID) {
checkTime(startTime, "startProcess: removing from pids map");
synchronized (mPidsSelfLocked) {
mPidsSelfLocked.remove(app.pid);
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
}
checkTime(startTime, "startProcess: done removing from pids map");
app.setPid(0);
}
if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG_PROCESSES,
"startProcessLocked removing on hold: "   app);
mProcessesOnHold.remove(app);
checkTime(startTime, "startProcess: starting to update cpu stats");
updateCpuStats();
checkTime(startTime, "startProcess: done updating cpu stats");
try {
try {
final int userId = UserHandle.getUserId(app.uid);
AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
int uid = app.uid;
int[] gids = null;
int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
if (!app.isolated) {
int[] permGids = null;
try {
checkTime(startTime, "startProcess: getting gids from package manager");
final IPackageManager pm = AppGlobals.getPackageManager();
permGids = pm.getPackageGids(app.info.packageName,
MATCH_DEBUG_TRIAGED_MISSING, app.userId);
StorageManagerInternal storageManagerInternal = LocalServices.getService(
StorageManagerInternal.class);
mountExternal = storageManagerInternal.getExternalStorageMountMode(uid,
app.info.packageName);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
/*
* Add shared application and profile GIDs so applications can share some
* resources like shared libraries and access user-wide resources
*/
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));
}
checkTime(startTime, "startProcess: building args");
if (mFactoryTest != FactoryTest.FACTORY_TEST_OFF) {
if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
&& mTopComponent != null
&& app.processName.equals(mTopComponent.getPackageName())) {
uid = 0;
}
if (mFactoryTest == FactoryTest.FACTORY_TEST_HIGH_LEVEL
&& (app.info.flags & ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
uid = 0;
}
}
int debugFlags = 0;
if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
debugFlags |= Zygote.DEBUG_ENABLE_JDWP;
debugFlags |= Zygote.DEBUG_JAVA_DEBUGGABLE;
// Also turn on CheckJNI for debuggable apps. It's quite
// awkward to turn on otherwise.
debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
}
// Run the app in safe mode if its manifest requests so or the
// system is booted in safe mode.
if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 ||
mSafeMode == true) {
debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
}
if ("1".equals(SystemProperties.get("debug.checkjni"))) {
debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
}
String genDebugInfoProperty = SystemProperties.get("debug.generate-debug-info");
if ("true".equals(genDebugInfoProperty)) {
debugFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO;
}
if ("1".equals(SystemProperties.get("debug.jni.logging"))) {
debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;
}
if ("1".equals(SystemProperties.get("debug.assert"))) {
debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
}
if (mNativeDebuggingApp != null && mNativeDebuggingApp.equals(app.processName)) {
// Enable all debug flags required by the native debugger.
debugFlags |= Zygote.DEBUG_ALWAYS_JIT;          // Don't interpret anything
debugFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO; // Generate debug info
debugFlags |= Zygote.DEBUG_NATIVE_DEBUGGABLE;   // Disbale optimizations
mNativeDebuggingApp = null;
}
String invokeWith = null;
if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
// Debuggable apps may include a wrapper script with their library directory.
String wrapperFileName = app.info.nativeLibraryDir   "/wrap.sh";
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
try {
if (new File(wrapperFileName).exists()) {
invokeWith = "/system/bin/logwrapper "   wrapperFileName;
}
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
}
String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;
if (requiredAbi == null) {
requiredAbi = Build.SUPPORTED_ABIS[0];
}
String instructionSet = null;
if (app.info.primaryCpuAbi != null) {
instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi);
}
app.gids = gids;
app.requiredAbi = requiredAbi;
app.instructionSet = instructionSet;
// the per-user SELinux context must be set
if (TextUtils.isEmpty(app.info.seInfoUser)) {
Slog.wtf(TAG, "SELinux tag not defined",
new IllegalStateException("SELinux tag not defined for "
app.info.packageName   " (uid "   app.uid   ")"));
}
final String seInfo = app.info.seInfo
(TextUtils.isEmpty(app.info.seInfoUser) ? "" : app.info.seInfoUser);
// Start the process.  It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.
boolean isActivityProcess = (entryPoint == null);
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: "  
app.processName);
checkTime(startTime, "startProcess: asking zygote to start proc");
ProcessStartResult startResult;
if (hostingType.equals("webview_service")) {
startResult = startWebView(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, entryPointArgs);
} else {
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, entryPointArgs);
}
checkTime(startTime, "startProcess: returned from zygote!");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
mBatteryStatsService.noteProcessStart(app.processName, app.info.uid);
checkTime(startTime, "startProcess: done updating battery stats");
EventLog.writeEvent(EventLogTags.AM_PROC_START,
UserHandle.getUserId(uid), startResult.pid, uid,
app.processName, hostingType,
hostingNameStr != null ? hostingNameStr : "");
try {
AppGlobals.getPackageManager().logAppProcessStartIfNeeded(app.processName, app.uid,
seInfo, app.info.sourceDir, startResult.pid);
} catch (RemoteException ex) {
// Ignore
}
if (app.persistent) {
Watchdog.getInstance().processStarted(app.processName, startResult.pid);
}
checkTime(startTime, "startProcess: building log message");
StringBuilder buf = mStringBuilder;
buf.setLength(0);
buf.append("Start proc ");
buf.append(startResult.pid);
buf.append(':');
buf.append(app.processName);
buf.append('/');
UserHandle.formatUid(buf, uid);
if (!isActivityProcess) {
buf.append(" [");
buf.append(entryPoint);
buf.append("]");
}
buf.append(" for ");
buf.append(hostingType);
if (hostingNameStr != null) {
buf.append(" ");
buf.append(hostingNameStr);
}
Slog.i(TAG, buf.toString());
app.setPid(startResult.pid);
app.usingWrapper = startResult.usingWrapper;
app.removed = false;
app.killed = false;
app.killedByAm = false;
checkTime(startTime, "startProcess: starting to update pids map");
ProcessRecord oldApp;
synchronized (mPidsSelfLocked) {
oldApp = mPidsSelfLocked.get(startResult.pid);
}
// If there is already an app occupying that pid that hasn't been cleaned up
if (oldApp != null && !app.isolated) {
// Clean up anything relating to this pid first
Slog.w(TAG, "Reusing pid "   startResult.pid
" while app is still mapped to it");
cleanUpApplicationRecordLocked(oldApp, false, false, -1,
true /*replacingPid*/);
}
synchronized (mPidsSelfLocked) {
this.mPidsSelfLocked.put(startResult.pid, app);
if (isActivityProcess) {
Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
msg.obj = app;
mHandler.sendMessageDelayed(msg, startResult.usingWrapper
? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
}
}
checkTime(startTime, "startProcess: done updating pids map");
} catch (RuntimeException e) {
Slog.e(TAG, "Failure starting process "   app.processName, e);
// Something went very wrong while trying to start this process; one
// common case is when the package is frozen due to an active
// upgrade. To recover, clean up any active bookkeeping related to
// starting this process. (We already invoked this method once when
// the package was initially frozen through KILL_APPLICATION_MSG, so
// it doesn't hurt to use it again.)
forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false,
false, true, false, false, UserHandle.getUserId(app.userId), "start failure");
}
}

     該方法中int uid = app.uid可以獲取到目標程序的uid,uid是標識目標程序身份的一個整數,它最原始的分配是在應用程序安裝時,由PackageManagerService分配好的,後續我們在分析應用程序的安裝過程時也會說到這點,如果大家平時有遇到一些關於uid的問題,想要查應用程序的uid的話,可以在手機/data/system/目錄下,找packages.xml、packages-backup.xml這兩個檔案,裡邊記錄了當前手機上所有安裝過的應用程序的資訊,包括許可權、uid等等。接下摟重要的工作就是根據該方法的傳入的第一個引數ProcessRecord
app中封裝好的資訊去給區域性變數debugFlags賦值,debug.checkjni屬性就是在進行JNI呼叫時是否要進行合法性檢查,大家平時處理問題單的時候應該也經常見過,比如我們把一個應用程序殺掉,然後開始記錄目錄,在Launcher上點選該應用啟動它,大家就會看到debug.checkjni = false的日誌,預設場景下,該值為false,如果開啟它的話,那麼就會使我們的呼叫過程變慢。String requiredAbi = (abiOverride != null) ? abiOverride
: app.info.primaryCpuAbi;這句邏輯是判斷目標應用啟動時,複製它要使用的Zygote是使用32位還是64位的,這個值後面會用到,該值最初的賦值是在Build類中的SUPPORTED_ABIS成員變數,它是一個String型別的陣列,Build類的目錄路徑為frameworks\base\core\java\android\os\Build.java,成員變數SUPPORTED_ABIS的定義原始碼為:

    /**
* An ordered list of ABIs supported by this device. The most preferred ABI is the first
* element in the list.
*
* See {@link #SUPPORTED_32_BIT_ABIS} and {@link #SUPPORTED_64_BIT_ABIS}.
*/
public static final String[] SUPPORTED_ABIS = getStringList("ro.product.cpu.abilist", ",");
/**
* An ordered list of <b>32 bit</b> ABIs supported by this device. The most preferred ABI
* is the first element in the list.
*
* See {@link #SUPPORTED_ABIS} and {@link #SUPPORTED_64_BIT_ABIS}.
*/
public static final String[] SUPPORTED_32_BIT_ABIS =
getStringList("ro.product.cpu.abilist32", ",");
/**
* An ordered list of <b>64 bit</b> ABIs supported by this device. The most preferred ABI
* is the first element in the list.
*
* See {@link #SUPPORTED_ABIS} and {@link #SUPPORTED_32_BIT_ABIS}.
*/
public static final String[] SUPPORTED_64_BIT_ABIS =
getStringList("ro.product.cpu.abilist64", ",");

     如果獲取到的requiredAbi為空,那麼就會預設使用Build.SUPPORTED_ABIS[0]來啟動目標程序,一般就是32位的Zygote了,接下來有一個非常重要的引數if (entryPoint == null) entryPoint = “android.app.ActivityThread”,看到它我們應用非常熟悉了,就是我們前面講Looper迴圈時提到的ActivityThread類了,它就是我們應用程序Java層的入口類,它的main函式就是應用的入口函式,這個區域性變數entryPoint的命名感覺非常合適,很準確的表達了該引數的意圖。上面的引數封裝完成後,接下來就會呼叫Process.start來執行真正的啟動了(我們假設hostingType.equals(“webview_service”)為false),啟動完成後得到返回結果ProcessStartResult
startResult,後面還會記錄相關的日誌,這些日誌對我們分析問題也有很大的幫助。好,我們接下來看一下Process.start方法是如何啟動應用程序的。Process類的目錄路徑為frameworks\base\core\java\android\os\Process.java,start方法的原始碼如下:

    /**
* Start a new process.
* 
* <p>If processes are enabled, a new process is created and the
* static main() function of a <var>processClass</var> is executed there.
* The process will continue running after this function returns.
* 
* <p>If processes are not enabled, a new thread in the caller's
* process is created and main() of <var>processClass</var> called there.
* 
* <p>The niceName parameter, if not an empty string, is a custom name to
* give to the process instead of using processClass.  This allows you to
* make easily identifyable processes even if you are using the same base
* <var>processClass</var> to start them.
* 
* When invokeWith is not null, the process will be started as a fresh app
* and not a zygote fork. Note that this is only allowed for uid 0 or when
* debugFlags contains DEBUG_ENABLE_DEBUGGER.
*
* @param processClass The class to use as the process's main entry
*                     point.
* @param niceName A more readable name to use for the process.
* @param uid The user-id under which the process will run.
* @param gid The group-id under which the process will run.
* @param gids Additional group-ids associated with the process.
* @param debugFlags Additional flags.
* @param targetSdkVersion The target SDK version for the app.
* @param seInfo null-ok SELinux information for the new process.
* @param abi non-null the ABI this app should be started with.
* @param instructionSet null-ok the instruction set to use.
* @param appDataDir null-ok the data directory of the app.
* @param invokeWith null-ok the command to invoke with.
* @param zygoteArgs Additional arguments to supply to the zygote process.
* 
* @return An object that describes the result of the attempt to start the process.
* @throws RuntimeException on fatal start failure
* 
* {@hide}
*/
public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
String[] zygoteArgs) {
return zygoteProcess.start(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
}

     可以看到該方法的註釋非常詳細,這是一個非常好的習慣,我自己寫程式碼時也非常喜歡加註釋,好的註釋可以很容易讓其他人理解你的方法意圖,能夠很好的提高我們程式碼的可讀性,所以請大家在寫程式碼時也一定要養成這樣好的習慣。該方法就是直接呼叫zygoteProcess.start來處理的,zygoteProcess是Process類的成員變數,型別為ZygoteProcess,目錄路徑為frameworks\base\core\java\android\os\ZygoteProcess.java,它的start方法的原始碼如下:

    /**
* Start a new process.
*
* <p>If processes are enabled, a new process is created and the
* static main() function of a <var>processClass</var> is executed there.
* The process will continue running after this function returns.
*
* <p>If processes are not enabled, a new thread in the caller's
* process is created and main() of <var>processClass</var> called there.
*
* <p>The niceName parameter, if not an empty string, is a custom name to
* give to the process instead of using processClass.  This allows you to
* make easily identifyable processes even if you are using the same base
* <var>processClass</var> to start them.
*
* When invokeWith is not null, the process will be started as a fresh app
* and not a zygote fork. Note that this is only allowed for uid 0 or when
* debugFlags contains DEBUG_ENABLE_DEBUGGER.
*
* @param processClass The class to use as the process's main entry
*                     point.
* @param niceName A more readable name to use for the process.
* @param uid The user-id under which the process will run.
* @param gid The group-id under which the process will run.
* @param gids Additional group-ids associated with the process.
* @param debugFlags Additional flags.
* @param targetSdkVersion The target SDK version for the app.
* @param seInfo null-ok SELinux information for the new process.
* @param abi non-null the ABI this app should be started with.
* @param instructionSet null-ok the instruction set to use.
* @param appDataDir null-ok the data directory of the app.
* @param invokeWith null-ok the command to invoke with.
* @param zygoteArgs Additional arguments to supply to the zygote process.
*
* @return An object that describes the result of the attempt to start the process.
* @throws RuntimeException on fatal start failure
*/
public final Process.ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, 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來處理的,startViaZygote方法的原始碼如下:

    private Process.ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
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);
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_JDWP) != 0) {
argsForZygote.add("--enable-jdwp");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) {
argsForZygote.add("--enable-checkjni");
}
if ((debugFlags & Zygote.DEBUG_GENERATE_DEBUG_INFO) != 0) {
argsForZygote.add("--generate-debug-info");
}
if ((debugFlags & Zygote.DEBUG_ALWAYS_JIT) != 0) {
argsForZygote.add("--always-jit");
}
if ((debugFlags & Zygote.DEBUG_NATIVE_DEBUGGABLE) != 0) {
argsForZygote.add("--native-debuggable");
}
if ((debugFlags & Zygote.DEBUG_JAVA_DEBUGGABLE) != 0) {
argsForZygote.add("--java-debuggable");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
argsForZygote.add("--enable-assert");
}
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);
}
argsForZygote.add(processClass);
if (extraArgs != null) {
for (String arg : extraArgs) {
argsForZygote.add(arg);
}
}
synchronized(mLock) {
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
}

     這裡會對上面我們傳入的引數進行打包,然後接著呼叫zygoteSendArgsAndGetResult繼續處理,這裡需要注意,呼叫該方法時,第一個引數是執行openZygoteSocketIfNeeded方法後的返回值,第二個引數就是我們上面封裝好的區域性變數argsForZygote,我們先來看一下openZygoteSocketIfNeeded方法的實現,然後接著回來看zygoteSendArgsAndGetResult的邏輯。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);
}
}
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);
}
}
if (secondaryZygoteState.matches(abi)) {
return secondaryZygoteState;
}
throw new ZygoteStartFailedEx("Unsupported zygote ABI: "   abi);
}

     呼叫該方法時傳入的引數就是上面我們說的abi了,也就是我們要啟動的目標程序到底是呼叫Zygote32來fork,還是呼叫Zygote64來fork。這裡先判斷primaryZygoteState是否為空或者已經關閉,如果是的話,就呼叫ZygoteState.connect(mSocket)開啟它,然後去匹配該方法的入參abi,如果匹配成功,那麼就使用主State來啟動目標程序,接下來判斷secondaryZygoteStater的邏輯和primaryZygoteState完全一樣,也是先判斷是否需要開啟,開啟成功後就去匹配,匹配成功,則返回secondaryZygoteStater。如果primaryZygoteState、secondaryZygoteStater都匹配失敗,就會直接丟擲Unsupported
zygote ABI異常,表示不支援當前指定的啟動引數abi。好,該方法執行完畢,我們就獲取到一個ZygoteState物件,然後使用它作為引數繼續執行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 {
// Throw early if any of the arguments are malformed. This means we can
// avoid writing a partial response to the zygote.
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;
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?
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);
}
}

     該方法中就是呼叫final BufferedWriter writer = zygoteState.writer獲取一個Buffer寫操作流,然後將前面封裝好的啟動引數寫到目標socket上,寫到目標socket上之後,Zygote就會接收到了。Zygote是在手機啟動的時候就已經啟動好了,它的啟動入口函式為ZygoteInit類的main函式,ZygoteInit類的目錄路徑為frameworks\base\core\java\com\android\internal\os\ZygoteInit.java,它的main函式的原始碼如下:

    public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();
// Mark zygote start. This ensures that thread creation will throw
// an error.
ZygoteHooks.startZygoteNoThreadCreation();
// Zygote goes into its own process group.
try {
Os.setpgid(0, 0);
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to setpgid(0,0)", ex);
}
try {
// Report Zygote start time to tron unless it is a runtime restart
if (!"1".equals(SystemProperties.get("sys.boot_completed"))) {
MetricsLogger.histogram(null, "boot_zygote_init",
(int) SystemClock.elapsedRealtime());
}
String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
BootTimingsTraceLog bootTimingsTraceLog = new BootTimingsTraceLog(bootTimeTag,
Trace.TRACE_TAG_DALVIK);
bootTimingsTraceLog.traceBegin("ZygoteInit");
RuntimeInit.enableDdms();
// Start profiling the zygote initialization.
SamplingProfilerIntegration.start();
boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
boolean enableLazyPreload = false;
for (int i = 1; i < argv.length; i  ) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
} else if ("--enable-lazy-preload".equals(argv[i])) {
enableLazyPreload = true;
} else if (argv[i].startsWith(ABI_LIST_ARG)) {
abiList = argv[i].substring(ABI_LIST_ARG.length());
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
socketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: "   argv[i]);
}
}
if (abiList == null) {
throw new RuntimeException("No ABI list supplied.");
}
zygoteServer.registerServerSocket(socketName);
// In some configurations, we avoid preloading resources and classes eagerly.
// In such cases, we will preload things prior to our first fork.
if (!enableLazyPreload) {
bootTimingsTraceLog.traceBegin("ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preload(bootTimingsTraceLog);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
} else {
Zygote.resetNicePriority();
}
// Finish profiling the zygote initialization.
SamplingProfilerIntegration.writeZygoteSnapshot();
// Do an initial gc to clean up after startup
bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
gcAndFinalize();
bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC
bootTimingsTraceLog.traceEnd(); // ZygoteInit
// Disable tracing so that forked processes do not inherit stale tracing tags from
// Zygote.
Trace.setTracingEnabled(false);
// Zygote process unmounts root storage spaces.
Zygote.nativeUnmountStorageOnInit();
// Set seccomp policy
Seccomp.setPolicy();
ZygoteHooks.stopZygoteNoThreadCreation();
if (startSystemServer) {
startSystemServer(abiList, socketName, zygoteServer);
}
Log.i(TAG, "Accepting command socket connections");
zygoteServer.runSelectLoop(abiList);
zygoteServer.closeServerSocket();
} catch (Zygote.MethodAndArgsCaller caller) {
caller.run();
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
zygoteServer.closeServerSocket();
throw ex;
}
}

     Zygote啟動成功之後,就會在zygoteServer.runSelectLoop(abiList)當中不斷迴圈,等待AMS來請求啟動新的程序。zygoteServer是一個區域性變數,型別為ZygoteServer,目錄路徑為frameworks\base\core\java\com\android\internal\os\ZygoteServer.java,它的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.
*
* @throws Zygote.MethodAndArgsCaller in a child process when a main()
* should be executed.
*/
void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);
while (true) {
StructPollfd[] pollFds = new StructPollfd[fds.size()];
for (int i = 0; i < pollFds.length;   i) {
pollFds[i] = new StructPollfd();
pollFds[i].fd = fds.get(i);
pollFds[i].events = (short) POLLIN;
}
try {
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
boolean done = peers.get(i).runOnce(this);
if (done) {
peers.remove(i);
fds.remove(i);
}
}
}
}
}

     這裡停一下,看到8.0的這塊原始碼,感覺和之前的版本相比,還是有一點點改動,Android系統在不斷的完善,程式碼邏輯也在不斷的調整,但是總體來說,改動並不大,大家要是看過8.0之前版本的這塊的原始碼,下面的流程應該都很好理解。上面我們把所有啟動引數通過Buffer操作流寫入之後,這裡的while (true) 無限迴圈就會檢測到了,接下來就會呼叫boolean done = peers.get(i).runOnce(this)繼續處理。peers的型別為ArrayList<ZygoteConnection>,那麼接下來就呼叫ZygoteConnection類的runOnce方法繼續處理。ZygoteConnection類的目錄路徑為frameworks\base\core\java\com\android\internal\os\ZygoteConnection.java,它的runOnce方法的原始碼如下:

    boolean runOnce(ZygoteServer zygoteServer) throws Zygote.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);
if (parsedArgs.abiListQuery) {
return handleAbiListQuery();
}
if (parsedArgs.preloadDefault) {
return handlePreload();
}
if (parsedArgs.preloadPackage != null) {
return handlePreloadPackage(parsedArgs.preloadPackage,
parsedArgs.preloadPackageLibs, parsedArgs.preloadPackageCacheKey);
}
if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
throw new ZygoteSecurityException("Client may not specify capabilities: "  
"permitted=0x"   Long.toHexString(parsedArgs.permittedCapabilities)  
", effective=0x"   Long.toHexString(parsedArgs.effectiveCapabilities));
}
applyUidSecurityPolicy(parsedArgs, peer);
applyInvokeWithSecurityPolicy(parsedArgs, peer);
applyDebuggerSystemProperty(parsedArgs);
applyInvokeWithSystemProperty(parsedArgs);
int[][] rlimits = null;
if (parsedArgs.rlimits != null) {
rlimits = parsedArgs.rlimits.toArray(intArray2d);
}
int[] fdsToIgnore = null;
if (parsedArgs.invokeWith != null) {
FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
childPipeFd = pipeFds[1];
serverPipeFd = pipeFds[0];
Os.fcntlInt(childPipeFd, F_SETFD, 0);
fdsToIgnore = new int[] { childPipeFd.getInt$(), serverPipeFd.getInt$() };
}
/**
* In order to avoid leaking descriptors to the Zygote child,
* the native code must close the two Zygote socket descriptors
* in the child process before it switches from Zygote-root to
* the UID and privileges of the application being launched.
*
* In order to avoid "bad file descriptor" errors when the
* two LocalSocket objects are closed, the Posix file
* descriptors are released via a dup2() call which closes
* the socket and substitutes an open descriptor to /dev/null.
*/
int [] fdsToClose = { -1, -1 };
FileDescriptor fd = mSocket.getFileDescriptor();
if (fd != null) {
fdsToClose[0] = fd.getInt$();
}
fd = zygoteServer.getServerSocketFileDescriptor();
if (fd != null) {
fdsToClose[1] = fd.getInt$();
}
fd = null;
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
parsedArgs.appDataDir);
} 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
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
// should never get here, the child is expected to either
// throw Zygote.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方法從mSocketReader中將socket流寫入的啟動引數讀取出來,然後又對它重新打包,將其封裝為一個Arguments型別的引數。Arguments是ZygoteConnection類的內部類。封裝好之後,就以它為引數呼叫Zygote.forkAndSpecialize繼續執行fork,該方法的返回值就是我們目標程序的pid了。再往下的邏輯就要分成兩股了,一股是pid == 0,則說明當前返回的是子程序,否則返回的是父程序。這裡的返回是兩次,每次返回的pid都不相同,這也是Linux神奇的地方了,一次呼叫會有兩次返回。而為什麼會有兩次返回呢?這就要去看看Linux系統的核心排程機制了。Linux核心當中,每個程序都是一個task_struct結構體,schedule排程程式會不斷的檢查當前啟用的程序(核心中使用的current巨集定義可以獲取到)的時間片,如果當前程序的時間片已用完,則選擇下一個最優程式進行執行。task_struct結構體定義在sched.h標頭檔案中,目錄路徑為include/linux/sched.h,原始碼如下:

struct task_struct {
#ifdef CONFIG_THREAD_INFO_IN_TASK
/*
* For reasons of header soup (see current_thread_info()), this
* must be the first element of task_struct.
*/
struct thread_info thread_info;
#endif
volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
void *stack;
atomic_t usage;
unsigned int flags;	/* per process flags, defined below */
unsigned int ptrace;
#ifdef CONFIG_SMP
struct llist_node wake_entry;
int on_cpu;
#ifdef CONFIG_THREAD_INFO_IN_TASK
unsigned int cpu;	/* current CPU */
#endif
unsigned int wakee_flips;
unsigned long wakee_flip_decay_ts;
struct task_struct *last_wakee;
int wake_cpu;
#endif
int on_rq;
int prio, static_prio, normal_prio;
unsigned int rt_priority;
const struct sched_class *sched_class;
struct sched_entity se;
struct sched_rt_entity rt;
#ifdef CONFIG_CGROUP_SCHED
struct task_group *sched_task_group;
#endif
struct sched_dl_entity dl;
#ifdef CONFIG_PREEMPT_NOTIFIERS
/* list of struct preempt_notifier: */
struct hlist_head preempt_notifiers;
#endif
#ifdef CONFIG_BLK_DEV_IO_TRACE
unsigned int btrace_seq;
#endif
unsigned int policy;
int nr_cpus_allowed;
cpumask_t cpus_allowed;
#ifdef CONFIG_PREEMPT_RCU
int rcu_read_lock_nesting;
union rcu_special rcu_read_unlock_special;
struct list_head rcu_node_entry;
struct rcu_node *rcu_blocked_node;
#endif /* #ifdef CONFIG_PREEMPT_RCU */
#ifdef CONFIG_TASKS_RCU
unsigned long rcu_tasks_nvcsw;
bool rcu_tasks_holdout;
struct list_head rcu_tasks_holdout_list;
int rcu_tasks_idle_cpu;
#endif /* #ifdef CONFIG_TASKS_RCU */
#ifdef CONFIG_SCHED_INFO
struct sched_info sched_info;
#endif
struct list_head tasks;
#ifdef CONFIG_SMP
struct plist_node pushable_tasks;
struct rb_node pushable_dl_tasks;
#endif
struct mm_struct *mm, *active_mm;
/* per-thread vma caching */
u32 vmacache_seqnum;
struct vm_area_struct *vmacache[VMACACHE_SIZE];
#if defined(SPLIT_RSS_COUNTING)
struct task_rss_stat	rss_stat;
#endif
/* task state */
int exit_state;
int exit_code, exit_signal;
int pdeath_signal;  /*  The signal sent when the parent dies  */
unsigned long jobctl;	/* JOBCTL_*, siglock protected */
/* Used for emulating ABI behavior of previous Linux versions */
unsigned int personality;
/* scheduler bits, serialized by scheduler locks */
unsigned sched_reset_on_fork:1;
unsigned sched_contributes_to_load:1;
unsigned sched_migrated:1;
unsigned sched_remote_wakeup:1;
unsigned :0; /* force alignment to the next boundary */
/* unserialized, strictly 'current' */
unsigned in_execve:1; /* bit to tell LSMs we're in execve */
unsigned in_iowait:1;
#if !defined(TIF_RESTORE_SIGMASK)
unsigned restore_sigmask:1;
#endif
#ifdef CONFIG_MEMCG
unsigned memcg_may_oom:1;
#ifndef CONFIG_SLOB
unsigned memcg_kmem_skip_account:1;
#endif
#endif
#ifdef CONFIG_COMPAT_BRK
unsigned brk_randomized:1;
#endif
unsigned long atomic_flags; /* Flags needing atomic access. */
struct restart_block restart_block;
pid_t pid;
pid_t tgid;
#ifdef CONFIG_CC_STACKPROTECTOR
/* Canary value for the -fstack-protector gcc feature */
unsigned long stack_canary;
#endif
/*
* pointers to (original) parent process, youngest child, younger sibling,
* older sibling, respectively.  (p->father can be replaced with
* p->real_parent->pid)
*/
struct task_struct __rcu *real_parent; /* real parent process */
struct task_struct __rcu *parent; /* recipient of SIGCHLD, wait4() reports */
/*
* children/sibling forms the list of my natural children
*/
struct list_head children;	/* list of my children */
struct list_head sibling;	/* linkage in my parent's children list */
struct task_struct *group_leader;	/* threadgroup leader */
/*
* ptraced is the list of tasks this task is using ptrace on.
* This includes both natural children and PTRACE_ATTACH targets.
* p->ptrace_entry is p's link on the p->parent->ptraced list.
*/
struct list_head ptraced;
struct list_head ptrace_entry;
/* PID/PID hash table linkage. */
struct pid_link pids[PIDTYPE_MAX];
struct list_head thread_group;
struct list_head thread_node;
struct completion *vfork_done;		/* for vfork() */
int __user *set_child_tid;		/* CLONE_CHILD_SETTID */
int __user *clear_child_tid;		/* CLONE_CHILD_CLEARTID */
cputime_t utime, stime;
#ifdef CONFIG_ARCH_HAS_SCALED_CPUTIME
cputime_t utimescaled, stimescaled;
#endif
cputime_t gtime;
struct prev_cputime prev_cputime;
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
seqcount_t vtime_seqcount;
unsigned long long vtime_snap;
enum {
/* Task is sleeping or running in a CPU with VTIME inactive */
VTIME_INACTIVE = 0,
/* Task runs in userspace in a CPU with VTIME active */
VTIME_USER,
/* Task runs in kernelspace in a CPU with VTIME active */
VTIME_SYS,
} vtime_snap_whence;
#endif
#ifdef CONFIG_NO_HZ_FULL
atomic_t tick_dep_mask;
#endif
unsigned long nvcsw, nivcsw; /* context switch counts */
u64 start_time;		/* monotonic time in nsec */
u64 real_start_time;	/* boot based time in nsec */
/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
unsigned long min_flt, maj_flt;
struct task_cputime cputime_expires;
struct list_head cpu_timers[3];
/* process credentials */
const struct cred __rcu *ptracer_cred; /* Tracer's credentials at attach */
const struct cred __rcu *real_cred; /* objective and real subjective task
* credentials (COW) */
const struct cred __rcu *cred;	/* effective (overridable) subjective task
* credentials (COW) */
char comm[TASK_COMM_LEN]; /* executable name excluding path
- access with [gs]et_task_comm (which lock
it with task_lock())
- initialized normally by setup_new_exec */
/* file system info */
struct nameidata *nameidata;
#ifdef CONFIG_SYSVIPC
/* ipc stuff */
struct sysv_sem sysvsem;
struct sysv_shm sysvshm;
#endif
#ifdef CONFIG_DETECT_HUNG_TASK
/* hung task detection */
unsigned long last_switch_count;
#endif
/* filesystem information */
struct fs_struct *fs;
/* open file information */
struct files_struct *files;
/* namespaces */
struct nsproxy *nsproxy;
/* signal handlers */
struct signal_struct *signal;
struct sighand_struct *sighand;
sigset_t blocked, real_blocked;
sigset_t saved_sigmask;	/* restored if set_restore_sigmask() was used */
struct sigpending pending;
unsigned long sas_ss_sp;
size_t sas_ss_size;
unsigned sas_ss_flags;
struct callback_head *task_works;
struct audit_context *audit_context;
#ifdef CONFIG_AUDITSYSCALL
kuid_t loginuid;
unsigned int sessionid;
#endif
struct seccomp seccomp;
/* Thread group tracking */
u32 parent_exec_id;
u32 self_exec_id;
/* Protection of (de-)allocation: mm, files, fs, tty, keyrings, mems_allowed,
* mempolicy */
spinlock_t alloc_lock;
/* Protection of the PI data structures: */
raw_spinlock_t pi_lock;
struct wake_q_node wake_q;
#ifdef CONFIG_RT_MUTEXES
/* PI waiters blocked on a rt_mutex held by this task */
struct rb_root pi_waiters;
struct rb_node *pi_waiters_leftmost;
/* Deadlock detection and priority inheritance handling */
struct rt_mutex_waiter *pi_blocked_on;
#endif
#ifdef CONFIG_DEBUG_MUTEXES
/* mutex deadlock detection */
struct mutex_waiter *blocked_on;
#endif
#ifdef CONFIG_TRACE_IRQFLAGS
unsigned int irq_events;
unsigned long hardirq_enable_ip;
unsigned long hardirq_disable_ip;
unsigned int hardirq_enable_event;
unsigned int hardirq_disable_event;
int hardirqs_enabled;
int hardirq_context;
unsigned long softirq_disable_ip;
unsigned long softirq_enable_ip;
unsigned int softirq_disable_event;
unsigned int softirq_enable_event;
int softirqs_enabled;
int softirq_context;
#endif
#ifdef CONFIG_LOCKDEP
# define MAX_LOCK_DEPTH 48UL
u64 curr_chain_key;
int lockdep_depth;
unsigned int lockdep_recursion;
struct held_lock held_locks[MAX_LOCK_DEPTH];
gfp_t lockdep_reclaim_gfp;
#endif
#ifdef CONFIG_UBSAN
unsigned int in_ubsan;
#endif
/* journalling filesystem info */
void *journal_info;
/* stacked block device info */
struct bio_list *bio_list;
#ifdef CONFIG_BLOCK
/* stack plugging */
struct blk_plug *plug;
#endif
/* VM state */
struct reclaim_state *reclaim_state;
struct backing_dev_info *backing_dev_info;
struct io_context *io_context;
unsigned long ptrace_message;
siginfo_t *last_siginfo; /* For ptrace use.  */
struct task_io_accounting ioac;
#if defined(CONFIG_TASK_XACCT)
u64 acct_rss_mem1;	/* accumulated rss usage */
u64 acct_vm_mem1;	/* accumulated virtual memory usage */
cputime_t acct_timexpd;	/* stime   utime since last update */
#endif
#ifdef CONFIG_CPUSETS
nodemask_t mems_allowed;	/* Protected by alloc_lock */
seqcount_t mems_allowed_seq;	/* Seqence no to catch updates */
int cpuset_mem_spread_rotor;
int cpuset_slab_spread_rotor;
#endif
#ifdef CONFIG_CGROUPS
/* Control Group info protected by css_set_lock */
struct css_set __rcu *cgroups;
/* cg_list protected by css_set_lock and tsk->alloc_lock */
struct list_head cg_list;
#endif
#ifdef CONFIG_INTEL_RDT_A
int closid;
#endif
#ifdef CONFIG_FUTEX
struct robust_list_head __user *robust_list;
#ifdef CONFIG_COMPAT
struct compat_robust_list_head __user *compat_robust_list;
#endif
struct list_head pi_state_list;
struct futex_pi_state *pi_state_cache;
#endif
#ifdef CONFIG_PERF_EVENTS
struct perf_event_context *perf_event_ctxp[perf_nr_task_contexts];
struct mutex perf_event_mutex;
struct list_head perf_event_list;
#endif
#ifdef CONFIG_DEBUG_PREEMPT
unsigned long preempt_disable_ip;
#endif
#ifdef CONFIG_NUMA
struct mempolicy *mempolicy;	/* Protected by alloc_lock */
short il_next;
short pref_node_fork;
#endif
#ifdef CONFIG_NUMA_BALANCING
int numa_scan_seq;
unsigned int numa_scan_period;
unsigned int numa_scan_period_max;
int numa_preferred_nid;
unsigned long numa_migrate_retry;
u64 node_stamp;			/* migration stamp  */
u64 last_task_numa_placement;
u64 last_sum_exec_runtime;
struct callback_head numa_work;
struct list_head numa_entry;
struct numa_group *numa_group;
/*
* numa_faults is an array split into four regions:
* faults_memory, faults_cpu, faults_memory_buffer, faults_cpu_buffer
* in this precise order.
*
* faults_memory: Exponential decaying average of faults on a per-node
* basis. Scheduling placement decisions are made based on these
* counts. The values remain static for the duration of a PTE scan.
* faults_cpu: Track the nodes the process was running on when a NUMA
* hinting fault was incurred.
* faults_memory_buffer and faults_cpu_buffer: Record faults per node
* during the current scan window. When the scan completes, the counts
* in faults_memory and faults_cpu decay and these values are copied.
*/
unsigned long *numa_faults;
unsigned long total_numa_faults;
/*
* numa_faults_locality tracks if faults recorded during the last
* scan window were remote/local or failed to migrate. The task scan
* period is adapted based on the locality of the faults with different
* weights depending on whether they were shared or private faults
*/
unsigned long numa_faults_locality[3];
unsigned long numa_pages_migrated;
#endif /* CONFIG_NUMA_BALANCING */
#ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
struct tlbflush_unmap_batch tlb_ubc;
#endif
struct rcu_head rcu;
/*
* cache last used pipe for splice
*/
struct pipe_inode_info *splice_pipe;
struct page_frag task_frag;
#ifdef	CONFIG_TASK_DELAY_ACCT
struct task_delay_info *delays;
#endif
#ifdef CONFIG_FAULT_INJECTION
int make_it_fail;
#endif
/*
* when (nr_dirtied >= nr_dirtied_pause), it's time to call
* balance_dirty_pages() for some dirty throttling pause
*/
int nr_dirtied;
int nr_dirtied_pause;
unsigned long dirty_paused_when; /* start of a write-and-pause period */
#ifdef CONFIG_LATENCYTOP
int latency_record_count;
struct latency_record latency_record[LT_SAVECOUNT];
#endif
/*
* time slack values; these are used to round up poll() and
* select() etc timeout values. These are in nanoseconds.
*/
u64 timer_slack_ns;
u64 default_timer_slack_ns;
#ifdef CONFIG_KASAN
unsigned int kasan_depth;
#endif
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
/* Index of current stored address in ret_stack */
int curr_ret_stack;
/* Stack of return addresses for return function tracing */
struct ftrace_ret_stack	*ret_stack;
/* time stamp for last schedule */
unsigned long long ftrace_timestamp;
/*
* Number of functions that haven't been traced
* because of depth overrun.
*/
atomic_t trace_overrun;
/* Pause for the tracing */
atomic_t tracing_graph_pause;
#endif
#ifdef CONFIG_TRACING
/* state flags for use by tracers */
unsigned long trace;
/* bitmask and counter of trace recursion */
unsigned long trace_recursion;
#endif /* CONFIG_TRACING */
#ifdef CONFIG_KCOV
/* Coverage collection mode enabled for this task (0 if disabled). */
enum kcov_mode kcov_mode;
/* Size of the kcov_area. */
unsigned	kcov_size;
/* Buffer for coverage collection. */
void		*kcov_area;
/* kcov desciptor wired with this task or NULL. */
struct kcov	*kcov;
#endif
#ifdef CONFIG_MEMCG
struct mem_cgroup *memcg_in_oom;
gfp_t memcg_oom_gfp_mask;
int memcg_oom_order;
/* number of pages to reclaim on returning to userland */
unsigned int memcg_nr_pages_over_high;
#endif
#ifdef CONFIG_UPROBES
struct uprobe_task *utask;
#endif
#if defined(CONFIG_BCACHE) || defined(CONFIG_BCACHE_MODULE)
unsigned int	sequential_io;
unsigned int	sequential_io_avg;
#endif
#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
unsigned long	task_state_change;
#endif
int pagefault_disabled;
#ifdef CONFIG_MMU
struct task_struct *oom_reaper_list;
#endif
#ifdef CONFIG_VMAP_STACK
struct vm_struct *stack_vm_area;
#endif
#ifdef CONFIG_THREAD_INFO_IN_TASK
/* A live task holds one reference. */
atomic_t stack_refcount;
#endif
/* CPU-specific state of this task */
struct thread_struct thread;
/*
* WARNING: on x86, 'thread_struct' contains a variable-sized
* structure.  It *MUST* be at the end of 'task_struct'.
*
* Do not put anything below here!
*/
};

     可以看到,task_struct結構體的定義真是複雜啊!!!大家如果有時間,可以多去看看Linux核心的原始碼,寫的真是好,就像少林龍爪手一樣,是經過多少年高手的打磨,實為武林不敗的武功!!學習Linux核心的話,強烈推薦:Linux核心原始碼情景分析(全冊高清帶書籤),下載連結如下,密碼:s9jq。

     Linux核心原始碼情景分析(全冊高清帶書籤)

     好,我們繼續。runOnce方法中啟動好目標程序後,返回到父程序中的邏輯我們就不分析了,主要來看看當pid == 0,也就是返回到子程序時的情況。我們還是按照呼叫邏輯,先看看Zygote.forkAndSpecialize方法的執行過程,然後再回來接著下面的邏輯。Zygote類的目錄路徑為frameworks\base\core\java\com\android\internal\os\Zygote.java,forkAndSpecialize方法的原始碼如下:

    public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
int[] fdsToIgnore, String instructionSet, String appDataDir) {
VM_HOOKS.preFork();
// Resets nice priority for zygote process.
resetNicePriority();
int pid = nativeForkAndSpecialize(
uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
fdsToIgnore, instructionSet, appDataDir);
// Enable tracing as soon as possible for the child process.
if (pid == 0) {
Trace.setTracingEnabled(true);
// Note that this event ends at the end of handleChildProc,
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
}
VM_HOOKS.postForkCommon();
return pid;
}

     該方法先呼叫VM_HOOKS.preFork()作一些fork前的準備工作,VM_HOOKS是Zygote的成員變數,型別為ZygoteHooks。緊接著呼叫nativeForkAndSpecialize,該方法的實現在com_android_internal_os_Zygote.cpp檔案中,目錄路徑為:frameworks\base\core\jni\com_android_internal_os_Zygote.cpp,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;
// Grant CAP_WAKE_ALARM to the Bluetooth process.
// Additionally, allow bluetooth to open packet sockets so it can start the DHCP client.
// Grant CAP_SYS_NICE to allow Bluetooth to set RT priority for
// audio-related threads.
// TODO: consider making such functionality an RPC to netd.
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);
}
return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags,
rlimits, capabilities, capabilities, mount_external, se_info,
se_name, false, fdsToClose, fdsToIgnore, instructionSet, appDataDir);
}

     該方法中也是呼叫ForkAndSpecializeCommon來進一步處理,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) {
SetSigChldHandler();
sigset_t sigchld;
sigemptyset(&sigchld);
sigaddset(&sigchld, SIGCHLD);
// Temporarily block SIGCHLD during forks. The SIGCHLD handler might
// log, which would result in the logging FDs we close being reopened.
// This would cause failures because the FDs are not whitelisted.
//
// Note that the zygote process is single threaded at this point.
if (sigprocmask(SIG_BLOCK, &sigchld, nullptr) == -1) {
ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno));
RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_BLOCK, { SIGCHLD }) failed.");
}
// Close any logging related FDs before we start evaluating the list of
// file descriptors.
__android_log_close();
// If this is the first fork for this zygote, create the open FD table.
// If it isn't, we just need to check whether the list of open files has
// changed (and it shouldn't in the normal case).
std::vector<int> fds_to_ignore;
FillFileDescriptorVector(env, fdsToIgnore, &fds_to_ignore);
if (gOpenFdTable == NULL) {
gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore);
if (gOpenFdTable == NULL) {
RuntimeAbort(env, __LINE__, "Unable to construct file descriptor table.");
}
} else if (!gOpenFdTable->Restat(fds_to_ignore)) {
RuntimeAbort(env, __LINE__, "Unable to restat file descriptor table.");
}
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);
// Re-open all remaining open file descriptors so that they aren't shared
// with the zygote across a fork.
if (!gOpenFdTable->ReopenOrDetach()) {
RuntimeAbort(env, __LINE__, "Unable to reopen whitelisted descriptors.");
}
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.");
}
// Keep capabilities across UID change, unless we're staying root.
if (uid != 0) {
EnableKeepCapabilities(env);
}
SetInheritable(env, permittedCapabilities);
DropCapabilitiesBoundingSet(env);
bool use_native_bridge = !is_system_server && (instructionSet != NULL)
&& android::NativeBridgeAvailable();
if (use_native_bridge) {
ScopedUtfChars isa_string(env, instructionSet);
use_native_bridge = android::NeedsNativeBridge(isa_string.c_str());
}
if (use_native_bridge && dataDir == NULL) {
// dataDir should never be null if we need to use a native bridge.
// In general, dataDir will never be null for normal applications. It can only happen in
// special cases (for isolated processes which are not associated with any app). These are
// launched by the framework and should not be emulated anyway.
use_native_bridge = false;
ALOGW("Native bridge will not be used because dataDir == NULL.");
}
if (!MountEmulatedStorage(uid, mount_external, use_native_bridge)) {
ALOGW("Failed to mount emulated storage: %s", strerror(errno));
if (errno == ENOTCONN || errno == EROFS) {
// When device is actively encrypting, we get ENOTCONN here
// since FUSE was mounted before the framework restarted.
// When encrypted device is booting, we get EROFS since
// FUSE hasn't been created yet by init.
// In either case, continue without external storage.
} else {
RuntimeAbort(env, __LINE__, "Cannot continue without emulated storage");
}
}
if (!is_system_server) {
int rc = createProcessGroup(uid, getpid());
if (rc != 0) {
if (rc == -EROFS) {
ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?");
} else {
ALOGE("createProcessGroup(%d, %d) failed: %s", uid, pid, strerror(-rc));
}
}
}
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());
}
int rc = setresgid(gid, gid, gid);
if (rc == -1) {
ALOGE("setresgid(%d) failed: %s", gid, strerror(errno));
RuntimeAbort(env, __LINE__, "setresgid failed");
}
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);
const char* se_info_c_str = NULL;
ScopedUtfChars* se_info = NULL;
if (java_se_info != NULL) {
se_info = new ScopedUtfChars(env, java_se_info);
se_info_c_str = se_info->c_str();
if (se_info_c_str == NULL) {
RuntimeAbort(env, __LINE__, "se_info_c_str == NULL");
}
}
const char* se_name_c_str = NULL;
ScopedUtfChars* se_name = NULL;
if (java_se_name != NULL) {
se_name = new ScopedUtfChars(env, java_se_name);
se_name_c_str = se_name->c_str();
if (se_name_c_str == NULL) {
RuntimeAbort(env, __LINE__, "se_name_c_str == NULL");
}
}
rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
if (rc == -1) {
ALOGE("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
is_system_server, se_info_c_str, se_name_c_str);
RuntimeAbort(env, __LINE__, "selinux_android_setcontext failed");
}
// Make it easier to debug audit logs by setting the main thread's name to the
// nice name rather than "app_process".
if (se_info_c_str == NULL && is_system_server) {
se_name_c_str = "system_server";
}
if (se_info_c_str != NULL) {
SetThreadName(se_name_c_str);
}
delete se_info;
delete se_name;
UnsetSigChldHandler();
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
// 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;
}

     這裡最核心的就是pid_t pid = fork()這句邏輯了,fork是Linux的系統函式,是真正執行復制的,一次呼叫兩次返回也是它實現的。下面的SetGids、setresgid、setresuid函式都是修改目標程序的uid、gid的,因為Zygote程序的許可權很高,fork會一模一樣的複製Zygote為目標程序,這樣的話就會導致目標應用程序也有很高的許可權去操作各種檔案,所以這裡要把PMS為應用程序分配好的uid、gid等其他資訊寫入進來。

     該方法執行完成後,我們返回到Zygote類的forkAndSpecialize函式當中,此時,核心執行拷貝已經完成,我們的目標程序已經從無到有,從0到1發生質的變化了,而且核心中和目標程序對應的task_struct結構體也都已經準備好了,只要schedule排程程式下次選中我們的目標程序排程時,就會真正執行我們的邏輯了。forkAndSpecialize函式最後呼叫VM_HOOKS.postForkCommon()來進行一些後處理。VM_HOOKS的型別為ZygoteHooks,目錄路徑為:libcore\dalvik\src\main\java\dalvik\system\ZygoteHooks.java,postForkCommon方法的原始碼如下:

    /**
* Called by the zygote in both the parent and child processes after
* every fork. In the child process, this method is called after
* {@code postForkChild}.
*/
public void postForkCommon() {
Daemons.startPostZygoteFork();
}

     該方法是直接呼叫了Daemons類的靜態成員方法startPostZygoteFork來繼續處理的。Daemons類的目錄路徑為:libcore\libart\src\main\java\java\lang\Daemons.java,startPostZygoteFork方法的原始碼如下:

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

     為什麼要說這個方法呢?看到該方法的原始碼,大家就非常清楚了,我們經常遇到ANR、tombstone等問題,而這些問題的日誌中會列印出程序crash時的所有執行緒堆疊,排在每個程序最前面的幾個執行緒就是這幾條了,它們都是當前程序的守護執行緒,和ART執行和活躍物件的記憶體分配、垃圾回收計算等工作都是由他們來完成的。

     好,這裡執行完成後,層層返回到ZygoteConnection類的runOnce方法中,當前的返回的pid為0,繼續呼叫handleChildProc進一步處理,該方法的原始碼如下:

    private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws Zygote.MethodAndArgsCaller {
/**
* By the time we get here, the native code has closed the two actual Zygote
* socket connections, and substituted /dev/null in their place.  The LocalSocket
* objects still need to be closed properly.
*/
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);
}
newStderr = System.err;
} 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);
if (parsedArgs.invokeWith != null) {
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
VMRuntime.getCurrentInstructionSet(),
pipeFd, parsedArgs.remainingArgs);
} else {
ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}

     首先關閉socket流,一般應用程序啟動時,parsedArgs.invokeWith引數為空,會執行else分支,呼叫ZygoteInit.zygoteInit函式繼續完成目標程序的啟動。ZygoteInit類的目錄路徑為:frameworks\base\core\java\com\android\internal\os\ZygoteInit.java,它的zygoteInit方法的原始碼如下:

    public static final void zygoteInit(int targetSdkVersion, String[] argv,
ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
if (RuntimeInit.DEBUG) {
Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
RuntimeInit.redirectLogStreams();
RuntimeInit.commonInit();
ZygoteInit.nativeZygoteInit();
RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}

     首先呼叫RuntimeInit類的commonInit()靜態成員方法,RuntimeInit類的目錄路徑為:frameworks\base\core\java\com\android\internal\os\RuntimeInit.java,commonInit()方法的原始碼如下:

    protected static final void commonInit() {
if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!");
/*
* set handlers; these apply to all threads in the VM. Apps can replace
* the default handler, but not the pre handler.
*/
Thread.setUncaughtExceptionPreHandler(new LoggingHandler());
Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler());
/*
* Install a TimezoneGetter subclass for ZoneInfo.db
*/
TimezoneGetter.setInstance(new TimezoneGetter() {
@Override
public String getId() {
return SystemProperties.get("persist.sys.timezone");
}
});
TimeZone.setDefault(null);
/*
* Sets handler for java.util.logging to use Android log facilities.
* The odd "new instance-and-then-throw-away" is a mirror of how
* the "java.util.logging.config.class" system property works. We
* can't use the system property here since the logger has almost
* certainly already been initialized.
*/
LogManager.getLogManager().reset();
new AndroidConfig();
/*
* Sets the default HTTP User-Agent used by HttpURLConnection.
*/
String userAgent = getDefaultUserAgent();
System.setProperty("http.agent", userAgent);
/*
* Wire socket tagging to traffic stats.
*/
NetworkManagementSocketTagger.install();
/*
* If we're running in an emulator launched with "-trace", put the
* VM into emulator trace profiling mode so that the user can hit
* F9/F10 at any time to capture traces.  This has performance
* consequences, so it's not something you want to do always.
*/
String trace = SystemProperties.get("ro.kernel.android.tracing");
if (trace.equals("1")) {
Slog.i(TAG, "NOTE: emulator trace profiling enabled");
Debug.enableEmulatorTraceOutput();
}
initialized = true;
}

     這裡就會為當前目標程序的主執行緒設定兩個Handler,一個是UncaughtExceptionPreHandler,一個是DefaultUncaughtExceptionHandler,第一個Handler用來記錄應用程序將要crash時的日誌,第二個Handler用來將當前程序kill掉。如果我們的程序當中發生了crash異常,它是怎麼崩潰退出的,根因也就在這裡了。大家可以試想一下,我們經常在呼叫邏輯時加上try/catch,這樣把異常捕獲處理掉,只要不丟擲,那麼我們的程序是不會crash的,就是因為發生了一些我們沒有處理的異常時,最終一層層往上拋,到了framework中,它已經為我們準備好了DefaultUncaughtExceptionHandler,這個Handler就會把我們的目標程序kill掉。大家可以自己製造一個crash,看一下crash時的堆疊資訊就非常清楚了。

     我們再回到ZygoteInit類的zygoteInit方法中,繼續看下面的邏輯,接著呼叫ZygoteInit.nativeZygoteInit()。該方法的實現在AndroidRuntime.cpp檔案中,目錄路徑為:frameworks\base\core\jni\AndroidRuntime.cpp,nativeZygoteInit方法的原始碼如下:

static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
gCurRuntime->onZygoteInit();
}

     gCurRuntime的型別為AndroidRuntime,也就是我們常說的ART了,onZygoteInit方法的實現在app_main.cpp檔案中,目錄路徑為:frameworks\base\cmds\app_process\app_main.cpp,onZygoteInit方法的原始碼如下:

    virtual void onZygoteInit()
{
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
proc->startThreadPool();
}

     這裡就會為我們的目標程序啟動一個Binder執行緒池,去處理程序間通訊的業務了。

     這裡分析完,我們再回到ZygoteInit類的zygoteInit方法中,最後就是呼叫RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader)來繼續處理了。RuntimeInit類的目錄路徑為:frameworks\base\core\java\com\android\internal\os\RuntimeInit.java,applicationInit方法的原始碼如下:

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

     這裡將我們的傳入的引數封裝成一個Arguments物件,然後呼叫invokeStaticMain繼續處理。invokeStaticMain方法的原始碼如下:

    private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
throws Zygote.MethodAndArgsCaller {
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.
*/
throw new Zygote.MethodAndArgsCaller(m, argv);
}

     這裡根據我們傳入的className獲取到它的Class物件,然後呼叫Class物件的getMethod方法,獲取到該類的帶一個String[]型別引數的main方法,最後呼叫throw new Zygote.MethodAndArgsCaller(m, argv)丟擲一個異常。咦,為什麼要丟擲一個異常呢???看看註釋就非常清楚了,就是為了在我們的目標程序啟動時清空的Java堆疊。傳入的類className是哪個類呢?就是我們一開始在AMS中封裝啟動引數時傳入的entryPoint = “android.app.ActivityThread”。這裡的異常一層層往上拋,直到ZygoteInit類的main方法中,當它發現有型別為Zygote.MethodAndArgsCaller的異常時才會捕獲處理,呼叫Zygote.MethodAndArgsCaller類的run方法,MethodAndArgsCaller是Zygote類的內部類,MethodAndArgsCaller類的完整原始碼如下:

    public static class MethodAndArgsCaller extends Exception
implements Runnable {
/** method to call */
private final Method mMethod;
/** argument array */
private final String[] mArgs;
public MethodAndArgsCaller(Method method, String[] args) {
mMethod = method;
mArgs = args;
}
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);
}
}
}

     該類是實現了Runnable介面的,run方法中就是呼叫成員變數mMethod的invoke方法去執行了,也就是通過反射呼叫ActivityThread類的main方法了,到這裡,我們的目標程序就真正啟動起來了。大家在程序出現crash時也可以非常清楚的看到java層的堆疊,最根上的起點就是這裡。

     好了,到這裡,應用程序的啟動過程的原始碼分析也就完了,中間還有涉及到Linux的知識,本人對Linux的東西懂的也很少。以後還要加強學習。

     祝大家晚安!!聖誕節快樂!!!!