上一篇文章分析了回调注册监听的调用流程,对于数据的回调正好是注册监听的逆向调用。首先前面提到过在 HWC2On1Adapter 中就会直接转型为每一个回调到上层,这里我们就看一下屏幕热插拔回调(hotplugHook)的调用流程。
一、硬件回调
1、HWC2On1Adapter.cpp
源码位置:/hardware/interfaces/graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp
class HWC2On1Adapter::Callbacks : public hwc_procs_t {
public:
explicit Callbacks(HWC2On1Adapter& adapter) : mAdapter(adapter) {
invalidate = &invalidateHook;
vsync = &vsyncHook;
hotplug = &hotplugHook;
}
……
static void hotplugHook(const hwc_procs_t* procs, int display, int connected) {
auto callbacks = static_cast<const Callbacks*>(procs);
callbacks->mAdapter.hwc1Hotplug(display, connected);
}
private:
HWC2On1Adapter& mAdapter;
};
这是我们传入底层的 Callback,当屏幕出现热插拔时会调用到 hotplugHook() 函数,这里又调用了自身的 hwc1Hotplug() 方法。
hwc1Hotplug
void HWC2On1Adapter::hwc1Hotplug(int hwc1DisplayId, int connected) {
ALOGV("Received hwc1Hotplug(%d, %d)", hwc1DisplayId, connected);
if (hwc1DisplayId != HWC_DISPLAY_EXTERNAL) {
ALOGE("hwc1Hotplug: Received hotplug for non-external display");
return;
}
std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
hwc2_display_t displayId = UINT64_MAX;
if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
if (connected == 0) {
ALOGW("hwc1Hotplug: Received disconnect for unconnected display");
return;
}
// 在connect上创建一个新显示
auto display = std::make_shared<HWC2On1Adapter::Display>(*this, HWC2::DisplayType::Physical);
display->setHwc1Id(HWC_DISPLAY_EXTERNAL);
display->populateConfigs();
displayId = display->getId();
mHwc1DisplayMap[HWC_DISPLAY_EXTERNAL] = displayId;
mDisplays.emplace(displayId, std::move(display));
} else {
if (connected != 0) {
ALOGW("hwc1Hotplug: Received connect for previously connected " "display");
return;
}
// 断开现有显示器
displayId = mHwc1DisplayMap[hwc1DisplayId];
mHwc1DisplayMap.erase(HWC_DISPLAY_EXTERNAL);
mDisplays.erase(displayId);
}
// 如果hwc2端回调还没有被注册,缓冲它直到它被注册
if (mCallbacks.count(Callback::Hotplug) == 0) {
mPendingHotplugs.emplace_back(hwc1DisplayId, connected);
return;
}
const auto& callbackInfo = mCallbacks[Callback::Hotplug];
// 未持有状态锁的情况下回调
lock.unlock();
auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(callbackInfo.pointer);
auto hwc2Connected = (connected == 0) ? HWC2::Connection::Disconnected : HWC2::Connection::Connected;
hotplug(callbackInfo.data, displayId, static_cast<int32_t>(hwc2Connected));
}
如果没有注册热插拔的监听,则会保存到 mPendingHotplugs 集合中,等待回调监听。该回调只处理物理屏幕的逻辑。如果 connect 是 0 且 mHwc1DisplayMap 大于 0 说明有屏幕链接过,现在断开链接了,则从 mHwc1DisplayMap 中销毁对应 id,销毁 mDisplays 对应的屏幕对象对象。如果 connect 为 1,说明有屏幕链接进来了。此时会生成一个 HWC2On1Adapter::Display 对象保存 mDisplays。最后调用了 hotplug() 方法。
2、HalImpl.cpp
源码位置:/hardware/google/graphics/common/hwc3/impl/HalImpl.cpp
void hotplug(hwc2_callback_data_t callbackData, hwc2_display_t hwcDisplay, int32_t connected) {
auto hal = static_cast<HalImpl*>(callbackData);
int64_t display;
h2a::translate(hwcDisplay, display);
hal->getEventCallback()->onHotplug(display, connected == HWC2_CONNECTION_CONNECTED);
}
这里的 hotplug() 方法对应的就是 Hal 层 HwcHal.h 中的 hotplugHook() 方法,对于如何实现的就要使用的 Hook 技术了。对于该技术在前面 PMS 专栏中有过介绍,这里就不重复介绍了。
二、Hal层回调
1、HwcHal.h
源码位置:/hardware/interfaces/graphics/composer/2.1/utils/passthrough/include/composer-passthrough/2.1/HwcHal.h
static void hotplugHook(hwc2_callback_data_t callbackData, hwc2_display_t display, int32_t connected) {
auto hal = static_cast<HwcHalImpl*>(callbackData);
hal->mEventCallback->onHotplug(display, static_cast<IComposerCallback::Connection>(connected));
}
这里的 hotplugHook 方法会回调到前面啊文章提到 HalEventCallback 中的对应方法。
2、ComposerClient.h
源码位置:/hardware/interfaces/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h
HalEventCallback
前面文章提到过,HalEventCallback 是对 IComposerCallback 的进一步封装。
class HalEventCallback : public Hal::EventCallback {
public:
HalEventCallback(Hal* hal, const sp<IComposerCallback> callback, ComposerResources* resources)
: mHal(hal), mCallback(callback), mResources(resources) {}
void onHotplug(Display display, IComposerCallback::Connection connected) {
if (connected == IComposerCallback::Connection::CONNECTED) {
if (mResources->hasDisplay(display)) {
// 这是一个后续的热插拔“连接”显示器。
// 表明显示发生了变化,因此需要重新分配缓冲区。
cleanDisplayResources(display, mResources, mHal);
mResources->removeDisplay(display);
}
mResources->addPhysicalDisplay(display);
} else if (connected == IComposerCallback::Connection::DISCONNECTED) {
mResources->removeDisplay(display);
}
auto ret = mCallback->onHotplug(display, connected);
ALOGE_IF(!ret.isOk(), "failed to send onHotplug: %s", ret.description().c_str());
}
protected:
Hal* const mHal;
const sp<IComposerCallback> mCallback;
ComposerResources* const mResources;
};
这个方法本质上就是为了集中 IComposerCallback 和 mResources 处理。在 HalEventCallback 中对应每一种回调都有自己的方法,他除了会调用 IComposerCallback 对应的回调之外,还会特别处理屏幕的热插拔,如果是插入则将一个屏幕对象(hwc2_display_t)添加到 ComposerResources 中进行管理。
而这里的 Callback 就是上层的 ComposerCallbackBridge,位于 HidlComposerHal.cpp 中。这里我们先来看一下 ComposerResources 管理的 addPhysicalDisplay() 方法。
3、ComposerResources.cpp
源码位置:/hardware/interfaces/graphics/composer/2.1/utils/resources/ComposerResources.cpp
Error ComposerResources::addPhysicalDisplay(Display display) {
auto displayResource = createDisplayResource(ComposerDisplayResource::DisplayType::PHYSICAL, 0);
std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
auto result = mDisplayResources.emplace(display, std::move(displayResource));
return result.second ? Error::NONE : Error::BAD_DISPLAY;
}
这里调用了 createDisplayResource() 方法。
createDisplayResource
std::unique_ptr<ComposerDisplayResource> ComposerResources::createDisplayResource(
ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) {
return std::make_unique<ComposerDisplayResource>(type, mImporter, outputBufferCacheSize);
}
在这个过程中,Composer 会把每一个 hwc2_display_t 最终封装成一个个 ComposerDisplayResource,加入到集合当中。
ComposerHandleCache
ComposerDisplayResource::ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer, uint32_t outputBufferCacheSize)
: mType(type),
mClientTargetCache(importer),
mOutputBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, outputBufferCacheSize),
mMustValidate(true) {}
可以看到,此时就是把 ComposerResources 中的图元申请服务交给 ComposerDisplayResource 持有,让 Display 自己拥有控制图元的能力,同时初始化缓存为 0。当缓存好 ComposerDisplayResource 之后就会继续回调到顶层。
3、HidlComposerHal.cpp
Return<void> onHotplug(Display display, Connection connection) override {
mCallback.onComposerHalHotplug(display, connection);
return Void();
}
private:
ComposerCallback& mCallback;
而这个 Callback 就是 SurfaceFlinger。所以这里调用的是 SurfaceFlinger 中的对应方法。
4、SurfaceFlinger
源码位置:/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
onComposerHalHotplug
void SurfaceFlinger::onComposerHalHotplug(hal::HWDisplayId hwcDisplayId, hal::Connection connection) {
const bool connected = connection == hal::Connection::CONNECTED;
ALOGI("%s HAL display %" PRIu64, connected ? "Connecting" : "Disconnecting", hwcDisplayId);
// 只有不在主线程时才锁。
// 这个函数通常是在hwbinder线程中调用的,但是对于主显示,它是在已经持有状态锁的主线程中调用的,所以不要试图在这里获取它。
ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
// 将接收到的热插拔事件添加到mPendingHotplugEvents队列中
mPendingHotplugEvents.emplace_back(HotplugEvent{hwcDisplayId, connection});
if (std::this_thread::get_id() == mMainThreadId) {
// 如果我们在主线程上,立即处理所有挂起的热插拔事件。
processDisplayHotplugEventsLocked();
}
// 标记需要进行一次显示相关的事务处理
setTransactionFlags(eDisplayTransactionNeeded);
}
该函数响应外部硬件事件(如显示器连接或断开),并高效、安全地安排这些事件的处理逻辑,确保了系统UI的实时性和一致性。此时终于来到了前面文章中解析的 SurfaceFlinger 层中屏幕的初始化流程中。
总结
- Composer 其实最重要的行为就是 createClient,创建一个 ComposerClient。
- ComposerClient 会持有 HwcHalImpl,该类因为持有 hw2_device_t,所以拥有了和硬件通信的能力。ComposerResource 中持有 ComposerInputHandler 这个对象负责图元服务的控制。ComposerCommandEngine 则是处理一些来自上层的命令。
- HWC2On1Adapter 则是为了适配 hw_device_t 和版本 2 之间的区别,同时注册一个监听到驱动中。
- 对于回调来讲,分为两部分,当 registerCallback 的时候会消耗从底层回调上来。另一部分则是从底层直接拿到对应的 HwcHalImpl 的 hook 函数向上回调。