/* * Copyright 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #undef LOG_TAG #define LOG_TAG "HwcComposer" #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "AidlComposerHal.h" #include #include #include #include #include #include #include #include #include #include #include #include "HWC2.h" namespace android { using hardware::hidl_handle; using hardware::hidl_vec; using hardware::Return; using aidl::android::hardware::graphics::composer3::BnComposerCallback; using aidl::android::hardware::graphics::composer3::Capability; using aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness; using aidl::android::hardware::graphics::composer3::PowerMode; using aidl::android::hardware::graphics::composer3::VirtualDisplay; using aidl::android::hardware::graphics::composer3::CommandResultPayload; using AidlColorMode = aidl::android::hardware::graphics::composer3::ColorMode; using AidlContentType = aidl::android::hardware::graphics::composer3::ContentType; using AidlDisplayIdentification = aidl::android::hardware::graphics::composer3::DisplayIdentification; using AidlDisplayContentSample = aidl::android::hardware::graphics::composer3::DisplayContentSample; using AidlDisplayAttribute = aidl::android::hardware::graphics::composer3::DisplayAttribute; using AidlDisplayCapability = aidl::android::hardware::graphics::composer3::DisplayCapability; using AidlHdrCapabilities = aidl::android::hardware::graphics::composer3::HdrCapabilities; using AidlHdrConversionCapability = aidl::android::hardware::graphics::common::HdrConversionCapability; using AidlHdrConversionStrategy = aidl::android::hardware::graphics::common::HdrConversionStrategy; using AidlOverlayProperties = aidl::android::hardware::graphics::composer3::OverlayProperties; using AidlPerFrameMetadata = aidl::android::hardware::graphics::composer3::PerFrameMetadata; using AidlPerFrameMetadataKey = aidl::android::hardware::graphics::composer3::PerFrameMetadataKey; using AidlPerFrameMetadataBlob = aidl::android::hardware::graphics::composer3::PerFrameMetadataBlob; using AidlRenderIntent = aidl::android::hardware::graphics::composer3::RenderIntent; using AidlVsyncPeriodChangeConstraints = aidl::android::hardware::graphics::composer3::VsyncPeriodChangeConstraints; using AidlVsyncPeriodChangeTimeline = aidl::android::hardware::graphics::composer3::VsyncPeriodChangeTimeline; using AidlDisplayContentSamplingAttributes = aidl::android::hardware::graphics::composer3::DisplayContentSamplingAttributes; using AidlFormatColorComponent = aidl::android::hardware::graphics::composer3::FormatColorComponent; using AidlDisplayConnectionType = aidl::android::hardware::graphics::composer3::DisplayConnectionType; using AidlColorTransform = aidl::android::hardware::graphics::common::ColorTransform; using AidlDataspace = aidl::android::hardware::graphics::common::Dataspace; using AidlDisplayHotplugEvent = aidl::android::hardware::graphics::common::DisplayHotplugEvent; using AidlFRect = aidl::android::hardware::graphics::common::FRect; using AidlRect = aidl::android::hardware::graphics::common::Rect; using AidlTransform = aidl::android::hardware::graphics::common::Transform; namespace Hwc2 { namespace { template To translate(From x) { return static_cast(x); } template std::vector translate(const std::vector& in) { std::vector out; out.reserve(in.size()); std::transform(in.begin(), in.end(), std::back_inserter(out), [](From x) { return translate(x); }); return out; } template <> AidlRect translate(IComposerClient::Rect x) { return AidlRect{ .left = x.left, .top = x.top, .right = x.right, .bottom = x.bottom, }; } template <> AidlFRect translate(IComposerClient::FRect x) { return AidlFRect{ .left = x.left, .top = x.top, .right = x.right, .bottom = x.bottom, }; } template <> AidlPerFrameMetadataBlob translate(IComposerClient::PerFrameMetadataBlob x) { AidlPerFrameMetadataBlob blob; blob.key = translate(x.key), std::copy(x.blob.begin(), x.blob.end(), std::inserter(blob.blob, blob.blob.end())); return blob; } template <> AidlPerFrameMetadata translate(IComposerClient::PerFrameMetadata x) { return AidlPerFrameMetadata{ .key = translate(x.key), .value = x.value, }; } template <> DisplayedFrameStats translate(AidlDisplayContentSample x) { return DisplayedFrameStats{ .numFrames = static_cast(x.frameCount), .component_0_sample = translate(x.sampleComponent0), .component_1_sample = translate(x.sampleComponent1), .component_2_sample = translate(x.sampleComponent2), .component_3_sample = translate(x.sampleComponent3), }; } template <> AidlVsyncPeriodChangeConstraints translate(IComposerClient::VsyncPeriodChangeConstraints x) { return AidlVsyncPeriodChangeConstraints{ .desiredTimeNanos = x.desiredTimeNanos, .seamlessRequired = x.seamlessRequired, }; } template <> VsyncPeriodChangeTimeline translate(AidlVsyncPeriodChangeTimeline x) { return VsyncPeriodChangeTimeline{ .newVsyncAppliedTimeNanos = x.newVsyncAppliedTimeNanos, .refreshRequired = x.refreshRequired, .refreshTimeNanos = x.refreshTimeNanos, }; } mat4 makeMat4(std::vector in) { return mat4(static_cast(in.data())); } } // namespace class AidlIComposerCallbackWrapper : public BnComposerCallback { public: AidlIComposerCallbackWrapper(HWC2::ComposerCallback& callback) : mCallback(callback) {} ::ndk::ScopedAStatus onHotplug(int64_t in_display, bool in_connected) override { const auto event = in_connected ? AidlDisplayHotplugEvent::CONNECTED : AidlDisplayHotplugEvent::DISCONNECTED; mCallback.onComposerHalHotplugEvent(translate(in_display), event); return ::ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus onRefresh(int64_t in_display) override { mCallback.onComposerHalRefresh(translate(in_display)); return ::ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus onSeamlessPossible(int64_t in_display) override { mCallback.onComposerHalSeamlessPossible(translate(in_display)); return ::ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus onVsync(int64_t in_display, int64_t in_timestamp, int32_t in_vsyncPeriodNanos) override { mCallback.onComposerHalVsync(translate(in_display), in_timestamp, static_cast(in_vsyncPeriodNanos)); return ::ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus onVsyncPeriodTimingChanged( int64_t in_display, const AidlVsyncPeriodChangeTimeline& in_updatedTimeline) override { mCallback.onComposerHalVsyncPeriodTimingChanged(translate(in_display), translate( in_updatedTimeline)); return ::ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus onVsyncIdle(int64_t in_display) override { mCallback.onComposerHalVsyncIdle(translate(in_display)); return ::ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus onRefreshRateChangedDebug( const RefreshRateChangedDebugData& refreshRateChangedDebugData) override { mCallback.onRefreshRateChangedDebug(refreshRateChangedDebugData); return ::ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus onHotplugEvent(int64_t in_display, AidlDisplayHotplugEvent event) override { mCallback.onComposerHalHotplugEvent(translate(in_display), event); return ::ndk::ScopedAStatus::ok(); } private: HWC2::ComposerCallback& mCallback; }; std::string AidlComposer::instance(const std::string& serviceName) { return std::string(AidlIComposer::descriptor) + "/" + serviceName; } bool AidlComposer::isDeclared(const std::string& serviceName) { return AServiceManager_isDeclared(instance(serviceName).c_str()); } AidlComposer::AidlComposer(const std::string& serviceName) { // This only waits if the service is actually declared mAidlComposer = AidlIComposer::fromBinder( ndk::SpAIBinder(AServiceManager_waitForService(instance(serviceName).c_str()))); if (!mAidlComposer) { LOG_ALWAYS_FATAL("Failed to get AIDL composer service"); return; } if (!mAidlComposer->createClient(&mAidlComposerClient).isOk()) { LOG_ALWAYS_FATAL("Can't create AidlComposerClient, fallback to HIDL"); return; } addReader(translate(kSingleReaderKey)); // If unable to read interface version, then become backwards compatible. const auto status = mAidlComposerClient->getInterfaceVersion(&mComposerInterfaceVersion); if (!status.isOk()) { ALOGE("getInterfaceVersion for AidlComposer constructor failed %s", status.getDescription().c_str()); } if (mComposerInterfaceVersion <= 1) { if (sysprop::clear_slots_with_set_layer_buffer(false)) { mClearSlotBuffer = sp::make(1, 1, PIXEL_FORMAT_RGBX_8888, GraphicBuffer::USAGE_HW_COMPOSER | GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_SW_WRITE_OFTEN, "AidlComposer"); if (!mClearSlotBuffer || mClearSlotBuffer->initCheck() != ::android::OK) { LOG_ALWAYS_FATAL("Failed to allocate a buffer for clearing layer buffer slots"); return; } } } if (getLayerLifecycleBatchCommand()) { mEnableLayerCommandBatchingFlag = FlagManager::getInstance().enable_layer_command_batching(); } ALOGI("Loaded AIDL composer3 HAL service"); } AidlComposer::~AidlComposer() = default; bool AidlComposer::isSupported(OptionalFeature feature) const { switch (feature) { case OptionalFeature::RefreshRateSwitching: case OptionalFeature::ExpectedPresentTime: case OptionalFeature::DisplayBrightnessCommand: case OptionalFeature::KernelIdleTimer: case OptionalFeature::PhysicalDisplayOrientation: return true; } } bool AidlComposer::isVrrSupported() const { return mComposerInterfaceVersion >= 3 && FlagManager::getInstance().vrr_config(); } std::vector AidlComposer::getCapabilities() { std::vector capabilities; const auto status = mAidlComposer->getCapabilities(&capabilities); if (!status.isOk()) { ALOGE("getCapabilities failed %s", status.getDescription().c_str()); return {}; } return capabilities; } std::string AidlComposer::dumpDebugInfo() { int pipefds[2]; int result = pipe(pipefds); if (result < 0) { ALOGE("dumpDebugInfo: pipe failed: %s", strerror(errno)); return {}; } std::string str; // Use other thread to read pipe to prevent // pipe is full, making HWC be blocked in writing. std::thread t([&]() { base::ReadFdToString(pipefds[0], &str); }); const auto status = mAidlComposer->dump(pipefds[1], /*args*/ nullptr, /*numArgs*/ 0); // Close the write-end of the pipe to make sure that when reading from the // read-end we will get eof instead of blocking forever close(pipefds[1]); if (status != STATUS_OK) { ALOGE("dumpDebugInfo: dump failed: %d", status); } t.join(); close(pipefds[0]); std::string hash; mAidlComposer->getInterfaceHash(&hash); return std::string(mAidlComposer->descriptor) + " version:" + std::to_string(mComposerInterfaceVersion) + " hash:" + hash + str; } void AidlComposer::registerCallback(HWC2::ComposerCallback& callback) { if (mAidlComposerCallback) { ALOGE("Callback already registered"); } mAidlComposerCallback = ndk::SharedRefBase::make(callback); ndk::SpAIBinder binder = mAidlComposerCallback->asBinder(); AIBinder_setMinSchedulerPolicy(binder.get(), SCHED_FIFO, 2); const auto status = mAidlComposerClient->registerCallback(mAidlComposerCallback); if (!status.isOk()) { ALOGE("registerCallback failed %s", status.getDescription().c_str()); } } Error AidlComposer::executeCommands(Display display) { mMutex.lock_shared(); auto error = execute(display); mMutex.unlock_shared(); return error; } uint32_t AidlComposer::getMaxVirtualDisplayCount() { int32_t count = 0; const auto status = mAidlComposerClient->getMaxVirtualDisplayCount(&count); if (!status.isOk()) { ALOGE("getMaxVirtualDisplayCount failed %s", status.getDescription().c_str()); return 0; } return static_cast(count); } Error AidlComposer::createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format, Display* outDisplay) { using AidlPixelFormat = aidl::android::hardware::graphics::common::PixelFormat; const int32_t bufferSlotCount = 1; VirtualDisplay virtualDisplay; const auto status = mAidlComposerClient->createVirtualDisplay(static_cast(width), static_cast(height), static_cast(*format), bufferSlotCount, &virtualDisplay); if (!status.isOk()) { ALOGE("createVirtualDisplay failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } *outDisplay = translate(virtualDisplay.display); *format = static_cast(virtualDisplay.format); addDisplay(translate(virtualDisplay.display)); return Error::NONE; } Error AidlComposer::destroyVirtualDisplay(Display display) { const auto status = mAidlComposerClient->destroyVirtualDisplay(translate(display)); if (!status.isOk()) { ALOGE("destroyVirtualDisplay failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } removeDisplay(display); return Error::NONE; } Error AidlComposer::acceptDisplayChanges(Display display) { Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get().acceptDisplayChanges(translate(display)); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } Error AidlComposer::createLayer(Display display, Layer* outLayer) { int64_t layer; Error error = Error::NONE; if (!mEnableLayerCommandBatchingFlag) { const auto status = mAidlComposerClient->createLayer(translate(display), kMaxLayerBufferCount, &layer); if (!status.isOk()) { ALOGE("createLayer failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } } else { // generate a unique layerID. map in AidlComposer with // Add this as a new displayCommand in execute command. // return the SF generated layerID instead of calling HWC layer = mLayerID++; mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get().setLayerLifecycleBatchCommandType(translate(display), translate(layer), LayerLifecycleBatchCommandType::CREATE); writer->get().setNewBufferSlotCount(translate(display), translate(layer), kMaxLayerBufferCount); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); } *outLayer = translate(layer); return error; } Error AidlComposer::destroyLayer(Display display, Layer layer) { Error error = Error::NONE; if (!mEnableLayerCommandBatchingFlag) { const auto status = mAidlComposerClient->destroyLayer(translate(display), translate(layer)); if (!status.isOk()) { ALOGE("destroyLayer failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } } else { mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get() .setLayerLifecycleBatchCommandType(translate(display), translate(layer), LayerLifecycleBatchCommandType::DESTROY); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); } return error; } Error AidlComposer::getActiveConfig(Display display, Config* outConfig) { int32_t config; const auto status = mAidlComposerClient->getActiveConfig(translate(display), &config); if (!status.isOk()) { ALOGE("getActiveConfig failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } *outConfig = translate(config); return Error::NONE; } Error AidlComposer::getChangedCompositionTypes( Display display, std::vector* outLayers, std::vector* outTypes) { std::vector changedLayers; Error error = Error::NONE; { mMutex.lock_shared(); if (auto reader = getReader(display)) { changedLayers = reader->get().takeChangedCompositionTypes(translate(display)); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); } outLayers->reserve(changedLayers.size()); outTypes->reserve(changedLayers.size()); for (const auto& layer : changedLayers) { outLayers->emplace_back(translate(layer.layer)); outTypes->emplace_back(layer.composition); } return error; } Error AidlComposer::getColorModes(Display display, std::vector* outModes) { std::vector modes; const auto status = mAidlComposerClient->getColorModes(translate(display), &modes); if (!status.isOk()) { ALOGE("getColorModes failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } *outModes = translate(modes); return Error::NONE; } Error AidlComposer::getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute, int32_t* outValue) { const auto status = mAidlComposerClient->getDisplayAttribute(translate(display), translate(config), static_cast(attribute), outValue); if (!status.isOk()) { ALOGE("getDisplayAttribute failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } return Error::NONE; } Error AidlComposer::getDisplayConfigs(Display display, std::vector* outConfigs) { std::vector configs; const auto status = mAidlComposerClient->getDisplayConfigs(translate(display), &configs); if (!status.isOk()) { ALOGE("getDisplayConfigs failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } *outConfigs = translate(configs); return Error::NONE; } Error AidlComposer::getDisplayConfigurations(Display display, int32_t maxFrameIntervalNs, std::vector* outConfigs) { const auto status = mAidlComposerClient->getDisplayConfigurations(translate(display), maxFrameIntervalNs, outConfigs); if (!status.isOk()) { ALOGE("getDisplayConfigurations failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } return Error::NONE; } Error AidlComposer::getDisplayName(Display display, std::string* outName) { const auto status = mAidlComposerClient->getDisplayName(translate(display), outName); if (!status.isOk()) { ALOGE("getDisplayName failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } return Error::NONE; } Error AidlComposer::getDisplayRequests(Display display, uint32_t* outDisplayRequestMask, std::vector* outLayers, std::vector* outLayerRequestMasks) { Error error = Error::NONE; DisplayRequest displayRequests; { mMutex.lock_shared(); if (auto reader = getReader(display)) { displayRequests = reader->get().takeDisplayRequests(translate(display)); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); } *outDisplayRequestMask = translate(displayRequests.mask); outLayers->reserve(displayRequests.layerRequests.size()); outLayerRequestMasks->reserve(displayRequests.layerRequests.size()); for (const auto& layer : displayRequests.layerRequests) { outLayers->emplace_back(translate(layer.layer)); outLayerRequestMasks->emplace_back(translate(layer.mask)); } return error; } Error AidlComposer::getDozeSupport(Display display, bool* outSupport) { std::vector capabilities; const auto status = mAidlComposerClient->getDisplayCapabilities(translate(display), &capabilities); if (!status.isOk()) { ALOGE("getDisplayCapabilities failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } *outSupport = std::find(capabilities.begin(), capabilities.end(), AidlDisplayCapability::DOZE) != capabilities.end(); return Error::NONE; } Error AidlComposer::hasDisplayIdleTimerCapability(Display display, bool* outSupport) { std::vector capabilities; const auto status = mAidlComposerClient->getDisplayCapabilities(translate(display), &capabilities); if (!status.isOk()) { ALOGE("getDisplayCapabilities failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } *outSupport = std::find(capabilities.begin(), capabilities.end(), AidlDisplayCapability::DISPLAY_IDLE_TIMER) != capabilities.end(); return Error::NONE; } Error AidlComposer::getHdrCapabilities(Display display, std::vector* outTypes, float* outMaxLuminance, float* outMaxAverageLuminance, float* outMinLuminance) { AidlHdrCapabilities capabilities; const auto status = mAidlComposerClient->getHdrCapabilities(translate(display), &capabilities); if (!status.isOk()) { ALOGE("getHdrCapabilities failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } *outTypes = capabilities.types; *outMaxLuminance = capabilities.maxLuminance; *outMaxAverageLuminance = capabilities.maxAverageLuminance; *outMinLuminance = capabilities.minLuminance; return Error::NONE; } bool AidlComposer::getLayerLifecycleBatchCommand() { std::vector capabilities = getCapabilities(); bool hasCapability = std::find(capabilities.begin(), capabilities.end(), Capability::LAYER_LIFECYCLE_BATCH_COMMAND) != capabilities.end(); return hasCapability; } Error AidlComposer::getOverlaySupport(AidlOverlayProperties* outProperties) { const auto status = mAidlComposerClient->getOverlaySupport(outProperties); if (!status.isOk()) { ALOGE("getOverlaySupport failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } return Error::NONE; } Error AidlComposer::getReleaseFences(Display display, std::vector* outLayers, std::vector* outReleaseFences) { Error error = Error::NONE; std::vector fences; { mMutex.lock_shared(); if (auto reader = getReader(display)) { fences = reader->get().takeReleaseFences(translate(display)); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); } outLayers->reserve(fences.size()); outReleaseFences->reserve(fences.size()); for (auto& fence : fences) { outLayers->emplace_back(translate(fence.layer)); // take ownership const int fenceOwner = fence.fence.get(); *fence.fence.getR() = -1; outReleaseFences->emplace_back(fenceOwner); } return error; } Error AidlComposer::presentDisplay(Display display, int* outPresentFence) { const auto displayId = translate(display); ATRACE_FORMAT("HwcPresentDisplay %" PRId64, displayId); Error error = Error::NONE; mMutex.lock_shared(); auto writer = getWriter(display); auto reader = getReader(display); if (writer && reader) { writer->get().presentDisplay(displayId); error = execute(display); } else { error = Error::BAD_DISPLAY; } if (error != Error::NONE) { mMutex.unlock_shared(); return error; } auto fence = reader->get().takePresentFence(displayId); mMutex.unlock_shared(); // take ownership *outPresentFence = fence.get(); *fence.getR() = -1; return Error::NONE; } Error AidlComposer::setActiveConfig(Display display, Config config) { const auto status = mAidlComposerClient->setActiveConfig(translate(display), translate(config)); if (!status.isOk()) { ALOGE("setActiveConfig failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } return Error::NONE; } Error AidlComposer::setClientTarget(Display display, uint32_t slot, const sp& target, int acquireFence, Dataspace dataspace, const std::vector& damage, float hdrSdrRatio) { const native_handle_t* handle = nullptr; if (target.get()) { handle = target->getNativeBuffer()->handle; } Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get() .setClientTarget(translate(display), slot, handle, acquireFence, translate( dataspace), translate(damage), hdrSdrRatio); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } Error AidlComposer::setColorMode(Display display, ColorMode mode, RenderIntent renderIntent) { const auto status = mAidlComposerClient->setColorMode(translate(display), translate(mode), translate(renderIntent)); if (!status.isOk()) { ALOGE("setColorMode failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } return Error::NONE; } Error AidlComposer::setColorTransform(Display display, const float* matrix) { auto error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get().setColorTransform(translate(display), matrix); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } Error AidlComposer::setOutputBuffer(Display display, const native_handle_t* buffer, int releaseFence) { auto error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get().setOutputBuffer(translate(display), 0, buffer, dup(releaseFence)); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } Error AidlComposer::setPowerMode(Display display, IComposerClient::PowerMode mode) { const auto status = mAidlComposerClient->setPowerMode(translate(display), translate(mode)); if (!status.isOk()) { ALOGE("setPowerMode failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } return Error::NONE; } Error AidlComposer::setVsyncEnabled(Display display, IComposerClient::Vsync enabled) { const bool enableVsync = enabled == IComposerClient::Vsync::ENABLE; const auto status = mAidlComposerClient->setVsyncEnabled(translate(display), enableVsync); if (!status.isOk()) { ALOGE("setVsyncEnabled failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } return Error::NONE; } Error AidlComposer::setClientTargetSlotCount(Display display) { const int32_t bufferSlotCount = BufferQueue::NUM_BUFFER_SLOTS; const auto status = mAidlComposerClient->setClientTargetSlotCount(translate(display), bufferSlotCount); if (!status.isOk()) { ALOGE("setClientTargetSlotCount failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } return Error::NONE; } Error AidlComposer::validateDisplay(Display display, nsecs_t expectedPresentTime, int32_t frameIntervalNs, uint32_t* outNumTypes, uint32_t* outNumRequests) { const auto displayId = translate(display); ATRACE_FORMAT("HwcValidateDisplay %" PRId64, displayId); Error error = Error::NONE; mMutex.lock_shared(); auto writer = getWriter(display); auto reader = getReader(display); if (writer && reader) { writer->get().validateDisplay(displayId, ClockMonotonicTimestamp{expectedPresentTime}, frameIntervalNs); error = execute(display); } else { error = Error::BAD_DISPLAY; } if (error != Error::NONE) { mMutex.unlock_shared(); return error; } reader->get().hasChanges(displayId, outNumTypes, outNumRequests); mMutex.unlock_shared(); return Error::NONE; } Error AidlComposer::presentOrValidateDisplay(Display display, nsecs_t expectedPresentTime, int32_t frameIntervalNs, uint32_t* outNumTypes, uint32_t* outNumRequests, int* outPresentFence, uint32_t* state) { const auto displayId = translate(display); ATRACE_FORMAT("HwcPresentOrValidateDisplay %" PRId64, displayId); Error error = Error::NONE; mMutex.lock_shared(); auto writer = getWriter(display); auto reader = getReader(display); if (writer && reader) { writer->get().presentOrvalidateDisplay(displayId, ClockMonotonicTimestamp{expectedPresentTime}, frameIntervalNs); error = execute(display); } else { error = Error::BAD_DISPLAY; } if (error != Error::NONE) { mMutex.unlock_shared(); return error; } const auto result = reader->get().takePresentOrValidateStage(displayId); if (!result.has_value()) { *state = translate(-1); mMutex.unlock_shared(); return Error::NO_RESOURCES; } *state = translate(*result); if (*result == PresentOrValidate::Result::Presented) { auto fence = reader->get().takePresentFence(displayId); // take ownership *outPresentFence = fence.get(); *fence.getR() = -1; } if (*result == PresentOrValidate::Result::Validated) { reader->get().hasChanges(displayId, outNumTypes, outNumRequests); } mMutex.unlock_shared(); return Error::NONE; } Error AidlComposer::setCursorPosition(Display display, Layer layer, int32_t x, int32_t y) { Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get().setLayerCursorPosition(translate(display), translate(layer), x, y); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } Error AidlComposer::setLayerBuffer(Display display, Layer layer, uint32_t slot, const sp& buffer, int acquireFence) { const native_handle_t* handle = nullptr; if (buffer.get()) { handle = buffer->getNativeBuffer()->handle; } Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get().setLayerBuffer(translate(display), translate(layer), slot, handle, acquireFence); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } Error AidlComposer::setLayerBufferSlotsToClear(Display display, Layer layer, const std::vector& slotsToClear, uint32_t activeBufferSlot) { if (slotsToClear.empty()) { return Error::NONE; } Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { if (mComposerInterfaceVersion > 1) { writer->get().setLayerBufferSlotsToClear(translate(display), translate(layer), slotsToClear); // Backwards compatible way of clearing buffer slots is to set the layer buffer with a // placeholder buffer, using the slot that needs to cleared... tricky. } else if (mClearSlotBuffer != nullptr) { for (uint32_t slot : slotsToClear) { // Don't clear the active buffer slot because we need to restore the active buffer // after clearing the requested buffer slots with a placeholder buffer. if (slot != activeBufferSlot) { writer->get().setLayerBufferWithNewCommand(translate(display), translate(layer), slot, mClearSlotBuffer->handle, /*fence*/ -1); } } // Since we clear buffers by setting them to a placeholder buffer, we want to make // sure that the last setLayerBuffer command is sent with the currently active // buffer, not the placeholder buffer, so that there is no perceptual change when // buffers are discarded. writer->get().setLayerBufferWithNewCommand(translate(display), translate(layer), activeBufferSlot, // The active buffer is still cached in // its slot and doesn't need a fence. /*buffer*/ nullptr, /*fence*/ -1); } } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } Error AidlComposer::setLayerSurfaceDamage(Display display, Layer layer, const std::vector& damage) { Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get().setLayerSurfaceDamage(translate(display), translate(layer), translate(damage)); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } Error AidlComposer::setLayerBlendMode(Display display, Layer layer, IComposerClient::BlendMode mode) { Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get().setLayerBlendMode(translate(display), translate(layer), translate(mode)); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } Error AidlComposer::setLayerColor(Display display, Layer layer, const Color& color) { Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get().setLayerColor(translate(display), translate(layer), color); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } Error AidlComposer::setLayerCompositionType( Display display, Layer layer, aidl::android::hardware::graphics::composer3::Composition type) { Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get().setLayerCompositionType(translate(display), translate(layer), type); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } Error AidlComposer::setLayerDataspace(Display display, Layer layer, Dataspace dataspace) { Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get().setLayerDataspace(translate(display), translate(layer), translate(dataspace)); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } Error AidlComposer::setLayerDisplayFrame(Display display, Layer layer, const IComposerClient::Rect& frame) { Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get().setLayerDisplayFrame(translate(display), translate(layer), translate(frame)); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } Error AidlComposer::setLayerPlaneAlpha(Display display, Layer layer, float alpha) { Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get().setLayerPlaneAlpha(translate(display), translate(layer), alpha); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } Error AidlComposer::setLayerSidebandStream(Display display, Layer layer, const native_handle_t* stream) { Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get().setLayerSidebandStream(translate(display), translate(layer), stream); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } Error AidlComposer::setLayerSourceCrop(Display display, Layer layer, const IComposerClient::FRect& crop) { Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get().setLayerSourceCrop(translate(display), translate(layer), translate(crop)); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } Error AidlComposer::setLayerTransform(Display display, Layer layer, Transform transform) { Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get().setLayerTransform(translate(display), translate(layer), translate(transform)); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } Error AidlComposer::setLayerVisibleRegion(Display display, Layer layer, const std::vector& visible) { Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get().setLayerVisibleRegion(translate(display), translate(layer), translate(visible)); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } Error AidlComposer::setLayerZOrder(Display display, Layer layer, uint32_t z) { Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get().setLayerZOrder(translate(display), translate(layer), z); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } Error AidlComposer::execute(Display display) { auto writer = getWriter(display); auto reader = getReader(display); if (!writer || !reader) { return Error::BAD_DISPLAY; } auto commands = writer->get().takePendingCommands(); if (commands.empty()) { return Error::NONE; } { // scope for results std::vector results; auto status = mAidlComposerClient->executeCommands(commands, &results); if (!status.isOk()) { ALOGE("executeCommands failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } reader->get().parse(std::move(results)); } const auto commandErrors = reader->get().takeErrors(); Error error = Error::NONE; for (const auto& cmdErr : commandErrors) { const auto index = static_cast(cmdErr.commandIndex); if (index < 0 || index >= commands.size()) { ALOGE("invalid command index %zu", index); return Error::BAD_PARAMETER; } const auto& command = commands[index]; if (command.validateDisplay || command.presentDisplay || command.presentOrValidateDisplay) { error = translate(cmdErr.errorCode); } else { ALOGW("command '%s' generated error %" PRId32, command.toString().c_str(), cmdErr.errorCode); } } return error; } Error AidlComposer::setLayerPerFrameMetadata( Display display, Layer layer, const std::vector& perFrameMetadatas) { Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get().setLayerPerFrameMetadata(translate(display), translate(layer), translate(perFrameMetadatas)); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } std::vector AidlComposer::getPerFrameMetadataKeys( Display display) { std::vector keys; const auto status = mAidlComposerClient->getPerFrameMetadataKeys(translate(display), &keys); if (!status.isOk()) { ALOGE("getPerFrameMetadataKeys failed %s", status.getDescription().c_str()); return {}; } return translate(keys); } Error AidlComposer::getRenderIntents(Display display, ColorMode colorMode, std::vector* outRenderIntents) { std::vector renderIntents; const auto status = mAidlComposerClient->getRenderIntents(translate(display), translate(colorMode), &renderIntents); if (!status.isOk()) { ALOGE("getRenderIntents failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } *outRenderIntents = translate(renderIntents); return Error::NONE; } Error AidlComposer::getDataspaceSaturationMatrix(Dataspace dataspace, mat4* outMatrix) { std::vector matrix; const auto status = mAidlComposerClient->getDataspaceSaturationMatrix(translate(dataspace), &matrix); if (!status.isOk()) { ALOGE("getDataspaceSaturationMatrix failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } *outMatrix = makeMat4(matrix); return Error::NONE; } Error AidlComposer::getDisplayIdentificationData(Display display, uint8_t* outPort, std::vector* outData) { AidlDisplayIdentification displayIdentification; const auto status = mAidlComposerClient->getDisplayIdentificationData(translate(display), &displayIdentification); if (!status.isOk()) { ALOGE("getDisplayIdentificationData failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } *outPort = static_cast(displayIdentification.port); *outData = displayIdentification.data; return Error::NONE; } Error AidlComposer::setLayerColorTransform(Display display, Layer layer, const float* matrix) { Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get().setLayerColorTransform(translate(display), translate(layer), matrix); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } Error AidlComposer::getDisplayedContentSamplingAttributes(Display display, PixelFormat* outFormat, Dataspace* outDataspace, uint8_t* outComponentMask) { if (!outFormat || !outDataspace || !outComponentMask) { return Error::BAD_PARAMETER; } AidlDisplayContentSamplingAttributes attributes; const auto status = mAidlComposerClient->getDisplayedContentSamplingAttributes(translate(display), &attributes); if (!status.isOk()) { ALOGE("getDisplayedContentSamplingAttributes failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } *outFormat = translate(attributes.format); *outDataspace = translate(attributes.dataspace); *outComponentMask = static_cast(attributes.componentMask); return Error::NONE; } Error AidlComposer::setDisplayContentSamplingEnabled(Display display, bool enabled, uint8_t componentMask, uint64_t maxFrames) { const auto status = mAidlComposerClient ->setDisplayedContentSamplingEnabled(translate(display), enabled, static_cast( componentMask), static_cast(maxFrames)); if (!status.isOk()) { ALOGE("setDisplayedContentSamplingEnabled failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } return Error::NONE; } Error AidlComposer::getDisplayedContentSample(Display display, uint64_t maxFrames, uint64_t timestamp, DisplayedFrameStats* outStats) { if (!outStats) { return Error::BAD_PARAMETER; } AidlDisplayContentSample sample; const auto status = mAidlComposerClient->getDisplayedContentSample(translate(display), static_cast(maxFrames), static_cast(timestamp), &sample); if (!status.isOk()) { ALOGE("getDisplayedContentSample failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } *outStats = translate(sample); return Error::NONE; } Error AidlComposer::setLayerPerFrameMetadataBlobs( Display display, Layer layer, const std::vector& metadata) { Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get().setLayerPerFrameMetadataBlobs(translate(display), translate(layer), translate(metadata)); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } Error AidlComposer::setDisplayBrightness(Display display, float brightness, float brightnessNits, const DisplayBrightnessOptions& options) { Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get().setDisplayBrightness(translate(display), brightness, brightnessNits); if (options.applyImmediately) { error = execute(display); mMutex.unlock_shared(); return error; } } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } Error AidlComposer::getDisplayCapabilities(Display display, std::vector* outCapabilities) { const auto status = mAidlComposerClient->getDisplayCapabilities(translate(display), outCapabilities); if (!status.isOk()) { ALOGE("getDisplayCapabilities failed %s", status.getDescription().c_str()); outCapabilities->clear(); return static_cast(status.getServiceSpecificError()); } return Error::NONE; } V2_4::Error AidlComposer::getDisplayConnectionType( Display display, IComposerClient::DisplayConnectionType* outType) { AidlDisplayConnectionType type; const auto status = mAidlComposerClient->getDisplayConnectionType(translate(display), &type); if (!status.isOk()) { ALOGE("getDisplayConnectionType failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } *outType = translate(type); return V2_4::Error::NONE; } V2_4::Error AidlComposer::getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) { int32_t vsyncPeriod; const auto status = mAidlComposerClient->getDisplayVsyncPeriod(translate(display), &vsyncPeriod); if (!status.isOk()) { ALOGE("getDisplayVsyncPeriod failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } *outVsyncPeriod = translate(vsyncPeriod); return V2_4::Error::NONE; } V2_4::Error AidlComposer::setActiveConfigWithConstraints( Display display, Config config, const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints, VsyncPeriodChangeTimeline* outTimeline) { AidlVsyncPeriodChangeTimeline timeline; const auto status = mAidlComposerClient ->setActiveConfigWithConstraints(translate(display), translate(config), translate( vsyncPeriodChangeConstraints), &timeline); if (!status.isOk()) { ALOGE("setActiveConfigWithConstraints failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } *outTimeline = translate(timeline); return V2_4::Error::NONE; } V2_4::Error AidlComposer::setAutoLowLatencyMode(Display display, bool on) { const auto status = mAidlComposerClient->setAutoLowLatencyMode(translate(display), on); if (!status.isOk()) { ALOGE("setAutoLowLatencyMode failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } return V2_4::Error::NONE; } V2_4::Error AidlComposer::getSupportedContentTypes( Display displayId, std::vector* outSupportedContentTypes) { std::vector types; const auto status = mAidlComposerClient->getSupportedContentTypes(translate(displayId), &types); if (!status.isOk()) { ALOGE("getSupportedContentTypes failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } *outSupportedContentTypes = translate(types); return V2_4::Error::NONE; } V2_4::Error AidlComposer::setContentType(Display display, IComposerClient::ContentType contentType) { const auto status = mAidlComposerClient->setContentType(translate(display), translate(contentType)); if (!status.isOk()) { ALOGE("setContentType failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } return V2_4::Error::NONE; } V2_4::Error AidlComposer::setLayerGenericMetadata(Display, Layer, const std::string&, bool, const std::vector&) { // There are no users for this API. See b/209691612. return V2_4::Error::UNSUPPORTED; } V2_4::Error AidlComposer::getLayerGenericMetadataKeys( std::vector*) { // There are no users for this API. See b/209691612. return V2_4::Error::UNSUPPORTED; } Error AidlComposer::setBootDisplayConfig(Display display, Config config) { const auto status = mAidlComposerClient->setBootDisplayConfig(translate(display), translate(config)); if (!status.isOk()) { ALOGE("setBootDisplayConfig failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } return Error::NONE; } Error AidlComposer::clearBootDisplayConfig(Display display) { const auto status = mAidlComposerClient->clearBootDisplayConfig(translate(display)); if (!status.isOk()) { ALOGE("clearBootDisplayConfig failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } return Error::NONE; } Error AidlComposer::getPreferredBootDisplayConfig(Display display, Config* config) { int32_t displayConfig; const auto status = mAidlComposerClient->getPreferredBootDisplayConfig(translate(display), &displayConfig); if (!status.isOk()) { ALOGE("getPreferredBootDisplayConfig failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } *config = translate(displayConfig); return Error::NONE; } Error AidlComposer::getHdrConversionCapabilities( std::vector* hdrConversionCapabilities) { const auto status = mAidlComposerClient->getHdrConversionCapabilities(hdrConversionCapabilities); if (!status.isOk()) { hdrConversionCapabilities = {}; ALOGE("getHdrConversionCapabilities failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } return Error::NONE; } Error AidlComposer::setHdrConversionStrategy(AidlHdrConversionStrategy hdrConversionStrategy, Hdr* outPreferredHdrOutputType) { const auto status = mAidlComposerClient->setHdrConversionStrategy(hdrConversionStrategy, outPreferredHdrOutputType); if (!status.isOk()) { ALOGE("setHdrConversionStrategy failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } return Error::NONE; } Error AidlComposer::setRefreshRateChangedCallbackDebugEnabled(Display displayId, bool enabled) { const auto status = mAidlComposerClient->setRefreshRateChangedCallbackDebugEnabled(translate( displayId), enabled); if (!status.isOk()) { ALOGE("setRefreshRateChangedCallbackDebugEnabled failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } return Error::NONE; } Error AidlComposer::notifyExpectedPresent(Display displayId, nsecs_t expectedPresentTime, int32_t frameIntervalNs) { const auto status = mAidlComposerClient->notifyExpectedPresent(translate(displayId), ClockMonotonicTimestamp{expectedPresentTime}, frameIntervalNs); if (!status.isOk()) { ALOGE("notifyExpectedPresent failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } return Error::NONE; } Error AidlComposer::getClientTargetProperty( Display display, ClientTargetPropertyWithBrightness* outClientTargetProperty) { Error error = Error::NONE; mMutex.lock_shared(); if (auto reader = getReader(display)) { *outClientTargetProperty = reader->get().takeClientTargetProperty(translate(display)); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } Error AidlComposer::setLayerBrightness(Display display, Layer layer, float brightness) { Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get().setLayerBrightness(translate(display), translate(layer), brightness); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } Error AidlComposer::setLayerBlockingRegion(Display display, Layer layer, const std::vector& blocking) { Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { writer->get().setLayerBlockingRegion(translate(display), translate(layer), translate(blocking)); } else { error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); return error; } Error AidlComposer::getDisplayDecorationSupport(Display display, std::optional* support) { const auto status = mAidlComposerClient->getDisplayDecorationSupport(translate(display), support); if (!status.isOk()) { ALOGE("getDisplayDecorationSupport failed %s", status.getDescription().c_str()); support->reset(); return static_cast(status.getServiceSpecificError()); } return Error::NONE; } Error AidlComposer::setIdleTimerEnabled(Display displayId, std::chrono::milliseconds timeout) { const auto status = mAidlComposerClient->setIdleTimerEnabled(translate(displayId), translate(timeout.count())); if (!status.isOk()) { ALOGE("setIdleTimerEnabled failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } return Error::NONE; } Error AidlComposer::getPhysicalDisplayOrientation(Display displayId, AidlTransform* outDisplayOrientation) { const auto status = mAidlComposerClient->getDisplayPhysicalOrientation(translate(displayId), outDisplayOrientation); if (!status.isOk()) { ALOGE("getPhysicalDisplayOrientation failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); } return Error::NONE; } ftl::Optional> AidlComposer::getWriter(Display display) REQUIRES_SHARED(mMutex) { return mWriters.get(display); } ftl::Optional> AidlComposer::getReader(Display display) REQUIRES_SHARED(mMutex) { if (mSingleReader) { display = translate(kSingleReaderKey); } return mReaders.get(display); } void AidlComposer::removeDisplay(Display display) { mMutex.lock(); bool wasErased = mWriters.erase(display); ALOGW_IF(!wasErased, "Attempting to remove writer for display %" PRId64 " which is not connected", translate(display)); if (!mSingleReader) { removeReader(display); } mMutex.unlock(); } void AidlComposer::onHotplugDisconnect(Display display) { removeDisplay(display); } bool AidlComposer::hasMultiThreadedPresentSupport(Display display) { if (!FlagManager::getInstance().multithreaded_present()) return false; const auto displayId = translate(display); std::vector capabilities; const auto status = mAidlComposerClient->getDisplayCapabilities(displayId, &capabilities); if (!status.isOk()) { ALOGE("getDisplayCapabilities failed %s", status.getDescription().c_str()); return false; } return std::find(capabilities.begin(), capabilities.end(), AidlDisplayCapability::MULTI_THREADED_PRESENT) != capabilities.end(); } void AidlComposer::addReader(Display display) { const auto displayId = translate(display); std::optional displayOpt; if (displayId != kSingleReaderKey) { displayOpt.emplace(displayId); } auto [it, added] = mReaders.try_emplace(display, std::move(displayOpt)); ALOGW_IF(!added, "Attempting to add writer for display %" PRId64 " which is already connected", displayId); } void AidlComposer::removeReader(Display display) { bool wasErased = mReaders.erase(display); ALOGW_IF(!wasErased, "Attempting to remove reader for display %" PRId64 " which is not connected", translate(display)); } void AidlComposer::addDisplay(Display display) { const auto displayId = translate(display); mMutex.lock(); auto [it, added] = mWriters.try_emplace(display, displayId); ALOGW_IF(!added, "Attempting to add writer for display %" PRId64 " which is already connected", displayId); if (mSingleReader) { if (hasMultiThreadedPresentSupport(display)) { mSingleReader = false; removeReader(translate(kSingleReaderKey)); // Note that this includes the new display. for (const auto& [existingDisplay, _] : mWriters) { addReader(existingDisplay); } } } else { addReader(display); } mMutex.unlock(); } void AidlComposer::onHotplugConnect(Display display) { addDisplay(display); } } // namespace Hwc2 } // namespace android