1 前言

上一篇文章中我们已经创建了一个Native示例应用,从使用者的角度了解了图形显示系统API的基本使用,从这篇文章开始我们将基于这个示例应用深入图形显示系统API的内部实现逻辑,分析运作流程。

本篇将聚焦应用和SurfaceFlinger的活动,即应用是如何与SurfaceFlinger这个服务建立连接并进行通信的。让我们开始吧!

注:本篇涉及的代码位置:

/frameworks/native/libs/gui/

/frameworks/native/libs/gui/include/gui/

/frameworks/native/libs/gui/include/private/gui/

/frameworks/native/services/surfaceflinger/


2 应用和SurfaceFlinger的通信

应用运行一开始便首先要去创建一个Native Surface,此时即开始了与SurfaceFlinger的互动,分步来看创建Surface的过程:

  • SurfaceFlinger系统服务的Binder RPC架构

在分析详细的代码前,我想先展示一下 SurfaceFlinger系统服务的Binder RPC架构,其中涉及哪些类?哪些接口?它们之间的关系如何?在宏观上去对这些对象的关系做了解,有助于我们理解具体的代码分析。

先看一张基本的类图:

SurfaceFlinger作为典型的Binder系统服务,遵循Binder服务设计的一般原则:

Interface接口:ISurfaceComposer 、ISurfaceComposerClient

Bp客户端:BpSurfaceComposer、BpSurfaceComposerClient

Bn服务端:BnSurfaceComposer、BnSurfaceComposerClient

服务实现:SurfaceFlinger、Client

具体Binder的原理在此就不展开讲了,相信你在网络上可以搜索到很多优秀的讲解文章。


这里请先留意两点:

  1. ComposerService中有成员mComposerService,它代表了SurfaceFlinger服务的代理客户端;
  2. SurfaceComposerClient中有成员mClient,它代表了SurfaceFlinger服务进程中的Client的代理客户端(这里应该是涉及所谓的匿名Binder的概念)

推荐两篇博文:https://blog.csdn.net/lewif/article/details/50696510

https://my.oschina.net/u/3897543/blog/4750360


  • 创建SurfaceComposerClient并建立与SurfaceFlinger的连接

应用首先去创建SurfaceComposerClient对象,透过这个对象建立和SurfaceFlinger的连接并进行后续的互动:

sp<SurfaceComposerClient> surfaceComposerClient = new SurfaceComposerClient;
status_t err = surfaceComposerClient->initCheck();
if (err != NO_ERROR) {
ALOGD("SurfaceComposerClient::initCheck error: %#x\n", err);
return;
}

SurfaceComposerClient 的定义非常简单,继承RefBase,其中成员mClient持有远程服务的代理客户端,基本操作都是以它作为桥梁传递到SurfaceFlinger的,如下:

// /frameworks/native/libs/gui/include/gui/SurfaceComposerClient.h
class SurfaceComposerClient : public RefBase
{
public:
SurfaceComposerClient();
SurfaceComposerClient(const sp<ISurfaceComposerClient>& client);
virtual ~SurfaceComposerClient();
......
private:
sp<ISurfaceComposerClient> mClient;
}

SurfaceComposerClient 的构造函数也十分简单,进行mStatus的初始化,其中mClient也可以外部传递进来初始值,或在onFirstRef的时候进行设置:

// /frameworks/native/libs/gui/SurfaceComposerClient.cpp
SurfaceComposerClient::SurfaceComposerClient()
: mStatus(NO_INIT)
{
} SurfaceComposerClient::SurfaceComposerClient(const sp<ISurfaceComposerClient>& client)
: mStatus(NO_ERROR), mClient(client)
{
}

对象第一次引用onFirstRef的时候,才真正的去建立和SurfaceFlinger的连接:

// /frameworks/native/libs/gui/SurfaceComposerClient.cpp
void SurfaceComposerClient::onFirstRef() {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
if (sf != nullptr && mStatus == NO_INIT) {
sp<ISurfaceComposerClient> conn;
conn = sf->createConnection();
if (conn != nullptr) {
mClient = conn;
mStatus = NO_ERROR;
}
}
}

