本文是 Android 系統學習系列文章中的第一章節第二小節內容,從源碼出發說明了 Android 應用進程是如何啟動的,經過哪些進程的通力合作,它們是如何是設計的。。對此系列感興趣的同學,可以收藏這個鏈接 Android 系統學習,也可以使用 RSS 進行訂閱。
閱讀的收益
討論的內容也就是一個應用進程是如何啟動的,私以為這一部分的內容頗為重要,即便不了解細節,也要知道其中的大體步驟。特別是針對我們應用開發者而言,理應了解我們的 App 是如何被啟動的,App 中的組件是如何被系統服務調用和組織的。
講應用進程啟動的文章不是很多,也都沒有說到點上,大抵都是對源碼的堆疊,沒有個人的理解在里面。如果非要看調用棧的話,在合適的地方掛上斷點,或者通過輸出異常棧的方式都可以看到,如下圖所示。老羅的文章 Android應用程序啟動過程源代碼分析 事無巨細,但感覺還是沒有說到點子上,因而這篇文章只做到拋磚引玉的作用,希望有更好的文章出現。細節是復雜的,原理是簡單的,這里盡可能地從原理角度出發進行說明,加深大家的理解。
對這篇文章閱讀后,你能了解從用戶點擊 Launcher 上的 App 圖標,到顯示出 App 界面時主要發生的事情,而通過對這個一過程的了解,將知曉以下知識點。
- Android Process 的創建過程,以及 Activity Manager Service 是如何參與這個步驟,以及在其中扮演的角色?
- Android 中所謂的主線程是怎么回事?主線程是誰?又如何被創建的。
- Android 系統是如何節省進程創建開銷的?
應用進程簡介
在 Android 中每一個應用程序都被設計為單獨的進程,應用程序也可以根據自己的需要去決定是否需要啟用多個進程,不過總而言之都與其他應用程序和系統服務是相互獨立的。從解耦和系統穩定性的角度上看都應該運行在不同的進程上,畢竟不能因為應用程序的崩潰就影響到其他應用進程或者系統服務進程。
應用進程不同于其他 Android 系統中的守護進程,當內存不夠的時候,某些應用進程可能會被系統回收掉,因而應用進程也是有其生命周期的,更多信息參考 Android Developer 官網對于 Process 的教程 。Android 應用組件不一定要運行在單獨的進程上,也可以運行在多個進程上,通過對 Android 組件指定運行的進程 android:process
,即可讓其運行在其他線程上。
每個應用進程都相當于一個 Sandbox 沙箱,Android 通過對每一個應用分配一個 UID,注意這里的 UID 不同于 Linux 系統的 User ID,可以將每個應用理解為一個 User
,只能對其目錄下的內容具有訪問和讀寫權限,這樣就從根源上保護了其他應用程序,下圖說明了其隔離效果。
Zygote 進程
Zygote 的中文意思是受精卵,從這個意思里也可以看出 Zygote 進程是用來分裂復制(fork)的,實際上所有的 App 進程都是通過對 Zygote 進程的 Fork 得來的。當 app_process 啟動 Zygote 時,Zygote 會在其啟動后,預加載必要的 Java Classes(相關列表查看 預加載文件) 和 Resources,并啟動 System Server ,并打開 /dev/socket/zygote
socket 去監聽啟動應用程序的請求,日后。在下面的代碼中,顯示了 Zygote 進程如何啟動,和加載 System Server 的。
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
public static void main(String argv[]) {
// ...
registerZygoteSocket(socketName); // 開啟 Zygote socket.
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preload(); // 預加載資源
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
// Finish profiling the zygote initialization.
SamplingProfilerIntegration.writeZygoteSnapshot();
// Do an initial gc to clean up after startup
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PostZygoteInitGC");
gcAndFinalize(); // 觸發 GC
if (startSystemServer) { // 啟動 System Server.
startSystemServer(abiList, socketName);
}
// ...
}
那么為何要做這種設計呢?每個應用程序的運行,都需要依托于相應的運行環境,而這個就是 Davlik (ART) 虛擬機,但每次啟動的開銷較大,而通過對 Zygote 進程的 Fork,能夠提升不小的效率。并且在這個工程中,采用了 Copy-on-Write 的方式,極大程度上地復用了 Zygote 上面的資源。更多信息也可以參考我這篇博文 詳解 Android 是如何啟動的。
App 應用進程啟動
接下來的內容涉及到很多 Binder 通信相關的東西,因此在閱讀本文前,建議查閱下 Binder 相關的文章,這里有下列文章供查考。
ActivityManager 架構
在我們編程過程中,涉及到許多 Activity 跳轉的事情,在 Launcher 中點擊 Icon 進行跳轉也是同樣的道理,調用 context.startActivity(intent)
方法。Launcher 出于一個線程,而啟動的 App 則運行在另一個進程中,在這其中勢必牽涉到跨進程 (IPC) 調用,這樣復雜的過程顯然需要一種中介者,或者一個系統來進行中轉和管理,而這個服務就是 ActivityManagerService
。
ActivityManagerService
作為一個守護進程運行在 Android Framework 中,如果讓開發者直接接觸這個類的話,就需要開發者自行處理 IPC 調用的問題,且這有不利于 Android 系統進行安全校驗等工作。因而 Android 系統實現了 ActivityManager
,通過這個 ActivityManager
作為一個入口,變相地和 ActivityManagerService
打交道。這種模式在 Android 系統中極為常見,類似的還有 WifiManager
, LocationManager
,WindowsManager
等等。而這些 Manger 在背后調用的東西就是前面提及的 Binder 機制。下面以 ActivityManger 為例看看其背后的運作方式。
Binder 體系架構可以分為 Client 和 Server 兩端,為了更方便 Client 的調用,這次采用了 AIDL 的方式,具體參考鏈接 Android Binder 完全解析(三)AIDL實現原理分析 。這里再用類比的方式來說明,方便大家理解。歷史上有不少垂簾聽政的故事,背后操作的人實際是通過控制傀儡來控制朝政,通過給傀儡皇帝傳遞命令,傀儡皇帝只是復述命令,起到傳遞的作用。更有甚者,不想去上朝的控權者,會通過手下的太監或者婢女,轉述給傀儡皇上。這種模式被我們稱為代理模式,ActivityManger
所使用的就是這種模式。
首先這里要針對要執行的命令進行抽象,這樣掌權者、太監、皇上和朝政才能聽懂。IActivityManager
就是對這個進行的抽象,點擊查看 源碼,這幾種就包括常見的 startActivity, showWaitingForDebugger, finishActivity 等等。ActivityManagerProxy
就相當于其他的太監或者婢女,Proxy 不需要懂具體的業務,只需要把指令傳遞過去就行。ActivityManagerService
就是具體的執行者,就是大臣們。ActivityManger
則就是具體的業務邏輯的外觀類(參加GOF的設計模式),也就是具體的掌權者們。它們的關系如下圖所示:
源碼分析從 Launcher 到 ActivityManager 啟動步驟
接下來分析下,在源碼里是具體操作的,也驗證我們前面的說法。
(1) 點擊 Launcher 的圖標,會調用到 Activity 的 startActivity 方法。在繼續往下看過去,這個里面會調用到 startActivityForResult 方法,在 startActivityForResult 方法中,疏通同歸,最后會調用 mInstrumentation.execStartActivity
方法。
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
if (mParent == null) {
// ### ...
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
} else {
// ### ...
}
}
(2) Instrumentation 執行 execStartActivity 方法。參數里面中的 contextThread 和 token 對象都是 IBinder 類型,而 Binder 可以在跨進程調用中依舊充當 Token 的角色,在多進程中由 Binder Driver 保證依然可以是唯一的。
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
// monitor ...
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess();
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
}
return null;
}
(3) ActivityManagerNative.getDefault().startActivity。getDefault 中實際返回的就是 Proxy 對象,在實際中只起到代理的重要,并不進行邏輯處理。
先看看 ActivityManagerNative.getDefault() 中的實現。
/**
* Retrieve the system's default/global activity manager.
*/
static public IActivityManager getDefault() {
return gDefault.get();
}
IActivityManager 根據前文的描述即是對于可操作接口的抽象,Singleton 則是對單例對象的封裝。也就是說 gDefault 返回了實現 IActivityManager 的單例。
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
/**
* Cast a Binder object into an activity manager interface, generating
* a proxy if needed.
*/
static public IActivityManager asInterface(IBinder obj) {
if (obj == null) {
return null;
}
IActivityManager in =
(IActivityManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
return new ActivityManagerProxy(obj);
}
在 asInterface 中返回了 ActivityManagerProxy, 這就是前文提及的 太監和婢女 角色,我們再看看 ActivityManagerProxy 內部是如何工作的。
(4) ActivityManagerProxy 的實現。從源碼里面可以看出,ActivityManagerProxy 將遠程 Binder 作為構造函數的參數,而在 startActivity 方法中,通過遠程 Binder 對象的 transact
方法,將參數寫入到 data
中,在遠程執行完畢后,結果寫入到 reply
里。這里實實在在地起到了 Proxy 的作用,只負責數據的傳輸。重點在下面這行代碼:
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
class ActivityManagerProxy implements IActivityManager {
public ActivityManagerProxy(IBinder remote) {
mRemote = remote;
}
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeString(callingPackage);
intent.writeToParcel(data, 0);
data.writeString(resolvedType);
data.writeStrongBinder(resultTo);
data.writeString(resultWho);
data.writeInt(requestCode);
data.writeInt(startFlags);
if (profilerInfo != null) {
data.writeInt(1);
profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
data.writeInt(0);
}
if (options != null) {
data.writeInt(1);
options.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
reply.readException();
int result = reply.readInt();
reply.recycle();
data.recycle();
return result;
}
// other methods.
}
(5) ActivityManagerService 的調用。
在上部分提及的 ActivityManagerProxy 中在構造函數里傳入的 mRemote 遠程Binder 是什么了?答案就在前面提及的 gDefault 里面。
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
IBinder b = ServiceManager.getService("activity");
上面這段代碼返回的即是 ActivityManagerService
。所有的系統服務都是 IBinder 對象,即他們必須支持遠程調用。而每個系統服務都會通過在 ServiceManager 注冊別名的方式,告知 ServiceManager 通過相應的別名即可訪問到我。而 activity 正是 ActivityManagerService 的別名。
從 ActivityManagerService 到 進程啟動
ActivityManagerService 在接受到相應的 Intent 請求后(Activity、Broadcast、Service、ContentProvider),會查看是否需要進行新建進程的工作,這里以 Activity 為例,其他組件的步驟與此原理相同,就不再贅述。
(1) ActivityManagerService 在啟動 Activity 之前,首先通過 resolveIntent 方法,來得到相應的 ResolveInfo,其后通過調用 startActivityLocked 往下啟動 Activity。
try {
ResolveInfo rInfo =
AppGlobals.getPackageManager().resolveIntent(
intent, null,
PackageManager.MATCH_DEFAULT_ONLY
| ActivityManagerService.STOCK_PM_FLAGS, userId);
aInfo = rInfo != null ? rInfo.activityInfo : null;
aInfo = mService.getActivityInfoForUser(aInfo, userId);
} catch (RemoteException e) {
aInfo = null;
}
int res = startActivityLocked(caller, intent, resolvedType, aInfo,
voiceSession, voiceInteractor, resultTo, resultWho,
requestCode, callingPid, callingUid, callingPackage,
realCallingPid, realCallingUid, startFlags, options,
componentSpecified, null, container, inTask);
(2) startSpecificActivityLocked 方法,判斷是否需要新建進程。從代碼中看出,這里對 ProcessRecord 進行了判斷,ProcessRecord 就是響應的進程記錄,如果存在相應的進程,就啟動相應的 Activity, 否則將創建進程。mService.startProcessLocked
這個方法實現了開啟進程,下面再看看里面的實現。
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);
r.task.stack.setLaunchTime(r);
if (app != null && app.thread != null) {
try {
// ignore some code...
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.
}
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);
}
(3) startProcessLocked 在內部調用了 Process.start
方法,并且指定了 android.app.ActivityThread
作為進程的入口,進程啟動后,將調用 android.app.ActivityThread
的 main 方法。
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
// ...
// 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";
checkTime(startTime, "startProcess: asking zygote to start proc");
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);
// ...
}
(4) 在 Process.start 方法中,實際調用的是 startViaZygote
方法,在這個方法里通過 openZygoteSocketIfNeeded 打開 Zygote 的 socket,并通過 zygoteSendArgsAndGetResult
進行交互。
根據前文提及的內容,zygote 開啟了一個 socket 監聽功能,監聽需要創建 Process 的請求,因而在這里,我們去查看 Zygote 的代碼,看其是怎么監聽請求的。
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
(5) ZygoteInit.runSelectLoop 方法,從源碼的實現中可以看出,這里是不斷地取 Socket 建立的鏈接(ZygoteConnection),然后調用 ZygoteConnection 中的 runOnce 方法。
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
FileDescriptor[] fdArray = new FileDescriptor[4];
fds.add(sServerSocket.getFileDescriptor());
peers.add(null);
int loopCount = GC_LOOP_COUNT;
while (true) {
int index;
/*
* Call gc() before we block in select().
* It's work that has to be done anyway, and it's better
* to avoid making every child do it. It will also
* madvise() any free memory as a side-effect.
*
* Don't call it every time, because walking the entire
* heap is a lot of overhead to free a few hundred bytes.
*/
if (loopCount <= 0) {
gc();
loopCount = GC_LOOP_COUNT;
} else {
loopCount--;
}
try {
fdArray = fds.toArray(fdArray);
index = selectReadable(fdArray);
} catch (IOException ex) {
throw new RuntimeException("Error in select()", ex);
}
if (index < 0) {
throw new RuntimeException("Error in select()");
} else if (index == 0) {
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDescriptor());
} else {
boolean done;
done = peers.get(index).runOnce();
if (done) {
peers.remove(index);
fds.remove(index);
}
}
}
}
(6) ZygoteConnection.runOnce 方法里,fork 了 Zygote 進程,這就是 應用進程
了,并返回相應的 process id,其具體實現是本地方法,這里就不再深究了。如果得到相應的 Pid,接下來看看應用進程是如何初始化的。
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
parsedArgs.appDataDir);
try {
if (pid == 0) {
// in child
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
// should never get here, the child is expected to either
// throw ZygoteInit.MethodAndArgsCaller or exec().
return true;
} else {
// in parent...pid of < 0 means failure
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
(7) handleChildProc 方法,其中的重點就在 RuntimeInit.zygoteInit 方法 和 ZygoteInit.invokeStaticMain 方法。一個調用初始化了相應的進程,另一個在調用了進程的 main 方法。
private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws ZygoteInit.MethodAndArgsCaller {
if (parsedArgs.runtimeInit) {
if (parsedArgs.invokeWith != null) {
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
pipeFd, parsedArgs.remainingArgs);
} else {
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}
try {
ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
} catch (RuntimeException ex) {
logAndPrintError(newStderr, "Error starting.", ex);
}
}
在 RuntimeInit.zygoteInit 方法里實現了相應的 AndroidRuntime 初始化,并初始化 Binder Driver 相關的文件,同時設置了 UncaughtHandler(應用程序崩潰)。在這個方法調用結束后,應用進程就具備與相應系統服務進行 IPC 通信的能力。
(8) ZygoteInit.invokeStaticMain 通過反射調用了 ZygoteInit.MethodAndArgsCaller,而這個就是相應的 ActivityThread.java
中的 main 方法,其所運行的進程,就是大家耳熟能祥的主線程,也成為 UI 線程。
static void invokeStaticMain(ClassLoader loader,
String className, String[] argv)
throws ZygoteInit.MethodAndArgsCaller {
Class<?> cl;
try {
cl = loader.loadClass(className);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}
/*
* This throw gets caught in ZygoteInit.main(), which responds
* by invoking the exception's run() method. This arrangement
* clears up all the stack frames that were required in setting
* up the process.
*/
throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}
到此為止,整個應用進程啟動完畢。
應用進程啟動總結
Launcher 中的 Icon 點擊,broadcast 發送,啟動 Service 等組件見的跳轉,都會通過 AndroidManagerProxy
來進行中轉,而 AndroidManagerProxy
通過向 SystemServer
請求名為 Activity
的 ActivityManagerService
的 Binder 對象,這個 Binder 對象可以粗略地看作是 ActivityManagerService
的句柄,從 Binder 對象可實際操作 ActivityManagerService
。
ActivityManagerService
在實際啟動相應組件時,會先判斷是否有相應的 ProcessRecord,如果不存在,就需要新建進程,這個進程就是相應的應用進程。ActivityManagerService
通過 Socket 通信的方式和 Zygote 進行協商,Zygote 在其監聽的 /dev/socket/zygote
socket 中發現有需要創建進程的請求后,會 fork 自身,并返回相應的 Process Id。這個 Process 會進行相應的初始化,使得其具備與系統服務進行 IPC 通信的能力,在此之后,調用 ActivityThread
中的 main 方法,開啟 Looper,主線程啟動。到此為止,整個應用進程啟動完畢。
參考文獻
- Android應用程序進程啟動過程的源代碼分析
- Android應用程序線程消息循環模型分析
- startActivity流程分析(一)
- Android四大組件 Activity啟動過程源碼分析
- Android Application Launch
文檔信息
- 版權聲明:自由轉載-非商用-非衍生-保持署名(創意共享3.0許可證)
- 發表日期: 2016年6月26日
- 社交媒體: weibo
- Feed訂閱:www.woaitqs.cc/feed.xml