Activity的启动流程

 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方法;
 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值