先看一下ComposerService的定义,这是一个Singleton,它持有SurfaceFlinger服务的代理客户端:sp<ISurfaceComposer> mComposerService

// /frameworks/native/libs/gui/include/private/gui/ComposerService.h
// This holds our connection to the composer service (i.e. SurfaceFlinger). class ComposerService : public Singleton<ComposerService>
{
sp<ISurfaceComposer> mComposerService; // composer service的代理端
sp<IBinder::DeathRecipient> mDeathObserver;
Mutex mLock; ComposerService();
bool connectLocked();
void composerServiceDied();
friend class Singleton<ComposerService>;
public:
// Get a connection to the Composer Service. This will block until
// a connection is established. Returns null if permission is denied.
static sp<ISurfaceComposer> getComposerService();
};

ComposerService在构建时,调用connectLocked获取SurfaceFlinger(composer service)服务的代理客户端:

//  /frameworks/native/libs/gui/SurfaceComposerClient.cpp

// ComposerService的构造函数,调用到connectLocked去创建和SurfaceFlinger的连接
ComposerService::ComposerService()
: Singleton<ComposerService>() {
Mutex::Autolock _l(mLock);
connectLocked();
} bool ComposerService::connectLocked() {
const String16 name("SurfaceFlinger");
mComposerService = waitForService<ISurfaceComposer>(name); // 通过ServiceManager去获取SurfaceFlinger这个系统服务
if (mComposerService == nullptr) {
return false; // fatal error or permission problem
} // Create the death listener.
class DeathObserver : public IBinder::DeathRecipient {
ComposerService& mComposerService;
virtual void binderDied(const wp<IBinder>& who) {
ALOGW("ComposerService remote (surfaceflinger) died [%p]",
who.unsafe_get());
mComposerService.composerServiceDied();
}
public:
explicit DeathObserver(ComposerService& mgr) : mComposerService(mgr) { }
}; mDeathObserver = new DeathObserver(*const_cast<ComposerService*>(this));
IInterface::asBinder(mComposerService)->linkToDeath(mDeathObserver);
return true;
}

上面connectLocked方法可以看到调用waitForService去向ServiceManager请求名称为SurfaceFlinger的系统服务,成功后就取得了SurfaceFlinger这个系统服务的远程代理客户端,之后就可以透过这个代理跨进程与SurfaceFlinger进行互动了。

DeathObserver是一个监听器,用于监听远程服务的状态,当远程服务异常退出Died,触发该监听器,进而呼叫到mComposerService.composerServiceDied()做一些清理保护

void ComposerService::composerServiceDied()
{
Mutex::Autolock _l(mLock);
mComposerService = nullptr;
mDeathObserver = nullptr;
}

再回到SurfaceComposerClient::onFirstRef方法中,透过ComposerService::getComposerService()获取到SurfaceFlinger服务的代理客户端后,接下来就是去初始化mClient了

// /frameworks/native/libs/gui/SurfaceComposerClient.cpp

sp<ISurfaceComposerClient> conn;
conn = sf->createConnection();
if (conn != nullptr) {
mClient = conn;
mStatus = NO_ERROR;
}

进而调用到了

// /frameworks/native/libs/gui/include/gui/ISurfaceComposer.h

/*
* Create a connection with SurfaceFlinger.
*/
virtual sp<ISurfaceComposerClient> createConnection() = 0;

createConnection是一个典型的Binder C/S架构下的跨进程调用,傻瓜式的理解调用流程:

