Android 7.1 GUI系统-surfaceflinger(四)

2023-11-10

surfaceflinger的启动:

Android P 图形显示系统 https://www.jianshu.com/u/f92447ae8445

Android GUI系统之SurfaceFlinger https://blog.csdn.net/vviccc/article/details/104860616

frameworks/native/services/surfaceflinger/surfaceflinger.rc
service surfaceflinger /system/bin/surfaceflinger
    class core
    user system
    group graphics drmrpc readproc
    onrestart restart zygote
    writepid /dev/stune/foreground/tasks

 

 

 

surfaceflinger属于系统的底层支撑服务,应该在系统开机的早期就要起来,比如开机动画的绘制就要依赖surfaceflinger,从它的rc文件可知,这个服务的class是core,所以在解析init.rc时,通过class_startcore就启动了所有class是core的服务。而且在surfaceflinger重启时,关键进程zygote也会重启。

插播截取的一段init.rc的代码看下究竟:

system/core/rootdir/init.rc
//长按power键,Healthd会通过发一个property信号触发一个full boot,也即是当属性sys.boot_from_charger_mode满足了值为1时就会触发,接着会触发late-init 这个action。
on property:sys.boot_from_charger_mode=1
	class_stop charger
	trigger late-init

//late-init这个action,主要是挂载文件系统,然后触发boot。
on late-init
	trigger early-fs
	trigger fs
	trigger late-fs
	trigger boot

//在boot事件中,基础网络初始话,基本的kernel参数,系统服务和后台进程的权限设置等,最后启动class类型是core的系统服务。
on boot
	hostname localhost
	write /proc/sys/vm/overcommit_memory 1
	chmod 0664 /sys/module/lowmemorykiller/parameters/adj
	chown system system /sys/power/state
	class_start core

 

接着分析surfaceflinger的启动。

 

main_surfaceflinger.cpp

 

int main(int, char**)@main_surfaceflinger.cpp {
//下面这三行代码是一个独立的进程起来时,必须调用的,其中ps->startThreadPool()会间接调用到IPCThreadState::self()->joinThreadPool(mIsMain);最终让这个进程进入一个binder_loop的循环。
	ProcessState::self()->setThreadPoolMaxThreadCount(4);
	sp<ProcessState> ps(ProcessState::self());
	ps->startThreadPool();
//实例化一个surfaceflinger,就是new SurfaceFlinger();
	sp<SurfaceFlinger> flinger = DisplayUtils::getInstance()→getSFInstance();
//设置进程优先级,PRIORITY_URGENT_DISPLAY这是级别还是很高的。
	setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);
//在client发起连接之前执行初始化。
	flinger→init();
//把surfaceflinger,GpuService注册到ServiceManager。
	sp<IServiceManager> sm(defaultServiceManager());
	sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);
	sp<GpuService> gpuservice = new GpuService();
	sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);
//运行surfaceflinger,等待client的请求。
	flinger->run();
	return 0;
}

 

 

 

SurfaceFlinger的构造函数中没有做太多事情,只是给变量赋了初始值,在它第一次被引用时会执行其onFirstRef函数。

 

void SurfaceFlinger::onFirstRef()@SurfaceFlinger.cpp{
//初始化事件队列MessageQueue,
    mEventQueue.init(this);
}

 

 

 

//这个MessageQueue.cpp是surfaceflinger自定义的,是消息循环处理机制的管理者,但是并不是系统标准的消息队列。

void MessageQueue::init(const sp<SurfaceFlinger>& flinger)@MessageQueue.cpp{
    mFlinger = flinger;
//Looper是系统中通用的实现,system/core/libutils/looper.cpp
    mLooper = new Looper(true);
//Handler也是surfaceflinger自定义的一个事件处理器,是MessageQueue.h的内部类,并不是通用的Handler。
    mHandler = new Handler(*this);
}

 

//surfaceflinger的初始化,包括egl的运行环境的设置,跟vsync脉冲信号有关的EventThread等。这块内容不在这里做展开。

 

 

