點選桌面圖示如何啟動的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的成員變量,初始化是在構造器中,如下圖:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TPB10drR1T6lleOpHOsJGcohVYsR2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLykjNzMTNxUTMxETNwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
2:接下來再看看ZygotePrecess構造器中的參數是什麼:ZygotePrecess構造器在Precess中調用
接下來再說說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
方法;看下圖:
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啟動流程總圖以便了解記憶。順便給點個贊謝謝祝,大家周末愉快!!!。