|  | /* | 
|  | * 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/threads.h> | 
|  |  | 
|  | #include <binder/IPCThreadState.h> | 
|  |  | 
|  | #include <ui/GraphicBuffer.h> | 
|  | #include <ui/Rect.h> | 
|  | #include <ui/StaticDisplayInfo.h> | 
|  |  | 
|  | #include <gui/BufferQueueCore.h> | 
|  | #include <gui/BLASTBufferQueue.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, | 
|  | const sp<IGraphicBufferProducer>& gbp, int32_t layerId, | 
|  | uint32_t w, uint32_t h, PixelFormat format, uint32_t transform, | 
|  | uint32_t flags) | 
|  | : mClient(client), | 
|  | mHandle(handle), | 
|  | mGraphicBufferProducer(gbp), | 
|  | mLayerId(layerId), | 
|  | mTransformHint(transform), | 
|  | mWidth(w), | 
|  | mHeight(h), | 
|  | mFormat(format), | 
|  | mCreateFlags(flags) {} | 
|  |  | 
|  | SurfaceControl::SurfaceControl(const sp<SurfaceControl>& other) { | 
|  | mClient = other->mClient; | 
|  | mHandle = other->mHandle; | 
|  | mGraphicBufferProducer = other->mGraphicBufferProducer; | 
|  | mTransformHint = other->mTransformHint; | 
|  | mLayerId = other->mLayerId; | 
|  | mWidth = other->mWidth; | 
|  | mHeight = other->mHeight; | 
|  | 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("bbq-wrapper"), 0, 0, mFormat, | 
|  | flags, mHandle, {}, &ignore); | 
|  | mBbq = sp<BLASTBufferQueue>::make("bbq-adapter", mBbqChild, mWidth, mHeight, mFormat); | 
|  |  | 
|  | // This surface is always consumed by SurfaceFlinger, so the | 
|  | // producerControlledByApp value doesn't matter; using false. | 
|  | mSurfaceData = mBbq->getSurface(true); | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | 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.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; | 
|  | 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.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 = | 
|  | new SurfaceControl(new SurfaceComposerClient( | 
|  | interface_cast<ISurfaceComposerClient>(client)), | 
|  | handle.get(), nullptr, layerId, | 
|  | 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; | 
|  | } | 
|  |  | 
|  | // ---------------------------------------------------------------------------- | 
|  | }; // namespace android |