| /* |
| * Copyright (C) 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. |
| */ |
| |
| #define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL) |
| |
| #include "ComposerClient.h" |
| |
| #include <android-base/logging.h> |
| #include <android/binder_ibinder_platform.h> |
| |
| #include "Util.h" |
| |
| namespace aidl::android::hardware::graphics::composer3::impl { |
| |
| bool ComposerClient::init() { |
| DEBUG_FUNC(); |
| mResources = IResourceManager::create(); |
| if (!mResources) { |
| LOG(ERROR) << "failed to create composer resources"; |
| return false; |
| } |
| |
| return true; |
| } |
| |
| ComposerClient::~ComposerClient() { |
| DEBUG_FUNC(); |
| LOG(DEBUG) << "destroying composer client"; |
| |
| mHal->unregisterEventCallback(); |
| destroyResources(); |
| |
| if (mOnClientDestroyed) { |
| mOnClientDestroyed(); |
| } |
| |
| LOG(DEBUG) << "removed composer client"; |
| } |
| |
| // no need to check nullptr for output parameter, the aidl stub code won't pass nullptr |
| ndk::ScopedAStatus ComposerClient::createLayer(int64_t display, int32_t bufferSlotCount, |
| int64_t* layer) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->createLayer(display, layer); |
| if (!err) { |
| err = mResources->addLayer(display, *layer, bufferSlotCount); |
| if (err) { |
| layer = 0; |
| } |
| } |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::createVirtualDisplay(int32_t width, int32_t height, |
| AidlPixelFormat formatHint, |
| int32_t outputBufferSlotCount, |
| VirtualDisplay* display) { |
| DEBUG_FUNC(); |
| auto err = mHal->createVirtualDisplay(width, height, formatHint, display); |
| if (!err) { |
| err = mResources->addVirtualDisplay(display->display, outputBufferSlotCount); |
| } |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::destroyLayer(int64_t display, int64_t layer) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->destroyLayer(display, layer); |
| if (!err) { |
| err = mResources->removeLayer(display, layer); |
| } |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::destroyVirtualDisplay(int64_t display) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->destroyVirtualDisplay(display); |
| if (!err) { |
| err = mResources->removeDisplay(display); |
| } |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::executeCommands(const std::vector<DisplayCommand>& commands, |
| std::vector<CommandResultPayload>* results) { |
| int64_t display = commands.empty() ? -1 : commands[0].display; |
| DEBUG_DISPLAY_FUNC(display); |
| ComposerCommandEngine engine(mHal, mResources.get()); |
| |
| auto err = engine.init(); |
| if (err != ::android::NO_ERROR) { |
| LOG(ERROR) << "executeCommands(): init ComposerCommandEngine failed " << err; |
| return TO_BINDER_STATUS(err); |
| } |
| |
| err = engine.execute(commands, results); |
| if (err != ::android::NO_ERROR) { |
| LOG(ERROR) << "executeCommands(): execute failed " << err; |
| return TO_BINDER_STATUS(err); |
| } |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getActiveConfig(int64_t display, int32_t* config) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->getActiveConfig(display, config); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getColorModes(int64_t display, |
| std::vector<ColorMode>* colorModes) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->getColorModes(display, colorModes); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getDataspaceSaturationMatrix(common::Dataspace dataspace, |
| std::vector<float>* matrix) { |
| DEBUG_FUNC(); |
| if (dataspace != common::Dataspace::SRGB_LINEAR) { |
| return TO_BINDER_STATUS(EX_BAD_PARAMETER); |
| } |
| |
| auto err = mHal->getDataspaceSaturationMatrix(dataspace, matrix); |
| if (err) { |
| constexpr std::array<float, 16> unit { |
| 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, |
| 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, |
| }; |
| matrix->clear(); |
| matrix->insert(matrix->begin(), unit.begin(), unit.end()); |
| } |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getDisplayAttribute(int64_t display, int32_t config, |
| DisplayAttribute attribute, int32_t* value) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->getDisplayAttribute(display, config, attribute, value); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getDisplayCapabilities(int64_t display, |
| std::vector<DisplayCapability>* caps) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->getDisplayCapabilities(display, caps); |
| if (!err) { |
| return TO_BINDER_STATUS(err); |
| } |
| bool support; |
| err = mHal->getDisplayBrightnessSupport(display, &support); |
| if (err == 0 && support) { |
| caps->push_back(DisplayCapability::BRIGHTNESS); |
| } |
| err = mHal->getDozeSupport(display, &support); |
| if (err == 0 && support) { |
| caps->push_back(DisplayCapability::DOZE); |
| } |
| |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getDisplayConfigs(int64_t display, |
| std::vector<int32_t>* configs) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->getDisplayConfigs(display, configs); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getDisplayConnectionType(int64_t display, |
| DisplayConnectionType* type) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->getDisplayConnectionType(display, type); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getDisplayIdentificationData(int64_t display, |
| DisplayIdentification* id) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->getDisplayIdentificationData(display, id); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getDisplayName(int64_t display, std::string* name) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->getDisplayName(display, name); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getDisplayVsyncPeriod(int64_t display, int32_t* vsyncPeriod) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->getDisplayVsyncPeriod(display, vsyncPeriod); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getDisplayedContentSample(int64_t display, int64_t maxFrames, |
| int64_t timestamp, |
| DisplayContentSample* samples) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->getDisplayedContentSample(display, maxFrames, timestamp, samples); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getDisplayedContentSamplingAttributes( |
| int64_t display, DisplayContentSamplingAttributes* attrs) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->getDisplayedContentSamplingAttributes(display, attrs); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getDisplayPhysicalOrientation(int64_t display, |
| common::Transform* orientation) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->getDisplayPhysicalOrientation(display, orientation); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getHdrCapabilities(int64_t display, HdrCapabilities* caps) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->getHdrCapabilities(display, caps); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getOverlaySupport(OverlayProperties* caps) { |
| DEBUG_FUNC(); |
| auto err = mHal->getOverlaySupport(caps); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getMaxVirtualDisplayCount(int32_t* count) { |
| DEBUG_FUNC(); |
| auto err = mHal->getMaxVirtualDisplayCount(count); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getPerFrameMetadataKeys(int64_t display, |
| std::vector<PerFrameMetadataKey>* keys) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->getPerFrameMetadataKeys(display, keys); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getReadbackBufferAttributes(int64_t display, |
| ReadbackBufferAttributes* attrs) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->getReadbackBufferAttributes(display, attrs); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getReadbackBufferFence(int64_t display, |
| ndk::ScopedFileDescriptor* acquireFence) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->getReadbackBufferFence(display, acquireFence); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getRenderIntents(int64_t display, ColorMode mode, |
| std::vector<RenderIntent>* intents) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->getRenderIntents(display, mode, intents); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getSupportedContentTypes(int64_t display, |
| std::vector<ContentType>* types) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->getSupportedContentTypes(display, types); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getDisplayDecorationSupport(int64_t __unused display, |
| std::optional<common::DisplayDecorationSupport>* supportStruct) { |
| supportStruct->reset(); |
| return ndk::ScopedAStatus::ok(); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::registerCallback( |
| const std::shared_ptr<IComposerCallback>& callback) { |
| DEBUG_FUNC(); |
| // no locking as we require this function to be called only once |
| mHalEventCallback = std::make_unique<HalEventCallback>(mHal, mResources.get(), callback); |
| mHal->registerEventCallback(mHalEventCallback.get()); |
| return ndk::ScopedAStatus::ok(); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setActiveConfig(int64_t display, int32_t config) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->setActiveConfig(display, config); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setActiveConfigWithConstraints( |
| int64_t display, int32_t config, const VsyncPeriodChangeConstraints& constraints, |
| VsyncPeriodChangeTimeline* timeline) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->setActiveConfigWithConstraints(display, config, constraints, timeline); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setBootDisplayConfig(int64_t display, int32_t config) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->setBootDisplayConfig(display, config); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::clearBootDisplayConfig(int64_t display) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->clearBootDisplayConfig(display); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getPreferredBootDisplayConfig(int64_t display, int32_t* config) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->getPreferredBootDisplayConfig(display, config); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::getHdrConversionCapabilities( |
| std::vector<common::HdrConversionCapability>* hdrConversionCapabilities) { |
| DEBUG_FUNC(); |
| auto err = mHal->getHdrConversionCapabilities(hdrConversionCapabilities); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setHdrConversionStrategy( |
| const common::HdrConversionStrategy& hdrConversionStrategy, |
| common::Hdr* preferredHdrOutputType) { |
| DEBUG_FUNC(); |
| auto err = mHal->setHdrConversionStrategy(hdrConversionStrategy, preferredHdrOutputType); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setAutoLowLatencyMode(int64_t display, bool on) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->setAutoLowLatencyMode(display, on); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setClientTargetSlotCount(int64_t display, int32_t count) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mResources->setDisplayClientTargetCacheSize(display, count); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setColorMode(int64_t display, ColorMode mode, |
| RenderIntent intent) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->setColorMode(display, mode, intent); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setContentType(int64_t display, ContentType type) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->setContentType(display, type); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setDisplayedContentSamplingEnabled( |
| int64_t display, bool enable, FormatColorComponent componentMask, int64_t maxFrames) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->setDisplayedContentSamplingEnabled(display, enable, componentMask, maxFrames); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setPowerMode(int64_t display, PowerMode mode) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->setPowerMode(display, mode); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setReadbackBuffer( |
| int64_t display, const AidlNativeHandle& aidlBuffer, |
| const ndk::ScopedFileDescriptor& releaseFence) { |
| DEBUG_DISPLAY_FUNC(display); |
| buffer_handle_t readbackBuffer; |
| // Note ownership of the buffer is not passed to resource manager. |
| buffer_handle_t buffer = ::android::makeFromAidl(aidlBuffer); |
| auto bufReleaser = mResources->createReleaser(true /* isBuffer */); |
| auto err = mResources->getDisplayReadbackBuffer(display, buffer, |
| readbackBuffer, bufReleaser.get()); |
| if (!err) { |
| err = mHal->setReadbackBuffer(display, readbackBuffer, releaseFence); |
| } |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setVsyncEnabled(int64_t display, bool enabled) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->setVsyncEnabled(display, enabled); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setIdleTimerEnabled(int64_t display, int32_t timeout) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto err = mHal->setIdleTimerEnabled(display, timeout); |
| return TO_BINDER_STATUS(err); |
| } |
| |
| ndk::ScopedAStatus ComposerClient::setRefreshRateChangedCallbackDebugEnabled(int64_t /* display */, |
| bool /* enabled */) { |
| // TODO(b/267825022) Add implementation for the HAL and pass appropriate binder status |
| return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); |
| } |
| |
| void ComposerClient::HalEventCallback::onRefreshRateChangedDebug( |
| const RefreshRateChangedDebugData&) { |
| // TODO(b/267825022) Add implementation for the HAL |
| } |
| |
| void ComposerClient::HalEventCallback::onHotplug(int64_t display, bool connected) { |
| DEBUG_DISPLAY_FUNC(display); |
| if (connected) { |
| if (mResources->hasDisplay(display)) { |
| // This is a subsequent hotplug "connected" for a display. This signals a |
| // display change and thus the framework may want to reallocate buffers. We |
| // need to free all cached handles, since they are holding a strong reference |
| // to the underlying buffers. |
| cleanDisplayResources(display); |
| mResources->removeDisplay(display); |
| } |
| mResources->addPhysicalDisplay(display); |
| } else { |
| mResources->removeDisplay(display); |
| } |
| |
| auto ret = mCallback->onHotplug(display, connected); |
| if (!ret.isOk()) { |
| LOG(ERROR) << "failed to send onHotplug:" << ret.getDescription(); |
| } |
| } |
| |
| void ComposerClient::HalEventCallback::onRefresh(int64_t display) { |
| DEBUG_DISPLAY_FUNC(display); |
| mResources->setDisplayMustValidateState(display, true); |
| auto ret = mCallback->onRefresh(display); |
| if (!ret.isOk()) { |
| LOG(ERROR) << "failed to send onRefresh:" << ret.getDescription(); |
| } |
| } |
| |
| void ComposerClient::HalEventCallback::onVsync(int64_t display, int64_t timestamp, |
| int32_t vsyncPeriodNanos) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto ret = mCallback->onVsync(display, timestamp, vsyncPeriodNanos); |
| if (!ret.isOk()) { |
| LOG(ERROR) << "failed to send onVsync:" << ret.getDescription(); |
| } |
| } |
| |
| void ComposerClient::HalEventCallback::onVsyncPeriodTimingChanged( |
| int64_t display, const VsyncPeriodChangeTimeline& timeline) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto ret = mCallback->onVsyncPeriodTimingChanged(display, timeline); |
| if (!ret.isOk()) { |
| LOG(ERROR) << "failed to send onVsyncPeriodTimingChanged:" << ret.getDescription(); |
| } |
| } |
| |
| void ComposerClient::HalEventCallback::onVsyncIdle(int64_t display) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto ret = mCallback->onVsyncIdle(display); |
| if (!ret.isOk()) { |
| LOG(ERROR) << "failed to send onVsyncIdle:" << ret.getDescription(); |
| } |
| } |
| |
| void ComposerClient::HalEventCallback::onSeamlessPossible(int64_t display) { |
| DEBUG_DISPLAY_FUNC(display); |
| auto ret = mCallback->onSeamlessPossible(display); |
| if (!ret.isOk()) { |
| LOG(ERROR) << "failed to send onSealmessPossible:" << ret.getDescription(); |
| } |
| } |
| |
| void ComposerClient::HalEventCallback::cleanDisplayResources(int64_t display) { |
| DEBUG_DISPLAY_FUNC(display); |
| size_t cacheSize; |
| auto err = mResources->getDisplayClientTargetCacheSize(display, &cacheSize); |
| if (!err) { |
| for (int slot = 0; slot < cacheSize; slot++) { |
| // Replace the buffer slots with NULLs. Keep the old handle until it is |
| // replaced in ComposerHal, otherwise we risk leaving a dangling pointer. |
| buffer_handle_t outHandle; |
| auto bufReleaser = mResources->createReleaser(true /* isBuffer */); |
| err = mResources->getDisplayClientTarget(display, slot, /*useCache*/ true, |
| /*rawHandle*/ nullptr, outHandle, |
| bufReleaser.get()); |
| if (err) { |
| continue; |
| } |
| const std::vector<common::Rect> damage; |
| ndk::ScopedFileDescriptor fence; // empty fence |
| common::Dataspace dataspace = common::Dataspace::UNKNOWN; |
| err = mHal->setClientTarget(display, outHandle, fence, dataspace, damage); |
| if (err) { |
| LOG(ERROR) << "Can't clean slot " << slot |
| << " of the client target buffer cache for display" << display; |
| } |
| } |
| } else { |
| LOG(ERROR) << "Can't clean client target cache for display " << display; |
| } |
| |
| err = mResources->getDisplayOutputBufferCacheSize(display, &cacheSize); |
| if (!err) { |
| for (int slot = 0; slot < cacheSize; slot++) { |
| // Replace the buffer slots with NULLs. Keep the old handle until it is |
| // replaced in ComposerHal, otherwise we risk leaving a dangling pointer. |
| buffer_handle_t outputBuffer; |
| auto bufReleaser = mResources->createReleaser(true /* isBuffer */); |
| err = mResources->getDisplayOutputBuffer(display, slot, /*useCache*/ true, |
| /*rawHandle*/ nullptr, outputBuffer, |
| bufReleaser.get()); |
| if (err) { |
| continue; |
| } |
| ndk::ScopedFileDescriptor emptyFd; |
| err = mHal->setOutputBuffer(display, outputBuffer, /*fence*/ emptyFd); |
| if (err) { |
| LOG(ERROR) << "Can't clean slot " << slot |
| << " of the output buffer cache for display " << display; |
| } |
| } |
| } else { |
| LOG(ERROR) << "Can't clean output buffer cache for display " << display; |
| } |
| } |
| |
| void ComposerClient::destroyResources() { |
| DEBUG_FUNC(); |
| // We want to call hwc2_close here (and move hwc2_open to the |
| // constructor), with the assumption that hwc2_close would |
| // |
| // - clean up all resources owned by the client |
| // - make sure all displays are blank (since there is no layer) |
| // |
| // But since SF used to crash at this point, different hwcomposer2 |
| // implementations behave differently on hwc2_close. Our only portable |
| // choice really is to abort(). But that is not an option anymore |
| // because we might also have VTS or VR as clients that can come and go. |
| // |
| // Below we manually clean all resources (layers and virtual |
| // displays), and perform a presentDisplay afterwards. |
| mResources->clear([this](int64_t display, bool isVirtual, const std::vector<int64_t> layers) { |
| LOG(WARNING) << "destroying client resources for display " << display; |
| for (auto layer : layers) { |
| mHal->destroyLayer(display, layer); |
| } |
| |
| if (isVirtual) { |
| mHal->destroyVirtualDisplay(display); |
| } else { |
| LOG(WARNING) << "performing a final presentDisplay"; |
| std::vector<int64_t> changedLayers; |
| std::vector<Composition> compositionTypes; |
| uint32_t displayRequestMask = 0; |
| std::vector<int64_t> requestedLayers; |
| std::vector<int32_t> requestMasks; |
| ClientTargetProperty clientTargetProperty; |
| mHal->validateDisplay(display, &changedLayers, &compositionTypes, &displayRequestMask, |
| &requestedLayers, &requestMasks, &clientTargetProperty); |
| mHal->acceptDisplayChanges(display); |
| |
| ndk::ScopedFileDescriptor presentFence; |
| std::vector<int64_t> releasedLayers; |
| std::vector<ndk::ScopedFileDescriptor> releaseFences; |
| mHal->presentDisplay(display, presentFence, &releasedLayers, &releaseFences); |
| } |
| }); |
| mResources.reset(); |
| } |
| |
| ::ndk::SpAIBinder ComposerClient::createBinder() { |
| auto binder = BnComposerClient::createBinder(); |
| AIBinder_setInheritRt(binder.get(), true); |
| return binder; |
| } |
| |
| } // namespace aidl::android::hardware::graphics::composer3::impl |