SurfaceFlinger和端侧的大体框架(2)

SurfaceFlinger和端侧的大体框架

简述

这篇博客会带大家探究app和WMS是怎么通过binder和SurfaceFlinger进行通信,主要围绕如何基于Binder去创建一个Surface来展开。
Binder是一个Android用于跨进程通信的方案,在Android中使用非常多,后面会专门写一个关于Binder专题,在阅读这篇文章之前,只要知道java和c++分别是怎么使用binder的就可以了。
WMS(WindowManagerService)是Android中的窗口管理服务,用来管理所有app创建的窗口,比如管理窗口Z轴顺序,窗口大小位置,窗口动画等等。app创建窗口一般会通过binder通知WMS,WMS再和SurfaceFlinger通信创建窗口,在WMS中会为一个窗口构建一个SurfaceControl类,并且会将创建完成的窗口返回给app,我们在app内的窗口渲染相关的逻辑会抽象在一个Surface类里,Surface可以提供对窗口绘制渲染的接口,SurfaceControl提供了对窗口的控制能力,比如修改窗口大小位置等。这样app就只能绘制窗口,想要修改窗口的属性就要通过WMS。 关于WMS后面会有一个专门的专题来介绍,这里只要知道他的大概理念即可。

app创建窗口

app创建窗口时,最终会调用到WMS的addWindow,经过一系列调用最终会构建一个WindowSurfaceController,在里面会构建SurfaceControl,这之间的过程后面在WMS的章节里会介绍,这里就不多赘述了。
在这里插入图片描述
在这里插入图片描述

1.1 在构造函数里通过Builder构造SurfaceControl

WindowSurfaceController(String name, int format, int flags, WindowStateAnimator animator,
        int windowType) {
    // ... 省略无关代码

    // 构建SurfaceControl
    final SurfaceControl.Builder b = win.makeSurface()
            .setParent(win.getSurfaceControl())
            .setName(name)
            .setFormat(format)
            .setFlags(flags)
            .setMetadata(METADATA_WINDOW_TYPE, windowType)
            .setMetadata(METADATA_OWNER_UID, mWindowSession.mUid)
            .setMetadata(METADATA_OWNER_PID, mWindowSession.mPid)
            .setCallsite("WindowSurfaceController");

    final boolean useBLAST = mService.mUseBLAST && ((win.getAttrs().privateFlags
            & WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST) != 0);

    if (useBLAST) {
        b.setBLASTLayer();
    }

    mSurfaceControl = b.build();
}

1.2 java层SurfaceControl的构造函数,SurfaceControl在c++层也有一个对应的类,他们是一对一的,这里会调用nativeCreate构造c++层对象,返回新建的c++层SurfaceControl的地址,记录到nativeObject,这样java层和c++层到SurfaceControl就一对一关联了。

private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,
        SurfaceControl parent, SparseIntArray metadata, WeakReference<View> localOwnerView,
        String callsite)
                throws OutOfResourcesException, IllegalArgumentException {
    //。。。省略部分代码
    try {
        //。。。省略部分代码
        // 构造对应native对象,返回的是c++层的SurfaceContorl地址,记录地址后就实现关联了
        nativeObject = nativeCreate(session, name, w, h, format, flags,
                parent != null ? parent.mNativeObject : 0, metaParcel);
    } finally {
        metaParcel.recycle();
    }
    // 。。。
    // nativeObject是native对象key,通过这个值可以找到对应native对象,这里把它记录到java层的变量里
    assignNativeObject(nativeObject, callsite);
}

1.3 对应c++逻辑在android_view_SurfaceControl.cpp内
这里的sessionObj参数是SurfaceSession,SurfaceComposerClient是和SufraceFlinger进行Binder通信的Client端的封装。
这里主要是构造SurfaceComposerClient,然后调用createSurfaceChecked