void SurfaceFlinger::init() @SurfaceFlinger.cpp{
	mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
	eglInitialize(mEGLDisplay, NULL, NULL);
	sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
		vsyncPhaseOffsetNs, true, "app");
	mEventThread = new EventThread(vsyncSrc, *this);
	mHwc = new HWComposer(this);
	mHwc->setEventHandler(static_cast<HWComposer::EventHandler*>(this));
	mEventControlThread = new EventControlThread(this);
	mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
	initializeDisplays();
}

 

 

 

接下来分析surfaceflinger的工作线程是怎么运行起来的。

void SurfaceFlinger::run() @SurfaceFlinger.cpp{
//可以看到这里是一个无线循环。
    do {
        waitForEvent();
    } while (true);
}

 

//进一步调用MessageQueue中的waitMessage。

 

void SurfaceFlinger::waitForEvent() @SurfaceFlinger.cpp{
    mEventQueue.waitMessage();
}

 

//这里依然是死循环,永远不会跳出,即使发生了错误,这也可以理解,surfaceflinger是整个GUI系统的核心,如果它退出了,基本系统也就瘫了。

 

void MessageQueue::waitMessage() @MessageQueue.cpp{
    do {
        IPCThreadState::self()->flushCommands();
        int32_t ret = mLooper->pollOnce(-1);
        switch (ret) {
            case Looper::POLL_WAKE:
            case Looper::POLL_CALLBACK:
                continue;
            case Looper::POLL_ERROR:
                ALOGE("Looper::POLL_ERROR");
                continue;
            case Looper::POLL_TIMEOUT:
                // timeout (should not happen)
                continue;
            default:
                // should not happen
                ALOGE("Looper::pollOnce() returned unknown status %d", ret);
                continue;
        }
    } while (true);
}

 

在上面的循环中,会通过mLooper->pollOnce(-1);不断的读取消息进行处理。前面说过这里的MessageQueue并不是android系统通用的消息队列,它是消息循环处理机制的管理者,在它的init函数中也看到,内部包含了looper和hander,Looper中的mMessageEnvelopes才是真正存储消息的地方,而这个handle也只是一个中介,并没有实际去处理发给surfaceflinger的消息请求,而是进一步回调了surfaceflinger的onMessageReceived方法。

 

void MessageQueue::Handler::handleMessage(const Message& message) @MessageQueue.cpp{
    switch (message.what) {
        case INVALIDATE:
            android_atomic_and(~eventMaskInvalidate, &mEventMask);
            mQueue.mFlinger->onMessageReceived(message.what);
            break;
        case REFRESH:
            android_atomic_and(~eventMaskRefresh, &mEventMask);
            mQueue.mFlinger->onMessageReceived(message.what);
            break;
    }
}

 

通过上面的分析,知道surfaceflinger的消息处理框架是通过MessageQueue把消息请求发送到Looper的mMessageEnvelopes队列,然后通过mLooper->pollOnce(-1);方法依次取出事件处理,其中的handle会把INVALIDATE,REFRESH这两类消息请求转给surfaceflinger做实质的处理。

 

 

应用程序向surfaceflinger发送的消息请求分同步、异步两种,异步推送就是消息发过去就直接返回了,不需要等待执行结果。接下来主要看下同步的请求是怎么处理的?

以前面的应用程序申请创建一个layer为例:

status_t Client::createSurface()@Client.cpp{
	 class MessageCreateLayer : public MessageBase {
		virtual bool handler() {
			result = flinger->createLayer(name, client, w, h, format, flags,
				handle, gbp);
			return true;
		}
	}
	sp<MessageBase> msg = new MessageCreateLayer(mFlinger.get(),…);
	mFlinger->postMessageSync(msg);
}

 

省略了很多代码,只关注消息处理相关的,这里通过postMessageSync发出一个同步消息,

