• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

activity显示过程梳理

android 搞代码 3年前 (2022-03-01) 23次浏览 已收录 0个评论

简略整顿下activity 显示流程, 次要为acitvity -> WindowManager -> WMS -> SurfaceFlinger建设连贯的过程。

本篇为鸡生蛋系列第四篇文章

  1. Linux input零碎数据上报流程
  2. Android InputManager剖析
  3. AMS startActivity()
  4. [activity显示过程梳理]()
  5. [HomeLauncher启动]()

第4篇都曾经拖了快两年了, 几次都想写来着, 可是能源有余, 可是又想实现, 哎…

[代码: Android 11]

http://aosp.opersys.com/xref/…

setContentView()

搞利用的人都相熟,onCreate()里, 通过setContentView()把利用布局设置下,之后就显示进去了界面,
那这个流程是咋个样子的呢?

AppCompat的setContentView()就不看了,
通过在frameworks/base/目录搜寻 setContentView , 其入口次要有Dialog和Activity的,

<code class="java">frameworks/base/core/java/android/app/
Dialog.java
Activity.java

持续看Activity的, 其进一歩调用了window的setContentView(),

<code class="java">frameworks/base/core/java/android/app/Activity.java
public void setContentView(@LayoutRes int layoutResID) {
    // 调用mWindow的setContentView()
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}

public Window getWindow() {
    return mWindow;
}

那这个mWindow是啥呢?

<code class="java">@UnsupportedAppUsage
final void attach(Context context, ActivityThread aThread,
......
        Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
......
    // mWinow为PhoneWindow
    mWindow = new PhoneWindow(this, window, activityConfigCallback);

它其实是 new PhoneWindow(),

这里顺便回顾下, attach()是在activity启动时会调用, (具体的可看下该系列第二篇文章 AMS startActivity())

其代码如下:

<code class="java">frameworks/base/core/java/android/app/ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
            ......
            // 调用activity attach()
            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);

咱们回到PhoneWindow 持续看 setContentView(),
PhoneWindow有三个setContentView()办法, 最终都是将Decor Layout和ViewGroup关系建设起来,

<code class="java">frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java
@Override
public void setContentView(int layoutResID) {
    ......
    if (mContentParent == null) {
        // 装置Decor,
        // mContentParent会在该函数里赋值 mContentParent = generateLayout(mDecor);
        installDecor();
    }
    ......
    if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                getContext());
        transitionTo(newScene);
    } else {
        // 将咱们应用程序的布局退出
        mLayoutInflater.inflate(layoutResID, mContentParent);
    }
    ......
}

// 应用程序除了通过指定资源ID形式调用setContentView()
// 也可通过传入参数View形式调用,
// 最终也是将该view退出 mContentParent
@Override
public void setContentView(View view) {
    setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}

@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
......
    if (mContentParent == null) {
        // 和参数为资源ID形式一样,先装置Decor
        installDecor();
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        mContentParent.removeAllViews();
    }
    if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        view.setLayoutParams(params);
        final Scene newScene = new Scene(mContentParent, view);
        transitionTo(newScene);
    } else {
        // 退出view
        mContentParent.addView(view, params);
    }
    mContentParent.requestApplyInsets();
......
}

对于 setContentView()更具体的代码解读可看
https://www.gaodaima.com/p/2ee&#8230;
我感觉这篇文章写得很好, 这里就不再讲了.

show

原本认为利用 onCreate() –> setContentView()之后, 利用就显示进去了, 可是来来回回钻研代码如同都不太对,
这时候再来看看文章后面提到的Dialog咋显示的呢?

咱们晓得对于Dialog用法个别为:

<code class="java">// 伪代码形容
Dialog mDialog = new Dialog();
mDialog 资源参数等设置
// 调用show就显示进去了
mDialog.show();

先new 一个Dialog()对象,而后设置资源参数等, 再调用其show()办法就能够将其显示进去.

那咱们就先看看其show()办法是咋玩的.