static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
    jstring nameStr, jint w, jint h, jint format, jint flags, jlong parentObject,
    jobject metadataParcel) {
    ScopedUtfChars name(env, nameStr);
    sp<SurfaceComposerClient> client;
    // SurfaceComposerClient的地址在SurfaceSession中有缓存,这里就是判断一下是否已经构建了
    if (sessionObj != NULL) {
        client = android_view_SurfaceSession_getClient(env, sessionObj);
    } else {
        // 第一次构建走这里
        // 具体查看1.3.1
        client = SurfaceComposerClient::getDefault();
    }
    // 这里是java侧传过来的父SurfaceControl
    SurfaceControl *parent = reinterpret_cast<SurfaceControl*>(parentObject);
    sp<SurfaceControl> surface;
    // 。。。

    sp<IBinder> parentHandle;
    if (parent != nullptr) {
        parentHandle = parent->getHandle();
    }
    //调用SurfaceComposerClient.createSurfaceChecked做创建相关的逻辑
    // 创建窗口,并且构造一个c++层的SurfaceControl,会通过surface参数返回,具体查看1.4
    status_t err = client->createSurfaceChecked(String8(name.c_str()), w, h, format, &surface,
                                                flags, parentHandle, std::move(metadata));
    // 。。。
    // 返回c++层的SurfaceControl地址,java层会记录这个地址相互关联
    return reinterpret_cast<jlong>(surface.get());
}

1.3.1 SurfaceComposerClient::getDefault()
构建SurfaceComposerClient

sp<SurfaceComposerClient> SurfaceComposerClient::getDefault() {
    // 查看1.3.2
    return DefaultComposerClient::getComposerClient();
}

1.3.2 DefaultComposerClient::getComposerClient()

static sp<SurfaceComposerClient> getComposerClient() {
    // 这里是个单例
    DefaultComposerClient& dc = DefaultComposerClient::getInstance();
    Mutex::Autolock _l(dc.mLock);
    if (dc.mClient == nullptr) {
        // 调用SurfaceComposerClient构造,赋值给智能指针,具体查看1.3.3
        dc.mClient = new SurfaceComposerClient;
    }
    return dc.mClient;
}

1.3.3 void SurfaceComposerClient::onFirstRef()
智能指针首次赋值时会调用类的onFirstRef,这里首先通过ServiceManager获取SurfaceFlinger binder服务的handle,想要访问binder服务都必须要有这个服务的handle,服务启动时候会告诉ServiceManager自己的handle,并且和一个固定的字符串进行绑定,后面其他进程想要访问这个binder服务就可以通过固定的字符串去和ServiceManager查询这个handle。
其他进程也是通过binder访问ServiceManager的,这时候就有个问题,那其他进程是怎么获取ServiceManager的handle呢,其实很简单,ServiceManager的handle是固定的。其他细节在专门介绍binder的章节来解释,这里只要知道它的接口是这么用的就行。
拿到SurfaceFlinger的binder就可以和SurfaceFlinger进行通信了,调用了binder接口createConnection来创建了一个Client对象并记录下来了。

void SurfaceComposerClient::onFirstRef() {
    // 连接SurfaceFlingerAIDL的binder,详见1.3.3.1
    sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
    if (sf != nullptr && mStatus == NO_INIT) {
        sp<ISurfaceComposerClient> conn;
        // 通过binder接口调用createConnection,创建和surfaceflinger的连接,详见1.3.4
        binder::Status status = sf->createConnection(&conn);
        if (status.isOk() && conn != nullptr) {
            // 返回的Client记录在这里
            mClient = conn;
            mStatus = NO_ERROR;
        }
    }
}

1.3.3.1 ComposerService::getComposerService()
调用connectLocked创建连接

sp<ISurfaceComposer> ComposerService::getComposerService() {
    ComposerService& instance = ComposerService::getInstance();
    Mutex::Autolock _l(instance.mLock);
    if (instance.mComposerService == nullptr) {
        // 这里创建连接,相见1.3.3.2
        if (ComposerService::getInstance().connectLocked()) {
            ALOGD("ComposerService reconnected");
        }
    }
    return instance.mComposerService;
}

