1. Application启动流程
AMS通过socket请求zygote创建进程, 然后反射创建ActivityThread,调用其main()方法
public final class ActivityThread extends ClientTransactionHandler {
//初始化ApplicationThread
final ApplicationThread mAppThread = new ApplicationThread();
//初始化Handler
final H mH = new H();
public static void main(String[] args){
...
//初始化Looper
Looper.prepareMainLooper();
//实例化一个ActivityThread
ActivityThread thread = new ActivityThread();
//这个方法最后就是为了发送出创建Application的消息
thread.attach(false);
...
//主线程进入无限循环状态,等待接收消息
Looper.loop();
}
}
ActivityThread的attach()方法通过binder接口调用到AMS的attachApplication()方法,并将ApplicationThread作为参数传递过去
public void attach(boolean system){
...
final IActivityManager mgr = ActivityManager.getService();
try {
//关键
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
...
}
查看AMS的attachApplication()方法可以看到,又调回了ApplicationThread的bindApplication().
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid, int callingUid, long startSeq) {
...
thread.bindApplication(processName, appInfo, providers,
instr2.mClass,
profilerInfo, instr2.mArguments,
instr2.mWatcher,
instr2.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode,
app.isPersistent(),
new
Configuration(app.getWindowProcessController().getConfiguration()),
app.compat, getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions);
...
}
ApplicationThread的bindApplication会给H
发送BIND_APPLICATION
消息,在H
中,通过handleBindApplication
处理application的绑定事务。ActivityThread通过ApplicationThread和AMS进行进程间通信,AMS以Binder的方式来完成ActivityThread的请求后回调ApplicationThread中的方法,ApplicationThread相当于Binder通信的服务端,然后ApplicationThread会向H发送消息,H收到消息后会将ApplicationThread中的逻辑切换到ActivityThread中去执行,即由ApplicationThread的Binder线程切换到了主线程,这也是H作为Hander的最大作用。
private class ApplicationThread extends IApplicationThread.Stub {
public final void bindApplication(String processName,
ApplicationInfo appInfo,
List<ProviderInfo> providers,
ComponentName instrumentationName,
ProfilerInfo profilerInfo,
Bundle instrumentationArgs,
IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection,
int debugMode,
boolean enableBinderTracking,
boolean trackAllocation,
boolean isRestrictedBackupMode,
boolean persistent,
Configuration config,
CompatibilityInfo compatInfo,
Map<String, IBinder> services,
Bundle coreSettings){
...
//发送消息
sendMessage(H.BIND_APPLICATION, data);
}
handleBindApplication最终会创建Application,并通过Instrumentation调用到Application的onCreate(),Instrumentation负责管理Activity和Application生命周期
private void handleBindApplication(AppBindData data) {
final ClassLoader cl = instrContext.getClassLoader();
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
...
mInstrumentation.callApplicationOnCreate(app);
}
2. Activity启动流程
Activity的启动从ActivityThread的handleLaunchActivity()开始
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
final Activity a = performLaunchActivity(r, customIntent);
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback,
r.assistToken);
mInstrumentation.callActivityOnCreate(activity, r.state);
}
在 performLaunchActivity()中同样通过Instrumentation创建Activity实例,然后调用activity的attach()方法,最后调用activity的onCreate(),至此Activity创建完成,接下来看activity页面是如何显示出来的的。
3. View的加载显示流程
1. setContentView
我们通常会在Activity的onCreate()方法中调用setContentView()设置布局文件,Activity 中将 setContentView 工作交给了 Window 对象去处理:
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
}
每个 Activity 内部都持有一个 Window 对象,而 Window 对象是在创建 Activity 流程中 attach 时就实例化的:
final void attach(...){
mWindow = new PhoneWindow(this, window, activityConfigCallback);
}
PhoneWindow 中会实际去 inflate 布局:
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
}
mLayoutInflater.inflate(layoutResID, mContentParent);
}
而 installDecor 中伪代码逻辑如下:
private void installDecor() {
if (mDecor == null) {
mDecor = new DecorView(...);
}
if (mContentParent == null) {
mContentParent = (ViewGroup)mDecor.findViewById(R.id.content);
}
}
setContentView创建了DecorView,并且结合这个顶层的view和我们传入的xml布局文件,生成了一个多层结构的View。下面就看如何显示出这个View
2. WindowManagerImpl
setContentView 只是创建好了 View 视图结构,还没告知 WMS。在 ActivityThread handleResumeActivity 方法中,才会与 WMS 通信开始添加 Activity 窗口,代码如下:
@Override
public void handleResumeActivity(IBinder token, ...) {
final ActivityClientRecord r = performResumeActivity(token, ...);
final Activity a = r.activity;
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
ViewManager wm = a.getWindowManager();
a.mDecor = decor;
wm.addView(decor, l);
}
r.activity.makeVisible();
}
其中 performResumeActivity 方法会回调 onResume 生命周期,之后调用 WindowManager 的 addView 方法并将 DecorView 传入。这里的 WindowManager 为 WindowManagerImpl 对象,与 Activity 内部的 window 一样,都是在 Activity attach 时创建。
final void attach(...){
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
}
//Window.java
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated;
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
//WindowManagerImpl.java
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
return new WindowManagerImpl(mContext, parentWindow);
}
WindowManagerImpl 中 addView 方法如下:
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
其进一步交给了 mGlobal 即 WindowManagerGlobal 去处理.
3. WindowManagerGlobal
接着来看 WindowManagerGlobal 的 addView 方法:
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
int index = findViewLocked(view, false);
if (index >= 0) {
if (mDyingViews.contains(view)) {
mRoots.get(index).doDie();
} else {
throw new IllegalStateException("View " + view
+ " has already been added to the window manager.");
}
}
ViewRootImpl root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
root.setView(view, wparams, panelParentView);
}
由于 WindowManagerGlobal 为进程单例,其内部的 mViews 则记录了全局添加的 View。当重复添加 View 时,就会抛出 "View has already been added to the window manager" 异常。
接着创建一个与 View 对应的 ViewRootImpl,将 View、ViewRootImpl 记录在 WindowManagerGlobal 中后,调用了 ViewRootImpl 的 setView 方法。
4. ViewRootImpl
先来看 ViewRootImpl 的构造函数:
public ViewRootImpl(Context context, Display display) {
mContext = context;
mWindowSession = WindowManagerGlobal.getWindowSession();
mWindow = new W(this);
...
}
其中 mWindowSession 是通过 WMS openSession 获取的匿名 binder,用于应用调用 WMS;mWindow 也是一个 binder 接口,用于 WMS 调用应用端。
接着看 ViewRootImpl setView 方法,关键代码如下:
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
//绘制
requestLayout();
//调用WMS的addWindow方法
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout,
mInputChannel);
//事件接收器
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
//设置this(ViewRootImpl)为view(decorView)的parent
view.assignParent(this);
}
}
}
值得注意的是,不需把 view 传给 WMS,这是因为 WMS 并不关心 View 树所表达的具体 UI 内容,它只要知道各应用进程显示界面的大小、窗口层级值即可。
5. WMS
到达 WMS 所在 system_server 进程后,WindowSession addToDisplay 会进一步调用 WindowManagerService 的 addWindow 方法,执行添加用户窗口工作,包括:
-
对用户窗口进行权限检查,比如 TYPE_PHONE 等窗口类型需要 SYSTEM_ALERT_WINDOW 权限
-
检查 mWindow,窗口最终会记录到 <IBinder,WindowState> HashMap 中,其中 IBinder 为应用端的 mWindow,即一个 mWindow 只允许添加唯一的窗口
-
检查窗口类型,比如子窗口必须依赖于一个父窗口
-
按照窗口层级添加合适的位置
-
等等...
6. 小结
-
每个 Activity 内部都持有一个 window 对象,其实现为 PhoneWindow,在 Activity attach()时创建
-
PhoneWindow 的根布局为 DecorView,其包括 TitleView 和 ContentView,Activity setContentView 就是把布局添加到 ContentView
-
当 Activity 第一次回调 onResume 后,开始将 Activity 的窗口添加到 WMS,首先调用了 WindowManagerImpl,WindowManagerImpl 进一步调用进程单例的 WindowManagerGlobal
-
WindowManagerGlobal 中创建了与 DecorView 对应的 ViewRootImpl,并将 DecorView 和 ViewRootImpl 记录下来
-
在 ViewRootImpl 中与 WMS 发生交互,应用端通过 WindowSession 调用 WMS,WMS 通过 IWindow 调用应用端
-
WMS 中会对窗口进行权限、类型等检查,最终将应用窗口信息记录下来
Activity、PhoneWindow、DecorView、ViewRootImpl 之间的关系?
PhoneWindow:是Activity和View交互的中间层,帮助Activity管理View。
DecorView:是所有View的最顶层View,也就是所有View的parent。
ViewRootImpl:用于处理View相关的事件,比如绘制,事件分发,也是DecorView的parent。
四者的创建时机?
Activity创建于performLaunchActivity方法中,在startActivity时候触发。
PhoneWindow,同样创建于performLaunchActivity方法中,再具体点就是Activity的attach方法。
DecorView,创建于setContentView->PhoneWindow.installDecor。
ViewRootImpl,创建于handleResumeActivity方法中,最后通过addView被创建。
View的第一次绘制发生在什么时候?
第一次绘制就是发生在handleResumeActivity方法中,通过addView方法,创建了ViewRootImpl,并调用了其setView方法。
最后调用到requestLayout方法开始了布局、测量、绘制的流程。
线程更新UI导致崩溃的原因?
在触发绘制方法requestLayout中,有个checkThread方法:
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
其中对mThread和当前线程进行了比较。而mThread是在ViewRootImpl实例化的时候赋值的。
所以崩溃的原因就是 view被绘制到界面时候的线程(也就是ViewRootImpl被创建时候的线程)和进行UI更新时候的线程不是同一个线程。
总结:
Activity的启动流程一般是通过调用startActivity或者是startActivityForResult来开始的
startActivity内部也是通过调用startActivityForResult来启动Activity,只不过传递的requestCode小于0
Activity的启动流程涉及到多个进程之间的通讯这里主要是ActivityThread与ActivityManagerService之间的通讯
ActivityThread向ActivityManagerService传递进程间消息通过ActivityManagerNative,ActivityManagerService向ActivityThread进程间传递消息通过IApplicationThread。
ActivityManagerService接收到应用进程创建Activity的请求之后会执行初始化操作,解析启动模式,保存请求信息等一系列操作。
ActivityManagerService保存完请求信息之后会将当前系统栈顶的Activity执行onPause操作,并且IApplication进程间通讯告诉应用程序继承执行当前栈顶的Activity的onPause方法;
ActivityThread接收到SystemServer的消息之后会统一交个自身定义的Handler对象处理分发;
ActivityThread执行完栈顶的Activity的onPause方法之后会通过ActivityManagerNative执行进程间通讯告诉ActivityManagerService,栈顶Actiity已经执行完成onPause方法,继续执行后续操作;
ActivityManagerService会继续执行启动Activity的逻辑,这时候会判断需要启动的Activity所属的应用进程是否已经启动,若没有启动则首先会启动这个Activity的应用程序进程;
ActivityManagerService会通过socket与Zygote继承通讯,并告知Zygote进程fork出一个新的应用程序进程,然后执行ActivityThread的main方法;
在ActivityThead.main方法中执行初始化操作,初始化主线程异步消息,然后通知ActivityManagerService执行进程初始化操作;
ActivityManagerService会在执行初始化操作的同时检测当前进程是否有需要创建的Activity对象,若有的话,则执行创建操作;
ActivityManagerService将执行创建Activity的通知告知ActivityThread,然后通过反射机制创建出Activity对象,并执行Activity的onCreate方法,onStart方法,onResume方法;
ActivityThread执行完成onResume方法之后告知ActivityManagerService onResume执行完成,开始执行栈顶Activity的onStop方法;
ActivityManagerService开始执行栈顶的onStop方法并告知ActivityThread;
ActivityThread执行真正的onStop方法;