Android 应用的真正入口是哪里?
先说结论:“入口”是一个太笼统的概念,如果说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.arg1&1) != 0, msg.arg2,
(msg.arg1&2) != 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<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);
}
}
}
}
一旦建立一个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("<pre-initialized>");
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等一起配合完成的。