<code class="java">frameworks/base/core/java/android/app/Dialog.java
public void show() {
    ......// 获取mDecor
    mDecor = mWindow.getDecorView();
    ......// 属性
    WindowManager.LayoutParams l = mWindow.getAttributes();
    ......
    // 增加view
    mWindowManager.addView(mDecor, l);

show() 里通过WindowManager的addView()办法, 与WinowManager分割上.

下面的mWindowManager即为WINDOW_SERVICE,

mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

须要留神的是 mWindowManager 为 WindowManagerImpl, 此时还处于用户过程中, 非WindowManagerService.
可通过看其 registerService() 注册服务时, 其的确为 new WindowManagerImpl()

<code class="java">frameworks/base/core/java/android/app/SystemServiceRegistry.java
registerService(Context.WINDOW_SERVICE, WindowManager.class,
        new CachedServiceFetcher<WindowManager>() {
    @Override
    public WindowManager createService(ContextImpl ctx) {
        return new WindowManagerImpl(ctx);
    }});

那么activity的mWindowManager.addView()在哪儿呢

这个时候就要举荐一本书了
<<深刻了解Android内核设计思维>> 林学森 著

这外面surface window view当然还有别的方面内容都讲得不错,
要是我能达到作者的高度这辈子也就值了,哎……

援用书中的话

  那么Activity 利用过程在什么时候会调用 addView,进而由WMS来解决addWindow 呢?
  Activity从启动到最终在屏幕上显示进去,别离要经验onCreate->onStart->onResume三个状态迁徙。其中 onResume是当界面行将可见时才会调用的,紧接着 ActivityThread 就会通过WindowManagerImpl来把应用程序窗口增加到零碎中。

具体代码如下:

<code class="java">frameworks/base/core/java/android/app/ActivityThread.java
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
        String reason) {
    ......
    // performResumeActivity()最终会调用activity的onResume()
    final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);

    if (r.window == null && !a.mFinished && willBeVisible) {
        r.window = r.activity.getWindow();
        // 获取decor, DecorView是activity 整棵View树最外围
        View decor = r.window.getDecorView();
        // 可见性
        decor.setVisibility(View.INVISIBLE);
        ViewManager wm = a.getWindowManager();
        WindowManager.LayoutParams l = r.window.getAttributes();
        a.mDecor = decor;
        ......
        if (a.mVisibleFromClient) {
            if (!a.mWindowAdded) {
                a.mWindowAdded = true;
                // *** 增加到view里
                wm.addView(decor, l);

从下面代码剖析可知,其最终也是通过wm.addView(), 最终和WMS分割上, 和后面的Dialog流程大体差不多,
略微有点小区别是其通过 createLocalWindowManager()创立进去的.

<code class="java">frameworks/base/core/java/android/view/Window.java
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
        boolean hardwareAccelerated) {
    ......
    if (wm == null) {
        wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
    }
    // wm最终为createLocalWindowManager()创立进去的
    mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);

从下面代码可知Dialog的show()和Activity 显示都最终调用了 WindowManagerImpl 的 addView()办法,
那这之后是咋和SurfaceFlinger分割在一起的呢? 咱们接着addView()看看。

addView() -> WMS

这些代码真是一层套一层, WindowManagerImpl addView() 最终又调用了 WindowManagerGlobal addView()

<code class="java">frameworks/base/core/java/android/view/WindowManagerImpl.java
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
            mContext.getUserId());
}