// 客户端端发送信息
BpSurfaceComposer::createConnection() {
remote()->transact(BnSurfaceComposer::CREATE_CONNECTION, data, &reply);
return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
} ==> // 服务端接收到信息
status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
uint32_t flags) {
status_t credentialCheck = CheckTransactCodeCredentials(code);
if (credentialCheck != OK) {
return credentialCheck;
} status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags); .... } BnSurfaceComposer::onTransact() {
case CREATE_CONNECTION: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> b = IInterface::asBinder(createConnection());
reply->writeStrongBinder(b);
return NO_ERROR;
}
} ==> // 服务具体实现
sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() {
const sp<Client> client = new Client(this);
return client->initCheck() == NO_ERROR ? client : nullptr;
}

SurfaceFlinger::createConnection方法中创建一个Client对象,Client继承自BnSurfaceComposerClient实现ISurfaceComposerClient接口,可以利用Binder机制传递回客户端。而且Client对象中含有SurfaceFlinger成员,这样SurfaceComposerClient::mClient就和SurfaceFlinger建立了连接。


Tips:

SurfaceFlinger进程中创建的Client对象,透过Binder IPC机制返回到了应用进程中,这里的具体原理感兴趣的可以研究下IInterface::asBinder /  writeStrongBinder / readStrongBinder / interface_cast 这些方法。这里我们就傻瓜式的理解为SurfaceComposerClient::mClient是SurfaceFlinger进程中Client对象的代理客户端,使用SurfaceComposerClient::mClient就可以呼叫到SurfaceFlinger进程中Client对象的方法。


前面的讲解看起来纷纷扰扰,简单的,抽象的概括就是:

  1. 创建SurfaceComposerClient对象;
  2. SurfaceComposerClient::onFirstRef方法中透过ComposerService::getComposerService()获取到SurfaceFlinger服务的代理客户端;
  3. 调用SurfaceFlinger服务的代理客户端的createConnection方法,进而跨进程调用到SurfaceFlinger::createConnection方法;
  4. SurfaceFlinger::createConnection方法中创建一个Client对象,并透过Binder返回给SurfaceComposerClient::mClient;

之后再调用SurfaceComposerClient中的方法时就可以通过mClient这个客户端去呼叫到SurfaceFlinger服务的功能了

结合上面的类图和下面的时序图,大概总结如下


3 小结

这一篇文章中讲解了应用进程中如何建立和SurfaceFlinger沟通的桥梁,即得到SurfaceFlinger的远程代理客户端,之后就通过这个代理客户端向SurfaceFlinger发送请求或获取信息。


必读:

Android 12(S) 图形显示系统 - 开篇