status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
        nsecs_t reltime, uint32_t /* flags */) @SurfaceFlinger.cpp{
    status_t res = mEventQueue.postMessage(msg, reltime);
    if (res == NO_ERROR) {
        msg->wait();
    }
    return res;
}

 

在上面的函数中,除了调用mEventQueue.postMessage把消息入队外,还调用了msg->wait();这个wait从字面意思也能看出是让调用者线程挂起了。

 

//下面的MessageQueue依然是surfaceflinger自定义的类。

 

MessageQueue.h
class MessageBase : public MessageHandler{
	void wait() const { barrier.wait(); }
}

 

 

 

这里是使用barrier来实现的同步,这个barrier只在surfaceflinger中有使用,应该说是专门为surfaceflinger设计的,所以有必要去了解下它的实现原理:

frameworks/native/services/surfaceflinger/Barrier.h
class Barrier
{
public:
    inline Barrier() : state(CLOSED) { }
    inline ~Barrier() { }
//释放等待在这个barrier上的线程。
    void open() {
        Mutex::Autolock _l(lock);
        state = OPENED;
        cv.broadcast();
    }
//重新设置barrier,wait方法会被block,直到open方法被调用。
    void close() {
        Mutex::Autolock _l(lock);
        state = CLOSED;
    }
//这里会一直等待,直到barrier的状态是OPEN。
    void wait() const {
        Mutex::Autolock _l(lock);
        while (state == CLOSED) {
            cv.wait(lock);
        }
    }
private:
    enum { OPENED, CLOSED };
    mutable     Mutex       lock;
    mutable     Condition   cv;
    volatile    int         state;
};

 

 

可以看到barrier是基于Mutex和condition实现的一个模型。Mutex实际上是基于pthread接口的在封装,只要是涉及到对某个共享资源的访问,都可以认为是Mutex的问题领域;但是有时候对某一个共享资源的访问的目的,只是想判断它是不是满足了某个条件,比如state==CLOSED,并且什么时候满足这一条件是未知的,这种情况下,如果依然用Mutex来处理,就要一直去轮询,这显然是太浪费cpu资源了,所以才有了condition,但是condition本身并不完整,比如它没有指定具体的条件是什么,所以它需要被填充了具体条件才能真正的使用,这里的barrier就是一个填充了具体条件的condition,这里的具体条件就是state == CLOSED或者state == OPEN。

 

 

 

介绍完了Barrier的实现原理,再来看下它是怎么使用的,postMessageSync时调用了barrier.wait()把调用者线程挂起,那什么时候把它唤醒呢?一种可能的情况就是这个消息请求被处理了,就应该把调用者唤醒,让他继续执行未完成的工作。

所以要从消息处理的接口入手:

前面分析过,在MessageQueue的waitMessage中,是通过mLooper->pollOnce(-1);不断的读取消息进行处理的。

 

system/core/libutils/Looper.cpp
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) @Looper.cpp{
	result = pollInner(timeoutMillis);
}

 

//从pollInner看出,它调用了message的handle中的方法handleMessage。

 

 

int Looper::pollInner(int timeoutMillis) {
	const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0);
	sp<MessageHandler> handler = messageEnvelope.handler;
	handler->handleMessage(message);
}

 

 

 

所以要看发送的那条消息中的handler是哪里来的?

MessageCreateLayer继承自MessageBase(MessageQueue.cpp中),

MessageQueue.cpp
void MessageBase::handleMessage(const Message&) {
    this->handler();
    barrier.open();
};

 

由于MessageBase的handler的方法是纯虚函数,所以这里调用的handle是子类的handler的方法,也即是MessageCreateLayer中的handler方法,这个方法会调用surfaceflinger来完成请求。

 

然后调用了barrier.open();唤醒被等待的线程。

 

分析了surfaceflinger的消息处理机制,再来看应用程序端是如何跟surfaceflinger通信的。

前面在分析BufferQueue时,引用过GLTest::SetUp()中一段代码,其中创建了SurfaceComposerClient实例,可以作为应用程序跟surfaceflinger通信的一个桥梁。

 