1.3.3.2 ComposerService::connectLocked()
获取SurfaceFinger aidl binder,之后就可以通过它和SurfaceFlinger进行通信了

bool ComposerServiceAIDL::connectLocked() {
    //通过AMS查询SurfaceFlingerAIDL的binder service(即SurfaceFlinger)
    //这样就可以和SurfaceFlinger通信了
    const String16 name("SurfaceFlingerAIDL");
    mComposerService = waitForService<gui::ISurfaceComposer>(name);
    if (mComposerService == nullptr) {
        return false; // fatal error or permission problem
    }
    // 。。。注册死亡回调
    return true;
}

1.3.4 ISurfaceComposer::createConnection
创建连接,构造一个Client对象,这里已经通过binder来到SurfaceFlinger进程里了。(在看android系统代码的时候,要时刻注意当前代码是在哪个进程,这个是初学者很容易弄混的点)
sp是智能指针,我们后面会单独写一篇文章来解释,这里make方法就是构造一个Client,Client是持有SurfaceFlinger引用的,可以用来访问SurfaceFlinger,然后会把Client返回给WMS进程

binder::Status SurfaceComposerAIDL::createConnection(sp<gui::ISurfaceComposerClient>* outClient) {
    // 构造一个Client类,并且通过binder把这个Client返回给客户端进程(WMS)
    const sp<Client> client = sp<Client>::make(mFlinger);
    if (client->initCheck() == NO_ERROR) {
        *outClient = client;
        return binder::Status::ok();
    } else {
        *outClient = nullptr;
        return binderStatusFromStatusT(BAD_VALUE);
    }

}

到这里为止我们就构建了一个SurfaceComposerClient对象,然后通过binder调用SurfaceFlinger构建了一个持有SurfaceFlinger引用的Client对象。

我们接着看1.3.1后面

1.4 SurfaceComposerClient.createSurfaceChecked
这里调用Client的createSurface让surfaceFlinger创建窗口,然后会返回一些窗口的信息存在result里,result有个handle字段,代表新创建的窗口的句柄。(关于这些handle,可以简单的认为handle就是一个id,可以查询到唯一的目标对象,这样理解后续看代码会简单一些)
然后会构造一个c++层的SurfaceControl,这个和java层是一对一的

status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32_t w, uint32_t h,
                                                 PixelFormat format,
                                                 sp<SurfaceControl>* outSurface, int32_t flags,
                                                 const sp<IBinder>& parentHandle,
                                                 LayerMetadata metadata,
                                                 uint32_t* outTransformHint) {
sp<SurfaceControl> sur;
status_t err = mStatus;

if (mStatus == NO_ERROR) {
    gui::CreateSurfaceResult result;
    // 调用上面Client的createSurface让surfaceFlinger创建窗口,具体查看1.5
    binder::Status status = mClient->createSurface(std::string(name.string()), flags,
                                                   parentHandle, std::move(metadata), &result);
    err = statusTFromBinderStatus(status);
    if (outTransformHint) {
        *outTransformHint = result.transformHint;
    }
    ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
    if (err == NO_ERROR) {
        // 构建c++层的SurfaceControl,持有窗口的handle,是一个binder对象。
        // 构造函数主要就是把这些参数记录到变量里,这里就不看了
        *outSurface = new SurfaceControl(this, result.handle, result.layerId,
                                         toString(result.layerName), w, h, format,
                                         result.transformHint, flags);
    }
}
return err;

}

1.5 Client::createSurface
这里就是构造一个LayerCreationArgs对象把参数封装一下,然后调用SurfaceFlinger的createLayer创建窗口。之前在简述里提到过,每个窗口在SurfaceFlinger里面对应的就是一个layer。

