| /* | |
| * Copyright (C) 2007 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 LOG_TAG "SurfaceControl" | |
| #include <stdint.h> | |
| #include <errno.h> | |
| #include <sys/types.h> | |
| #include <sys/stat.h> | |
| #include <android/native_window.h> | |
| #include <utils/Errors.h> | |
| #include <utils/KeyedVector.h> | |
| #include <utils/Log.h> | |
| #include <utils/Looper.h> | |
| #include <utils/threads.h> | |
| #include <binder/IPCThreadState.h> | |
| #include <ui/GraphicBuffer.h> | |
| #include <ui/Rect.h> | |
| #include <ui/StaticDisplayInfo.h> | |
| #include <gui/BLASTBufferQueue.h> | |
| #include <gui/BufferQueueCore.h> | |
| #include <gui/Choreographer.h> | |
| #include <gui/ISurfaceComposer.h> | |
| #include <gui/Surface.h> | |
| #include <gui/SurfaceComposerClient.h> | |
| #include <gui/SurfaceControl.h> | |
| #include <private/gui/ParcelUtils.h> | |
| namespace android { | |
| // ============================================================================ | |
| // SurfaceControl | |
| // ============================================================================ | |
| SurfaceControl::SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle, | |
| int32_t layerId, const std::string& name, uint32_t w, uint32_t h, | |
| PixelFormat format, uint32_t transform, uint32_t flags) | |
| : mClient(client), | |
| mHandle(handle), | |
| mLayerId(layerId), | |
| mName(name), | |
| mTransformHint(transform), | |
| mWidth(w), | |
| mHeight(h), | |
| mFormat(format), | |
| mCreateFlags(flags) {} | |
| SurfaceControl::SurfaceControl(const sp<SurfaceControl>& other) { | |
| mClient = other->mClient; | |
| mHandle = other->mHandle; | |
| mTransformHint = other->mTransformHint; | |
| mLayerId = other->mLayerId; | |
| mName = other->mName; | |
| mWidth = other->mWidth; | |
| mHeight = other->mHeight; | |
| mFormat = other->mFormat; | |
| mCreateFlags = other->mCreateFlags; | |
| } | |
| SurfaceControl::~SurfaceControl() | |
| { | |
| // Trigger an IPC now, to make sure things | |
| // happen without delay, since these resources are quite heavy. | |
| mClient.clear(); | |
| mHandle.clear(); | |
| mBbq.clear(); | |
| IPCThreadState::self()->flushCommands(); | |
| } | |
| void SurfaceControl::disconnect() { | |
| if (getIGraphicBufferProducer() != nullptr) { | |
| getIGraphicBufferProducer()->disconnect( | |
| BufferQueueCore::CURRENTLY_CONNECTED_API); | |
| } | |
| } | |
| bool SurfaceControl::isSameSurface( | |
| const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs) | |
| { | |
| if (lhs == nullptr || rhs == nullptr) | |
| return false; | |
| return lhs->mHandle == rhs->mHandle; | |
| } | |
| status_t SurfaceControl::clearLayerFrameStats() const { | |
| status_t err = validate(); | |
| if (err != NO_ERROR) return err; | |
| const sp<SurfaceComposerClient>& client(mClient); | |
| return client->clearLayerFrameStats(mHandle); | |
| } | |
| status_t SurfaceControl::getLayerFrameStats(FrameStats* outStats) const { | |
| status_t err = validate(); | |
| if (err != NO_ERROR) return err; | |
| const sp<SurfaceComposerClient>& client(mClient); | |
| return client->getLayerFrameStats(mHandle, outStats); | |
| } | |
| status_t SurfaceControl::validate() const | |
| { | |
| if (mHandle==nullptr || mClient==nullptr) { | |
| ALOGE("invalid handle (%p) or client (%p)", | |
| mHandle.get(), mClient.get()); | |
| return NO_INIT; | |
| } | |
| return NO_ERROR; | |
| } | |
| status_t SurfaceControl::writeSurfaceToParcel( | |
| const sp<SurfaceControl>& control, Parcel* parcel) | |
| { | |
| sp<IGraphicBufferProducer> bp; | |
| if (control != nullptr) { | |
| bp = control->getIGraphicBufferProducer(); | |
| } | |
| return parcel->writeStrongBinder(IInterface::asBinder(bp)); | |
| } | |
| sp<Surface> SurfaceControl::generateSurfaceLocked() | |
| { | |
| uint32_t ignore; | |
| auto flags = mCreateFlags & (ISurfaceComposerClient::eCursorWindow | | |
| ISurfaceComposerClient::eOpaque); | |
| mBbqChild = mClient->createSurface(String8::format("[BBQ] %s", mName.c_str()), 0, 0, mFormat, | |
| flags, mHandle, {}, &ignore); | |
| mBbq = sp<BLASTBufferQueue>::make("[BBQ] " + mName, /* updateDestinationFrame */ true); | |
| mBbq->update(mBbqChild, mWidth, mHeight, mFormat); | |
| // This surface is always consumed by SurfaceFlinger, so the | |
| // producerControlledByApp value doesn't matter; using false. | |
| mSurfaceData = mBbq->getSurface(true); | |
| if (Surface::IsCursorPlaneCompatibilitySupported()) { | |
| mSurfaceData->setIsForCursor(flags & ISurfaceComposerClient::eCursorWindow); | |
| } | |
| return mSurfaceData; | |
| } | |
| sp<Surface> SurfaceControl::getSurface() | |
| { | |
| Mutex::Autolock _l(mLock); | |
| if (mSurfaceData == nullptr) { | |
| return generateSurfaceLocked(); | |
| } | |
| return mSurfaceData; | |
| } | |
| sp<Surface> SurfaceControl::createSurface() | |
| { | |
| return getSurface(); | |
| } | |
| void SurfaceControl::updateDefaultBufferSize(uint32_t width, uint32_t height) { | |
| Mutex::Autolock _l(mLock); | |
| mWidth = width; | |
| mHeight = height; | |
| if (mBbq) { | |
| mBbq->update(mBbqChild, width, height, mFormat); | |
| } | |
| } | |
| sp<IBinder> SurfaceControl::getLayerStateHandle() const | |
| { | |
| return mHandle; | |
| } | |
| sp<IBinder> SurfaceControl::getHandle() const { | |
| if (mBbqChild != nullptr) { | |
| return mBbqChild->getHandle(); | |
| } | |
| return getLayerStateHandle(); | |
| } | |
| int32_t SurfaceControl::getLayerId() const { | |
| return mLayerId; | |
| } | |
| const std::string& SurfaceControl::getName() const { | |
| return mName; | |
| } | |
| std::shared_ptr<Choreographer> SurfaceControl::getChoreographer() { | |
| if (mChoreographer) { | |
| return mChoreographer; | |
| } | |
| sp<Looper> looper = Looper::getForThread(); | |
| if (!looper.get()) { | |
| ALOGE("%s: No looper prepared for thread", __func__); | |
| return nullptr; | |
| } | |
| mChoreographer = std::make_shared<Choreographer>(looper, getHandle()); | |
| status_t result = mChoreographer->initialize(); | |
| if (result != OK) { | |
| ALOGE("Failed to initialize choreographer"); | |
| mChoreographer = nullptr; | |
| } | |
| return mChoreographer; | |
| } | |
| sp<IGraphicBufferProducer> SurfaceControl::getIGraphicBufferProducer() | |
| { | |
| getSurface(); | |
| Mutex::Autolock _l(mLock); | |
| return mBbq->getIGraphicBufferProducer(); | |
| } | |
| sp<SurfaceComposerClient> SurfaceControl::getClient() const | |
| { | |
| return mClient; | |
| } | |
| uint32_t SurfaceControl::getTransformHint() const { | |
| Mutex::Autolock _l(mLock); | |
| return mTransformHint; | |
| } | |
| void SurfaceControl::setTransformHint(uint32_t hint) { | |
| Mutex::Autolock _l(mLock); | |
| mTransformHint = hint; | |
| } | |
| status_t SurfaceControl::writeToParcel(Parcel& parcel) { | |
| SAFE_PARCEL(parcel.writeStrongBinder, ISurfaceComposerClient::asBinder(mClient->getClient())); | |
| SAFE_PARCEL(parcel.writeStrongBinder, mHandle); | |
| SAFE_PARCEL(parcel.writeInt32, mLayerId); | |
| SAFE_PARCEL(parcel.writeUtf8AsUtf16, mName); | |
| SAFE_PARCEL(parcel.writeUint32, mTransformHint); | |
| SAFE_PARCEL(parcel.writeUint32, mWidth); | |
| SAFE_PARCEL(parcel.writeUint32, mHeight); | |
| SAFE_PARCEL(parcel.writeUint32, mFormat); | |
| return NO_ERROR; | |
| } | |
| status_t SurfaceControl::readFromParcel(const Parcel& parcel, | |
| sp<SurfaceControl>* outSurfaceControl) { | |
| sp<IBinder> client; | |
| sp<IBinder> handle; | |
| int32_t layerId; | |
| std::string layerName; | |
| uint32_t transformHint; | |
| uint32_t width; | |
| uint32_t height; | |
| uint32_t format; | |
| SAFE_PARCEL(parcel.readStrongBinder, &client); | |
| SAFE_PARCEL(parcel.readStrongBinder, &handle); | |
| SAFE_PARCEL(parcel.readInt32, &layerId); | |
| SAFE_PARCEL(parcel.readUtf8FromUtf16, &layerName); | |
| SAFE_PARCEL(parcel.readUint32, &transformHint); | |
| SAFE_PARCEL(parcel.readUint32, &width); | |
| SAFE_PARCEL(parcel.readUint32, &height); | |
| SAFE_PARCEL(parcel.readUint32, &format); | |
| // We aren't the original owner of the surface. | |
| *outSurfaceControl = | |
| sp<SurfaceControl>::make(sp<SurfaceComposerClient>::make( | |
| interface_cast<ISurfaceComposerClient>(client)), | |
| handle, layerId, layerName, width, height, format, | |
| transformHint); | |
| return NO_ERROR; | |
| } | |
| status_t SurfaceControl::readNullableFromParcel(const Parcel& parcel, | |
| sp<SurfaceControl>* outSurfaceControl) { | |
| bool isNotNull; | |
| SAFE_PARCEL(parcel.readBool, &isNotNull); | |
| if (isNotNull) { | |
| SAFE_PARCEL(SurfaceControl::readFromParcel, parcel, outSurfaceControl); | |
| } | |
| return NO_ERROR; | |
| } | |
| status_t SurfaceControl::writeNullableToParcel(Parcel& parcel, | |
| const sp<SurfaceControl>& surfaceControl) { | |
| auto isNotNull = surfaceControl != nullptr; | |
| SAFE_PARCEL(parcel.writeBool, isNotNull); | |
| if (isNotNull) { | |
| SAFE_PARCEL(surfaceControl->writeToParcel, parcel); | |
| } | |
| return NO_ERROR; | |
| } | |
| sp<SurfaceControl> SurfaceControl::getParentingLayer() { | |
| if (mBbqChild != nullptr) { | |
| return mBbqChild; | |
| } | |
| return this; | |
| } | |
| uint64_t SurfaceControl::resolveFrameNumber(const std::optional<uint64_t>& frameNumber) { | |
| if (frameNumber.has_value()) { | |
| auto ret = frameNumber.value(); | |
| // Set the fallback to something far enough ahead that in the unlikely event of mixed | |
| // "real" frame numbers and fallback frame numbers, we still won't collide in any | |
| // meaningful capacity | |
| mFallbackFrameNumber = ret + 100; | |
| return ret; | |
| } else { | |
| return mFallbackFrameNumber++; | |
| } | |
| } | |
| // ---------------------------------------------------------------------------- | |
| }; // namespace android |