frameworks/base/core/java/android/view/WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow, int userId) {
        ......
        root = new ViewRootImpl(view.getContext(), display);

        // do this last because it fires off messages to start doing things
        try {
            // ViewRootImpl setView()
            root.setView(view, wparams, panelParentView, userId);

WindowManagerGlobal setView() 进一通过 ViewRootImpl setView()

<code class="java">frameworks/base/core/java/android/view/ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
        int userId) {
    synchronized (this) {
        if (mView == null) {
            mView = view;
            ......// final IWindowSession mWindowSession;
                 res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,
                         getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame,
                         mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                         mAttachInfo.mDisplayCutout, inputChannel,
                         mTempInsets, mTempControls);

进一步调用IWindowSession addToDisplayAsUser(), 其最终实现为

<code class="java">frameworks/base/services/core/java/com/android/server/wm/Session.java
public int addToDisplayAsUser(IWindow window,......) {
    return mService.addWindow(...);
}

下面的mService为

final WindowManagerService mService;

到这里才终于和WMS扯上点关系,

从上剖析, ViewRootImpl通过IWindowSession为桥梁,建设与WMS分割

ViewRootImpl <-> IWindowSession <-> WindowManagerService

WMS -> SurfaceFlinger

从下面终于看到利用activity通过一系列的调用, 终于和WMS关联上了, 那与SurfaceFlinger咋关联上的呢?
那就持续看addWindow()流程吧

<code class="java">frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public int addWindow(Session session, IWindow client, int seq,
        LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
        Rect outContentInsets, Rect outStableInsets,
        DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
        InsetsState outInsetsState, InsetsSourceControl[] outActiveControls,
        int requestUserId) {
        // 好多好多的查看
        ....
        // WMS用WindowState治理window
        final WindowState win = new WindowState(this, session, client, token, parentWindow,
                appOp[0], seq, attrs, viewVisibility, session.mUid, userId,
                session.mCanAddInternalSystemWindow);
        ....
        if  (openInputChannels) {
            // 与 input建立联系
            win.openInputChannel(outInputChannel);
        }
        ....
        // 与SurfaceFlinger建立联系
        win.attach();

addWindow()是一个比拟长也比拟重要的函数, 从中咱们能够理解到 WMS用 WindowState 形容窗口, 并通过openInputChannel()与输出关联上,
而其与SurfaceFlinger是通过 WindowState.attach() --> Session.windowAddedLocked() --> SurfaceSession() --> SurfaceComposerClient() 分割上的.

代码如下:

<code class="java">frameworks/base/services/core/java/com/android/server/wm/WindowState.java
void attach() {
    if (DEBUG) Slog.v(TAG, "Attaching " + this + " token=" + mToken);
    mSession.windowAddedLocked(mAttrs.packageName);
}

frameworks/base/services/core/java/com/android/server/wm/Session.java
void windowAddedLocked(String packageName) {......
    if (mSurfaceSession == null) {......
        mSurfaceSession = new SurfaceSession();

SurfaceSession()就会与SF建立联系, 可看下代码正文, 不再具体讲解.

frameworks/base/core/java/android/view/SurfaceSession.java
public SurfaceSession() {
    // 进结构函数调用JNI nativeCreate()
    mNativeClient = nativeCreate();
}

frameworks/base/core/jni/android_view_SurfaceSession.cpp
static jlong nativeCreate(JNIEnv* env, jclass clazz) {
    // JNI里new了个SurfaceComposerClient, 咱们晓得其为SurfaceFlinger的client端,
    // 用于和SF通信.
    // 如果不相熟该局部的可持续往后看代码
    SurfaceComposerClient* client = new SurfaceComposerClient();

frameworks/native/libs/gui/SurfaceComposerClient.cpp
// SurfaceComposerClient的构造函数里并没有做啥, 其继承RefBase, 所以接下来看其onFirstRef()
void SurfaceComposerClient::onFirstRef() {
    // 这里的ComposerService::getComposerService()失去的为 mComposerService, 也即是SurfaceFlinger服务
    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
    if (sf != nullptr && mStatus == NO_INIT) {
        sp<ISurfaceComposerClient> conn;
        // 创立连贯
        conn = sf->createConnection();

/*static*/ sp<ISurfaceComposer> ComposerService::getComposerService() {
    // getInstance()获取实例
    ComposerService& instance = ComposerService::getInstance();
    ......
    // 返回实例的 mComposerService
    return instance.mComposerService;

// 因为ComposerService继承自单例, 调用其getInstance()如果没创建对象的话, 会创立一个,
// 所以看下其构造函数
ComposerService::ComposerService()
: Singleton<ComposerService>() {
    Mutex::Autolock _l(mLock);
    // 构造函数里调用connectLocked()
    connectLocked();
}

void ComposerService::connectLocked() {
    // 获取SurfaceFlinger服务并赋值给 mComposerService
    const String16 name("SurfaceFlinger");
    while (getService(name, &mComposerService) != NO_ERROR) {

再回头看下

<code class="cpp">void SurfaceComposerClient::onFirstRef() {
        conn = sf->createConnection();

其在SurfaceFlinger创立了一个client进行治理

<code class="cpp">frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() {
    const sp<Client> client = new Client(this);
    return client->initCheck() == NO_ERROR ? client : nullptr;
}

NOTE

Window <1–1> WMS的WindowState <1–1> SurfaceSession <1–1> SurfaceComposerClient <1–1> SurfaceFlinger过程里的Client

它们是一一对应的


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:activity显示过程梳理

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址