binder::Status Client::createSurface(const std::string& name, int32_t flags,
                                 const sp<IBinder>& parent, const gui::LayerMetadata& metadata,
                                 gui::CreateSurfaceResult* outResult) {
    sp<IBinder> handle;
    // 封装参数
    LayerCreationArgs args(mFlinger.get(), sp<Client>::fromExisting(this), name.c_str(),
                        static_cast<uint32_t>(flags), std::move(metadata));
    args.parentHandle = parent;
    // 调用createLayer创建窗口,详细查看2.1
    const status_t status = mFlinger->createLayer(args, *outResult);
    return binderStatusFromStatusT(status);
}

SurfaceFlinger创建layer

2.1 SurfaceFlinger::createLayer
通过createBufferStateLayer构造layer对象
关联父layer节点
然后调用addClientLayer做layer的添加

status_t SurfaceFlinger::createLayer(LayerCreationArgs& args,             gui::CreateSurfaceResult& outResult) {
    status_t result = NO_ERROR;

    sp<Layer> layer;

    switch (args.flags & ISurfaceComposerClient::eFXSurfaceMask) {
        case ISurfaceComposerClient::eFXSurfaceBufferQueue:
        case ISurfaceComposerClient::eFXSurfaceContainer:
        case ISurfaceComposerClient::eFXSurfaceBufferState:
            args.flags |= ISurfaceComposerClient::eNoColorFill;
            FMT_FALLTHROUGH;
        case ISurfaceComposerClient::eFXSurfaceEffect: {
            // 构造layer对象,详见2.1.1
            result = createBufferStateLayer(args, &outResult.handle, &layer);
            std::atomic<int32_t>* pendingBufferCounter = layer->getPendingBufferCounter();
            if (pendingBufferCounter) {
                std::string counterName = layer->getPendingBufferCounterName();
                mBufferCountTracker.add(outResult.handle->localBinder(), counterName,
                                        pendingBufferCounter);
            }
        } break;
        default:
            result = BAD_VALUE;
            break;
    }

    if (result != NO_ERROR) {
        return result;
    }

    args.addToRoot = args.addToRoot && callingThreadHasUnscopedSurfaceFlingerAccess();
    // 根据入参关联父layer
    sp<Layer> parent = LayerHandle::getLayer(args.parentHandle.promote());
    if (args.parentHandle != nullptr && parent == nullptr) {
        ALOGE("Invalid parent handle %p", args.parentHandle.promote().get());
        args.addToRoot = false;
    }

    uint32_t outTransformHint;
    // 添加layer,详见2.2
    result = addClientLayer(args, outResult.handle, layer, parent, &outTransformHint);
    if (result != NO_ERROR) {
        return result;
    }

    outResult.transformHint = static_cast<int32_t>(outTransformHint);
    outResult.layerId = layer->sequence;
    outResult.layerName = String16(layer->getDebugName());
    return result;
}

2.1.1 createBufferStateLayer
通过getNewTexture获取一个纹理索引,opengl渲染用的,后面在合成的章节我们再详细介绍
工厂模式构建layer,这里实际调用的是DefaultFactory构建layer,其实里面就是调用了sp::make(args)直接构造了layer对象。layer构造方法里主要是大量的变量初始化,以及构造一个layerFE对象,这些是和合成相关的逻辑我们会在合成的章节再介绍。

status_t SurfaceFlinger::createBufferStateLayer(LayerCreationArgs& args, sp<IBinder>* handle,
                                            sp<Layer>* outLayer) {
    // 获取一个纹理索引,opengl渲染需要
    args.textureName = getNewTexture();
    // 构造layer对象
    *outLayer = getFactory().createBufferStateLayer(args);
    // 这里是关联layer的binder对象,回传给client侧的。
    *handle = (*outLayer)->getHandle();
    return NO_ERROR;
}

