前言:
从打开一个 app 到手机屏幕上看到的界面基本上要经历以下的三个步骤:
步骤1:android 程序启动 Activity 加载并完成生命周期
步骤2:setContentView()
步骤3:图形绘制
(1)Android 应用程序如何启动的,生命周期是如何调用的?
(2)在 onCreate() 中 setContentView() 是如何加载 ui 文件的?
(3)ui 是如何绘制的?
UI 的绘制流程基本上就是围绕以上三个问题进行展开的,也是接下来几个章节的核心内容。
1. 应用程序的启动
1.1 从应用进程的启动到 ActivityThread
其实就是进程的创建,这部分内容在 framework 笔记13 中有讲到,这里就简述一下过程:
(1)在 Launcher 中的图表点击事件启动 app:startAppShortcutOrInfoActivity(v);在 framework 笔记12 中有提到;
(2)最终调用的还是 Activity 中的 startActivity();
(3)startActivity() 调用 startActivityForResult(),在这个方法中调用了 mInstrumentation.execStartActivity() 进行跨进程通信;也就是 int result = ActivityManagerNative.getDefault().startActivity(...),最终交给 AMS 进行处理;
(4)经过一系列的调用最终 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); // 根据uid和进程名进行查询
r.task.stack.setLaunchTime(r);
if (app != null && app.thread != null) { // 第一次打开某个进程时,肯定不会进入这个分支
// ... 以后的笔记中再分析
try {
if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
|| !"android".equals(r.info.packageName)) {
app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
mService.mProcessStats);
}
realStartActivityLocked(r, app, andResume, checkConfig); // 启动activity
return;
} catch (RemoteException e) {
// ... Log信息
}
}
// 进程的创建、application的创建和绑定
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);
}
(5)AMS 与 Zygote 的通信过程:r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true
// 第一步:AMS 中 startProcessLocked()
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;
// ...省略一些代码
if (app == null) { // 本节学习进程的创建,所以从此处开始
checkTime(startTime, "startProcess: creating new process record");
// 创建新的Process Record对象
app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
app.crashHandler = crashHandler;
if (app == null) {
return null;
}
mProcessNames.put(processName, app.uid, app);
if (isolated) {
mIsolatedProcesses.put(app.uid, app);
}
checkTime(startTime, "startProcess: done creating new process record");
} else {
// 如果这是进程中新package,则添加到列表
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, "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(
app, hostingType, hostingNameStr, abiOverride, entryPoint,entryPointArgs);
checkTime(startTime, "startProcess: done starting proc!");
return (app.pid != 0) ? app : null;
}
// 第二步:AMS 中 startProcessLocked()
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
long startTime = SystemClock.elapsedRealtime();
// ...
try {
// ...
boolean isActivityProcess = (entryPoint == null);
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
// 见第三步
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);
// ...
synchronized (mPidsSelfLocked) {
this.mPidsSelfLocked.put(startResult.pid, app); // 保存pid
// ...
}
} catch (RuntimeException e) {
// ...
}
}
// 第三步:
// Process 中的 start()方法:
public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG, "Starting VM process through Zygote failed");
throw new RuntimeException("Starting VM process through Zygote failed", ex);
}
}
// startViaZygote() 方法:
private static ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String[] extraArgs)
throws ZygoteStartFailedEx {
synchronized(Process.class) {
ArrayList argsForZygote = new ArrayList();
// --runtime-init, --setuid=, --setgid=,
// and --setgroups= must go first
argsForZygote.add("--runtime-init");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
// ...
// --setgroups is a comma-separated list
if (gids != null && gids.length > 0) {
StringBuilder sb = new StringBuilder();
sb.append("--setgroups=");
int sz = gids.length;
for (int i = 0; i < sz; i++) {
if (i != 0) {
sb.append(',');
}
sb.append(gids[i]);
}
argsForZygote.add(sb.toString());
}
if (niceName != null) {
argsForZygote.add("--nice-name=" + niceName); // nicieName是class的名字
}
if (seInfo != null) {
argsForZygote.add("--seinfo=" + seInfo);
}
if (instructionSet != null) {
argsForZygote.add("--instruction-set=" + instructionSet);
}
if (appDataDir != null) {
argsForZygote.add("--app-data-dir=" + appDataDir);
}
argsForZygote.add(processClass); // 是刚才传入的 "android.app.ActivityThread"
if (extraArgs != null) {
for (String arg : extraArgs) {
argsForZygote.add(arg);
}
}
// 调用的是zygoteSendArgsAndGetResult()
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
}
接下来就是 Zygote fork 出一个进程的过程,此部分内容在 framework 笔记13 中有介绍,不明白的可以去看看。以下是大致的步骤:
(a)Zygote 在 main() 方法中调用了 runSelectLoop(),而 runSelectLoop() 中有一个死循环,当有客户端连接时便会执行 ZygoteConnection.runOnce() 方法,再经过层层调用后 fork 出新的应用进程;
(b)fork 完成后子进程进行处理handleChildProc():关键代码在 ZygoteInit.invokeStaticMain(cloader, className, mainArgs) 方法中;
static void invokeStaticMain(ClassLoader loader,
String className, String[] argv)
throws ZygoteInit.MethodAndArgsCaller {
Class> cl;
try { // className 是传入的 "android.app.ActivityThread"
cl = loader.loadClass(className); // 获取class的名字
} catch (ClassNotFoundException ex) {
// ...
}
Method m;
try {
// 这里的方法 m 是 android.app.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);
}
// 关键代码
throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}
/**
* Helper exception class which holds a method and arguments and
* can call them. This is used as part of a trampoline to get rid of
* the initial process setup stack frames.
*/
// ZygoteInit内部类:
public static class MethodAndArgsCaller extends Exception
implements Runnable {
/** method to call */
private final Method mMethod;
/** argument array */
private final String[] mArgs;
public MethodAndArgsCaller(Method method, String[] args) {
mMethod = method;
mArgs = args;
}
public void run() {
// 这里的方法 mMethod 是 android.app.ActivityThread 的 main() 方法
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);
}
}
}
讲了这么多,从应用的启动,一直到调用 ActivityThread 的 main() 方法,之所以这么做,是想把整个流程走通,有助于全面理解进程的启动,自己亲身经历过某些一讲进程启动就直接 ActivityThread 的 main() 方法走起,这种生硬的灌输或者说死记硬背并不能让我很好的理解,所以在这里分享给大家。
1.2 入口 main() 函数
进程在 Zygote 进行 fork 、JNI 环境绑定等完成后,使用反射的方式执行了 ActivityThread 的 main() 方法,在这个 main 方法中,有三个需要注意的地方,如下代码中所示:
public static void main(String[] args) {
// ... 省略部分代码
//(1)准备MainLooper
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false); //(2)这里是重点
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
// ...
//(3)消息机制:有兴趣可以看看之前的文章中有 handler 消息机制的分析;
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
ActivityThread 的 attach() 方法:
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) { // 非系统app
ViewRootImpl.addFirstDrawHandler(new Runnable() {
@Override
public void run() {
ensureJitEnabled();
}
});
android.ddm.DdmHandleAppName.setAppName("",
UserHandle.myUserId());
RuntimeInit.setApplicationObject(mAppThread.asBinder());
final IActivityManager mgr = ActivityManagerNative.getDefault(); // 获取到AMS
try {
// binder 通讯,和之前的一样;mAppThread -> ApplicationThread,底层是BBinder
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
// Ignore
}
// Watch for getting close to heap limit.
BinderInternal.addGcWatcher(new Runnable() {
@Override public void run() {
if (!mSomeActivitiesChanged) {
return;
}
Runtime runtime = Runtime.getRuntime();
long dalvikMax = runtime.maxMemory();
long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
if (dalvikUsed > ((3*dalvikMax)/4)) {
mSomeActivitiesChanged = false;
try {
mgr.releaseSomeActivities(mAppThread);
} catch (RemoteException e) {
}
}
}
});
} else {
// ...
}
}
代码简要解析:下面这两行代码是关键
(1)IActivityManager mgr = ActivityManagerNative.getDefault():
通过 Binder 驱动获取 AMS,详细的过程在 framework 笔记10 中有,此处不再赘述;
(2)mgr.attachApplication(mAppThread):
在 framework 笔记13 也有讲到 AMS.attachApplication() 这个方法;
mgr.attachApplication(mAppThread) ->
ActivityManagerService.attachApplicationLocked() ->
thread.bindApplication() -> ----- 这里的 thread 是 ApplicationThread
使用 Handler 发送消息,执行 handleBindApplication(data) ->
创建 Application:Application app = data.info.makeApplication(data.restrictedBackupMode, null) ->
执行 Application 的 onCreate() 方法:mInstrumentation.callApplicationOnCreate(app)
至此,一个新的进程就创建完成了。
2. Activity 的启动
当前面的进程完成创建后,继续执行 ActivityManagerService.attachApplicationLocked() 的方法:
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
// ...
try {
// ...
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), app.compat, getCommonServicesLocked(),
mCoreSettingsObserver.getCoreSettingsLocked());
updateLruProcessLocked(app, false, null);
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
} catch (Exception e) {
// ...
return false;
}
if (normalMode) {
try {
// 下面的这行代码就要是启动 Manifest.xml 中配置的Activity 了
if (mStackSupervisor.attachApplicationLocked(app)) {
didSomething = true;
}
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true;
}
}
// Find any services that should be running in this process...
if (!badApp) {
try {
didSomething |= mServices.attachApplicationLocked(app, processName);
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
badApp = true;
}
}
// ...
}
boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
final String processName = app.processName;
boolean didSomething = false;
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
ArrayList stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
if (!isFrontStack(stack)) {
continue;
}
ActivityRecord hr = stack.topRunningActivityLocked(null);
if (hr != null) {
if (hr.app == null && app.uid == hr.info.applicationInfo.uid
&& processName.equals(hr.processName)) {
try {
if (realStartActivityLocked(hr, app, true, true)) { // 看到这里了没
didSomething = true;
}
} catch (RemoteException e) {
throw e;
}
}
}
}
}
if (!didSomething) {
ensureActivitiesVisibleLocked(null, 0);
}
return didSomething;
}
执行到 realStartActivityLocked(hr, app, true, true) 里,剩下的就是 Activity 的启动流程和生命周期的调用,具体的内容都在 framework 笔记14 中,这里跳过。
本章节内容并没有很多的内容,主要是对以前的知识有一个小的梳理和扩充。把进程的启动全部串联了起来,下一章节讲对 setContentView() 进行分析。