SurfaceComposerClient.cpp
void SurfaceComposerClient::onFirstRef() {
    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
    if (sm != 0) {
        sp<ISurfaceComposerClient> conn = sm->createConnection();
        if (conn != 0) {
            mClient = conn;
            mStatus = NO_ERROR;
        }
    }
}

 

 

 

上面的实现中,首先获取surfaceflinger的句柄ISurfaceComposer,这个名字起的容易误解,surfaceflinger虽然注册在ServiceManager中的名字是“surfaceflinger”,但是其服务端实现的binder接口却是ISurfaceComposer,可以从它的继承关系得到验证:

 

class SurfaceFlinger : public BnSurfaceComposer,private Ibinder::DeathRecipient,
	private HWComposer::EventHandler{}

接着SurfaceComposerClient::onFirstRef() 分析,通过surfaceflinger的 createConnection返回一个ISurfaceComposerClient 实例,ISurfaceComposerClient对应的服务端是Client,
sp<ISurfaceComposerClient> SurfaceFlinger::createConnection()
	@SurfaceFlinger.cpp{
    sp<ISurfaceComposerClient> bclient;
    sp<Client> client(new Client(this));
    status_t err = client->initCheck();
    if (err == NO_ERROR) {
        bclient = client;
    }
    return bclient;
}

 

 

 