2.2 addClientLayer
首先判断一下layer是否超过上限,如果超过上限就打印一些日志用于排查问题
然后将需要添加的layer存储到mCreatedLayers里,同时将args构造成RequestedLayerState添加到mNewLayers。实际上这两者只有一个会被用到,具体使用哪个会由一个属性控制,感觉像是版本遗留产物,且这两个容器都是临时存储的中间容器,会在下一个Vsync信号来的时候进行真正的处理。
setTransactionFlags标记需要更新layer,且会在里面注册下一个Vsync信号。

status_t SurfaceFlinger::addClientLayer(LayerCreationArgs& args, const sp<IBinder>& handle,
                                    const sp<Layer>& layer, const wp<Layer>& parent,
                                    uint32_t* outTransformHint) {
    if (mNumLayers >= MAX_LAYERS) {
        // 。。。
        // 如果当前layer数量超过上限,这里主要做一些错误日志的打印,以便排除是否有页面泄漏
        return NO_MEMORY;
    }

    layer->updateTransformHint(mActiveDisplayTransformHint);
    if (outTransformHint) {
        *outTransformHint = mActiveDisplayTransformHint;
    }
    // 如果有父layer或者镜像layer,也封装到args参数里
    args.parentId = LayerHandle::getLayerId(args.parentHandle.promote());
    args.layerIdToMirror = LayerHandle::getLayerId(args.mirrorLayerHandle.promote());
    {
        // 这里会把当前的layer添加到mCreatedLayers里面去
        // 并且通过args构造一个RequestedLayerState对象添加到mNewLayers
        // 这两个都是vector,用来临时存储需要添加layer到信息,等到下一个vsync信号SurfaceFlinger才会真的去处理layer的添加。
        std::scoped_lock<std::mutex> lock(mCreatedLayersLock);
        mCreatedLayers.emplace_back(layer, parent, args.addToRoot);
        mNewLayers.emplace_back(std::make_unique<frontend::RequestedLayerState>(args));
        args.mirrorLayerHandle.clear();
        args.parentHandle.clear();
        mNewLayerArgs.emplace_back(std::move(args));
    }
    // 更新标记位表示更新,并且注册下一个Vsync信号,详见2.3
    setTransactionFlags(eTransactionNeeded);
    return NO_ERROR;
}

2.3 setTransactionFlags
更新了 mTransactionFlags标记
通过scheduleCommit注册了下一个Vsync信号

void SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule schedule,
                                     const sp<IBinder>& applyToken, FrameHint frameHint) {
    // Vsync模拟信号参数更新,在Vsync篇章会讲
    mScheduler->modulateVsync({}, &VsyncModulator::setTransactionSchedule, schedule, applyToken);
    // 更新flag
    uint32_t transactionFlags = mTransactionFlags.fetch_or(mask);
    ATRACE_INT("mTransactionFlags", transactionFlags);

    if (const bool scheduled = transactionFlags & mask; !scheduled) {
        // 里面实际调用了mScheduler->scheduleFrame(),注册下一个Vsync
        scheduleCommit(frameHint);
    } else if (frameHint == FrameHint::kActive) {
        mScheduler->resetIdleTimer();
    }
}

到下一个Vsync信号,我们SurfaceFlinger侧的layer就创建完成了。接下去看看app侧构建Surface

app侧构建Surface

3.1 WMS在构建完成SurfaceControl之后会把这个SurfaceControl返回给app,app会用这个SurfaceContorl构建SurfaceFlinger,具体代码位置在ViewRootImpl里面,这里流程我们不细说了,主要聚焦和SurfaceFLinger有关系的地方。
WMS会通过mSurfaceControl返回新建的SurfaceContorl。
这里BLAST是Android 12开始的,主要是Surface下面的消费者生产者模型的区别,以前的模型消费者在app进程,而生产者在SurfaceFlinger进程,而现在都在app进程内。
关于BLAST消费者生产者模型后面会有专门的章节来解释。