Android 12(S) 图形显示系统 - 应用建立和SurfaceFlinger的沟通桥梁(三)的更多相关文章

  1. Android 12(S) 图形显示系统 - 简单聊聊 SurfaceView 与 BufferQueue的关联(十三)

    必读: Android 12(S) 图形显示系统 - 开篇 一.前言 前面的文章中,讲解的内容基本都是从我们提供的一个 native demo Android 12(S) 图形显示系统 - 示例应用( ...

  2. Android 12(S) 图形显示系统 - 示例应用(二)

    1 前言 为了更深刻的理解Android图形系统抽象的概念和BufferQueue的工作机制,这篇文章我们将从Native Level入手,基于Android图形系统API写作一个简单的图形处理小程序 ...

  3. Android 12(S) 图形显示系统 - createSurface的流程(五)

    题外话 刚刚开始着笔写作这篇文章时,正好看电视在采访一位92岁的考古学家,在他的日记中有这样一句话,写在这里与君共勉"不要等待幸运的降临,要去努力的掌握知识".如此朴实的一句话,此 ...

  4. Android 12(S) 图形显示系统 - BufferQueue/BLASTBufferQueue之初识(六)

    题外话 你有没有听见,心里有一声咆哮,那一声咆哮,它好像在说:我就是要从后面追上去! 写文章真的好痛苦,特别是自己对这方面的知识也一知半解就更加痛苦了.这已经是这个系列的第六篇了,很多次都想放弃了,但 ...

  5. Android 12(S) 图形显示系统 - 初识ANativeWindow/Surface/SurfaceControl(七)

    题外话 "行百里者半九十",是说步行一百里路,走过九十里,只能算是走了一半.因为步行越接近目的地,走起来越困难.借指凡事到了接近成功,往往是最吃力.最艰难的时段.劝人做事贵在坚持, ...

  6. Android 12(S) 图形显示系统 - BufferQueue的工作流程(九)

    题外话 Covid-19疫情的强烈反弹,小区里检测出了无症状感染者.小区封闭管理,我也不得不居家办公了.既然这么大把的时间可以光明正大的宅家里,自然要好好利用,八个字 == 努力工作,好好学习 一.前 ...

  7. Android 12(S) 图形显示系统 - 解读Gralloc架构及GraphicBuffer创建/传递/释放(十四)

    必读: Android 12(S) 图形显示系统 - 开篇 一.前言 在前面的文章中,已经出现过 GraphicBuffer 的身影,GraphicBuffer 是Android图形显示系统中的一个重 ...

  8. Android 12(S) 图形显示系统 - 基本概念(一)

    1 前言 Android图形系统是系统框架中一个非常重要的子系统,与其它子系统一样,Android 框架提供了各种用于 2D 和 3D 图形渲染的 API供开发者使用来创建绚丽多彩的应用APP.图形渲 ...

  9. Android 12(S) 图形显示系统 - SurfaceFlinger的启动和消息队列处理机制(四)

    1 前言 SurfaceFlinger作为Android图形显示系统处理逻辑的核心单元,我们有必要去了解其是如何启动,初始化及进行消息处理的.这篇文章我们就来简单分析SurfaceFlinger这个B ...

随机推荐

  1. CentOS系统 python3+python2 & Ipython安装

    https://www.cnblogs.com/albertrui/p/8093384.html 一.安装依赖环境 输入命令: yum -y install zlib-devel bzip2-deve ...

  2. 【LeetCode】716. Max Stack 解题报告(C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 双栈 日期 题目地址:https://leetcode ...

  3. 【九度OJ】题目1028:继续畅通工程 解题报告

    [九度OJ]题目1028:继续畅通工程 解题报告 标签(空格分隔): 九度OJ 原题地址:http://ac.jobdu.com/problem.php?pid=1028 题目描述: 省政府" ...

  4. vue 核心加解密工具类 方法

    1 /* base64 加解密 2 */ 3 export let Base64 = require('js-base64').Base64 4 5 /* md5 加解密 6 */ 7 export ...

  5. python xlrd读Excel表

    1 xlrd第三方库 注意:xlrd较新版本不支持读xlsx表,需安装1.2.0版本(pip install xlrd==1.2.0)或使用其他库. xlrd库官方文档:https://xlrd.re ...

  6. Windows下安装配置MySQL

    Windows下安装配置MySQL的基本步骤 一.MySQL下载 MySQL官方下载地址https://dev.mysql.com/downloads/mysql/5.7.html#downloads ...

  7. JavaScript交互式网页设计 • 【第1章 JavaScript 基本语法】

    全部章节   >>>> 本章目录 1.1 JavaScript 概述 1.1.1 JavaScript 简介 1.1.2 JavaScript 的概念和执行原理 1.1.3 J ...

  8. 编写Java程序,使用Set实现不重复添加用户

    返回本章节 返回作业目录 需求说明: 在控制台输入用户信息,用户信息包括姓名.性别和年龄,将用户信息保存至User对象中. 将User对象保存至HashSet集合中. 规定如果两个User对象的姓名. ...

  9. Kafka基础教程(四):.net core集成使用Kafka消息队列

    .net core使用Kafka可以像上一篇介绍的封装那样使用(Kafka基础教程(三):C#使用Kafka消息队列),但是我还是觉得再做一层封装比较好,同时还能使用它做一个日志收集的功能. 因为代码 ...

  10. java运算符2

    续: 位运算符(<<,>>,>>>) 1.<<: 3<<2,二进制左移2位,右边用0补齐       3的二进制:00000000 0 ...