Android App启动(下文)
2021-12-02 本文已影响0人
圣明
ps:Android 27
本文从ActivityThread#main
开始,一只到Application
创建结束
首先是发生在ActivityThread内的
我们先来看下入口main函数
ActivityThread.main
public static void main(String[] args) {
...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
...
Looper.loop();
}
- 创建主线程looper
- 创新主线程ActivityThread
- Looper开启消息循环
ActivityThread 重要成员
# 负责进程间通信的IApplicationThread.stub对象
final ApplicationThread mAppThread = new ApplicationThread();
private class ApplicationThread extends IApplicationThread.Stub {
...
}
# 负责主线程消息分发的消息Handler
final H mH = new H();
private class H extends Handler {
...
}
ActivityThread. attach
// 不是系统进程,所以system是false
private void attach(boolean system) {
...
if (!system) {
...
// 获取系统 AMS
final IActivityManager mgr = ActivityManager.getService();
try {
// attach mAppThread ( IApplicationThread.stub) to ams
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
...
}
...
}
现在我们转到AMS
Ams也是一个Stub类,实现了IActivityManager.stub 接口,为了跨进程通信
,我们来看看Ams
的attachApplication
方法做了哪些
ActivityManagerService.attachApplication
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
ActivityManagerService.attachApplicationLocked
两件事:
- 通知ActivityThread 创建Application
- 尝试启动第一个Activity,最终也是通知ActivityThread.ApplicationThread#scheduleLaunchActivity处理的
private final boolean attachApplicationLocked(IApplicationThread thread,int pid){
// 找到已经创建的Application record
ProcessRecord app;
long startTime = SystemClock.uptimeMillis();
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
}
} else {
app = null;
}
...
// 调回 ActivityThread
if (app.instr != null) {
thread.bindApplication(...)
}
...
if (normalMode) {
try {
// 尝试启动第一个Activity
if (mStackSupervisor.attachApplicationLocked(app)) {
didSomething = true;
}
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true;
}
}
}
然后再转到ActivityThread内查看ApplicationThread
ActivityThread.ApplicationThread#bindApplication
public final void bindApplication(xxxx) {
...
// 往主线程发送一个BIND_APPLICATION的消息
sendMessage(H.BIND_APPLICATION, data);
}
ActivityThread.H#handleMessage(Message msg)
public void handleMessage(Message msg) {
switch (msg.what) {
case BIND_APPLICATION:
AppBindData data = (AppBindData)msg.obj;
handleBindApplication(data);
break;
}
}
ActivityThread#handleBindApplication
private void handleBindApplication(AppBindData data){
Application app;
try {
....
// 创建Application对象
app = data.info.makeApplication(data.restrictedBackupMode, null);
...
try {
// 执行application的onCreate()
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
..
}
}
}
LoadedApk#makeApplication
public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) {
...
Application app = null;
// 获取Application的全路径
String appClass = mApplicationInfo.className;
if (forceDefaultAppClass || (appClass == null)) {
// 没取到自定义的就是要默认的
appClass = "android.app.Application";
}
try {
java.lang.ClassLoader cl = getClassLoader();
// 创建一个baseContext,application中attachBaseContext的就是这个baseContext
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
// 调用mInstrumentation的newApplication创建Application
app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);
appContext.setOuterContext(app);
} catch (Exception e) {
...
}
...
return app;
}
内部是反射创建,就不对贴代码了
// Instrumentation#newApplication
static public Application newApplication(Class<?> clazz, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = (Application)clazz.newInstance();
app.attach(context);
return app;
}
// Application#attach
final void attach(Context context) {
// 这里就是开始创建的baseContext,所以在Application的attachBaseContext内调用getApplicationContext会返回空
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
然后会处理启动第一个Activity的消息去启动第一个Activity。