这个Client才是surfaceflinger跟应用程序交互的纽带,比如应用程序申请surface的请求就是经过client传递到surfaceFlinger,可以任务client是surfaceflinger安排在应用程序中一个代理,任何有UI界面的应用程序在surfaceflinger中都有对应的Client实例,但是应用程序并没有直接使用Client,而是通过ISurfaceComposerClient,ISurfaceComposerClient是应用程序与Client之间的binder接口,所以应用程序端一个请求先是通过ISurfaceComposerClient,然后传到Client,client收到者请求后,没有让surfaceflinger马上执行,而是把让先投递到surfaceflinger的消息队列,然后让client所在的线程wait,因为surfaceflinger会处理所有应用程序的请求,不能来一个请求就就打断surfaceflinger正在执行的操作,最后SurfaceFlinger处理完成后,返回结果,唤醒wait的应用程序。

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android 7.1 GUI系统-surfaceflinger(四) 的相关文章

  • 多个对象以某种方式相互干扰[原始版本]

    我有一个神经网络 NN 当应用于单个数据集时 它可以完美地工作 但是 如果我想在一组数据上运行神经网络 然后创建一个新的神经网络实例以在不同的数据集 甚至再次同一组数据 上运行 那么新实例将产生完全错误的预测 例如 对 XOR 模式进行训练
  • 如何让JComboBox中的内容居中显示?

    目前我有这个JComboBox 我怎样才能将其中的内容居中 String strs new String 15158133110 15158133124 15158133458 JComboBox com new JComboBox str
  • 使用ssl和socket的python客户端身份验证

    我有一个 python 服务器 需要客户端使用证书进行身份验证 我如何制作一个客户端脚本 使用客户端证书由 python 中的服务器使用 ssl 和套接字模块进行身份验证 有没有仅使用套接字和 ssl 而不扭曲的示例 from OpenSS
  • Android Jasper 报告

    Jasper Reporting 可以集成到 Android 应用程序中吗 我正在尝试从 jrxml 文件生成 PDF CSV 文本和 XLS 报告 但是 我没有看到 Android SDK 支持 net sf jasperreports
  • 查找总和为给定数字的值组合的函数

    这个帖子查找提供的 Sum 值的组合 https stackoverflow com a 20194023 1561176呈现函数subsets with sum 它在数组中查找总和等于给定值的值的组合 但由于这个帖子已经有6年多了 我发这
  • Bootstrap 3 / 显示模式不适用于 javascript 方式

    我用Modal http getbootstrap com javascript modalsBootstrap 3 0 的功能 我有这个代码 a href myNestedContent Open the modal containing
  • 在 VS2008 的 XAML 编辑器中禁用 Intellisense?

    有没有办法在 Visual Studio 2008 的 XAML 编辑器中禁用 Intellisense 打字时通常会消耗很大的性能 有时我会等待十秒或更长时间 直到列表自动弹出 似乎在 选项 gt 文本编辑器 gt XAML 中 Inte
  • 查询联系人 - 有时返回空游标

    我正在尝试查询联系人的显示名称 Override public void onActivityResult int requestCode int resultCode Intent data switch requestCode case
  • 在 javascript 中使用 xPath 解析具有默认命名空间的 XML

    我需要创建一个 XML xPath 解析器 所有解析都必须在客户端进行 使用 JavaScript 我创建了一个 javascript 来执行此操作 在默认名称空间发挥作用之前 一切看起来都正常 我根本无法查询具有默认命名空间的 XML 我
  • C++ Boost ASIO 简单的周期性定时器?

    我想要一个非常简单的周期性计时器每 50 毫秒调用我的代码 我可以创建一个始终休眠 50 毫秒的线程 但这很痛苦 我可以开始研究用于制作计时器的 Linux API 但它不可移植 I d like使用升压 我只是不确定这是否可能 boost
  • 在门户中查看 Azure WebJob 计划?

    我创建了一个简单的 Azure WebJob 并通过 Visual Studio 集成制定了每天运行一次的计划 我已经部署了 WebJob 并看到它列在我在 Azure 上的应用程序中 schema http schemastore org
  • Apache Beam Pipeline 写表后查询表

    我有一个 Apache Beam Dataflow 管道 它将结果写入 BigQuery 表 然后我想查询该表以获取管道的单独部分 但是 我似乎无法弄清楚如何正确设置此管道依赖性 我编写的新表 然后想要查询 与一个单独的表连接以进行某些过滤
  • 嵌入式二进制资源 - 如何枚举嵌入的图像文件?

    我按照中的说明进行操作这本书 http www apress com book view 9781430225492 关于资源等的章节 我不太明白的是 如何替换它 images Add new BitmapImage new Uri Ima
  • 以 Rails 形式处理 MongoMapper EmbeddedDocument

    首先 我对一般编程和 Rails 都是新手 我选择 Rails 是因为它看起来是一种很容易上手的语言 对于我的项目 我将 MongoMapper 与 Rails 结合使用 我正在尝试以与文档相同的形式处理嵌入文档 我有以下模型 class
  • 在 for 循环比较中使用集合大小

    Java 中 Collections 的 size 方法是否有编译器优化 考虑以下代码 for int i 0 i
  • 根据列中的部分字符串匹配选择数据框行

    我想根据列中字符串的部分匹配从数据框中选择行 例如列 x 包含字符串 hsa 使用sqldf if它有一个like语法 我会做类似的事情 select from lt gt where x like hsa 很遗憾 sqldf不支持该语法
  • 小于或等于

    使用暂停命令我发现错误位于此代码的第一行 if choice 1 if energy gt m2enc set a enemhp enemhp m1hpd earmr pause set a energy energy m1enc set
  • CLion - 命令行程序参数

    当我分配给 运行 调试配置 程序参数 之类的 aaa bbb 然后打印它时 任何人都可以告诉我 JetBrains CLion 有什么问题吗 printf s n argv 1 我刚刚得到 aaa 而它必须是 aaa bbb 因为它们用双引
  • jQuery:动态添加 DOM 元素时尝试将函数挂钩到 onclick,但它立即执行该函数

    我正在使用 jQuery 动态 我的意思是在运行时 向页面的 DOM 添加一个 span 元素 create add task button document createElement span attr id activityNameH
  • Android Espresso - 如果未选中,请单击复选框

    I have onView withId R id check box perform click 但我只想在尚未选中该复选框时执行此操作 我怎样才能在浓缩咖啡中做到这一点 我还想根据其之前的状态来切换复选框 开关 起初 我尝试用此方法打开

随机推荐