Android 應用的真正入口是哪裡?
是 ActivityThread.main 呢 還是 ZygoteInit 呢?
經常會看到文章說 ActivityThread.main 是入口,但是從調用路徑來看:at android.app.ActivityThread.main(ActivityThread.java:5151)at java.lang.reflect.Method.invokeNative(Method.java)at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:684)at dalvik.system.NativeStart.main(NativeStart.java)是 ZygoteInit.main 先執行,並且 ZygoteInit 調用了 ActivityThread.main那麼是不是說 ZygoteInit 是 APP的入口更加合適一些?
先說結論:「入口」是一個太籠統的概念,如果說Android應用進程是如何被啟動的,那毫無疑問是ZygoteInit,但如果說Android應用中主線程的執行入口,則可以說是ActivityThread.main(),不過其實ActivityThread.main()也是在ZygoteInit中被反射調用的。
由於其中涉及的代碼非常多,這裡只羅列出一些重要的點。另外,下面的分析中涉及較多Zygote的知識,對Zygote不了解的童鞋,可以看我的Zygote系列博客:Zygote完全解析(1)
下面以點擊Launcher中某個icon啟動應用為例,系統地分析Android中應用的啟動過程。
首先,Launcher其實也是一個Activity,點擊icon的事件處理如下:public void onClick(View v) {
...
Object tag = v.getTag();
if (tag instanceof ShortcutInfo) {
// Open shortcut
final Intent intent = ((ShortcutInfo) tag).intent;
int[] pos = new int[2];
v.getLocationOnScreen(pos);
intent.setSourceBounds(new Rect(pos[0], pos[1],
pos[0] + v.getWidth(), pos[1] + v.getHeight()));
//here is where to start activity
boolean success = startActivitySafely(v, intent, tag);
if (success v instanceof BubbleTextView) {
mWaitingForResume = (BubbleTextView) v;
mWaitingForResume.setStayPressed(true);
}
} else if (tag instanceof FolderInfo) {
if (v instanceof FolderIcon) {
FolderIcon fi = (FolderIcon) v;
handleFolderClick(fi);
}
} else if (v == mAllAppsButton) {
...
}
}
startActivitySafely()最終會通過Binder通信調用到AMS中的startActivity(),如下為AMS中對應的方法:
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle options) {
return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
resultWho, requestCode, startFlags, profilerInfo, options,
UserHandle.getCallingUserId());
}
為了啟動App並使其Activity進入resumed狀態,需要先使當前運行的Activity(也就是Launcher)進入Paused狀態,在AMS中最終會調用到以下方法:
final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,
boolean dontWait) {
if (mPausingActivity != null) {
Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity);
completePauseLocked(false);
}
ActivityRecord prev = mResumedActivity;
if (prev == null) {
if (!resuming) {
Slog.wtf(TAG, "Trying to pause when nothing is resumed");
mStackSupervisor.resumeTopActivitiesLocked();
}
return false;
}
if (mActivityContainer.mParentActivity == null) {
// Top level stack, not a child. Look for child stacks.
mStackSupervisor.pauseChildStacks(prev, userLeaving, uiSleeping, resuming, dontWait);
}
if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSING: " + prev);
else if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
mResumedActivity = null;
mPausingActivity = prev;
mLastPausedActivity = prev;
mLastNoHistoryActivity = (prev.intent.getFlags() Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
|| (prev.info.flags ActivityInfo.FLAG_NO_HISTORY) != 0 ? prev : null;
prev.state = ActivityState.PAUSING;
prev.task.touchActiveTime();
clearLaunchTime(prev);
final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();
if (mService.mHasRecents (next == null || next.noDisplay || next.task != prev.task)) {
prev.updateThumbnail(screenshotActivities(prev), null);
}
stopFullyDrawnTraceIfNeeded();
mService.updateCpuStats();
if (prev.app != null prev.app.thread != null) {
if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending pause: " + prev);
try {
EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
prev.userId, System.identityHashCode(prev),
prev.shortComponentName);
mService.updateUsageStats(prev, false);
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
userLeaving, prev.configChangeFlags, dontWait);
} catch (Exception e) {
// Ignore exception, if process died other code will cleanup.
Slog.w(TAG, "Exception thrown during pause", e);
mPausingActivity = null;
mLastPausedActivity = null;
mLastNoHistoryActivity = null;
}
} else {
mPausingActivity = null;
mLastPausedActivity = null;
mLastNoHistoryActivity = null;
}
// If we are not going to sleep, we want to ensure the device is
// awake until the next activity is started.
if (!mService.isSleepingOrShuttingDown()) {
mStackSupervisor.acquireLaunchWakelock();
}
if (mPausingActivity != null) {
// Have the window manager pause its key dispatching until the new
// activity has started. If we"re pausing the activity just because
// the screen is being turned off and the UI is sleeping, don"t interrupt
// key dispatch; the same activity will pick it up again on wakeup.
if (!uiSleeping) {
prev.pauseKeyDispatchingLocked();
} else {
if (DEBUG_PAUSE) Slog.v(TAG, "Key dispatch not paused for screen off");
}
if (dontWait) {
// If the caller said they don"t want to wait for the pause, then complete
// the pause now.
completePauseLocked(false);
return false;
} else {
// Schedule a pause timeout in case the app doesn"t respond.
// We don"t give it much time because this directly impacts the
// responsiveness seen by the user.
Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
msg.obj = prev;
prev.pauseTime = SystemClock.uptimeMillis();
mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
if (DEBUG_PAUSE) Slog.v(TAG, "Waiting for pause to complete...");
return true;
}
} else {
// This activity failed to schedule the
// pause, so just treat it as being paused now.
if (DEBUG_PAUSE) Slog.v(TAG, "Activity not running, resuming next.");
if (!resuming) {
mStackSupervisor.getFocusedStack().resumeTopActivityLocked(null);
}
return false;
}
}
之後又通過Binder通信調用到ApplicationThread的如下方法:
public final void schedulePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport) {
sendMessage(
finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
token,
(userLeaving ? 1 : 0) | (dontReport ? 2 : 0),
configChanges);
}
之後會通過H(Handler的子類)發送消息,處理消息的邏輯在ActivityThread中:
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">&>&> handling: " + codeToString(msg.what));
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
case RELAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
handleRelaunchActivity(r);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
case PAUSE_ACTIVITY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
handlePauseActivity((IBinder)msg.obj, false, (msg.arg11) != 0, msg.arg2,
(msg.arg12) != 0);
maybeSnapshot();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
...
}
}
執行該方法後,最終會調用Activity的performPause()方法:
inal void performPause() {
mDoReportFullyDrawn = false;
mFragments.dispatchPause();
mCalled = false;
onPause();
mResumed = false;
if (!mCalled getApplicationInfo().targetSdkVersion &>= android.os.Build.VERSION_CODES.GINGERBREAD) {
throw new SuperNotCalledException(
"Activity " + mComponent.toShortString() + " did not call through to super.onPause()");
}
mResumed = false;
}
這裡可以看到onPause()這個回調。之後在handlePauseActivity()中會調用ActivityManagerNative.getDefault().activityPaused(token);通過Binder機制調用AMS中的activityPaused()方法,如下:
public final void activityPaused(IBinder token) {
final long origId = Binder.clearCallingIdentity();
synchronized(this) {
ActivityStack stack = ActivityRecord.getStackLocked(token);
if (stack != null) {
stack.activityPausedLocked(token, false);
}
}
Binder.restoreCallingIdentity(origId);
}
之後會有很多的跳轉,最終調用startProcessLocked()方法:
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
String hostingType, ComponentName hostingName, boolean allowWhileBooting,
boolean isolated, boolean keepIfLarge) {
return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
null /* crashHandler */);
}
最終調用的重載方法中有以下代碼,注意這裡傳入了ActivityThread類的路徑:
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);
Process.start()實際上是調用Zygote來fork一個新的進程,並且在最後會調用ActivityThread的main()方法.AMS 所在的進程和 Zygote 所在的進程通過Socket通信,ZygoteInit中循環偵聽Socket連接:
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
ArrayList&
ArrayList&
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);
}
}
}
}
一旦建立一個ZygoteConnection,就調用runOnce()進行處理,runOnce()中的核心代碼如下:
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);
}
Zygote.forkAndSpecialize()最終會調用到一個naitve方法來fork進程,最後在子進程(即App進程)中執行handleChildProc()方法,代碼如下:
private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws ZygoteInit.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();
ZygoteInit.closeServerSocket();
if (descriptors != null) {
try {
ZygoteInit.reopenStdio(descriptors[0],
descriptors[1], descriptors[2]);
for (FileDescriptor fd: descriptors) {
IoUtils.closeQuietly(fd);
}
newStderr = System.err;
} catch (IOException ex) {
Log.e(TAG, "Error reopening stdio", ex);
}
}
if (parsedArgs.niceName != null) {
Process.setArgV0(parsedArgs.niceName);
}
if (parsedArgs.runtimeInit) {
if (parsedArgs.invokeWith != null) {
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
pipeFd, parsedArgs.remainingArgs);
} else {
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
} else {
String className;
try {
className = parsedArgs.remainingArgs[0];
} catch (ArrayIndexOutOfBoundsException ex) {
logAndPrintError(newStderr,
"Missing required class name argument", null);
return;
}
String[] mainArgs = new String[parsedArgs.remainingArgs.length - 1];
System.arraycopy(parsedArgs.remainingArgs, 1,
mainArgs, 0, mainArgs.length);
if (parsedArgs.invokeWith != null) {
WrapperInit.execStandalone(parsedArgs.invokeWith,
parsedArgs.classpath, className, mainArgs);
} else {
ClassLoader cloader;
if (parsedArgs.classpath != null) {
cloader = new PathClassLoader(parsedArgs.classpath,
ClassLoader.getSystemClassLoader());
} else {
cloader = ClassLoader.getSystemClassLoader();
}
try {
ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
} catch (RuntimeException ex) {
logAndPrintError(newStderr, "Error starting.", ex);
}
}
}
}
注意最後面的ZygoteInit.invokeStaticMain()方法,就是在這裡調用ActivityThread的main()方法,而main()方法的代碼如下:
public static void main(String[] args) {
SamplingProfilerIntegration.start();
// 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());
Security.addProvider(new AndroidKeyStoreProvider());
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("&
");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
AsyncTask.init();
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
從這裡開始,準備主線程的消息隊列,並為App配置一個ActivityThread,再通過thread.attach()將ActivityThead,ApplicationThread與AMS關聯起來,注意這裡的ActivityThread才是屬於剛剛啟動的App進程的,之前的ApplicationThread和ActivityThread是屬於Launcher所在的進程的,後續AMS通過Binder通知ActivityThread進行App中主線程的調度工作。
綜上,說ActivityThread.main()是應用的入口也可以,但是不太嚴謹,因為App的啟動是Zygote,AMS,ApplicationThread,ActivityThread等一起配合完成的。
謝邀。
1. 從源碼位置上來講,這個其實蠻明顯的,我們可以看源碼中 ActivityThread的位置:/frameworks/base/core/java/android/app/ActivityThread.java可以看到是位於 app 這個包裡面的。而ZygoteInit 的源碼位置如下:
/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java是放在internal/os下面的。(internal的意思是:內部的;內在的;國內的)2. 從功能上來講,ZygoteInit 的幾大函數已經很能說明他是幹什麼的了:private static void registerZygoteSocket(String socketName)
static void preload() // 預載入資源
private static void handleSystemServerProcess()
private static PathClassLoader createSystemServerClassLoader(String systemServerClasspath, int targetSdkVersion)
private static boolean startSystemServer(String abiList, String socketName) 、、啟動SystemServer進程。
簡單來說就是建立Socket通信,預載入資源,啟動SystemServer. 人如其名,就是初始化 Zygote用的。而進程的fork,是Zygote乾的事情。
而ActivityThread 則是 App的管家,個人覺得叫 AppProcessManager 更貼切一些。具體內容可以參考其代碼。
其main函數主要幹了兩件事:1. 創建 MainLooper.2. 創建 ActivityThread 對象.ActivityThread 乾的事情才和具體的 App 有關係,而ZygoteInit 只是做Zygote的初始化工作,儘管一個App的進程是從 Zygote fork 出來的。
總之,多看源碼總是沒錯的。Android菜鳥來一答。純爪機手打。
個人認為應該是ZygoteInit.我以前也一直認為是ActivityThread,但是看到這個異常很明顯列印的是函數調用棧,從底層調用往上拋的,這讓我想起了linux應用編程中的fork原理,Zygote進程fork時父進程是Zygote,子進程是app進程,父進程會把資源拷貝到子進程中,ZygoteInit應該是這個時候拷貝到了app進程中,而ActivityThread只是UI主線程,駐留在app進程中。
當用戶在Launcher應用中點擊app圖標,Launcher會向AMS發送是否啟動app進程,AMS向Zygote進程請求fork應用進程,Zygote拷貝一系列應用初始化所需要的資源,然後在子進程中運行,然後初始化ActivityThread,創建好了以後通知AMS,並把IAplicationThread傳遞進去作為AMS回調的對象,然後,AMS開始控制Activity的方法調用。推薦閱讀:
※有哪些大齡非 CS 科班出身的青年轉行程序員,結果失敗的例子?
※怎樣搭高質量的Android項目框架,框架的結構具體描述?
※Android的UI底層是用CPU繪圖的還是GPU繪圖的呢?以及surfaceview,window,普通view是如何實現的?
※智能手機感測器里的線性加速度器、陀螺儀、重力感應儀,有什麼區別?