private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
        boolean insetsPending) throws RemoteException {
    // 。。。
    // 之前是从这里请求WMS去处理是否需要新增窗口的,SurfaceControl会通过mSurfaceControl返回
    relayoutResult = mWindowSession.relayout(mWindow, params,
                requestedWidth, requestedHeight, viewVisibility,
                insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, mRelayoutSeq,
                mLastSyncSeqId, mTmpFrames, mPendingMergedConfiguration, mSurfaceControl,
                mTempInsets, mTempControls, mRelayoutBundle);
    // 。。。

    if (mSurfaceControl.isValid()) {
        // 构建Surface,新版本Android都是使用BLAST的,会走下面
        if (!useBLAST()) {
            mSurface.copyFrom(mSurfaceControl);
        } else {
            // 构建Blast模型的Surface,详见3.2
            updateBlastSurfaceIfNeeded();
        }
        // 。。。
    }
    // 。。。
}

3.2 updateBlastSurfaceIfNeeded
构建消费者生产者模型,然后通过该对象构建Surface,这里其实可以推断出来,Surface和buffer队列关系紧密,Surface提供一些封装的渲染能力,渲染后的数据会存储到这个buffer队列进行消费。关于这个队列我们会有专门的篇章来介绍。

void updateBlastSurfaceIfNeeded() {
    if (!mSurfaceControl.isValid()) {
        return;
    }

    if (mBlastBufferQueue != null && mBlastBufferQueue.isSameSurfaceControl(mSurfaceControl)) {
        mBlastBufferQueue.update(mSurfaceControl,
            mSurfaceSize.x, mSurfaceSize.y,
            mWindowAttributes.format);
        return;
    }

    if (mBlastBufferQueue != null) {
        mBlastBufferQueue.destroy();
    }
    // 首次走这里,构建消费者生产者队列模型。
    mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl,
            mSurfaceSize.x, mSurfaceSize.y, mWindowAttributes.format);
    mBlastBufferQueue.setTransactionHangCallback(sTransactionHangCallback);
    // 构建Surface
    Surface blastSurface = mBlastBufferQueue.createSurface();
    mSurface.transferFrom(blastSurface);
}

小结

我们通过这边文章主要介绍了app通过WMS是怎么构建了SurfaceContorl,和SurfaceFLinger通信,并且在SufraceFLinger侧构建了一个layer对象。然后app侧通过SurfaceContorl去构建Surface,引出了BlastBufferQueue。

  • 17
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
探索全栈前端技术的魅力:HTML+CSS+JS+JQ+Bootstrap网站源码深度解析 在这个数字化时代,构建一个既美观又功能强大的网站成为了许多开发者和企业追逐的目标。本份资源精心汇集了一套完整网站源码,融合了HTML的骨架搭建、CSS的视觉美化、JavaScript的交互逻辑、jQuery的高效操作以及Bootstrap的响应式设计,全方位揭秘了现代网页开发的精髓。 HTML,作为网页的基础,它构建了信息的框架;CSS则赋予网页生动的外观,让设计创意跃然屏上;JavaScript的加入,使网站拥有了灵动的交互体验;jQuery,作为JavaScript的强力辅助,简化了DOM操作与事件处理,让编码更为高效;而Bootstrap的融入,则确保了网站在不同设备上的完美呈现,响应式设计让访问无界限。 通过这份源码,你将: 学习如何高效组织HTML结构,提升页面加载速度与SEO友好度; 掌握CSS高级技巧,如Flexbox与Grid布局,打造适应各种屏幕的视觉盛宴; 理解JavaScript核心概念,动手实现动画、表单验证等动态效果; 利用jQuery插件快速增强用户体验,实现滑动效果、Ajax请求等; 深入Bootstrap框架,掌握移动优先的开发策略,响应式设计信手拈来。 无论是前端开发新手渴望系统学习,还是资深开发者寻求灵感与实用技巧,这份资源都是不可多得的宝藏。立即深入了解,开启你的全栈前端探索之旅,让每一个网页都成为技术与艺术的完美融合!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值