diff options
Diffstat (limited to 'libs')
229 files changed, 10710 insertions, 4824 deletions
diff --git a/libs/arect/include/android/rect.h b/libs/arect/include/android/rect.h index 80741c0442..b36728e934 100644 --- a/libs/arect/include/android/rect.h +++ b/libs/arect/include/android/rect.h @@ -33,23 +33,26 @@ extern "C" { #endif /** - * {@link ARect} is a struct that represents a rectangular window area. + * Rectangular window area. * - * It is used with {@link - * ANativeActivityCallbacks::onContentRectChanged} event callback and - * ANativeWindow_lock() function. + * This is the NDK equivalent of the android.graphics.Rect class in Java. It is + * used with {@link ANativeActivityCallbacks::onContentRectChanged} event + * callback and the ANativeWindow_lock() function. + * + * In a valid ARect, left <= right and top <= bottom. ARect with left=0, top=10, + * right=1, bottom=11 contains only one pixel at x=0, y=10. */ typedef struct ARect { #ifdef __cplusplus typedef int32_t value_type; #endif - /** left position */ + /// Minimum X coordinate of the rectangle. int32_t left; - /** top position */ + /// Minimum Y coordinate of the rectangle. int32_t top; - /** left position */ + /// Maximum X coordinate of the rectangle. int32_t right; - /** bottom position */ + /// Maximum Y coordinate of the rectangle. int32_t bottom; } ARect; diff --git a/libs/binder/ActivityManager.cpp b/libs/binder/ActivityManager.cpp new file mode 100644 index 0000000000..2728f35408 --- /dev/null +++ b/libs/binder/ActivityManager.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2017 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. + */ + +#include <mutex> +#include <unistd.h> + +#include <binder/ActivityManager.h> +#include <binder/Binder.h> +#include <binder/IServiceManager.h> + +#include <utils/SystemClock.h> + +namespace android { + +ActivityManager::ActivityManager() +{ +} + +sp<IActivityManager> ActivityManager::getService() +{ + std::lock_guard<Mutex> scoped_lock(mLock); + int64_t startTime = 0; + sp<IActivityManager> service = mService; + while (service == NULL || !IInterface::asBinder(service)->isBinderAlive()) { + sp<IBinder> binder = defaultServiceManager()->checkService(String16("activity")); + if (binder == NULL) { + // Wait for the activity service to come back... + if (startTime == 0) { + startTime = uptimeMillis(); + ALOGI("Waiting for activity service"); + } else if ((uptimeMillis() - startTime) > 1000000) { + ALOGW("Waiting too long for activity service, giving up"); + service = NULL; + break; + } + usleep(25000); + } else { + service = interface_cast<IActivityManager>(binder); + mService = service; + } + } + return service; +} + +int ActivityManager::openContentUri(const String16& stringUri) +{ + sp<IActivityManager> service = getService(); + return service != NULL ? service->openContentUri(stringUri) : -1; +} + +void ActivityManager::registerUidObserver(const sp<IUidObserver>& observer, + const int32_t event, + const int32_t cutpoint, + const String16& callingPackage) +{ + sp<IActivityManager> service = getService(); + if (service != NULL) { + service->registerUidObserver(observer, event, cutpoint, callingPackage); + } +} + +void ActivityManager::unregisterUidObserver(const sp<IUidObserver>& observer) +{ + sp<IActivityManager> service = getService(); + if (service != NULL) { + service->unregisterUidObserver(observer); + } +} + +bool ActivityManager::isUidActive(const uid_t uid, const String16& callingPackage) +{ + sp<IActivityManager> service = getService(); + if (service != NULL) { + return service->isUidActive(uid, callingPackage); + } + return false; +} + +status_t ActivityManager::linkToDeath(const sp<IBinder::DeathRecipient>& recipient) { + sp<IActivityManager> service = getService(); + if (service != NULL) { + return IInterface::asBinder(service)->linkToDeath(recipient); + } + return INVALID_OPERATION; +} + +status_t ActivityManager::unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient) { + sp<IActivityManager> service = getService(); + if (service != NULL) { + return IInterface::asBinder(service)->unlinkToDeath(recipient); + } + return INVALID_OPERATION; +} + +}; // namespace android diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index d4db8c81b4..b8d6c78f6a 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -39,6 +39,7 @@ cc_library { double_loadable: true, srcs: [ + "ActivityManager.cpp", "AppOpsManager.cpp", "Binder.cpp", "BpBinder.cpp", @@ -57,11 +58,13 @@ cc_library { "IResultReceiver.cpp", "IServiceManager.cpp", "IShellCallback.cpp", + "IUidObserver.cpp", "MemoryBase.cpp", "MemoryDealer.cpp", "MemoryHeapBase.cpp", "Parcel.cpp", "PermissionCache.cpp", + "PermissionController.cpp", "PersistableBundle.cpp", "ProcessInfoService.cpp", "ProcessState.cpp", @@ -73,6 +76,28 @@ cc_library { ":libbinder_aidl", ], + target: { + vendor: { + exclude_srcs: [ + "ActivityManager.cpp", + "AppOpsManager.cpp", + "IActivityManager.cpp", + "IAppOpsCallback.cpp", + "IAppOpsService.cpp", + "IBatteryStats.cpp", + "IMediaResourceMonitor.cpp", + "IPermissionController.cpp", + "IProcessInfoService.cpp", + "IUidObserver.cpp", + "PermissionCache.cpp", + "PermissionController.cpp", + "ProcessInfoService.cpp", + "IpPrefix.cpp", + ":libbinder_aidl", + ], + }, + }, + aidl: { export_aidl_headers: true, }, diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp index 4a9b9a7608..a494e22392 100644 --- a/libs/binder/AppOpsManager.cpp +++ b/libs/binder/AppOpsManager.cpp @@ -100,11 +100,12 @@ int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPa : APP_OPS_MANAGER_UNAVAILABLE_MODE; } -int32_t AppOpsManager::startOp(int32_t op, int32_t uid, const String16& callingPackage) { +int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, + bool startIfModeDefault) { sp<IAppOpsService> service = getService(); return service != nullptr - ? service->startOperation(getToken(service), op, uid, callingPackage) - : APP_OPS_MANAGER_UNAVAILABLE_MODE; + ? service->startOperation(getToken(service), op, uid, callingPackage, + startIfModeDefault) : APP_OPS_MANAGER_UNAVAILABLE_MODE; } void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage) { diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index 49ff46033c..734212626a 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -21,6 +21,7 @@ #include <binder/IPCThreadState.h> #include <binder/IResultReceiver.h> +#include <cutils/compiler.h> #include <utils/Log.h> #include <stdio.h> @@ -32,6 +33,23 @@ namespace android { // --------------------------------------------------------------------------- +Mutex BpBinder::sTrackingLock; +std::unordered_map<int32_t,uint32_t> BpBinder::sTrackingMap; +int BpBinder::sNumTrackedUids = 0; +std::atomic_bool BpBinder::sCountByUidEnabled(false); +binder_proxy_limit_callback BpBinder::sLimitCallback; +bool BpBinder::sBinderProxyThrottleCreate = false; + +// Arbitrarily high value that probably distinguishes a bad behaving app +uint32_t BpBinder::sBinderProxyCountHighWatermark = 2500; +// Another arbitrary value a binder count needs to drop below before another callback will be called +uint32_t BpBinder::sBinderProxyCountLowWatermark = 2000; + +enum { + LIMIT_REACHED_MASK = 0x80000000, // A flag denoting that the limit has been reached + COUNTING_VALUE_MASK = 0x7FFFFFFF, // A mask of the remaining bits for the count value +}; + BpBinder::ObjectManager::ObjectManager() { } @@ -87,16 +105,47 @@ void BpBinder::ObjectManager::kill() // --------------------------------------------------------------------------- -BpBinder::BpBinder(int32_t handle) + +BpBinder* BpBinder::create(int32_t handle) { + int32_t trackedUid = -1; + if (sCountByUidEnabled) { + trackedUid = IPCThreadState::self()->getCallingUid(); + AutoMutex _l(sTrackingLock); + uint32_t trackedValue = sTrackingMap[trackedUid]; + if (CC_UNLIKELY(trackedValue & LIMIT_REACHED_MASK)) { + if (sBinderProxyThrottleCreate) { + return nullptr; + } + } else { + if ((trackedValue & COUNTING_VALUE_MASK) >= sBinderProxyCountHighWatermark) { + ALOGE("Too many binder proxy objects sent to uid %d from uid %d (%d proxies held)", + getuid(), trackedUid, trackedValue); + sTrackingMap[trackedUid] |= LIMIT_REACHED_MASK; + if (sLimitCallback) sLimitCallback(trackedUid); + if (sBinderProxyThrottleCreate) { + ALOGI("Throttling binder proxy creates from uid %d in uid %d until binder proxy" + " count drops below %d", + trackedUid, getuid(), sBinderProxyCountLowWatermark); + return nullptr; + } + } + } + sTrackingMap[trackedUid]++; + } + return new BpBinder(handle, trackedUid); +} + +BpBinder::BpBinder(int32_t handle, int32_t trackedUid) : mHandle(handle) , mAlive(1) , mObitsSent(0) , mObituaries(nullptr) + , mTrackedUid(trackedUid) { ALOGV("Creating BpBinder %p handle %d\n", this, mHandle); extendObjectLifetime(OBJECT_LIFETIME_WEAK); - IPCThreadState::self()->incWeakHandle(handle); + IPCThreadState::self()->incWeakHandle(handle, this); } bool BpBinder::isDescriptorCached() const { @@ -315,6 +364,26 @@ BpBinder::~BpBinder() IPCThreadState* ipc = IPCThreadState::self(); + if (mTrackedUid >= 0) { + AutoMutex _l(sTrackingLock); + uint32_t trackedValue = sTrackingMap[mTrackedUid]; + if (CC_UNLIKELY((trackedValue & COUNTING_VALUE_MASK) == 0)) { + ALOGE("Unexpected Binder Proxy tracking decrement in %p handle %d\n", this, mHandle); + } else { + if (CC_UNLIKELY( + (trackedValue & LIMIT_REACHED_MASK) && + ((trackedValue & COUNTING_VALUE_MASK) <= sBinderProxyCountLowWatermark) + )) { + ALOGI("Limit reached bit reset for uid %d (fewer than %d proxies from uid %d held)", + getuid(), mTrackedUid, sBinderProxyCountLowWatermark); + sTrackingMap[mTrackedUid] &= ~LIMIT_REACHED_MASK; + } + if (--sTrackingMap[mTrackedUid] == 0) { + sTrackingMap.erase(mTrackedUid); + } + } + } + mLock.lock(); Vector<Obituary>* obits = mObituaries; if(obits != nullptr) { @@ -340,7 +409,7 @@ void BpBinder::onFirstRef() { ALOGV("onFirstRef BpBinder %p handle %d\n", this, mHandle); IPCThreadState* ipc = IPCThreadState::self(); - if (ipc) ipc->incStrongHandle(mHandle); + if (ipc) ipc->incStrongHandle(mHandle, this); } void BpBinder::onLastStrongRef(const void* /*id*/) @@ -360,6 +429,42 @@ bool BpBinder::onIncStrongAttempted(uint32_t /*flags*/, const void* /*id*/) return ipc ? ipc->attemptIncStrongHandle(mHandle) == NO_ERROR : false; } +uint32_t BpBinder::getBinderProxyCount(uint32_t uid) +{ + AutoMutex _l(sTrackingLock); + auto it = sTrackingMap.find(uid); + if (it != sTrackingMap.end()) { + return it->second & COUNTING_VALUE_MASK; + } + return 0; +} + +void BpBinder::getCountByUid(Vector<uint32_t>& uids, Vector<uint32_t>& counts) +{ + AutoMutex _l(sTrackingLock); + uids.setCapacity(sTrackingMap.size()); + counts.setCapacity(sTrackingMap.size()); + for (const auto& it : sTrackingMap) { + uids.push_back(it.first); + counts.push_back(it.second & COUNTING_VALUE_MASK); + } +} + +void BpBinder::enableCountByUid() { sCountByUidEnabled.store(true); } +void BpBinder::disableCountByUid() { sCountByUidEnabled.store(false); } +void BpBinder::setCountByUidEnabled(bool enable) { sCountByUidEnabled.store(enable); } + +void BpBinder::setLimitCallback(binder_proxy_limit_callback cb) { + AutoMutex _l(sTrackingLock); + sLimitCallback = cb; +} + +void BpBinder::setBinderProxyCountWatermarks(int high, int low) { + AutoMutex _l(sTrackingLock); + sBinderProxyCountHighWatermark = high; + sBinderProxyCountLowWatermark = low; +} + // --------------------------------------------------------------------------- }; // namespace android diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp index 50a8b28aae..428db4d579 100644 --- a/libs/binder/IActivityManager.cpp +++ b/libs/binder/IActivityManager.cpp @@ -56,6 +56,40 @@ public: } return fd; } + + virtual void registerUidObserver(const sp<IUidObserver>& observer, + const int32_t event, + const int32_t cutpoint, + const String16& callingPackage) + { + Parcel data, reply; + data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor()); + data.writeStrongBinder(IInterface::asBinder(observer)); + data.writeInt32(event); + data.writeInt32(cutpoint); + data.writeString16(callingPackage); + remote()->transact(REGISTER_UID_OBSERVER_TRANSACTION, data, &reply); + } + + virtual void unregisterUidObserver(const sp<IUidObserver>& observer) + { + Parcel data, reply; + data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor()); + data.writeStrongBinder(IInterface::asBinder(observer)); + remote()->transact(UNREGISTER_UID_OBSERVER_TRANSACTION, data, &reply); + } + + virtual bool isUidActive(const uid_t uid, const String16& callingPackage) + { + Parcel data, reply; + data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor()); + data.writeInt32(uid); + data.writeString16(callingPackage); + remote()->transact(IS_UID_ACTIVE_TRANSACTION, data, &reply); + // fail on exception + if (reply.readExceptionCode() != 0) return false; + return reply.readInt32() == 1; + } }; // ------------------------------------------------------------------------------------ diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp index c38568c40f..068664b418 100644 --- a/libs/binder/IAppOpsService.cpp +++ b/libs/binder/IAppOpsService.cpp @@ -61,13 +61,14 @@ public: } virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid, - const String16& packageName) { + const String16& packageName, bool startIfModeDefault) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); data.writeStrongBinder(token); data.writeInt32(code); data.writeInt32(uid); data.writeString16(packageName); + data.writeInt32(startIfModeDefault ? 1 : 0); remote()->transact(START_OPERATION_TRANSACTION, data, &reply); // fail on exception if (reply.readExceptionCode() != 0) return MODE_ERRORED; @@ -159,7 +160,8 @@ status_t BnAppOpsService::onTransact( int32_t code = data.readInt32(); int32_t uid = data.readInt32(); String16 packageName = data.readString16(); - int32_t res = startOperation(token, code, uid, packageName); + bool startIfModeDefault = data.readInt32() == 1; + int32_t res = startOperation(token, code, uid, packageName, startIfModeDefault); reply->writeNoException(); reply->writeInt32(res); return NO_ERROR; diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 33ec65f10e..b2217b5333 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -409,6 +409,15 @@ void IPCThreadState::flushCommands() if (mProcess->mDriverFD <= 0) return; talkWithDriver(false); + // The flush could have caused post-write refcount decrements to have + // been executed, which in turn could result in BC_RELEASE/BC_DECREFS + // being queued in mOut. So flush again, if we need to. + if (mOut.dataSize() > 0) { + talkWithDriver(false); + } + if (mOut.dataSize() > 0) { + ALOGW("mOut.dataSize() > 0 after flushCommands()"); + } } void IPCThreadState::blockUntilThreadAvailable() @@ -501,6 +510,21 @@ void IPCThreadState::processPendingDerefs() } } +void IPCThreadState::processPostWriteDerefs() +{ + for (size_t i = 0; i < mPostWriteWeakDerefs.size(); i++) { + RefBase::weakref_type* refs = mPostWriteWeakDerefs[i]; + refs->decWeak(mProcess.get()); + } + mPostWriteWeakDerefs.clear(); + + for (size_t i = 0; i < mPostWriteStrongDerefs.size(); i++) { + RefBase* obj = mPostWriteStrongDerefs[i]; + obj->decStrong(mProcess.get()); + } + mPostWriteStrongDerefs.clear(); +} + void IPCThreadState::joinThreadPool(bool isMain) { LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid()); @@ -627,11 +651,14 @@ status_t IPCThreadState::transact(int32_t handle, return err; } -void IPCThreadState::incStrongHandle(int32_t handle) +void IPCThreadState::incStrongHandle(int32_t handle, BpBinder *proxy) { LOG_REMOTEREFS("IPCThreadState::incStrongHandle(%d)\n", handle); mOut.writeInt32(BC_ACQUIRE); mOut.writeInt32(handle); + // Create a temp reference until the driver has handled this command. + proxy->incStrong(mProcess.get()); + mPostWriteStrongDerefs.push(proxy); } void IPCThreadState::decStrongHandle(int32_t handle) @@ -641,11 +668,14 @@ void IPCThreadState::decStrongHandle(int32_t handle) mOut.writeInt32(handle); } -void IPCThreadState::incWeakHandle(int32_t handle) +void IPCThreadState::incWeakHandle(int32_t handle, BpBinder *proxy) { LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)\n", handle); mOut.writeInt32(BC_INCREFS); mOut.writeInt32(handle); + // Create a temp reference until the driver has handled this command. + proxy->getWeakRefs()->incWeak(mProcess.get()); + mPostWriteWeakDerefs.push(proxy->getWeakRefs()); } void IPCThreadState::decWeakHandle(int32_t handle) @@ -897,8 +927,10 @@ status_t IPCThreadState::talkWithDriver(bool doReceive) if (bwr.write_consumed > 0) { if (bwr.write_consumed < mOut.dataSize()) mOut.remove(0, bwr.write_consumed); - else + else { mOut.setDataSize(0); + processPostWriteDerefs(); + } } if (bwr.read_consumed > 0) { mIn.setDataSize(bwr.read_consumed); diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp index 674bddf218..89ebc6c1aa 100644 --- a/libs/binder/IPermissionController.cpp +++ b/libs/binder/IPermissionController.cpp @@ -49,6 +49,19 @@ public: return reply.readInt32() != 0; } + virtual int32_t noteOp(const String16& op, int32_t uid, const String16& packageName) + { + Parcel data, reply; + data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor()); + data.writeString16(op); + data.writeInt32(uid); + data.writeString16(packageName); + remote()->transact(NOTE_OP_TRANSACTION, data, &reply); + // fail on exception + if (reply.readExceptionCode() != 0) return 2; // MODE_ERRORED + return reply.readInt32(); + } + virtual void getPackagesForUid(const uid_t uid, Vector<String16>& packages) { Parcel data, reply; @@ -78,6 +91,18 @@ public: if (reply.readExceptionCode() != 0) return false; return reply.readInt32() != 0; } + + virtual int getPackageUid(const String16& package, int flags) + { + Parcel data, reply; + data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor()); + data.writeString16(package); + data.writeInt32(flags); + remote()->transact(GET_PACKAGE_UID_TRANSACTION, data, &reply); + // fail on exception + if (reply.readExceptionCode() != 0) return false; + return reply.readInt32(); + } }; IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController"); @@ -99,6 +124,17 @@ status_t BnPermissionController::onTransact( return NO_ERROR; } break; + case NOTE_OP_TRANSACTION: { + CHECK_INTERFACE(IPermissionController, data, reply); + String16 op = data.readString16(); + int32_t uid = data.readInt32(); + String16 packageName = data.readString16(); + int32_t res = noteOp(op, uid, packageName); + reply->writeNoException(); + reply->writeInt32(res); + return NO_ERROR; + } break; + case GET_PACKAGES_FOR_UID_TRANSACTION: { CHECK_INTERFACE(IPermissionController, data, reply); int32_t uid = data.readInt32(); @@ -122,6 +158,16 @@ status_t BnPermissionController::onTransact( return NO_ERROR; } break; + case GET_PACKAGE_UID_TRANSACTION: { + CHECK_INTERFACE(IPermissionController, data, reply); + String16 package = data.readString16(); + int flags = data.readInt32(); + const int uid = getPackageUid(package, flags); + reply->writeNoException(); + reply->writeInt32(uid); + return NO_ERROR; + } break; + default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 001dc9e6cd..17e098c541 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -20,7 +20,11 @@ #include <utils/Log.h> #include <binder/IPCThreadState.h> +#ifndef __ANDROID_VNDK__ +#include <binder/IPermissionController.h> +#endif #include <binder/Parcel.h> +#include <cutils/properties.h> #include <utils/String8.h> #include <utils/SystemClock.h> #include <utils/CallStack.h> @@ -48,6 +52,9 @@ sp<IServiceManager> defaultServiceManager() return gDefaultServiceManager; } +#ifndef __ANDROID_VNDK__ +// IPermissionController is not accessible to vendors + bool checkCallingPermission(const String16& permission) { return checkCallingPermission(permission, nullptr, nullptr); @@ -122,6 +129,8 @@ bool checkPermission(const String16& permission, pid_t pid, uid_t uid) } } +#endif //__ANDROID_VNDK__ + // ---------------------------------------------------------------------- class BpServiceManager : public BpInterface<IServiceManager> @@ -134,20 +143,35 @@ public: virtual sp<IBinder> getService(const String16& name) const { - unsigned n; - for (n = 0; n < 5; n++){ - if (n > 0) { - if (!strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder")) { - ALOGI("Waiting for vendor service %s...", String8(name).string()); - CallStack stack(LOG_TAG); - } else { - ALOGI("Waiting for service %s...", String8(name).string()); - } - sleep(1); + sp<IBinder> svc = checkService(name); + if (svc != nullptr) return svc; + + const bool isVendorService = + strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0; + const long timeout = uptimeMillis() + 5000; + if (!gSystemBootCompleted) { + char bootCompleted[PROPERTY_VALUE_MAX]; + property_get("sys.boot_completed", bootCompleted, "0"); + gSystemBootCompleted = strcmp(bootCompleted, "1") == 0 ? true : false; + } + // retry interval in millisecond. + const long sleepTime = gSystemBootCompleted ? 1000 : 100; + + int n = 0; + while (uptimeMillis() < timeout) { + n++; + if (isVendorService) { + ALOGI("Waiting for vendor service %s...", String8(name).string()); + CallStack stack(LOG_TAG); + } else if (n%10 == 0) { + ALOGI("Waiting for service %s...", String8(name).string()); } + usleep(1000*sleepTime); + sp<IBinder> svc = checkService(name); if (svc != nullptr) return svc; } + ALOGW("Service %s didn't start. Returning NULL", String8(name).string()); return nullptr; } @@ -161,19 +185,18 @@ public: } virtual status_t addService(const String16& name, const sp<IBinder>& service, - bool allowIsolated) - { + bool allowIsolated, int dumpsysPriority) { Parcel data, reply; data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); data.writeString16(name); data.writeStrongBinder(service); data.writeInt32(allowIsolated ? 1 : 0); + data.writeInt32(dumpsysPriority); status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply); return err == NO_ERROR ? reply.readExceptionCode() : err; } - virtual Vector<String16> listServices() - { + virtual Vector<String16> listServices(int dumpsysPriority) { Vector<String16> res; int n = 0; @@ -181,6 +204,7 @@ public: Parcel data, reply; data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); data.writeInt32(n++); + data.writeInt32(dumpsysPriority); status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply); if (err != NO_ERROR) break; diff --git a/libs/binder/IShellCallback.cpp b/libs/binder/IShellCallback.cpp index 4568a426cd..dd4a65ee84 100644 --- a/libs/binder/IShellCallback.cpp +++ b/libs/binder/IShellCallback.cpp @@ -39,11 +39,13 @@ public: { } - virtual int openOutputFile(const String16& path, const String16& seLinuxContext) { + virtual int openFile(const String16& path, const String16& seLinuxContext, + const String16& mode) { Parcel data, reply; data.writeInterfaceToken(IShellCallback::getInterfaceDescriptor()); data.writeString16(path); data.writeString16(seLinuxContext); + data.writeString16(mode); remote()->transact(OP_OPEN_OUTPUT_FILE, data, &reply, 0); reply.readExceptionCode(); int fd = reply.readParcelFileDescriptor(); @@ -64,7 +66,8 @@ status_t BnShellCallback::onTransact( CHECK_INTERFACE(IShellCallback, data, reply); String16 path(data.readString16()); String16 seLinuxContext(data.readString16()); - int fd = openOutputFile(path, seLinuxContext); + String16 mode(data.readString16()); + int fd = openFile(path, seLinuxContext, mode); if (reply != nullptr) { reply->writeNoException(); if (fd >= 0) { diff --git a/libs/binder/IUidObserver.cpp b/libs/binder/IUidObserver.cpp new file mode 100644 index 0000000000..697e948a6d --- /dev/null +++ b/libs/binder/IUidObserver.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2017 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. + */ + +#include <binder/IUidObserver.h> + +#include <binder/Parcel.h> + +namespace android { + +// ------------------------------------------------------------------------------------ + +class BpUidObserver : public BpInterface<IUidObserver> +{ +public: + explicit BpUidObserver(const sp<IBinder>& impl) + : BpInterface<IUidObserver>(impl) + { + } + + virtual void onUidGone(uid_t uid, bool disabled) + { + Parcel data, reply; + data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor()); + data.writeInt32((int32_t) uid); + data.writeInt32(disabled ? 1 : 0); + remote()->transact(ON_UID_GONE_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY); + } + + virtual void onUidActive(uid_t uid) + { + Parcel data, reply; + data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor()); + data.writeInt32((int32_t) uid); + remote()->transact(ON_UID_ACTIVE_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY); + } + + virtual void onUidIdle(uid_t uid, bool disabled) + { + Parcel data, reply; + data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor()); + data.writeInt32((int32_t) uid); + data.writeInt32(disabled ? 1 : 0); + remote()->transact(ON_UID_IDLE_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY); + } +}; + +// ---------------------------------------------------------------------- + +IMPLEMENT_META_INTERFACE(UidObserver, "android.app.IUidObserver"); + +// ---------------------------------------------------------------------- + +status_t BnUidObserver::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case ON_UID_GONE_TRANSACTION: { + CHECK_INTERFACE(IUidObserver, data, reply); + uid_t uid = data.readInt32(); + bool disabled = data.readInt32() == 1; + onUidGone(uid, disabled); + return NO_ERROR; + } break; + + case ON_UID_ACTIVE_TRANSACTION: { + CHECK_INTERFACE(IUidObserver, data, reply); + uid_t uid = data.readInt32(); + onUidActive(uid); + return NO_ERROR; + } break; + + case ON_UID_IDLE_TRANSACTION: { + CHECK_INTERFACE(IUidObserver, data, reply); + uid_t uid = data.readInt32(); + bool disabled = data.readInt32() == 1; + onUidIdle(uid, disabled); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +}; // namespace android diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 03aef1791c..eb8188b3ca 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -433,6 +433,7 @@ void Parcel::setDataPosition(size_t pos) const mDataPos = pos; mNextObjectHint = 0; + mObjectsSorted = false; } status_t Parcel::setDataCapacity(size_t size) @@ -1276,7 +1277,7 @@ status_t Parcel::write(const FlattenableHelperInterface& val) if (err) return err; // payload - void* const buf = this->writeInplace(pad_size(len)); + void* const buf = this->writeInplace(len); if (buf == nullptr) return BAD_VALUE; @@ -1469,6 +1470,59 @@ void Parcel::remove(size_t /*start*/, size_t /*amt*/) LOG_ALWAYS_FATAL("Parcel::remove() not yet implemented!"); } +status_t Parcel::validateReadData(size_t upperBound) const +{ + // Don't allow non-object reads on object data + if (mObjectsSorted || mObjectsSize <= 1) { +data_sorted: + // Expect to check only against the next object + if (mNextObjectHint < mObjectsSize && upperBound > mObjects[mNextObjectHint]) { + // For some reason the current read position is greater than the next object + // hint. Iterate until we find the right object + size_t nextObject = mNextObjectHint; + do { + if (mDataPos < mObjects[nextObject] + sizeof(flat_binder_object)) { + // Requested info overlaps with an object + ALOGE("Attempt to read from protected data in Parcel %p", this); + return PERMISSION_DENIED; + } + nextObject++; + } while (nextObject < mObjectsSize && upperBound > mObjects[nextObject]); + mNextObjectHint = nextObject; + } + return NO_ERROR; + } + // Quickly determine if mObjects is sorted. + binder_size_t* currObj = mObjects + mObjectsSize - 1; + binder_size_t* prevObj = currObj; + while (currObj > mObjects) { + prevObj--; + if(*prevObj > *currObj) { + goto data_unsorted; + } + currObj--; + } + mObjectsSorted = true; + goto data_sorted; + +data_unsorted: + // Insertion Sort mObjects + // Great for mostly sorted lists. If randomly sorted or reverse ordered mObjects become common, + // switch to std::sort(mObjects, mObjects + mObjectsSize); + for (binder_size_t* iter0 = mObjects + 1; iter0 < mObjects + mObjectsSize; iter0++) { + binder_size_t temp = *iter0; + binder_size_t* iter1 = iter0 - 1; + while (iter1 >= mObjects && *iter1 > temp) { + *(iter1 + 1) = *iter1; + iter1--; + } + *(iter1 + 1) = temp; + } + mNextObjectHint = 0; + mObjectsSorted = true; + goto data_sorted; +} + status_t Parcel::read(void* outData, size_t len) const { if (len > INT32_MAX) { @@ -1479,6 +1533,15 @@ status_t Parcel::read(void* outData, size_t len) const if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize && len <= pad_size(len)) { + if (mObjectsSize > 0) { + status_t err = validateReadData(mDataPos + pad_size(len)); + if(err != NO_ERROR) { + // Still increment the data position by the expected length + mDataPos += pad_size(len); + ALOGV("read Setting data pos of %p to %zu", this, mDataPos); + return err; + } + } memcpy(outData, mData+mDataPos, len); mDataPos += pad_size(len); ALOGV("read Setting data pos of %p to %zu", this, mDataPos); @@ -1497,6 +1560,16 @@ const void* Parcel::readInplace(size_t len) const if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize && len <= pad_size(len)) { + if (mObjectsSize > 0) { + status_t err = validateReadData(mDataPos + pad_size(len)); + if(err != NO_ERROR) { + // Still increment the data position by the expected length + mDataPos += pad_size(len); + ALOGV("readInplace Setting data pos of %p to %zu", this, mDataPos); + return nullptr; + } + } + const void* data = mData+mDataPos; mDataPos += pad_size(len); ALOGV("readInplace Setting data pos of %p to %zu", this, mDataPos); @@ -1510,6 +1583,15 @@ status_t Parcel::readAligned(T *pArg) const { COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T)); if ((mDataPos+sizeof(T)) <= mDataSize) { + if (mObjectsSize > 0) { + status_t err = validateReadData(mDataPos + sizeof(T)); + if(err != NO_ERROR) { + // Still increment the data position by the expected length + mDataPos += sizeof(T); + return err; + } + } + const void* data = mData+mDataPos; mDataPos += sizeof(T); *pArg = *reinterpret_cast<const T*>(data); @@ -2366,6 +2448,7 @@ void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize, mObjects = const_cast<binder_size_t*>(objects); mObjectsSize = mObjectsCapacity = objectsCount; mNextObjectHint = 0; + mObjectsSorted = false; mOwner = relFunc; mOwnerCookie = relCookie; for (size_t i = 0; i < mObjectsSize; i++) { @@ -2524,6 +2607,7 @@ status_t Parcel::restartWrite(size_t desired) mObjects = nullptr; mObjectsSize = mObjectsCapacity = 0; mNextObjectHint = 0; + mObjectsSorted = false; mHasFds = false; mFdsKnown = true; mAllowFds = true; @@ -2610,6 +2694,7 @@ status_t Parcel::continueWrite(size_t desired) mDataCapacity = desired; mObjectsSize = mObjectsCapacity = objectsSize; mNextObjectHint = 0; + mObjectsSorted = false; } else if (mData) { if (objectsSize < mObjectsSize) { @@ -2631,6 +2716,7 @@ status_t Parcel::continueWrite(size_t desired) } mObjectsSize = objectsSize; mNextObjectHint = 0; + mObjectsSorted = false; } // We own the data, so we can just do a realloc(). @@ -2703,6 +2789,7 @@ void Parcel::initState() mObjectsSize = 0; mObjectsCapacity = 0; mNextObjectHint = 0; + mObjectsSorted = false; mHasFds = false; mFdsKnown = true; mAllowFds = true; diff --git a/libs/binder/PermissionController.cpp b/libs/binder/PermissionController.cpp new file mode 100644 index 0000000000..96df33c9cf --- /dev/null +++ b/libs/binder/PermissionController.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2018 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. + */ + +#include <mutex> +#include <binder/PermissionController.h> +#include <binder/Binder.h> +#include <binder/IServiceManager.h> + +#include <utils/SystemClock.h> + +namespace android { + +PermissionController::PermissionController() +{ +} + +sp<IPermissionController> PermissionController::getService() +{ + std::lock_guard<Mutex> scoped_lock(mLock); + int64_t startTime = 0; + sp<IPermissionController> service = mService; + while (service == nullptr || !IInterface::asBinder(service)->isBinderAlive()) { + sp<IBinder> binder = defaultServiceManager()->checkService(String16("permission")); + if (binder == nullptr) { + // Wait for the activity service to come back... + if (startTime == 0) { + startTime = uptimeMillis(); + ALOGI("Waiting for permission service"); + } else if ((uptimeMillis() - startTime) > 10000) { + ALOGW("Waiting too long for permission service, giving up"); + service = NULL; + break; + } + sleep(1); + } else { + service = interface_cast<IPermissionController>(binder); + mService = service; + } + } + return service; +} + +bool PermissionController::checkPermission(const String16& permission, int32_t pid, int32_t uid) +{ + sp<IPermissionController> service = getService(); + return service != NULL ? service->checkPermission(permission, pid, uid) : false; +} + +int32_t PermissionController::noteOp(const String16& op, int32_t uid, const String16& packageName) +{ + sp<IPermissionController> service = getService(); + return service != NULL ? service->noteOp(op, uid, packageName) : MODE_ERRORED; +} + +void PermissionController::getPackagesForUid(const uid_t uid, Vector<String16> &packages) +{ + sp<IPermissionController> service = getService(); + if (service != nullptr) { + service->getPackagesForUid(uid, packages); + } +} + +bool PermissionController::isRuntimePermission(const String16& permission) +{ + sp<IPermissionController> service = getService(); + return service != nullptr ? service->isRuntimePermission(permission) : false; +} + +int PermissionController::getPackageUid(const String16& package, int flags) +{ + sp<IPermissionController> service = getService(); + return service != nullptr ? service->getPackageUid(package, flags) : -1; +} + +}; // namespace android diff --git a/libs/binder/PersistableBundle.cpp b/libs/binder/PersistableBundle.cpp index d617b5a179..c0aec0a979 100644 --- a/libs/binder/PersistableBundle.cpp +++ b/libs/binder/PersistableBundle.cpp @@ -39,8 +39,9 @@ using std::vector; using namespace ::android::binder; enum { - // Keep in sync with BUNDLE_MAGIC in frameworks/base/core/java/android/os/BaseBundle.java. + // Keep them in sync with BUNDLE_MAGIC* in frameworks/base/core/java/android/os/BaseBundle.java. BUNDLE_MAGIC = 0x4C444E42, + BUNDLE_MAGIC_NATIVE = 0x4C444E44, }; namespace { @@ -99,7 +100,7 @@ status_t PersistableBundle::writeToParcel(Parcel* parcel) const { size_t length_pos = parcel->dataPosition(); RETURN_IF_FAILED(parcel->writeInt32(1)); // dummy, will hold length - RETURN_IF_FAILED(parcel->writeInt32(BUNDLE_MAGIC)); + RETURN_IF_FAILED(parcel->writeInt32(BUNDLE_MAGIC_NATIVE)); size_t start_pos = parcel->dataPosition(); RETURN_IF_FAILED(writeToParcelInner(parcel)); @@ -392,7 +393,7 @@ status_t PersistableBundle::readFromParcelInner(const Parcel* parcel, size_t len int32_t magic; RETURN_IF_FAILED(parcel->readInt32(&magic)); - if (magic != BUNDLE_MAGIC) { + if (magic != BUNDLE_MAGIC && magic != BUNDLE_MAGIC_NATIVE) { ALOGE("Bad magic number for PersistableBundle: 0x%08x", magic); return BAD_VALUE; } diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index 6e7c427b12..3e871f87f9 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -282,7 +282,7 @@ sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle) return nullptr; } - b = new BpBinder(handle); + b = BpBinder::create(handle); e->binder = b; if (b) e->refs = b->getWeakRefs(); result = b; @@ -316,7 +316,7 @@ wp<IBinder> ProcessState::getWeakProxyForHandle(int32_t handle) // arriving from the driver. IBinder* b = e->binder; if (b == nullptr || !e->refs->attemptIncWeak(this)) { - b = new BpBinder(handle); + b = BpBinder::create(handle); result = b; e->binder = b; if (b) e->refs = b->getWeakRefs(); diff --git a/libs/binder/Static.cpp b/libs/binder/Static.cpp index c3ba5a23c5..bd0e6f9a11 100644 --- a/libs/binder/Static.cpp +++ b/libs/binder/Static.cpp @@ -72,13 +72,16 @@ TextOutput& aerr(gStderrTextOutput); // ------------ ProcessState.cpp -Mutex gProcessMutex; +Mutex& gProcessMutex = *new Mutex; sp<ProcessState> gProcess; // ------------ IServiceManager.cpp Mutex gDefaultServiceManagerLock; sp<IServiceManager> gDefaultServiceManager; +#ifndef __ANDROID_VNDK__ sp<IPermissionController> gPermissionController; +#endif +bool gSystemBootCompleted = false; } // namespace android diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp index 006f7f94e9..a9d5055549 100644 --- a/libs/binder/Status.cpp +++ b/libs/binder/Status.cpp @@ -102,6 +102,15 @@ status_t Status::readFromParcel(const Parcel& parcel) { } mMessage = String8(message); + // Skip over the remote stack trace data + int32_t remote_stack_trace_header_size; + status = parcel.readInt32(&remote_stack_trace_header_size); + if (status != OK) { + setFromStatusT(status); + return status; + } + parcel.setDataPosition(parcel.dataPosition() + remote_stack_trace_header_size); + if (mException == EX_SERVICE_SPECIFIC) { status = parcel.readInt32(&mErrorCode); } else if (mException == EX_PARCELABLE) { @@ -137,6 +146,7 @@ status_t Status::writeToParcel(Parcel* parcel) const { return status; } status = parcel->writeString16(String16(mMessage)); + status = parcel->writeInt32(0); // Empty remote stack trace header if (mException == EX_SERVICE_SPECIFIC) { status = parcel->writeInt32(mErrorCode); } else if (mException == EX_PARCELABLE) { diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl index 3264666a21..5b66b923e7 100644 --- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl +++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl @@ -52,6 +52,6 @@ interface IPackageManagerNative { * Unknown or unknowable versions are returned as 0. */ - int getVersionCodeForPackage(in String packageName); + long getVersionCodeForPackage(in String packageName); } diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include/binder/ActivityManager.h new file mode 100644 index 0000000000..b8db09145f --- /dev/null +++ b/libs/binder/include/binder/ActivityManager.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef ANDROID_ACTIVITY_MANAGER_H +#define ANDROID_ACTIVITY_MANAGER_H + +#ifndef __ANDROID_VNDK__ + +#include <binder/IActivityManager.h> + +#include <utils/threads.h> + +// --------------------------------------------------------------------------- +namespace android { + +class ActivityManager +{ +public: + + enum { + // Flag for registerUidObserver: report uid gone + UID_OBSERVER_GONE = 1<<1, + // Flag for registerUidObserver: report uid has become idle + UID_OBSERVER_IDLE = 1<<2, + // Flag for registerUidObserver: report uid has become active + UID_OBSERVER_ACTIVE = 1<<3 + }; + + enum { + // Not a real process state + PROCESS_STATE_UNKNOWN = -1 + }; + + ActivityManager(); + + int openContentUri(const String16& stringUri); + void registerUidObserver(const sp<IUidObserver>& observer, + const int32_t event, + const int32_t cutpoint, + const String16& callingPackage); + void unregisterUidObserver(const sp<IUidObserver>& observer); + bool isUidActive(const uid_t uid, const String16& callingPackage); + + status_t linkToDeath(const sp<IBinder::DeathRecipient>& recipient); + status_t unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient); + +private: + Mutex mLock; + sp<IActivityManager> mService; + sp<IActivityManager> getService(); +}; + + +}; // namespace android +// --------------------------------------------------------------------------- +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + +#endif // ANDROID_ACTIVITY_MANAGER_H diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h index 4212776e89..c5b57c7edf 100644 --- a/libs/binder/include/binder/AppOpsManager.h +++ b/libs/binder/include/binder/AppOpsManager.h @@ -17,6 +17,8 @@ #ifndef ANDROID_APP_OPS_MANAGER_H #define ANDROID_APP_OPS_MANAGER_H +#ifndef __ANDROID_VNDK__ + #include <binder/IAppOpsService.h> #include <utils/threads.h> @@ -99,7 +101,8 @@ public: int32_t checkOp(int32_t op, int32_t uid, const String16& callingPackage); int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage); - int32_t startOp(int32_t op, int32_t uid, const String16& callingPackage); + int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, + bool startIfModeDefault); void finishOp(int32_t op, int32_t uid, const String16& callingPackage); void startWatchingMode(int32_t op, const String16& packageName, const sp<IAppOpsCallback>& callback); @@ -116,4 +119,8 @@ private: }; // namespace android // --------------------------------------------------------------------------- +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + #endif // ANDROID_APP_OPS_MANAGER_H diff --git a/libs/binder/include/binder/BinderService.h b/libs/binder/include/binder/BinderService.h index ef703bda90..9230e89cdf 100644 --- a/libs/binder/include/binder/BinderService.h +++ b/libs/binder/include/binder/BinderService.h @@ -34,15 +34,17 @@ template<typename SERVICE> class BinderService { public: - static status_t publish(bool allowIsolated = false) { + static status_t publish(bool allowIsolated = false, + int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) { sp<IServiceManager> sm(defaultServiceManager()); - return sm->addService( - String16(SERVICE::getServiceName()), - new SERVICE(), allowIsolated); + return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated, + dumpFlags); } - static void publishAndJoinThreadPool(bool allowIsolated = false) { - publish(allowIsolated); + static void publishAndJoinThreadPool( + bool allowIsolated = false, + int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) { + publish(allowIsolated, dumpFlags); joinThreadPool(); } diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h index 7ef93aa390..8bd297bcfb 100644 --- a/libs/binder/include/binder/BpBinder.h +++ b/libs/binder/include/binder/BpBinder.h @@ -19,15 +19,20 @@ #include <binder/IBinder.h> #include <utils/KeyedVector.h> +#include <utils/Mutex.h> #include <utils/threads.h> +#include <unordered_map> + // --------------------------------------------------------------------------- namespace android { +using binder_proxy_limit_callback = void(*)(int); + class BpBinder : public IBinder { public: - BpBinder(int32_t handle); + static BpBinder* create(int32_t handle); inline int32_t handle() const { return mHandle; } @@ -61,6 +66,14 @@ public: status_t setConstantData(const void* data, size_t size); void sendObituary(); + static uint32_t getBinderProxyCount(uint32_t uid); + static void getCountByUid(Vector<uint32_t>& uids, Vector<uint32_t>& counts); + static void enableCountByUid(); + static void disableCountByUid(); + static void setCountByUidEnabled(bool enable); + static void setLimitCallback(binder_proxy_limit_callback cb); + static void setBinderProxyCountWatermarks(int high, int low); + class ObjectManager { public: @@ -91,6 +104,7 @@ public: }; protected: + BpBinder(int32_t handle,int32_t trackedUid); virtual ~BpBinder(); virtual void onFirstRef(); virtual void onLastStrongRef(const void* id); @@ -115,6 +129,16 @@ private: ObjectManager mObjects; Parcel* mConstantData; mutable String16 mDescriptorCache; + int32_t mTrackedUid; + + static Mutex sTrackingLock; + static std::unordered_map<int32_t,uint32_t> sTrackingMap; + static int sNumTrackedUids; + static std::atomic_bool sCountByUidEnabled; + static binder_proxy_limit_callback sLimitCallback; + static uint32_t sBinderProxyCountHighWatermark; + static uint32_t sBinderProxyCountLowWatermark; + static bool sBinderProxyThrottleCreate; }; }; // namespace android diff --git a/libs/binder/include/binder/IActivityManager.h b/libs/binder/include/binder/IActivityManager.h index 5ad218035a..f34969be51 100644 --- a/libs/binder/include/binder/IActivityManager.h +++ b/libs/binder/include/binder/IActivityManager.h @@ -17,7 +17,10 @@ #ifndef ANDROID_IACTIVITY_MANAGER_H #define ANDROID_IACTIVITY_MANAGER_H +#ifndef __ANDROID_VNDK__ + #include <binder/IInterface.h> +#include <binder/IUidObserver.h> namespace android { @@ -28,10 +31,19 @@ class IActivityManager : public IInterface public: DECLARE_META_INTERFACE(ActivityManager) - virtual int openContentUri(const String16& /* stringUri */) = 0; + virtual int openContentUri(const String16& stringUri) = 0; + virtual void registerUidObserver(const sp<IUidObserver>& observer, + const int32_t event, + const int32_t cutpoint, + const String16& callingPackage) = 0; + virtual void unregisterUidObserver(const sp<IUidObserver>& observer) = 0; + virtual bool isUidActive(const uid_t uid, const String16& callingPackage) = 0; enum { - OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, + REGISTER_UID_OBSERVER_TRANSACTION, + UNREGISTER_UID_OBSERVER_TRANSACTION, + IS_UID_ACTIVE_TRANSACTION }; }; @@ -39,4 +51,8 @@ public: }; // namespace android -#endif // ANDROID_IACTIVITY_MANAGER_H
\ No newline at end of file +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + +#endif // ANDROID_IACTIVITY_MANAGER_H diff --git a/libs/binder/include/binder/IAppOpsCallback.h b/libs/binder/include/binder/IAppOpsCallback.h index b62e9e264d..e5b12a9720 100644 --- a/libs/binder/include/binder/IAppOpsCallback.h +++ b/libs/binder/include/binder/IAppOpsCallback.h @@ -18,6 +18,8 @@ #ifndef ANDROID_IAPP_OPS_CALLBACK_H #define ANDROID_IAPP_OPS_CALLBACK_H +#ifndef __ANDROID_VNDK__ + #include <binder/IInterface.h> namespace android { @@ -51,5 +53,9 @@ public: }; // namespace android +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + #endif // ANDROID_IAPP_OPS_CALLBACK_H diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h index dc18045975..f0c5e1743d 100644 --- a/libs/binder/include/binder/IAppOpsService.h +++ b/libs/binder/include/binder/IAppOpsService.h @@ -18,6 +18,8 @@ #ifndef ANDROID_IAPP_OPS_SERVICE_H #define ANDROID_IAPP_OPS_SERVICE_H +#ifndef __ANDROID_VNDK__ + #include <binder/IAppOpsCallback.h> #include <binder/IInterface.h> @@ -33,7 +35,7 @@ public: virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0; virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName) = 0; virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid, - const String16& packageName) = 0; + const String16& packageName, bool startIfModeDefault) = 0; virtual void finishOperation(const sp<IBinder>& token, int32_t code, int32_t uid, const String16& packageName) = 0; virtual void startWatchingMode(int32_t op, const String16& packageName, @@ -75,4 +77,8 @@ public: }; // namespace android +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + #endif // ANDROID_IAPP_OPS_SERVICE_H diff --git a/libs/binder/include/binder/IBatteryStats.h b/libs/binder/include/binder/IBatteryStats.h index e15d6f07e9..59e806c177 100644 --- a/libs/binder/include/binder/IBatteryStats.h +++ b/libs/binder/include/binder/IBatteryStats.h @@ -17,6 +17,8 @@ #ifndef ANDROID_IBATTERYSTATS_H #define ANDROID_IBATTERYSTATS_H +#ifndef __ANDROID_VNDK__ + #include <binder/IInterface.h> namespace android { @@ -76,4 +78,8 @@ public: }; // namespace android +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + #endif // ANDROID_IBATTERYSTATS_H diff --git a/libs/binder/include/binder/IMediaResourceMonitor.h b/libs/binder/include/binder/IMediaResourceMonitor.h index b21047fc49..213ee63ea8 100644 --- a/libs/binder/include/binder/IMediaResourceMonitor.h +++ b/libs/binder/include/binder/IMediaResourceMonitor.h @@ -17,6 +17,8 @@ #ifndef ANDROID_I_MEDIA_RESOURCE_MONITOR_H #define ANDROID_I_MEDIA_RESOURCE_MONITOR_H +#ifndef __ANDROID_VNDK__ + #include <binder/IInterface.h> namespace android { @@ -52,4 +54,8 @@ public: }; // namespace android +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + #endif // ANDROID_I_MEDIA_RESOURCE_MONITOR_H diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h index 245607e74e..c1d9a9a8f7 100644 --- a/libs/binder/include/binder/IPCThreadState.h +++ b/libs/binder/include/binder/IPCThreadState.h @@ -64,9 +64,9 @@ public: uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); - void incStrongHandle(int32_t handle); + void incStrongHandle(int32_t handle, BpBinder *proxy); void decStrongHandle(int32_t handle); - void incWeakHandle(int32_t handle); + void incWeakHandle(int32_t handle, BpBinder *proxy); void decWeakHandle(int32_t handle); status_t attemptIncStrongHandle(int32_t handle); static void expungeHandle(int32_t handle, IBinder* binder); @@ -106,6 +106,7 @@ private: status_t getAndExecuteCommand(); status_t executeCommand(int32_t command); void processPendingDerefs(); + void processPostWriteDerefs(); void clearCaller(); @@ -118,7 +119,8 @@ private: const sp<ProcessState> mProcess; Vector<BBinder*> mPendingStrongDerefs; Vector<RefBase::weakref_type*> mPendingWeakDerefs; - + Vector<RefBase*> mPostWriteStrongDerefs; + Vector<RefBase::weakref_type*> mPostWriteWeakDerefs; Parcel mIn; Parcel mOut; status_t mLastError; diff --git a/libs/binder/include/binder/IPermissionController.h b/libs/binder/include/binder/IPermissionController.h index 25f34313f0..3ec459fc32 100644 --- a/libs/binder/include/binder/IPermissionController.h +++ b/libs/binder/include/binder/IPermissionController.h @@ -18,6 +18,8 @@ #ifndef ANDROID_IPERMISSION_CONTROLLER_H #define ANDROID_IPERMISSION_CONTROLLER_H +#ifndef __ANDROID_VNDK__ + #include <binder/IInterface.h> #include <stdlib.h> @@ -32,14 +34,20 @@ public: virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid) = 0; + virtual int32_t noteOp(const String16& op, int32_t uid, const String16& packageName) = 0; + virtual void getPackagesForUid(const uid_t uid, Vector<String16> &packages) = 0; virtual bool isRuntimePermission(const String16& permission) = 0; + virtual int getPackageUid(const String16& package, int flags) = 0; + enum { CHECK_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, - GET_PACKAGES_FOR_UID_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 1, - IS_RUNTIME_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 2 + NOTE_OP_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 1, + GET_PACKAGES_FOR_UID_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 2, + IS_RUNTIME_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 3, + GET_PACKAGE_UID_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 4 }; }; @@ -58,5 +66,9 @@ public: }; // namespace android +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + #endif // ANDROID_IPERMISSION_CONTROLLER_H diff --git a/libs/binder/include/binder/IProcessInfoService.h b/libs/binder/include/binder/IProcessInfoService.h index 2669f9193d..033c145363 100644 --- a/libs/binder/include/binder/IProcessInfoService.h +++ b/libs/binder/include/binder/IProcessInfoService.h @@ -17,6 +17,8 @@ #ifndef ANDROID_I_PROCESS_INFO_SERVICE_H #define ANDROID_I_PROCESS_INFO_SERVICE_H +#ifndef __ANDROID_VNDK__ + #include <binder/IInterface.h> namespace android { @@ -46,4 +48,8 @@ public: }; // namespace android +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + #endif // ANDROID_I_PROCESS_INFO_SERVICE_H diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h index 3b23f81e43..197026d5d6 100644 --- a/libs/binder/include/binder/IServiceManager.h +++ b/libs/binder/include/binder/IServiceManager.h @@ -19,7 +19,6 @@ #define ANDROID_ISERVICE_MANAGER_H #include <binder/IInterface.h> -#include <binder/IPermissionController.h> #include <utils/Vector.h> #include <utils/String16.h> @@ -31,6 +30,22 @@ class IServiceManager : public IInterface { public: DECLARE_META_INTERFACE(ServiceManager) + /** + * Must match values in IServiceManager.java + */ + /* Allows services to dump sections according to priorities. */ + static const int DUMP_FLAG_PRIORITY_CRITICAL = 1 << 0; + static const int DUMP_FLAG_PRIORITY_HIGH = 1 << 1; + static const int DUMP_FLAG_PRIORITY_NORMAL = 1 << 2; + /** + * Services are by default registered with a DEFAULT dump priority. DEFAULT priority has the + * same priority as NORMAL priority but the services are not called with dump priority + * arguments. + */ + static const int DUMP_FLAG_PRIORITY_DEFAULT = 1 << 3; + static const int DUMP_FLAG_PRIORITY_ALL = DUMP_FLAG_PRIORITY_CRITICAL | + DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PRIORITY_DEFAULT; + static const int DUMP_FLAG_PROTO = 1 << 4; /** * Retrieve an existing service, blocking for a few seconds @@ -46,14 +61,14 @@ public: /** * Register a service. */ - virtual status_t addService( const String16& name, - const sp<IBinder>& service, - bool allowIsolated = false) = 0; + virtual status_t addService(const String16& name, const sp<IBinder>& service, + bool allowIsolated = false, + int dumpsysFlags = DUMP_FLAG_PRIORITY_DEFAULT) = 0; /** * Return list of all existing services. */ - virtual Vector<String16> listServices() = 0; + virtual Vector<String16> listServices(int dumpsysFlags = DUMP_FLAG_PRIORITY_ALL) = 0; enum { GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, diff --git a/libs/binder/include/binder/IShellCallback.h b/libs/binder/include/binder/IShellCallback.h index fda9ee6ba7..b47e995183 100644 --- a/libs/binder/include/binder/IShellCallback.h +++ b/libs/binder/include/binder/IShellCallback.h @@ -29,7 +29,8 @@ class IShellCallback : public IInterface public: DECLARE_META_INTERFACE(ShellCallback); - virtual int openOutputFile(const String16& path, const String16& seLinuxContext) = 0; + virtual int openFile(const String16& path, const String16& seLinuxContext, + const String16& mode) = 0; enum { OP_OPEN_OUTPUT_FILE = IBinder::FIRST_CALL_TRANSACTION diff --git a/libs/binder/include/binder/IUidObserver.h b/libs/binder/include/binder/IUidObserver.h new file mode 100644 index 0000000000..d81789e399 --- /dev/null +++ b/libs/binder/include/binder/IUidObserver.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2017 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. + */ + +// +#ifndef ANDROID_IUID_OBSERVER_H +#define ANDROID_IUID_OBSERVER_H + +#ifndef __ANDROID_VNDK__ + +#include <binder/IInterface.h> + +namespace android { + +// ---------------------------------------------------------------------- + +class IUidObserver : public IInterface +{ +public: + DECLARE_META_INTERFACE(UidObserver) + + virtual void onUidGone(uid_t uid, bool disabled) = 0; + virtual void onUidActive(uid_t uid) = 0; + virtual void onUidIdle(uid_t uid, bool disabled) = 0; + + enum { + ON_UID_GONE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, + ON_UID_ACTIVE_TRANSACTION, + ON_UID_IDLE_TRANSACTION + }; +}; + +// ---------------------------------------------------------------------- + +class BnUidObserver : public BnInterface<IUidObserver> +{ +public: + virtual status_t onTransact(uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags = 0); +}; + +// ---------------------------------------------------------------------- + +}; // namespace android + +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + +#endif // ANDROID_IUID_OBSERVER_H diff --git a/libs/binder/include/binder/IpPrefix.h b/libs/binder/include/binder/IpPrefix.h index 96ebaac437..dd5bc3aafd 100644 --- a/libs/binder/include/binder/IpPrefix.h +++ b/libs/binder/include/binder/IpPrefix.h @@ -17,6 +17,8 @@ #ifndef ANDROID_IP_PREFIX_H #define ANDROID_IP_PREFIX_H +#ifndef __ANDROID_VNDK__ + #include <netinet/in.h> #include <binder/Parcelable.h> @@ -85,4 +87,8 @@ private: } // namespace android +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + #endif // ANDROID_IP_PREFIX_H diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index 5d36526cb3..dede78f61e 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -417,6 +417,7 @@ private: void freeDataNoInit(); void initState(); void scanForFds() const; + status_t validateReadData(size_t len) const; template<class T> status_t readAligned(T *pArg) const; @@ -463,6 +464,7 @@ private: size_t mObjectsSize; size_t mObjectsCapacity; mutable size_t mNextObjectHint; + mutable bool mObjectsSorted; mutable bool mFdsKnown; mutable bool mHasFds; diff --git a/libs/binder/include/binder/PermissionCache.h b/libs/binder/include/binder/PermissionCache.h index bcdf0c2914..95eabff7ac 100644 --- a/libs/binder/include/binder/PermissionCache.h +++ b/libs/binder/include/binder/PermissionCache.h @@ -17,6 +17,8 @@ #ifndef BINDER_PERMISSION_H #define BINDER_PERMISSION_H +#ifndef __ANDROID_VNDK__ + #include <stdint.h> #include <unistd.h> @@ -77,4 +79,8 @@ public: // --------------------------------------------------------------------------- }; // namespace android +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + #endif /* BINDER_PERMISSION_H */ diff --git a/libs/binder/include/binder/PermissionController.h b/libs/binder/include/binder/PermissionController.h new file mode 100644 index 0000000000..d81f5142bc --- /dev/null +++ b/libs/binder/include/binder/PermissionController.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef ANDROID_PERMISSION_CONTROLLER_H +#define ANDROID_PERMISSION_CONTROLLER_H + +#ifndef __ANDROID_VNDK__ + +#include <binder/IPermissionController.h> + +#include <utils/threads.h> + +// --------------------------------------------------------------------------- +namespace android { + +class PermissionController +{ +public: + + enum { + MATCH_SYSTEM_ONLY = 1<<16, + MATCH_UNINSTALLED_PACKAGES = 1<<13, + MATCH_FACTORY_ONLY = 1<<21, + MATCH_INSTANT = 1<<23 + }; + + enum { + MODE_ALLOWED = 0, + MODE_IGNORED = 1, + MODE_ERRORED = 2, + MODE_DEFAULT = 3, + }; + + PermissionController(); + + bool checkPermission(const String16& permission, int32_t pid, int32_t uid); + int32_t noteOp(const String16& op, int32_t uid, const String16& packageName); + void getPackagesForUid(const uid_t uid, Vector<String16>& packages); + bool isRuntimePermission(const String16& permission); + int getPackageUid(const String16& package, int flags); + +private: + Mutex mLock; + sp<IPermissionController> mService; + + sp<IPermissionController> getService(); +}; + + +}; // namespace android +// --------------------------------------------------------------------------- +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + +#endif // ANDROID_PERMISSION_CONTROLLER_H diff --git a/libs/binder/include/binder/ProcessInfoService.h b/libs/binder/include/binder/ProcessInfoService.h index 0da61ee3cb..a03aae98ee 100644 --- a/libs/binder/include/binder/ProcessInfoService.h +++ b/libs/binder/include/binder/ProcessInfoService.h @@ -17,6 +17,8 @@ #ifndef ANDROID_PROCESS_INFO_SERVICE_H #define ANDROID_PROCESS_INFO_SERVICE_H +#ifndef __ANDROID_VNDK__ + #include <binder/IProcessInfoService.h> #include <utils/Errors.h> #include <utils/Singleton.h> @@ -78,5 +80,9 @@ public: }; // namespace android +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + #endif // ANDROID_PROCESS_INFO_SERVICE_H diff --git a/libs/binder/include/private/binder/Static.h b/libs/binder/include/private/binder/Static.h index 3d10456a8d..171be7791e 100644 --- a/libs/binder/include/private/binder/Static.h +++ b/libs/binder/include/private/binder/Static.h @@ -21,7 +21,9 @@ #include <binder/IBinder.h> #include <binder/ProcessState.h> +#ifndef __ANDROID_VNDK__ #include <binder/IPermissionController.h> +#endif #include <binder/IServiceManager.h> namespace android { @@ -30,12 +32,15 @@ namespace android { extern Vector<int32_t> gTextBuffers; // For ProcessState.cpp -extern Mutex gProcessMutex; +extern Mutex& gProcessMutex; extern sp<ProcessState> gProcess; // For IServiceManager.cpp extern Mutex gDefaultServiceManagerLock; extern sp<IServiceManager> gDefaultServiceManager; +#ifndef __ANDROID_VNDK__ extern sp<IPermissionController> gPermissionController; +#endif +extern bool gSystemBootCompleted; } // namespace android diff --git a/libs/binder/tests/binderThroughputTest.cpp b/libs/binder/tests/binderThroughputTest.cpp index da7fc39a8f..b7909972ff 100644 --- a/libs/binder/tests/binderThroughputTest.cpp +++ b/libs/binder/tests/binderThroughputTest.cpp @@ -215,7 +215,7 @@ void worker_fx(int num, int target = cs_pair ? num % server_count : rand() % workers.size(); int sz = payload_size; - while (sz > sizeof(uint32_t)) { + while (sz >= sizeof(uint32_t)) { data.writeInt32(0); sz -= sizeof(uint32_t); } @@ -381,6 +381,7 @@ int main(int argc, char *argv[]) // No need to run training round in this case. if (atoi(argv[i+1]) > 0) { max_time_bucket = strtoull(argv[i+1], (char **)nullptr, 10) * 1000; + time_per_bucket = max_time_bucket / num_buckets; i++; } else { cout << "Max latency -m must be positive." << endl; diff --git a/libs/dumputils/Android.bp b/libs/dumputils/Android.bp new file mode 100644 index 0000000000..3412e14f17 --- /dev/null +++ b/libs/dumputils/Android.bp @@ -0,0 +1,34 @@ +// Copyright (C) 2018 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. + +cc_library { + name: "libdumputils", + + shared_libs: [ + "libbase", + "libbinder", + "libhidlbase", + "libhidltransport", + "liblog", + "libutils", + ], + + srcs: ["dump_utils.cpp"], + + cflags: ["-Wall", "-Werror"], + + export_include_dirs: [ + "include", + ], +} diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp new file mode 100644 index 0000000000..8b2f842a44 --- /dev/null +++ b/libs/dumputils/dump_utils.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2018 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. + */ +#include <set> + +#include <android-base/file.h> +#include <android-base/stringprintf.h> +#include <android/hidl/manager/1.0/IServiceManager.h> +#include <dumputils/dump_utils.h> +#include <log/log.h> + +/* list of native processes to include in the native dumps */ +// This matches the /proc/pid/exe link instead of /proc/pid/cmdline. +static const char* native_processes_to_dump[] = { + "/system/bin/audioserver", + "/system/bin/cameraserver", + "/system/bin/drmserver", + "/system/bin/mediadrmserver", + "/system/bin/mediaextractor", // media.extractor + "/system/bin/mediametrics", // media.metrics + "/system/bin/mediaserver", + "/system/bin/sdcard", + "/system/bin/statsd", + "/system/bin/surfaceflinger", + "/system/bin/vehicle_network_service", + "/vendor/bin/hw/android.hardware.media.omx@1.0-service", // media.codec + NULL, +}; + +/* list of hal interface to dump containing process during native dumps */ +static const char* hal_interfaces_to_dump[] { + "android.hardware.audio@2.0::IDevicesFactory", + "android.hardware.audio@4.0::IDevicesFactory", + "android.hardware.bluetooth@1.0::IBluetoothHci", + "android.hardware.camera.provider@2.4::ICameraProvider", + "android.hardware.drm@1.0::IDrmFactory", + "android.hardware.graphics.composer@2.1::IComposer", + "android.hardware.media.omx@1.0::IOmx", + "android.hardware.media.omx@1.0::IOmxStore", + "android.hardware.sensors@1.0::ISensors", + "android.hardware.vr@1.0::IVr", + NULL, +}; + +bool should_dump_hal_interface(const char* interface) { + for (const char** i = hal_interfaces_to_dump; *i; i++) { + if (!strcmp(*i, interface)) { + return true; + } + } + return false; +} + +bool should_dump_native_traces(const char* path) { + for (const char** p = native_processes_to_dump; *p; p++) { + if (!strcmp(*p, path)) { + return true; + } + } + return false; +} + +std::set<int> get_interesting_hal_pids() { + using android::hidl::manager::V1_0::IServiceManager; + using android::sp; + using android::hardware::Return; + + sp<IServiceManager> manager = IServiceManager::getService(); + std::set<int> pids; + + Return<void> ret = manager->debugDump([&](auto& hals) { + for (const auto &info : hals) { + if (info.pid == static_cast<int>(IServiceManager::PidConstant::NO_PID)) { + continue; + } + + if (!should_dump_hal_interface(info.interfaceName.c_str())) { + continue; + } + + pids.insert(info.pid); + } + }); + + if (!ret.isOk()) { + ALOGE("Could not get list of HAL PIDs: %s\n", ret.description().c_str()); + } + + return pids; // whether it was okay or not +} + +bool IsZygote(int pid) { + static const std::string kZygotePrefix = "zygote"; + + std::string cmdline; + if (!android::base::ReadFileToString(android::base::StringPrintf("/proc/%d/cmdline", pid), + &cmdline)) { + return true; + } + + return (cmdline.find(kZygotePrefix) == 0); +} diff --git a/libs/dumputils/include/dumputils/dump_utils.h b/libs/dumputils/include/dumputils/dump_utils.h new file mode 100644 index 0000000000..25f712733a --- /dev/null +++ b/libs/dumputils/include/dumputils/dump_utils.h @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2016, 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. + */ + +#ifndef DUMPUTILS_H_ +#define DUMPUTILS_H_ + +#include <set> + +bool should_dump_native_traces(const char* path); + +std::set<int> get_interesting_hal_pids(); + +bool IsZygote(int pid); + +#endif // DUMPUTILS_H_ diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp index 9f995380bd..4da30e9980 100644 --- a/libs/graphicsenv/Android.bp +++ b/libs/graphicsenv/Android.bp @@ -22,7 +22,6 @@ cc_library_shared { cflags: ["-Wall", "-Werror"], shared_libs: [ - "libnativeloader", "liblog", ], diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 39b5829faf..961f1011e0 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -20,12 +20,23 @@ #include <mutex> +#include <android/dlext.h> #include <log/log.h> -#include <nativeloader/dlext_namespaces.h> // TODO(b/37049319) Get this from a header once one exists extern "C" { android_namespace_t* android_get_exported_namespace(const char*); + android_namespace_t* android_create_namespace(const char* name, + const char* ld_library_path, + const char* default_library_path, + uint64_t type, + const char* permitted_when_isolated_path, + android_namespace_t* parent); + + enum { + ANDROID_NAMESPACE_TYPE_ISOLATED = 1, + ANDROID_NAMESPACE_TYPE_SHARED = 2, + }; } namespace android { @@ -45,6 +56,32 @@ void GraphicsEnv::setDriverPath(const std::string path) { mDriverPath = path; } +void GraphicsEnv::setLayerPaths(android_namespace_t* appNamespace, const std::string layerPaths) { + if (mLayerPaths.empty()) { + mLayerPaths = layerPaths; + mAppNamespace = appNamespace; + } else { + ALOGV("Vulkan layer search path already set, not clobbering with '%s' for namespace %p'", + layerPaths.c_str(), appNamespace); + } +} + +android_namespace_t* GraphicsEnv::getAppNamespace() { + return mAppNamespace; +} + +const std::string GraphicsEnv::getLayerPaths(){ + return mLayerPaths; +} + +const std::string GraphicsEnv::getDebugLayers() { + return mDebugLayers; +} + +void GraphicsEnv::setDebugLayers(const std::string layers) { + mDebugLayers = layers; +} + android_namespace_t* GraphicsEnv::getDriverNamespace() { static std::once_flag once; std::call_once(once, [this]() { diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index 781707694a..213580c20b 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -35,10 +35,20 @@ public: void setDriverPath(const std::string path); android_namespace_t* getDriverNamespace(); + void setLayerPaths(android_namespace_t* appNamespace, const std::string layerPaths); + android_namespace_t* getAppNamespace(); + const std::string getLayerPaths(); + + void setDebugLayers(const std::string layers); + const std::string getDebugLayers(); + private: GraphicsEnv() = default; std::string mDriverPath; + std::string mDebugLayers; + std::string mLayerPaths; android_namespace_t* mDriverNamespace = nullptr; + android_namespace_t* mAppNamespace = nullptr; }; } // namespace android diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 02d29a3e69..b29c1d5157 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -19,7 +19,7 @@ cc_library_headers { cc_library_shared { name: "libgui", - vendor_available: true, + vendor_available: false, vndk: { enabled: true, }, @@ -63,6 +63,12 @@ cc_library_shared { // Allow documentation warnings "-Wno-documentation", + // Allow implicit instantiation for templated class function + "-Wno-undefined-func-template", + + // Allow explicitly marking struct as packed even when unnecessary + "-Wno-packed", + "-DDEBUG_ONLY_CODE=0", ], @@ -77,6 +83,8 @@ cc_library_shared { srcs: [ "BitTube.cpp", + "BufferHubConsumer.cpp", + "BufferHubProducer.cpp", "BufferItem.cpp", "BufferItemConsumer.cpp", "BufferQueue.cpp", @@ -90,6 +98,7 @@ cc_library_shared { "FrameTimestamps.cpp", "GLConsumer.cpp", "GuiConfig.cpp", + "HdrMetadata.cpp", "IDisplayEventConnection.cpp", "IConsumerListener.cpp", "IGraphicBufferConsumer.cpp", @@ -111,8 +120,11 @@ cc_library_shared { ], shared_libs: [ + "android.hardware.graphics.common@1.1", "libsync", "libbinder", + "libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui. + "libpdx_default_transport", "libcutils", "libEGL", "libGLESv2", @@ -128,9 +140,26 @@ cc_library_shared { "android.hardware.configstore-utils", ], + // bufferhub is not used when building libgui for vendors + target: { + vendor: { + cflags: ["-DNO_BUFFERHUB"], + exclude_srcs: [ + "BufferHubConsumer.cpp", + "BufferHubProducer.cpp", + ], + exclude_shared_libs: [ + "libbufferhubqueue", + "libpdx_default_transport", + ], + }, + }, + header_libs: [ + "libdvr_headers", "libnativebase_headers", "libgui_headers", + "libpdx_headers", ], export_shared_lib_headers: [ @@ -140,6 +169,7 @@ cc_library_shared { "libui", "android.hidl.token@1.0-utils", "android.hardware.graphics.bufferqueue@1.0", + "android.hardware.graphics.common@1.1", ], export_header_lib_headers: [ diff --git a/libs/gui/BufferHubConsumer.cpp b/libs/gui/BufferHubConsumer.cpp new file mode 100644 index 0000000000..b5cdeb280a --- /dev/null +++ b/libs/gui/BufferHubConsumer.cpp @@ -0,0 +1,161 @@ +/* + * Copyright 2018 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. + */ + +#include <gui/BufferHubConsumer.h> + +namespace android { + +using namespace dvr; + +/* static */ +sp<BufferHubConsumer> BufferHubConsumer::Create(const std::shared_ptr<ConsumerQueue>& queue) { + sp<BufferHubConsumer> consumer = new BufferHubConsumer; + consumer->mQueue = queue; + return consumer; +} + +/* static */ sp<BufferHubConsumer> BufferHubConsumer::Create(ConsumerQueueParcelable parcelable) { + if (!parcelable.IsValid()) { + ALOGE("BufferHubConsumer::Create: Invalid consumer parcelable."); + return nullptr; + } + + sp<BufferHubConsumer> consumer = new BufferHubConsumer; + consumer->mQueue = ConsumerQueue::Import(parcelable.TakeChannelHandle()); + return consumer; +} + +status_t BufferHubConsumer::acquireBuffer(BufferItem* /*buffer*/, nsecs_t /*presentWhen*/, + uint64_t /*maxFrameNumber*/) { + ALOGE("BufferHubConsumer::acquireBuffer: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::detachBuffer(int /*slot*/) { + ALOGE("BufferHubConsumer::detachBuffer: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::attachBuffer(int* /*outSlot*/, const sp<GraphicBuffer>& /*buffer*/) { + ALOGE("BufferHubConsumer::attachBuffer: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::releaseBuffer(int /*buf*/, uint64_t /*frameNumber*/, + EGLDisplay /*display*/, EGLSyncKHR /*fence*/, + const sp<Fence>& /*releaseFence*/) { + ALOGE("BufferHubConsumer::releaseBuffer: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::consumerConnect(const sp<IConsumerListener>& /*consumer*/, + bool /*controlledByApp*/) { + ALOGE("BufferHubConsumer::consumerConnect: not implemented."); + + // TODO(b/73267953): Make BufferHub honor producer and consumer connection. Returns NO_ERROR to + // make IGraphicBufferConsumer_test happy. + return NO_ERROR; +} + +status_t BufferHubConsumer::consumerDisconnect() { + ALOGE("BufferHubConsumer::consumerDisconnect: not implemented."); + + // TODO(b/73267953): Make BufferHub honor producer and consumer connection. Returns NO_ERROR to + // make IGraphicBufferConsumer_test happy. + return NO_ERROR; +} + +status_t BufferHubConsumer::getReleasedBuffers(uint64_t* /*slotMask*/) { + ALOGE("BufferHubConsumer::getReleasedBuffers: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) { + ALOGE("BufferHubConsumer::setDefaultBufferSize: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::setMaxBufferCount(int /*bufferCount*/) { + ALOGE("BufferHubConsumer::setMaxBufferCount: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::setMaxAcquiredBufferCount(int /*maxAcquiredBuffers*/) { + ALOGE("BufferHubConsumer::setMaxAcquiredBufferCount: not implemented."); + + // TODO(b/73267953): Make BufferHub honor producer and consumer connection. Returns NO_ERROR to + // make IGraphicBufferConsumer_test happy. + return NO_ERROR; +} + +status_t BufferHubConsumer::setConsumerName(const String8& /*name*/) { + ALOGE("BufferHubConsumer::setConsumerName: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::setDefaultBufferFormat(PixelFormat /*defaultFormat*/) { + ALOGE("BufferHubConsumer::setDefaultBufferFormat: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::setDefaultBufferDataSpace(android_dataspace /*defaultDataSpace*/) { + ALOGE("BufferHubConsumer::setDefaultBufferDataSpace: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::setConsumerUsageBits(uint64_t /*usage*/) { + ALOGE("BufferHubConsumer::setConsumerUsageBits: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::setConsumerIsProtected(bool /*isProtected*/) { + ALOGE("BufferHubConsumer::setConsumerIsProtected: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::setTransformHint(uint32_t /*hint*/) { + ALOGE("BufferHubConsumer::setTransformHint: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::getSidebandStream(sp<NativeHandle>* /*outStream*/) const { + ALOGE("BufferHubConsumer::getSidebandStream: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::getOccupancyHistory( + bool /*forceFlush*/, std::vector<OccupancyTracker::Segment>* /*outHistory*/) { + ALOGE("BufferHubConsumer::getOccupancyHistory: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::discardFreeBuffers() { + ALOGE("BufferHubConsumer::discardFreeBuffers: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::dumpState(const String8& /*prefix*/, String8* /*outResult*/) const { + ALOGE("BufferHubConsumer::dumpState: not implemented."); + return INVALID_OPERATION; +} + +IBinder* BufferHubConsumer::onAsBinder() { + ALOGE("BufferHubConsumer::onAsBinder: BufferHubConsumer should never be used as an Binder " + "object."); + return nullptr; +} + +} // namespace android diff --git a/libs/gui/BufferHubProducer.cpp b/libs/gui/BufferHubProducer.cpp new file mode 100644 index 0000000000..ae5cca2d20 --- /dev/null +++ b/libs/gui/BufferHubProducer.cpp @@ -0,0 +1,717 @@ +/* + * Copyright 2018 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. + */ + +#include <dvr/dvr_api.h> +#include <gui/BufferHubProducer.h> +#include <inttypes.h> +#include <log/log.h> +#include <system/window.h> + +namespace android { + +using namespace dvr; + +/* static */ +sp<BufferHubProducer> BufferHubProducer::Create(const std::shared_ptr<ProducerQueue>& queue) { + sp<BufferHubProducer> producer = new BufferHubProducer; + producer->queue_ = queue; + return producer; +} + +/* static */ +sp<BufferHubProducer> BufferHubProducer::Create(ProducerQueueParcelable parcelable) { + if (!parcelable.IsValid()) { + ALOGE("BufferHubProducer::Create: Invalid producer parcelable."); + return nullptr; + } + + sp<BufferHubProducer> producer = new BufferHubProducer; + producer->queue_ = ProducerQueue::Import(parcelable.TakeChannelHandle()); + return producer; +} + +status_t BufferHubProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) { + ALOGV("requestBuffer: slot=%d", slot); + + std::unique_lock<std::mutex> lock(mutex_); + + if (connected_api_ == kNoConnectedApi) { + ALOGE("requestBuffer: BufferHubProducer has no connected producer"); + return NO_INIT; + } + + if (slot < 0 || slot >= max_buffer_count_) { + ALOGE("requestBuffer: slot index %d out of range [0, %d)", slot, max_buffer_count_); + return BAD_VALUE; + } else if (!buffers_[slot].mBufferState.isDequeued()) { + ALOGE("requestBuffer: slot %d is not owned by the producer (state = %s)", slot, + buffers_[slot].mBufferState.string()); + return BAD_VALUE; + } else if (buffers_[slot].mGraphicBuffer != nullptr) { + ALOGE("requestBuffer: slot %d is not empty.", slot); + return BAD_VALUE; + } else if (buffers_[slot].mBufferProducer == nullptr) { + ALOGE("requestBuffer: slot %d is not dequeued.", slot); + return BAD_VALUE; + } + + const auto& buffer_producer = buffers_[slot].mBufferProducer; + sp<GraphicBuffer> graphic_buffer = buffer_producer->buffer()->buffer(); + + buffers_[slot].mGraphicBuffer = graphic_buffer; + buffers_[slot].mRequestBufferCalled = true; + + *buf = graphic_buffer; + return NO_ERROR; +} + +status_t BufferHubProducer::setMaxDequeuedBufferCount(int max_dequeued_buffers) { + ALOGV("setMaxDequeuedBufferCount: max_dequeued_buffers=%d", max_dequeued_buffers); + + std::unique_lock<std::mutex> lock(mutex_); + + if (max_dequeued_buffers <= 0 || + max_dequeued_buffers > + int(BufferHubQueue::kMaxQueueCapacity - kDefaultUndequeuedBuffers)) { + ALOGE("setMaxDequeuedBufferCount: %d out of range (0, %zu]", max_dequeued_buffers, + BufferHubQueue::kMaxQueueCapacity); + return BAD_VALUE; + } + + // The new dequeued_buffers count should not be violated by the number + // of currently dequeued buffers. + int dequeued_count = 0; + for (const auto& buf : buffers_) { + if (buf.mBufferState.isDequeued()) { + dequeued_count++; + } + } + if (dequeued_count > max_dequeued_buffers) { + ALOGE("setMaxDequeuedBufferCount: the requested dequeued_buffers" + "count (%d) exceeds the current dequeued buffer count (%d)", + max_dequeued_buffers, dequeued_count); + return BAD_VALUE; + } + + max_dequeued_buffer_count_ = max_dequeued_buffers; + return NO_ERROR; +} + +status_t BufferHubProducer::setAsyncMode(bool async) { + if (async) { + // TODO(b/36724099) BufferHubQueue's consumer end always acquires the buffer + // automatically and behaves differently from IGraphicBufferConsumer. Thus, + // android::BufferQueue's async mode (a.k.a. allocating an additional buffer + // to prevent dequeueBuffer from being blocking) technically does not apply + // here. + // + // In Daydream, non-blocking producer side dequeue is guaranteed by careful + // buffer consumer implementations. In another word, BufferHubQueue based + // dequeueBuffer should never block whether setAsyncMode(true) is set or + // not. + // + // See: IGraphicBufferProducer::setAsyncMode and + // BufferQueueProducer::setAsyncMode for more about original implementation. + ALOGW("BufferHubProducer::setAsyncMode: BufferHubQueue should always be " + "asynchronous. This call makes no effact."); + return NO_ERROR; + } + return NO_ERROR; +} + +status_t BufferHubProducer::dequeueBuffer(int* out_slot, sp<Fence>* out_fence, uint32_t width, + uint32_t height, PixelFormat format, uint64_t usage, + uint64_t* /*outBufferAge*/, + FrameEventHistoryDelta* /* out_timestamps */) { + ALOGV("dequeueBuffer: w=%u, h=%u, format=%d, usage=%" PRIu64, width, height, format, usage); + + status_t ret; + std::unique_lock<std::mutex> lock(mutex_); + + if (connected_api_ == kNoConnectedApi) { + ALOGE("dequeueBuffer: BufferQueue has no connected producer"); + return NO_INIT; + } + + const uint32_t kLayerCount = 1; + if (int32_t(queue_->capacity()) < max_dequeued_buffer_count_ + kDefaultUndequeuedBuffers) { + // Lazy allocation. When the capacity of |queue_| has not reached + // |max_dequeued_buffer_count_|, allocate new buffer. + // TODO(jwcai) To save memory, the really reasonable thing to do is to go + // over existing slots and find first existing one to dequeue. + ret = AllocateBuffer(width, height, kLayerCount, format, usage); + if (ret < 0) return ret; + } + + size_t slot = 0; + std::shared_ptr<BufferProducer> buffer_producer; + + for (size_t retry = 0; retry < BufferHubQueue::kMaxQueueCapacity; retry++) { + LocalHandle fence; + auto buffer_status = queue_->Dequeue(dequeue_timeout_ms_, &slot, &fence); + if (!buffer_status) return NO_MEMORY; + + buffer_producer = buffer_status.take(); + if (!buffer_producer) return NO_MEMORY; + + if (width == buffer_producer->width() && height == buffer_producer->height() && + uint32_t(format) == buffer_producer->format()) { + // The producer queue returns a buffer producer matches the request. + break; + } + + // Needs reallocation. + // TODO(jwcai) Consider use VLOG instead if we find this log is not useful. + ALOGI("dequeueBuffer: requested buffer (w=%u, h=%u, format=%u) is different " + "from the buffer returned at slot: %zu (w=%u, h=%u, format=%u). Need " + "re-allocattion.", + width, height, format, slot, buffer_producer->width(), buffer_producer->height(), + buffer_producer->format()); + // Mark the slot as reallocating, so that later we can set + // BUFFER_NEEDS_REALLOCATION when the buffer actually get dequeued. + buffers_[slot].mIsReallocating = true; + + // Remove the old buffer once the allocation before allocating its + // replacement. + RemoveBuffer(slot); + + // Allocate a new producer buffer with new buffer configs. Note that if + // there are already multiple buffers in the queue, the next one returned + // from |queue_->Dequeue| may not be the new buffer we just reallocated. + // Retry up to BufferHubQueue::kMaxQueueCapacity times. + ret = AllocateBuffer(width, height, kLayerCount, format, usage); + if (ret < 0) return ret; + } + + // With the BufferHub backed solution. Buffer slot returned from + // |queue_->Dequeue| is guaranteed to avaiable for producer's use. + // It's either in free state (if the buffer has never been used before) or + // in queued state (if the buffer has been dequeued and queued back to + // BufferHubQueue). + LOG_ALWAYS_FATAL_IF((!buffers_[slot].mBufferState.isFree() && + !buffers_[slot].mBufferState.isQueued()), + "dequeueBuffer: slot %zu is not free or queued, actual state: %s.", slot, + buffers_[slot].mBufferState.string()); + + buffers_[slot].mBufferState.freeQueued(); + buffers_[slot].mBufferState.dequeue(); + ALOGV("dequeueBuffer: slot=%zu", slot); + + // TODO(jwcai) Handle fence properly. |BufferHub| has full fence support, we + // just need to exopose that through |BufferHubQueue| once we need fence. + *out_fence = Fence::NO_FENCE; + *out_slot = int(slot); + ret = NO_ERROR; + + if (buffers_[slot].mIsReallocating) { + ret |= BUFFER_NEEDS_REALLOCATION; + buffers_[slot].mIsReallocating = false; + } + + return ret; +} + +status_t BufferHubProducer::detachBuffer(int /* slot */) { + ALOGE("BufferHubProducer::detachBuffer not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubProducer::detachNextBuffer(sp<GraphicBuffer>* /* out_buffer */, + sp<Fence>* /* out_fence */) { + ALOGE("BufferHubProducer::detachNextBuffer not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubProducer::attachBuffer(int* /* out_slot */, + const sp<GraphicBuffer>& /* buffer */) { + // With this BufferHub backed implementation, we assume (for now) all buffers + // are allocated and owned by the BufferHub. Thus the attempt of transfering + // ownership of a buffer to the buffer queue is intentionally unsupported. + LOG_ALWAYS_FATAL("BufferHubProducer::attachBuffer not supported."); + return INVALID_OPERATION; +} + +status_t BufferHubProducer::queueBuffer(int slot, const QueueBufferInput& input, + QueueBufferOutput* output) { + ALOGV("queueBuffer: slot %d", slot); + + if (output == nullptr) { + return BAD_VALUE; + } + + int64_t timestamp; + bool is_auto_timestamp; + android_dataspace dataspace; + Rect crop(Rect::EMPTY_RECT); + int scaling_mode; + uint32_t transform; + sp<Fence> fence; + + input.deflate(×tamp, &is_auto_timestamp, &dataspace, &crop, &scaling_mode, &transform, + &fence); + + // Check input scaling mode is valid. + switch (scaling_mode) { + case NATIVE_WINDOW_SCALING_MODE_FREEZE: + case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: + case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: + case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP: + break; + default: + ALOGE("queueBuffer: unknown scaling mode %d", scaling_mode); + return BAD_VALUE; + } + + // Check input fence is valid. + if (fence == nullptr) { + ALOGE("queueBuffer: fence is NULL"); + return BAD_VALUE; + } + + std::unique_lock<std::mutex> lock(mutex_); + + if (connected_api_ == kNoConnectedApi) { + ALOGE("queueBuffer: BufferQueue has no connected producer"); + return NO_INIT; + } + + if (slot < 0 || slot >= max_buffer_count_) { + ALOGE("queueBuffer: slot index %d out of range [0, %d)", slot, max_buffer_count_); + return BAD_VALUE; + } else if (!buffers_[slot].mBufferState.isDequeued()) { + ALOGE("queueBuffer: slot %d is not owned by the producer (state = %s)", slot, + buffers_[slot].mBufferState.string()); + return BAD_VALUE; + } else if ((!buffers_[slot].mRequestBufferCalled || buffers_[slot].mGraphicBuffer == nullptr)) { + ALOGE("queueBuffer: slot %d is not requested (mRequestBufferCalled=%d, " + "mGraphicBuffer=%p)", + slot, buffers_[slot].mRequestBufferCalled, buffers_[slot].mGraphicBuffer.get()); + return BAD_VALUE; + } + + // Post the buffer producer with timestamp in the metadata. + const auto& buffer_producer = buffers_[slot].mBufferProducer; + + // Check input crop is not out of boundary of current buffer. + Rect buffer_rect(buffer_producer->width(), buffer_producer->height()); + Rect cropped_rect(Rect::EMPTY_RECT); + crop.intersect(buffer_rect, &cropped_rect); + if (cropped_rect != crop) { + ALOGE("queueBuffer: slot %d has out-of-boundary crop.", slot); + return BAD_VALUE; + } + + LocalHandle fence_fd(fence->isValid() ? fence->dup() : -1); + + DvrNativeBufferMetadata meta_data; + meta_data.timestamp = timestamp; + meta_data.is_auto_timestamp = int32_t(is_auto_timestamp); + meta_data.dataspace = int32_t(dataspace); + meta_data.crop_left = crop.left; + meta_data.crop_top = crop.top; + meta_data.crop_right = crop.right; + meta_data.crop_bottom = crop.bottom; + meta_data.scaling_mode = int32_t(scaling_mode); + meta_data.transform = int32_t(transform); + + buffer_producer->PostAsync(&meta_data, fence_fd); + buffers_[slot].mBufferState.queue(); + + output->width = buffer_producer->width(); + output->height = buffer_producer->height(); + output->transformHint = 0; // default value, we don't use it yet. + + // |numPendingBuffers| counts of the number of buffers that has been enqueued + // by the producer but not yet acquired by the consumer. Due to the nature + // of BufferHubQueue design, this is hard to trace from the producer's client + // side, but it's safe to assume it's zero. + output->numPendingBuffers = 0; + + // Note that we are not setting nextFrameNumber here as it seems to be only + // used by surface flinger. See more at b/22802885, ag/791760. + output->nextFrameNumber = 0; + + return NO_ERROR; +} + +status_t BufferHubProducer::cancelBuffer(int slot, const sp<Fence>& fence) { + ALOGV(__FUNCTION__); + + std::unique_lock<std::mutex> lock(mutex_); + + if (connected_api_ == kNoConnectedApi) { + ALOGE("cancelBuffer: BufferQueue has no connected producer"); + return NO_INIT; + } + + if (slot < 0 || slot >= max_buffer_count_) { + ALOGE("cancelBuffer: slot index %d out of range [0, %d)", slot, max_buffer_count_); + return BAD_VALUE; + } else if (!buffers_[slot].mBufferState.isDequeued()) { + ALOGE("cancelBuffer: slot %d is not owned by the producer (state = %s)", slot, + buffers_[slot].mBufferState.string()); + return BAD_VALUE; + } else if (fence == nullptr) { + ALOGE("cancelBuffer: fence is NULL"); + return BAD_VALUE; + } + + auto buffer_producer = buffers_[slot].mBufferProducer; + queue_->Enqueue(buffer_producer, size_t(slot), 0ULL); + buffers_[slot].mBufferState.cancel(); + buffers_[slot].mFence = fence; + ALOGV("cancelBuffer: slot %d", slot); + + return NO_ERROR; +} + +status_t BufferHubProducer::query(int what, int* out_value) { + ALOGV(__FUNCTION__); + + std::unique_lock<std::mutex> lock(mutex_); + + if (out_value == nullptr) { + ALOGE("query: out_value was NULL"); + return BAD_VALUE; + } + + int value = 0; + switch (what) { + case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: + // TODO(b/36187402) This should be the maximum number of buffers that this + // producer queue's consumer can acquire. Set to be at least one. Need to + // find a way to set from the consumer side. + value = kDefaultUndequeuedBuffers; + break; + case NATIVE_WINDOW_BUFFER_AGE: + value = 0; + break; + case NATIVE_WINDOW_WIDTH: + value = int32_t(queue_->default_width()); + break; + case NATIVE_WINDOW_HEIGHT: + value = int32_t(queue_->default_height()); + break; + case NATIVE_WINDOW_FORMAT: + value = int32_t(queue_->default_format()); + break; + case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: + // BufferHubQueue is always operating in async mode, thus semantically + // consumer can never be running behind. See BufferQueueCore.cpp core + // for more information about the original meaning of this flag. + value = 0; + break; + case NATIVE_WINDOW_CONSUMER_USAGE_BITS: + // TODO(jwcai) This is currently not implement as we don't need + // IGraphicBufferConsumer parity. + value = 0; + break; + case NATIVE_WINDOW_DEFAULT_DATASPACE: + // TODO(jwcai) Return the default value android::BufferQueue is using as + // there is no way dvr::ConsumerQueue can set it. + value = 0; // HAL_DATASPACE_UNKNOWN + break; + case NATIVE_WINDOW_STICKY_TRANSFORM: + // TODO(jwcai) Return the default value android::BufferQueue is using as + // there is no way dvr::ConsumerQueue can set it. + value = 0; + break; + case NATIVE_WINDOW_CONSUMER_IS_PROTECTED: + // In Daydream's implementation, the consumer end (i.e. VR Compostior) + // knows how to handle protected buffers. + value = 1; + break; + default: + return BAD_VALUE; + } + + ALOGV("query: key=%d, v=%d", what, value); + *out_value = value; + return NO_ERROR; +} + +status_t BufferHubProducer::connect(const sp<IProducerListener>& /* listener */, int api, + bool /* producer_controlled_by_app */, + QueueBufferOutput* output) { + // Consumer interaction are actually handled by buffer hub, and we need + // to maintain consumer operations here. We only need to perform basic input + // parameter checks here. + ALOGV(__FUNCTION__); + + if (output == nullptr) { + return BAD_VALUE; + } + + std::unique_lock<std::mutex> lock(mutex_); + + if (connected_api_ != kNoConnectedApi) { + return BAD_VALUE; + } + + if (!queue_->is_connected()) { + ALOGE("BufferHubProducer::connect: This BufferHubProducer is not " + "connected to bufferhud. Has it been taken out as a parcelable?"); + return BAD_VALUE; + } + + switch (api) { + case NATIVE_WINDOW_API_EGL: + case NATIVE_WINDOW_API_CPU: + case NATIVE_WINDOW_API_MEDIA: + case NATIVE_WINDOW_API_CAMERA: + connected_api_ = api; + + output->width = queue_->default_width(); + output->height = queue_->default_height(); + + // default values, we don't use them yet. + output->transformHint = 0; + output->numPendingBuffers = 0; + output->nextFrameNumber = 0; + output->bufferReplaced = false; + + break; + default: + ALOGE("BufferHubProducer::connect: unknow API %d", api); + return BAD_VALUE; + } + + return NO_ERROR; +} + +status_t BufferHubProducer::disconnect(int api, DisconnectMode /*mode*/) { + // Consumer interaction are actually handled by buffer hub, and we need + // to maintain consumer operations here. We only need to perform basic input + // parameter checks here. + ALOGV(__FUNCTION__); + + std::unique_lock<std::mutex> lock(mutex_); + + if (kNoConnectedApi == connected_api_) { + return NO_INIT; + } else if (api != connected_api_) { + return BAD_VALUE; + } + + FreeAllBuffers(); + connected_api_ = kNoConnectedApi; + return NO_ERROR; +} + +status_t BufferHubProducer::setSidebandStream(const sp<NativeHandle>& stream) { + if (stream != nullptr) { + // TODO(jwcai) Investigate how is is used, maybe use BufferHubBuffer's + // metadata. + ALOGE("SidebandStream is not currently supported."); + return INVALID_OPERATION; + } + return NO_ERROR; +} + +void BufferHubProducer::allocateBuffers(uint32_t /* width */, uint32_t /* height */, + PixelFormat /* format */, uint64_t /* usage */) { + // TODO(jwcai) |allocateBuffers| aims to preallocate up to the maximum number + // of buffers permitted by the current BufferQueue configuration (aka + // |max_buffer_count_|). + ALOGE("BufferHubProducer::allocateBuffers not implemented."); +} + +status_t BufferHubProducer::allowAllocation(bool /* allow */) { + ALOGE("BufferHubProducer::allowAllocation not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubProducer::setGenerationNumber(uint32_t generation_number) { + ALOGV(__FUNCTION__); + + std::unique_lock<std::mutex> lock(mutex_); + generation_number_ = generation_number; + return NO_ERROR; +} + +String8 BufferHubProducer::getConsumerName() const { + // BufferHub based implementation could have one to many producer/consumer + // relationship, thus |getConsumerName| from the producer side does not + // make any sense. + ALOGE("BufferHubProducer::getConsumerName not supported."); + return String8("BufferHubQueue::DummyConsumer"); +} + +status_t BufferHubProducer::setSharedBufferMode(bool shared_buffer_mode) { + if (shared_buffer_mode) { + ALOGE("BufferHubProducer::setSharedBufferMode(true) is not supported."); + // TODO(b/36373181) Front buffer mode for buffer hub queue as ANativeWindow. + return INVALID_OPERATION; + } + // Setting to default should just work as a no-op. + return NO_ERROR; +} + +status_t BufferHubProducer::setAutoRefresh(bool auto_refresh) { + if (auto_refresh) { + ALOGE("BufferHubProducer::setAutoRefresh(true) is not supported."); + return INVALID_OPERATION; + } + // Setting to default should just work as a no-op. + return NO_ERROR; +} + +status_t BufferHubProducer::setDequeueTimeout(nsecs_t timeout) { + ALOGV(__FUNCTION__); + + std::unique_lock<std::mutex> lock(mutex_); + dequeue_timeout_ms_ = static_cast<int>(timeout / (1000 * 1000)); + return NO_ERROR; +} + +status_t BufferHubProducer::getLastQueuedBuffer(sp<GraphicBuffer>* /* out_buffer */, + sp<Fence>* /* out_fence */, + float /*out_transform_matrix*/[16]) { + ALOGE("BufferHubProducer::getLastQueuedBuffer not implemented."); + return INVALID_OPERATION; +} + +void BufferHubProducer::getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) { + ALOGE("BufferHubProducer::getFrameTimestamps not implemented."); +} + +status_t BufferHubProducer::getUniqueId(uint64_t* out_id) const { + ALOGV(__FUNCTION__); + + *out_id = unique_id_; + return NO_ERROR; +} + +status_t BufferHubProducer::getConsumerUsage(uint64_t* out_usage) const { + ALOGV(__FUNCTION__); + + // same value as returned by querying NATIVE_WINDOW_CONSUMER_USAGE_BITS + *out_usage = 0; + return NO_ERROR; +} + +status_t BufferHubProducer::TakeAsParcelable(ProducerQueueParcelable* out_parcelable) { + if (!out_parcelable || out_parcelable->IsValid()) return BAD_VALUE; + + if (connected_api_ != kNoConnectedApi) { + ALOGE("BufferHubProducer::TakeAsParcelable: BufferHubProducer has " + "connected client. Must disconnect first."); + return BAD_VALUE; + } + + if (!queue_->is_connected()) { + ALOGE("BufferHubProducer::TakeAsParcelable: This BufferHubProducer " + "is not connected to bufferhud. Has it been taken out as a " + "parcelable?"); + return BAD_VALUE; + } + + auto status = queue_->TakeAsParcelable(); + if (!status) { + ALOGE("BufferHubProducer::TakeAsParcelable: Failed to take out " + "ProducuerQueueParcelable from the producer queue, error: %s.", + status.GetErrorMessage().c_str()); + return BAD_VALUE; + } + + *out_parcelable = status.take(); + return NO_ERROR; +} + +status_t BufferHubProducer::AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count, + PixelFormat format, uint64_t usage) { + auto status = queue_->AllocateBuffer(width, height, layer_count, uint32_t(format), usage); + if (!status) { + ALOGE("BufferHubProducer::AllocateBuffer: Failed to allocate buffer: %s", + status.GetErrorMessage().c_str()); + return NO_MEMORY; + } + + size_t slot = status.get(); + auto buffer_producer = queue_->GetBuffer(slot); + + LOG_ALWAYS_FATAL_IF(buffer_producer == nullptr, "Failed to get buffer producer at slot: %zu", + slot); + + buffers_[slot].mBufferProducer = buffer_producer; + + return NO_ERROR; +} + +status_t BufferHubProducer::RemoveBuffer(size_t slot) { + auto status = queue_->RemoveBuffer(slot); + if (!status) { + ALOGE("BufferHubProducer::RemoveBuffer: Failed to remove buffer: %s", + status.GetErrorMessage().c_str()); + return INVALID_OPERATION; + } + + // Reset in memory objects related the the buffer. + buffers_[slot].mBufferProducer = nullptr; + buffers_[slot].mGraphicBuffer = nullptr; + buffers_[slot].mBufferState.detachProducer(); + return NO_ERROR; +} + +status_t BufferHubProducer::FreeAllBuffers() { + for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) { + // Reset in memory objects related the the buffer. + buffers_[slot].mGraphicBuffer = nullptr; + buffers_[slot].mBufferState.reset(); + buffers_[slot].mRequestBufferCalled = false; + buffers_[slot].mBufferProducer = nullptr; + buffers_[slot].mFence = Fence::NO_FENCE; + } + + auto status = queue_->FreeAllBuffers(); + if (!status) { + ALOGE("BufferHubProducer::FreeAllBuffers: Failed to free all buffers on " + "the queue: %s", + status.GetErrorMessage().c_str()); + } + + if (queue_->capacity() != 0 || queue_->count() != 0) { + LOG_ALWAYS_FATAL("BufferHubProducer::FreeAllBuffers: Not all buffers are freed."); + } + + return NO_ERROR; +} + +status_t BufferHubProducer::exportToParcel(Parcel* parcel) { + status_t res = TakeAsParcelable(&pending_producer_parcelable_); + if (res != NO_ERROR) return res; + + if (!pending_producer_parcelable_.IsValid()) { + ALOGE("BufferHubProducer::exportToParcel: Invalid parcelable object."); + return BAD_VALUE; + } + + res = parcel->writeUint32(USE_BUFFER_HUB); + if (res != NO_ERROR) { + ALOGE("BufferHubProducer::exportToParcel: Cannot write magic, res=%d.", res); + return res; + } + + return pending_producer_parcelable_.writeToParcel(parcel); +} + +IBinder* BufferHubProducer::onAsBinder() { + ALOGE("BufferHubProducer::onAsBinder: BufferHubProducer should never be used as an Binder " + "object."); + return nullptr; +} + +} // namespace android diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp index 9da4ea80e0..f50379b3ed 100644 --- a/libs/gui/BufferItem.cpp +++ b/libs/gui/BufferItem.cpp @@ -39,8 +39,8 @@ static inline constexpr T to64(const uint32_t lo, const uint32_t hi) { } BufferItem::BufferItem() : - mGraphicBuffer(nullptr), - mFence(nullptr), + mGraphicBuffer(NULL), + mFence(NULL), mCrop(Rect::INVALID_RECT), mTransform(0), mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), @@ -55,7 +55,8 @@ BufferItem::BufferItem() : mSurfaceDamage(), mAutoRefresh(false), mQueuedBuffer(true), - mIsStale(false) { + mIsStale(false), + mApi(0) { } BufferItem::~BufferItem() {} @@ -84,30 +85,32 @@ size_t BufferItem::getPodSize() const { addAligned(size, mAutoRefresh); addAligned(size, mQueuedBuffer); addAligned(size, mIsStale); + addAligned(size, mApi); return size; } size_t BufferItem::getFlattenedSize() const { size_t size = sizeof(uint32_t); // Flags - if (mGraphicBuffer != nullptr) { + if (mGraphicBuffer != 0) { size += mGraphicBuffer->getFlattenedSize(); size = FlattenableUtils::align<4>(size); } - if (mFence != nullptr) { + if (mFence != 0) { size += mFence->getFlattenedSize(); size = FlattenableUtils::align<4>(size); } size += mSurfaceDamage.getFlattenedSize(); + size += mHdrMetadata.getFlattenedSize(); size = FlattenableUtils::align<8>(size); return size + getPodSize(); } size_t BufferItem::getFdCount() const { size_t count = 0; - if (mGraphicBuffer != nullptr) { + if (mGraphicBuffer != 0) { count += mGraphicBuffer->getFdCount(); } - if (mFence != nullptr) { + if (mFence != 0) { count += mFence->getFdCount(); } return count; @@ -134,13 +137,13 @@ status_t BufferItem::flatten( FlattenableUtils::advance(buffer, size, sizeof(uint32_t)); flags = 0; - if (mGraphicBuffer != nullptr) { + if (mGraphicBuffer != 0) { status_t err = mGraphicBuffer->flatten(buffer, size, fds, count); if (err) return err; size -= FlattenableUtils::align<4>(buffer); flags |= 1; } - if (mFence != nullptr) { + if (mFence != 0) { status_t err = mFence->flatten(buffer, size, fds, count); if (err) return err; size -= FlattenableUtils::align<4>(buffer); @@ -151,6 +154,10 @@ status_t BufferItem::flatten( if (err) return err; FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize()); + err = mHdrMetadata.flatten(buffer, size); + if (err) return err; + FlattenableUtils::advance(buffer, size, mHdrMetadata.getFlattenedSize()); + // Check we still have enough space if (size < getPodSize()) { return NO_MEMORY; @@ -172,6 +179,7 @@ status_t BufferItem::flatten( writeAligned(buffer, size, mAutoRefresh); writeAligned(buffer, size, mQueuedBuffer); writeAligned(buffer, size, mIsStale); + writeAligned(buffer, size, mApi); return NO_ERROR; } @@ -212,6 +220,10 @@ status_t BufferItem::unflatten( if (err) return err; FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize()); + err = mHdrMetadata.unflatten(buffer, size); + if (err) return err; + FlattenableUtils::advance(buffer, size, mHdrMetadata.getFlattenedSize()); + // Check we still have enough space if (size < getPodSize()) { return NO_MEMORY; @@ -238,6 +250,7 @@ status_t BufferItem::unflatten( readAligned(buffer, size, mAutoRefresh); readAligned(buffer, size, mQueuedBuffer); readAligned(buffer, size, mIsStale); + readAligned(buffer, size, mApi); return NO_ERROR; } diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp index 3aa4e449cc..89bc0c4c2d 100644 --- a/libs/gui/BufferItemConsumer.cpp +++ b/libs/gui/BufferItemConsumer.cpp @@ -49,16 +49,6 @@ BufferItemConsumer::BufferItemConsumer( BufferItemConsumer::~BufferItemConsumer() {} -void BufferItemConsumer::setName(const String8& name) { - Mutex::Autolock _l(mMutex); - if (mAbandoned) { - BI_LOGE("setName: BufferItemConsumer is abandoned!"); - return; - } - mName = name; - mConsumer->setConsumerName(name); -} - void BufferItemConsumer::setBufferFreedListener( const wp<BufferFreedListener>& listener) { Mutex::Autolock _l(mMutex); @@ -102,10 +92,13 @@ status_t BufferItemConsumer::releaseBuffer(const BufferItem &item, Mutex::Autolock _l(mMutex); err = addReleaseFenceLocked(item.mSlot, item.mGraphicBuffer, releaseFence); + if (err != OK) { + BI_LOGE("Failed to addReleaseFenceLocked"); + } err = releaseBufferLocked(item.mSlot, item.mGraphicBuffer, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); - if (err != OK) { + if (err != OK && err != IGraphicBufferConsumer::STALE_BUFFER_SLOT) { BI_LOGE("Failed to release buffer: %s (%d)", strerror(-err), err); } @@ -114,7 +107,7 @@ status_t BufferItemConsumer::releaseBuffer(const BufferItem &item, void BufferItemConsumer::freeBufferLocked(int slotIndex) { sp<BufferFreedListener> listener = mBufferFreedListener.promote(); - if (listener != nullptr && mSlots[slotIndex].mGraphicBuffer != nullptr) { + if (listener != NULL && mSlots[slotIndex].mGraphicBuffer != NULL) { // Fire callback if we have a listener registered and the buffer being freed is valid. BI_LOGV("actually calling onBufferFreed"); listener->onBufferFreed(mSlots[slotIndex].mGraphicBuffer); diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 7da4db4d3f..a8da1347cb 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -18,6 +18,11 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 +#ifndef NO_BUFFERHUB +#include <gui/BufferHubConsumer.h> +#include <gui/BufferHubProducer.h> +#endif + #include <gui/BufferQueue.h> #include <gui/BufferQueueConsumer.h> #include <gui/BufferQueueCore.h> @@ -33,7 +38,7 @@ BufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {} void BufferQueue::ProxyConsumerListener::onDisconnect() { sp<ConsumerListener> listener(mConsumerListener.promote()); - if (listener != nullptr) { + if (listener != NULL) { listener->onDisconnect(); } } @@ -41,7 +46,7 @@ void BufferQueue::ProxyConsumerListener::onDisconnect() { void BufferQueue::ProxyConsumerListener::onFrameAvailable( const BufferItem& item) { sp<ConsumerListener> listener(mConsumerListener.promote()); - if (listener != nullptr) { + if (listener != NULL) { listener->onFrameAvailable(item); } } @@ -49,21 +54,21 @@ void BufferQueue::ProxyConsumerListener::onFrameAvailable( void BufferQueue::ProxyConsumerListener::onFrameReplaced( const BufferItem& item) { sp<ConsumerListener> listener(mConsumerListener.promote()); - if (listener != nullptr) { + if (listener != NULL) { listener->onFrameReplaced(item); } } void BufferQueue::ProxyConsumerListener::onBuffersReleased() { sp<ConsumerListener> listener(mConsumerListener.promote()); - if (listener != nullptr) { + if (listener != NULL) { listener->onBuffersReleased(); } } void BufferQueue::ProxyConsumerListener::onSidebandStreamChanged() { sp<ConsumerListener> listener(mConsumerListener.promote()); - if (listener != nullptr) { + if (listener != NULL) { listener->onSidebandStreamChanged(); } } @@ -80,25 +85,53 @@ void BufferQueue::ProxyConsumerListener::addAndGetFrameTimestamps( void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer, sp<IGraphicBufferConsumer>* outConsumer, bool consumerIsSurfaceFlinger) { - LOG_ALWAYS_FATAL_IF(outProducer == nullptr, + LOG_ALWAYS_FATAL_IF(outProducer == NULL, "BufferQueue: outProducer must not be NULL"); - LOG_ALWAYS_FATAL_IF(outConsumer == nullptr, + LOG_ALWAYS_FATAL_IF(outConsumer == NULL, "BufferQueue: outConsumer must not be NULL"); sp<BufferQueueCore> core(new BufferQueueCore()); - LOG_ALWAYS_FATAL_IF(core == nullptr, + LOG_ALWAYS_FATAL_IF(core == NULL, "BufferQueue: failed to create BufferQueueCore"); sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core, consumerIsSurfaceFlinger)); - LOG_ALWAYS_FATAL_IF(producer == nullptr, + LOG_ALWAYS_FATAL_IF(producer == NULL, "BufferQueue: failed to create BufferQueueProducer"); sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core)); - LOG_ALWAYS_FATAL_IF(consumer == nullptr, + LOG_ALWAYS_FATAL_IF(consumer == NULL, "BufferQueue: failed to create BufferQueueConsumer"); *outProducer = producer; *outConsumer = consumer; } +#ifndef NO_BUFFERHUB +void BufferQueue::createBufferHubQueue(sp<IGraphicBufferProducer>* outProducer, + sp<IGraphicBufferConsumer>* outConsumer) { + LOG_ALWAYS_FATAL_IF(outProducer == NULL, "BufferQueue: outProducer must not be NULL"); + LOG_ALWAYS_FATAL_IF(outConsumer == NULL, "BufferQueue: outConsumer must not be NULL"); + + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + + dvr::ProducerQueueConfigBuilder configBuilder; + std::shared_ptr<dvr::ProducerQueue> producerQueue = + dvr::ProducerQueue::Create(configBuilder.Build(), dvr::UsagePolicy{}); + LOG_ALWAYS_FATAL_IF(producerQueue == NULL, "BufferQueue: failed to create ProducerQueue."); + + std::shared_ptr<dvr::ConsumerQueue> consumerQueue = producerQueue->CreateConsumerQueue(); + LOG_ALWAYS_FATAL_IF(consumerQueue == NULL, "BufferQueue: failed to create ConsumerQueue."); + + producer = BufferHubProducer::Create(producerQueue); + consumer = BufferHubConsumer::Create(consumerQueue); + + LOG_ALWAYS_FATAL_IF(producer == NULL, "BufferQueue: failed to create BufferQueueProducer"); + LOG_ALWAYS_FATAL_IF(consumer == NULL, "BufferQueue: failed to create BufferQueueConsumer"); + + *outProducer = producer; + *outConsumer = consumer; +} +#endif + }; // namespace android diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index 31eb29b8f6..d70e1422b0 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -35,7 +35,9 @@ #include <gui/IProducerListener.h> #include <binder/IPCThreadState.h> +#ifndef __ANDROID_VNDK__ #include <binder/PermissionCache.h> +#endif #include <system/window.h> @@ -253,7 +255,7 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, // mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer // on the consumer side if (outBuffer->mAcquireCalled) { - outBuffer->mGraphicBuffer = nullptr; + outBuffer->mGraphicBuffer = NULL; } mCore->mQueue.erase(front); @@ -270,7 +272,7 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, VALIDATE_CONSISTENCY(); } - if (listener != nullptr) { + if (listener != NULL) { for (int i = 0; i < numDroppedBuffers; ++i) { listener->onBufferReleased(); } @@ -319,10 +321,10 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot, const sp<android::GraphicBuffer>& buffer) { ATRACE_CALL(); - if (outSlot == nullptr) { + if (outSlot == NULL) { BQ_LOGE("attachBuffer: outSlot must not be NULL"); return BAD_VALUE; - } else if (buffer == nullptr) { + } else if (buffer == NULL) { BQ_LOGE("attachBuffer: cannot attach NULL buffer"); return BAD_VALUE; } @@ -411,7 +413,7 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, ATRACE_BUFFER_INDEX(slot); if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS || - releaseFence == nullptr) { + releaseFence == NULL) { BQ_LOGE("releaseBuffer: slot %d out of range or fence %p NULL", slot, releaseFence.get()); return BAD_VALUE; @@ -463,7 +465,7 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, } // Autolock scope // Call back without lock held - if (listener != nullptr) { + if (listener != NULL) { listener->onBufferReleased(); } @@ -474,7 +476,7 @@ status_t BufferQueueConsumer::connect( const sp<IConsumerListener>& consumerListener, bool controlledByApp) { ATRACE_CALL(); - if (consumerListener == nullptr) { + if (consumerListener == NULL) { BQ_LOGE("connect: consumerListener may not be NULL"); return BAD_VALUE; } @@ -502,13 +504,13 @@ status_t BufferQueueConsumer::disconnect() { Mutex::Autolock lock(mCore->mMutex); - if (mCore->mConsumerListener == nullptr) { + if (mCore->mConsumerListener == NULL) { BQ_LOGE("disconnect: no consumer is connected"); return BAD_VALUE; } mCore->mIsAbandoned = true; - mCore->mConsumerListener = nullptr; + mCore->mConsumerListener = NULL; mCore->mQueue.clear(); mCore->freeAllBuffersLocked(); mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT; @@ -519,7 +521,7 @@ status_t BufferQueueConsumer::disconnect() { status_t BufferQueueConsumer::getReleasedBuffers(uint64_t *outSlotMask) { ATRACE_CALL(); - if (outSlotMask == nullptr) { + if (outSlotMask == NULL) { BQ_LOGE("getReleasedBuffers: outSlotMask may not be NULL"); return BAD_VALUE; } @@ -671,7 +673,7 @@ status_t BufferQueueConsumer::setMaxAcquiredBufferCount( } } // Call back without lock held - if (listener != nullptr) { + if (listener != NULL) { listener->onBuffersReleased(); } @@ -757,14 +759,20 @@ status_t BufferQueueConsumer::dumpState(const String8& prefix, String8* outResul } const IPCThreadState* ipc = IPCThreadState::self(); - const pid_t pid = ipc->getCallingPid(); const uid_t uid = ipc->getCallingUid(); +#ifndef __ANDROID_VNDK__ + // permission check can't be done for vendors as vendors have no access to + // the PermissionController + const pid_t pid = ipc->getCallingPid(); if ((uid != shellUid) && !PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) { outResult->appendFormat("Permission Denial: can't dump BufferQueueConsumer " "from pid=%d, uid=%d\n", pid, uid); +#else + if (uid != shellUid) { +#endif android_errorWriteWithInfoLog(0x534e4554, "27046057", - static_cast<int32_t>(uid), nullptr, 0); + static_cast<int32_t>(uid), NULL, 0); return PERMISSION_DENIED; } diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 0c7b7e20db..c8021e4d54 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -166,7 +166,7 @@ status_t BufferQueueProducer::setMaxDequeuedBufferCount( } // Autolock scope // Call back without lock held - if (listener != nullptr) { + if (listener != NULL) { listener->onBuffersReleased(); } @@ -221,7 +221,7 @@ status_t BufferQueueProducer::setAsyncMode(bool async) { } // Autolock scope // Call back without lock held - if (listener != nullptr) { + if (listener != NULL) { listener->onBuffersReleased(); } return NO_ERROR; @@ -450,11 +450,11 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* ou mSlots[found].mBufferState.dequeue(); - if ((buffer == nullptr) || + if ((buffer == NULL) || buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage)) { mSlots[found].mAcquireCalled = false; - mSlots[found].mGraphicBuffer = nullptr; + mSlots[found].mGraphicBuffer = NULL; mSlots[found].mRequestBufferCalled = false; mSlots[found].mEglDisplay = EGL_NO_DISPLAY; mSlots[found].mEglFence = EGL_NO_SYNC_KHR; @@ -472,7 +472,7 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* ou BQ_LOGV("dequeueBuffer: setting buffer age to %" PRIu64, mCore->mBufferAge); - if (CC_UNLIKELY(mSlots[found].mFence == nullptr)) { + if (CC_UNLIKELY(mSlots[found].mFence == NULL)) { BQ_LOGE("dequeueBuffer: about to return a NULL fence - " "slot=%d w=%d h=%d format=%u", found, buffer->width, buffer->height, buffer->format); @@ -613,7 +613,7 @@ status_t BufferQueueProducer::detachBuffer(int slot) { listener = mCore->mConsumerListener; } - if (listener != nullptr) { + if (listener != NULL) { listener->onBuffersReleased(); } @@ -624,10 +624,10 @@ status_t BufferQueueProducer::detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) { ATRACE_CALL(); - if (outBuffer == nullptr) { + if (outBuffer == NULL) { BQ_LOGE("detachNextBuffer: outBuffer must not be NULL"); return BAD_VALUE; - } else if (outFence == nullptr) { + } else if (outFence == NULL) { BQ_LOGE("detachNextBuffer: outFence must not be NULL"); return BAD_VALUE; } @@ -671,7 +671,7 @@ status_t BufferQueueProducer::detachNextBuffer(sp<GraphicBuffer>* outBuffer, listener = mCore->mConsumerListener; } - if (listener != nullptr) { + if (listener != NULL) { listener->onBuffersReleased(); } @@ -682,10 +682,10 @@ status_t BufferQueueProducer::attachBuffer(int* outSlot, const sp<android::GraphicBuffer>& buffer) { ATRACE_CALL(); - if (outSlot == nullptr) { + if (outSlot == NULL) { BQ_LOGE("attachBuffer: outSlot must not be NULL"); return BAD_VALUE; - } else if (buffer == nullptr) { + } else if (buffer == NULL) { BQ_LOGE("attachBuffer: cannot attach NULL buffer"); return BAD_VALUE; } @@ -765,8 +765,9 @@ status_t BufferQueueProducer::queueBuffer(int slot, &crop, &scalingMode, &transform, &acquireFence, &stickyTransform, &getFrameTimestamps); const Region& surfaceDamage = input.getSurfaceDamage(); + const HdrMetadata& hdrMetadata = input.getHdrMetadata(); - if (acquireFence == nullptr) { + if (acquireFence == NULL) { BQ_LOGE("queueBuffer: fence is NULL"); return BAD_VALUE; } @@ -825,9 +826,9 @@ status_t BufferQueueProducer::queueBuffer(int slot, } BQ_LOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64 " dataSpace=%d" - " crop=[%d,%d,%d,%d] transform=%#x scale=%s", - slot, mCore->mFrameCounter + 1, requestedPresentTimestamp, - dataSpace, crop.left, crop.top, crop.right, crop.bottom, + " validHdrMetadataTypes=0x%x crop=[%d,%d,%d,%d] transform=%#x scale=%s", + slot, mCore->mFrameCounter + 1, requestedPresentTimestamp, dataSpace, + hdrMetadata.validTypes, crop.left, crop.top, crop.right, crop.bottom, transform, BufferItem::scalingModeName(static_cast<uint32_t>(scalingMode))); @@ -866,6 +867,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, item.mTimestamp = requestedPresentTimestamp; item.mIsAutoTimestamp = isAutoTimestamp; item.mDataSpace = dataSpace; + item.mHdrMetadata = hdrMetadata; item.mFrameNumber = currentFrameNumber; item.mSlot = slot; item.mFence = acquireFence; @@ -876,6 +878,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, item.mSurfaceDamage = surfaceDamage; item.mQueuedBuffer = true; item.mAutoRefresh = mCore->mSharedBufferMode && mCore->mAutoRefresh; + item.mApi = mCore->mConnectedApi; mStickyTransform = stickyTransform; @@ -970,9 +973,9 @@ status_t BufferQueueProducer::queueBuffer(int slot, mCallbackCondition.wait(mCallbackMutex); } - if (frameAvailableListener != nullptr) { + if (frameAvailableListener != NULL) { frameAvailableListener->onFrameAvailable(item); - } else if (frameReplacedListener != nullptr) { + } else if (frameReplacedListener != NULL) { frameReplacedListener->onFrameReplaced(item); } @@ -1037,7 +1040,7 @@ status_t BufferQueueProducer::cancelBuffer(int slot, const sp<Fence>& fence) { BQ_LOGE("cancelBuffer: slot %d is not owned by the producer " "(state = %s)", slot, mSlots[slot].mBufferState.string()); return BAD_VALUE; - } else if (fence == nullptr) { + } else if (fence == NULL) { BQ_LOGE("cancelBuffer: fence is NULL"); return BAD_VALUE; } @@ -1067,7 +1070,7 @@ int BufferQueueProducer::query(int what, int *outValue) { ATRACE_CALL(); Mutex::Autolock lock(mCore->mMutex); - if (outValue == nullptr) { + if (outValue == NULL) { BQ_LOGE("query: outValue was NULL"); return BAD_VALUE; } @@ -1118,6 +1121,9 @@ int BufferQueueProducer::query(int what, int *outValue) { case NATIVE_WINDOW_CONSUMER_IS_PROTECTED: value = static_cast<int32_t>(mCore->mConsumerIsProtected); break; + case NATIVE_WINDOW_MAX_BUFFER_COUNT: + value = static_cast<int32_t>(mCore->mMaxBufferCount); + break; default: return BAD_VALUE; } @@ -1140,12 +1146,12 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener, return NO_INIT; } - if (mCore->mConsumerListener == nullptr) { + if (mCore->mConsumerListener == NULL) { BQ_LOGE("connect: BufferQueue has no consumer"); return NO_INIT; } - if (output == nullptr) { + if (output == NULL) { BQ_LOGE("connect: output was NULL"); return BAD_VALUE; } @@ -1183,10 +1189,10 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener, output->nextFrameNumber = mCore->mFrameCounter + 1; output->bufferReplaced = false; - if (listener != nullptr) { + if (listener != NULL) { // Set up a death notification so that we can disconnect // automatically if the remote producer dies - if (IInterface::asBinder(listener)->remoteBinder() != nullptr) { + if (IInterface::asBinder(listener)->remoteBinder() != NULL) { status = IInterface::asBinder(listener)->linkToDeath( static_cast<IBinder::DeathRecipient*>(this)); if (status != NO_ERROR) { @@ -1263,7 +1269,7 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) { mCore->freeAllBuffersLocked(); // Remove our death notification callback if we have one - if (mCore->mLinkedToDeath != nullptr) { + if (mCore->mLinkedToDeath != NULL) { sp<IBinder> token = IInterface::asBinder(mCore->mLinkedToDeath); // This can fail if we're here because of the death @@ -1273,8 +1279,8 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) { } mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT; - mCore->mLinkedToDeath = nullptr; - mCore->mConnectedProducerListener = nullptr; + mCore->mLinkedToDeath = NULL; + mCore->mConnectedProducerListener = NULL; mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API; mCore->mConnectedPid = -1; mCore->mSidebandStream.clear(); @@ -1297,7 +1303,7 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) { } // Autolock scope // Call back without lock held - if (listener != nullptr) { + if (listener != NULL) { listener->onBuffersReleased(); listener->onDisconnect(); } @@ -1313,7 +1319,7 @@ status_t BufferQueueProducer::setSidebandStream(const sp<NativeHandle>& stream) listener = mCore->mConsumerListener; } // Autolock scope - if (listener != nullptr) { + if (listener != NULL) { listener->onSidebandStreamChanged(); } return NO_ERROR; @@ -1328,6 +1334,7 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, uint32_t allocHeight = 0; PixelFormat allocFormat = PIXEL_FORMAT_UNKNOWN; uint64_t allocUsage = 0; + std::string allocName; { // Autolock scope Mutex::Autolock lock(mCore->mMutex); mCore->waitWhileAllocatingLocked(); @@ -1347,6 +1354,7 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, allocHeight = height > 0 ? height : mCore->mDefaultHeight; allocFormat = format != 0 ? format : mCore->mDefaultBufferFormat; allocUsage = usage | mCore->mConsumerUsageBits; + allocName.assign(mCore->mConsumerName.string(), mCore->mConsumerName.size()); mCore->mIsAllocating = true; } // Autolock scope @@ -1355,7 +1363,7 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, for (size_t i = 0; i < newBufferCount; ++i) { sp<GraphicBuffer> graphicBuffer = new GraphicBuffer( allocWidth, allocHeight, allocFormat, BQ_LAYER_COUNT, - allocUsage, {mConsumerName.string(), mConsumerName.size()}); + allocUsage, allocName); status_t result = graphicBuffer->initCheck(); @@ -1527,7 +1535,7 @@ void BufferQueueProducer::addAndGetFrameTimestamps( Mutex::Autolock lock(mCore->mMutex); listener = mCore->mConsumerListener; } - if (listener != nullptr) { + if (listener != NULL) { listener->addAndGetFrameTimestamps(newTimestamps, outDelta); } } diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index 2a9d742fc9..f9e292e199 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -96,7 +96,7 @@ void ConsumerBase::onLastStrongRef(const void* id __attribute__((unused))) { void ConsumerBase::freeBufferLocked(int slotIndex) { CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); - mSlots[slotIndex].mGraphicBuffer = nullptr; + mSlots[slotIndex].mGraphicBuffer = 0; mSlots[slotIndex].mFence = Fence::NO_FENCE; mSlots[slotIndex].mFrameNumber = 0; } @@ -110,7 +110,7 @@ void ConsumerBase::onFrameAvailable(const BufferItem& item) { listener = mFrameAvailableListener.promote(); } - if (listener != nullptr) { + if (listener != NULL) { CB_LOGV("actually calling onFrameAvailable"); listener->onFrameAvailable(item); } @@ -125,7 +125,7 @@ void ConsumerBase::onFrameReplaced(const BufferItem &item) { listener = mFrameAvailableListener.promote(); } - if (listener != nullptr) { + if (listener != NULL) { CB_LOGV("actually calling onFrameReplaced"); listener->onFrameReplaced(item); } @@ -182,6 +182,16 @@ bool ConsumerBase::isAbandoned() { return mAbandoned; } +void ConsumerBase::setName(const String8& name) { + Mutex::Autolock _l(mMutex); + if (mAbandoned) { + CB_LOGE("setName: ConsumerBase is abandoned!"); + return; + } + mName = name; + mConsumer->setConsumerName(name); +} + void ConsumerBase::setFrameAvailableListener( const wp<FrameAvailableListener>& listener) { CB_LOGV("setFrameAvailableListener"); @@ -237,6 +247,50 @@ status_t ConsumerBase::setDefaultBufferDataSpace( return mConsumer->setDefaultBufferDataSpace(defaultDataSpace); } +status_t ConsumerBase::setConsumerUsageBits(uint64_t usage) { + Mutex::Autolock lock(mMutex); + if (mAbandoned) { + CB_LOGE("setConsumerUsageBits: ConsumerBase is abandoned!"); + return NO_INIT; + } + return mConsumer->setConsumerUsageBits(usage); +} + +status_t ConsumerBase::setTransformHint(uint32_t hint) { + Mutex::Autolock lock(mMutex); + if (mAbandoned) { + CB_LOGE("setTransformHint: ConsumerBase is abandoned!"); + return NO_INIT; + } + return mConsumer->setTransformHint(hint); +} + +status_t ConsumerBase::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { + Mutex::Autolock lock(mMutex); + if (mAbandoned) { + CB_LOGE("setMaxAcquiredBufferCount: ConsumerBase is abandoned!"); + return NO_INIT; + } + return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers); +} + +sp<NativeHandle> ConsumerBase::getSidebandStream() const { + Mutex::Autolock _l(mMutex); + if (mAbandoned) { + CB_LOGE("getSidebandStream: ConsumerBase is abandoned!"); + return nullptr; + } + + sp<NativeHandle> stream; + status_t err = mConsumer->getSidebandStream(&stream); + if (err != NO_ERROR) { + CB_LOGE("failed to get sideband stream: %d", err); + return nullptr; + } + + return stream; +} + status_t ConsumerBase::getOccupancyHistory(bool forceFlush, std::vector<OccupancyTracker::Segment>* outHistory) { Mutex::Autolock _l(mMutex); @@ -298,8 +352,8 @@ status_t ConsumerBase::acquireBufferLocked(BufferItem *item, return err; } - if (item->mGraphicBuffer != nullptr) { - if (mSlots[item->mSlot].mGraphicBuffer != nullptr) { + if (item->mGraphicBuffer != NULL) { + if (mSlots[item->mSlot].mGraphicBuffer != NULL) { freeBufferLocked(item->mSlot); } mSlots[item->mSlot].mGraphicBuffer = item->mGraphicBuffer; @@ -414,7 +468,7 @@ bool ConsumerBase::stillTracking(int slot, if (slot < 0 || slot >= BufferQueue::NUM_BUFFER_SLOTS) { return false; } - return (mSlots[slot].mGraphicBuffer != nullptr && + return (mSlots[slot].mGraphicBuffer != NULL && mSlots[slot].mGraphicBuffer->handle == graphicBuffer->handle); } diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp index 9f09e0c0d4..8edf60400c 100644 --- a/libs/gui/CpuConsumer.cpp +++ b/libs/gui/CpuConsumer.cpp @@ -18,11 +18,11 @@ #define LOG_TAG "CpuConsumer" //#define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include <cutils/compiler.h> -#include <utils/Log.h> -#include <gui/BufferItem.h> #include <gui/CpuConsumer.h> +#include <gui/BufferItem.h> +#include <utils/Log.h> + #define CC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) //#define CC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) //#define CC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) @@ -44,20 +44,19 @@ CpuConsumer::CpuConsumer(const sp<IGraphicBufferConsumer>& bq, mConsumer->setMaxAcquiredBufferCount(static_cast<int32_t>(maxLockedBuffers)); } -CpuConsumer::~CpuConsumer() { - // ConsumerBase destructor does all the work. +size_t CpuConsumer::findAcquiredBufferLocked(uintptr_t id) const { + for (size_t i = 0; i < mMaxLockedBuffers; i++) { + const auto& ab = mAcquiredBuffers[i]; + // note that this finds AcquiredBuffer::kUnusedId as well + if (ab.mLockedBufferId == id) { + return i; + } + } + return mMaxLockedBuffers; // an invalid index } - - -void CpuConsumer::setName(const String8& name) { - Mutex::Autolock _l(mMutex); - if (mAbandoned) { - CC_LOGE("setName: CpuConsumer is abandoned!"); - return; - } - mName = name; - mConsumer->setConsumerName(name); +static uintptr_t getLockedBufferId(const CpuConsumer::LockedBuffer& buffer) { + return reinterpret_cast<uintptr_t>(buffer.data); } static bool isPossiblyYUV(PixelFormat format) { @@ -88,10 +87,74 @@ static bool isPossiblyYUV(PixelFormat format) { } } +status_t CpuConsumer::lockBufferItem(const BufferItem& item, LockedBuffer* outBuffer) const { + android_ycbcr ycbcr = android_ycbcr(); + + PixelFormat format = item.mGraphicBuffer->getPixelFormat(); + PixelFormat flexFormat = format; + if (isPossiblyYUV(format)) { + int fenceFd = item.mFence.get() ? item.mFence->dup() : -1; + status_t err = item.mGraphicBuffer->lockAsyncYCbCr(GraphicBuffer::USAGE_SW_READ_OFTEN, + item.mCrop, &ycbcr, fenceFd); + if (err == OK) { + flexFormat = HAL_PIXEL_FORMAT_YCbCr_420_888; + if (format != HAL_PIXEL_FORMAT_YCbCr_420_888) { + CC_LOGV("locking buffer of format %#x as flex YUV", format); + } + } else if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) { + CC_LOGE("Unable to lock YCbCr buffer for CPU reading: %s (%d)", strerror(-err), err); + return err; + } + } + + if (ycbcr.y != nullptr) { + outBuffer->data = reinterpret_cast<uint8_t*>(ycbcr.y); + outBuffer->stride = static_cast<uint32_t>(ycbcr.ystride); + outBuffer->dataCb = reinterpret_cast<uint8_t*>(ycbcr.cb); + outBuffer->dataCr = reinterpret_cast<uint8_t*>(ycbcr.cr); + outBuffer->chromaStride = static_cast<uint32_t>(ycbcr.cstride); + outBuffer->chromaStep = static_cast<uint32_t>(ycbcr.chroma_step); + } else { + // not flexible YUV; try lockAsync + void* bufferPointer = nullptr; + int fenceFd = item.mFence.get() ? item.mFence->dup() : -1; + status_t err = item.mGraphicBuffer->lockAsync(GraphicBuffer::USAGE_SW_READ_OFTEN, + item.mCrop, &bufferPointer, fenceFd); + if (err != OK) { + CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)", strerror(-err), err); + return err; + } + + outBuffer->data = reinterpret_cast<uint8_t*>(bufferPointer); + outBuffer->stride = item.mGraphicBuffer->getStride(); + outBuffer->dataCb = nullptr; + outBuffer->dataCr = nullptr; + outBuffer->chromaStride = 0; + outBuffer->chromaStep = 0; + } + + outBuffer->width = item.mGraphicBuffer->getWidth(); + outBuffer->height = item.mGraphicBuffer->getHeight(); + outBuffer->format = format; + outBuffer->flexFormat = flexFormat; + + outBuffer->crop = item.mCrop; + outBuffer->transform = item.mTransform; + outBuffer->scalingMode = item.mScalingMode; + outBuffer->timestamp = item.mTimestamp; + outBuffer->dataSpace = item.mDataSpace; + outBuffer->frameNumber = item.mFrameNumber; + + return OK; +} + status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { status_t err; if (!nativeBuffer) return BAD_VALUE; + + Mutex::Autolock _l(mMutex); + if (mCurrentLockedBuffers == mMaxLockedBuffers) { CC_LOGW("Max buffers have been locked (%zd), cannot lock anymore.", mMaxLockedBuffers); @@ -99,9 +162,6 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { } BufferItem b; - - Mutex::Autolock _l(mMutex); - err = acquireBufferLocked(&b, 0); if (err != OK) { if (err == BufferQueue::NO_BUFFER_AVAILABLE) { @@ -112,94 +172,23 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { } } - int slot = b.mSlot; - - void *bufferPointer = nullptr; - android_ycbcr ycbcr = android_ycbcr(); - - PixelFormat format = mSlots[slot].mGraphicBuffer->getPixelFormat(); - PixelFormat flexFormat = format; - if (isPossiblyYUV(format)) { - if (b.mFence.get()) { - err = mSlots[slot].mGraphicBuffer->lockAsyncYCbCr( - GraphicBuffer::USAGE_SW_READ_OFTEN, - b.mCrop, - &ycbcr, - b.mFence->dup()); - } else { - err = mSlots[slot].mGraphicBuffer->lockYCbCr( - GraphicBuffer::USAGE_SW_READ_OFTEN, - b.mCrop, - &ycbcr); - } - if (err == OK) { - bufferPointer = ycbcr.y; - flexFormat = HAL_PIXEL_FORMAT_YCbCr_420_888; - if (format != HAL_PIXEL_FORMAT_YCbCr_420_888) { - CC_LOGV("locking buffer of format %#x as flex YUV", format); - } - } else if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) { - CC_LOGE("Unable to lock YCbCr buffer for CPU reading: %s (%d)", - strerror(-err), err); - return err; - } + if (b.mGraphicBuffer == nullptr) { + b.mGraphicBuffer = mSlots[b.mSlot].mGraphicBuffer; } - if (bufferPointer == nullptr) { // not flexible YUV - if (b.mFence.get()) { - err = mSlots[slot].mGraphicBuffer->lockAsync( - GraphicBuffer::USAGE_SW_READ_OFTEN, - b.mCrop, - &bufferPointer, - b.mFence->dup()); - } else { - err = mSlots[slot].mGraphicBuffer->lock( - GraphicBuffer::USAGE_SW_READ_OFTEN, - b.mCrop, - &bufferPointer); - } - if (err != OK) { - CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)", - strerror(-err), err); - return err; - } + err = lockBufferItem(b, nativeBuffer); + if (err != OK) { + return err; } - size_t lockedIdx = 0; - for (; lockedIdx < static_cast<size_t>(mMaxLockedBuffers); lockedIdx++) { - if (mAcquiredBuffers[lockedIdx].mSlot == - BufferQueue::INVALID_BUFFER_SLOT) { - break; - } - } - assert(lockedIdx < mMaxLockedBuffers); - - AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx); - ab.mSlot = slot; - ab.mBufferPointer = bufferPointer; - ab.mGraphicBuffer = mSlots[slot].mGraphicBuffer; - - nativeBuffer->data = - reinterpret_cast<uint8_t*>(bufferPointer); - nativeBuffer->width = mSlots[slot].mGraphicBuffer->getWidth(); - nativeBuffer->height = mSlots[slot].mGraphicBuffer->getHeight(); - nativeBuffer->format = format; - nativeBuffer->flexFormat = flexFormat; - nativeBuffer->stride = (ycbcr.y != nullptr) ? - static_cast<uint32_t>(ycbcr.ystride) : - mSlots[slot].mGraphicBuffer->getStride(); - - nativeBuffer->crop = b.mCrop; - nativeBuffer->transform = b.mTransform; - nativeBuffer->scalingMode = b.mScalingMode; - nativeBuffer->timestamp = b.mTimestamp; - nativeBuffer->dataSpace = b.mDataSpace; - nativeBuffer->frameNumber = b.mFrameNumber; - - nativeBuffer->dataCb = reinterpret_cast<uint8_t*>(ycbcr.cb); - nativeBuffer->dataCr = reinterpret_cast<uint8_t*>(ycbcr.cr); - nativeBuffer->chromaStride = static_cast<uint32_t>(ycbcr.cstride); - nativeBuffer->chromaStep = static_cast<uint32_t>(ycbcr.chroma_step); + // find an unused AcquiredBuffer + size_t lockedIdx = findAcquiredBufferLocked(AcquiredBuffer::kUnusedId); + ALOG_ASSERT(lockedIdx < mMaxLockedBuffers); + AcquiredBuffer& ab = mAcquiredBuffers.editItemAt(lockedIdx); + + ab.mSlot = b.mSlot; + ab.mGraphicBuffer = b.mGraphicBuffer; + ab.mLockedBufferId = getLockedBufferId(*nativeBuffer); mCurrentLockedBuffers++; @@ -208,60 +197,34 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) { Mutex::Autolock _l(mMutex); - size_t lockedIdx = 0; - void *bufPtr = reinterpret_cast<void *>(nativeBuffer.data); - for (; lockedIdx < static_cast<size_t>(mMaxLockedBuffers); lockedIdx++) { - if (bufPtr == mAcquiredBuffers[lockedIdx].mBufferPointer) break; - } + uintptr_t id = getLockedBufferId(nativeBuffer); + size_t lockedIdx = + (id != AcquiredBuffer::kUnusedId) ? findAcquiredBufferLocked(id) : mMaxLockedBuffers; if (lockedIdx == mMaxLockedBuffers) { CC_LOGE("%s: Can't find buffer to free", __FUNCTION__); return BAD_VALUE; } - return releaseAcquiredBufferLocked(lockedIdx); -} + AcquiredBuffer& ab = mAcquiredBuffers.editItemAt(lockedIdx); -status_t CpuConsumer::releaseAcquiredBufferLocked(size_t lockedIdx) { - status_t err; - int fd = -1; - - err = mAcquiredBuffers[lockedIdx].mGraphicBuffer->unlockAsync(&fd); + int fenceFd = -1; + status_t err = ab.mGraphicBuffer->unlockAsync(&fenceFd); if (err != OK) { CC_LOGE("%s: Unable to unlock graphic buffer %zd", __FUNCTION__, lockedIdx); return err; } - int buf = mAcquiredBuffers[lockedIdx].mSlot; - if (CC_LIKELY(fd != -1)) { - sp<Fence> fence(new Fence(fd)); - addReleaseFenceLocked( - mAcquiredBuffers[lockedIdx].mSlot, - mSlots[buf].mGraphicBuffer, - fence); - } - // release the buffer if it hasn't already been freed by the BufferQueue. - // This can happen, for example, when the producer of this buffer - // disconnected after this buffer was acquired. - if (CC_LIKELY(mAcquiredBuffers[lockedIdx].mGraphicBuffer == - mSlots[buf].mGraphicBuffer)) { - releaseBufferLocked( - buf, mAcquiredBuffers[lockedIdx].mGraphicBuffer, - EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); - } + sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); + addReleaseFenceLocked(ab.mSlot, ab.mGraphicBuffer, fence); + releaseBufferLocked(ab.mSlot, ab.mGraphicBuffer); - AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx); - ab.mSlot = BufferQueue::INVALID_BUFFER_SLOT; - ab.mBufferPointer = nullptr; - ab.mGraphicBuffer.clear(); + ab.reset(); mCurrentLockedBuffers--; - return OK; -} -void CpuConsumer::freeBufferLocked(int slotIndex) { - ConsumerBase::freeBufferLocked(slotIndex); + return OK; } } // namespace android diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp index f5cf1c4d5a..1757ec1cd3 100644 --- a/libs/gui/DisplayEventReceiver.cpp +++ b/libs/gui/DisplayEventReceiver.cpp @@ -34,9 +34,9 @@ namespace android { DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource) { sp<ISurfaceComposer> sf(ComposerService::getComposerService()); - if (sf != nullptr) { + if (sf != NULL) { mEventConnection = sf->createDisplayEventConnection(vsyncSource); - if (mEventConnection != nullptr) { + if (mEventConnection != NULL) { mDataChannel = std::make_unique<gui::BitTube>(); mEventConnection->stealReceiveChannel(mDataChannel.get()); } @@ -47,13 +47,13 @@ DisplayEventReceiver::~DisplayEventReceiver() { } status_t DisplayEventReceiver::initCheck() const { - if (mDataChannel != nullptr) + if (mDataChannel != NULL) return NO_ERROR; return NO_INIT; } int DisplayEventReceiver::getFd() const { - if (mDataChannel == nullptr) + if (mDataChannel == NULL) return NO_INIT; return mDataChannel->getFd(); @@ -63,7 +63,7 @@ status_t DisplayEventReceiver::setVsyncRate(uint32_t count) { if (int32_t(count) < 0) return BAD_VALUE; - if (mEventConnection != nullptr) { + if (mEventConnection != NULL) { mEventConnection->setVsyncRate(count); return NO_ERROR; } @@ -71,7 +71,7 @@ status_t DisplayEventReceiver::setVsyncRate(uint32_t count) { } status_t DisplayEventReceiver::requestNextVsync() { - if (mEventConnection != nullptr) { + if (mEventConnection != NULL) { mEventConnection->requestNextVsync(); return NO_ERROR; } diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp index fccca97f54..a379ad6306 100644 --- a/libs/gui/FrameTimestamps.cpp +++ b/libs/gui/FrameTimestamps.cpp @@ -628,7 +628,6 @@ FrameEventHistoryDelta& FrameEventHistoryDelta::operator=( ALOGE("FrameEventHistoryDelta assign clobbering history."); } mDeltas = std::move(src.mDeltas); - ALOGE_IF(src.mDeltas.empty(), "Source mDeltas not empty."); return *this; } diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index 59e78cc6bf..885efec9b9 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -31,6 +31,8 @@ #include <hardware/hardware.h> +#include <math/mat4.h> + #include <gui/BufferItem.h> #include <gui/GLConsumer.h> #include <gui/ISurfaceComposer.h> @@ -75,33 +77,7 @@ static const struct { "_______________" }; -// Transform matrices -static float mtxIdentity[16] = { - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1, -}; -static float mtxFlipH[16] = { - -1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 1, 0, 0, 1, -}; -static float mtxFlipV[16] = { - 1, 0, 0, 0, - 0, -1, 0, 0, - 0, 0, 1, 0, - 0, 1, 0, 1, -}; -static float mtxRot90[16] = { - 0, 1, 0, 0, - -1, 0, 0, 0, - 0, 0, 1, 0, - 1, 0, 0, 1, -}; - -static void mtxMul(float out[16], const float a[16], const float b[16]); +static const mat4 mtxIdentity; Mutex GLConsumer::sStaticInitLock; sp<GraphicBuffer> GLConsumer::sReleasedTexImageBuffer; @@ -173,7 +149,7 @@ GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex, { GLC_LOGV("GLConsumer"); - memcpy(mCurrentTransformMatrix, mtxIdentity, + memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix)); mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); @@ -202,7 +178,7 @@ GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t texTarget, { GLC_LOGV("GLConsumer"); - memcpy(mCurrentTransformMatrix, mtxIdentity, + memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix)); mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); @@ -315,7 +291,7 @@ status_t GLConsumer::releaseTexImage() { return err; } - if (mReleasedTexImage == nullptr) { + if (mReleasedTexImage == NULL) { mReleasedTexImage = new EglImage(getDebugTexImageBuffer()); } @@ -345,7 +321,7 @@ status_t GLConsumer::releaseTexImage() { sp<GraphicBuffer> GLConsumer::getDebugTexImageBuffer() { Mutex::Autolock _l(sStaticInitLock); - if (CC_UNLIKELY(sReleasedTexImageBuffer == nullptr)) { + if (CC_UNLIKELY(sReleasedTexImageBuffer == NULL)) { // The first time, create the debug texture in case the application // continues to use it. sp<GraphicBuffer> buffer = new GraphicBuffer( @@ -381,7 +357,7 @@ status_t GLConsumer::acquireBufferLocked(BufferItem *item, // If item->mGraphicBuffer is not null, this buffer has not been acquired // before, so any prior EglImage created is using a stale buffer. This // replaces any old EglImage with a new one (using the new buffer). - if (item->mGraphicBuffer != nullptr) { + if (item->mGraphicBuffer != NULL) { int slot = item->mSlot; mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer); } @@ -455,7 +431,7 @@ status_t GLConsumer::updateAndReleaseLocked(const BufferItem& item, GLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture, mCurrentTextureImage != NULL ? - mCurrentTextureImage->graphicBufferHandle() : nullptr, + mCurrentTextureImage->graphicBufferHandle() : 0, slot, mSlots[slot].mGraphicBuffer->handle); // Hang onto the pointer so that it isn't freed in the call to @@ -515,7 +491,7 @@ status_t GLConsumer::bindTextureImageLocked() { glBindTexture(mTexTarget, mTexName); if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && - mCurrentTextureImage == nullptr) { + mCurrentTextureImage == NULL) { GLC_LOGE("bindTextureImage: no currently-bound texture"); return NO_INIT; } @@ -679,7 +655,7 @@ status_t GLConsumer::attachToContext(uint32_t tex) { mTexName = tex; mAttached = true; - if (mCurrentTextureImage != nullptr) { + if (mCurrentTextureImage != NULL) { // This may wait for a buffer a second time. This is likely required if // this is a different context, since otherwise the wait could be skipped // by bouncing through another context. For the same context the extra @@ -700,7 +676,7 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { if (SyncFeatures::getInstance().useNativeFenceSync()) { EGLSyncKHR sync = eglCreateSyncKHR(dpy, - EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr); + EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); if (sync == EGL_NO_SYNC_KHR) { GLC_LOGE("syncForReleaseLocked: error creating EGL fence: %#x", eglGetError()); @@ -744,7 +720,7 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { // Create a fence for the outstanding accesses in the current // OpenGL ES context. - fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr); + fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL); if (fence == EGL_NO_SYNC_KHR) { GLC_LOGE("syncForReleaseLocked: error creating fence: %#x", eglGetError()); @@ -758,25 +734,6 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { return OK; } -bool GLConsumer::isExternalFormat(PixelFormat format) -{ - switch (format) { - // supported YUV formats - case HAL_PIXEL_FORMAT_YV12: - // Legacy/deprecated YUV formats - case HAL_PIXEL_FORMAT_YCbCr_422_SP: - case HAL_PIXEL_FORMAT_YCrCb_420_SP: - case HAL_PIXEL_FORMAT_YCbCr_422_I: - return true; - } - - // Any OEM format needs to be considered - if (format>=0x100 && format<=0x1FF) - return true; - - return false; -} - uint32_t GLConsumer::getCurrentTextureTarget() const { return mTexTarget; } @@ -795,11 +752,11 @@ void GLConsumer::setFilteringEnabled(bool enabled) { bool needsRecompute = mFilteringEnabled != enabled; mFilteringEnabled = enabled; - if (needsRecompute && mCurrentTextureImage==nullptr) { + if (needsRecompute && mCurrentTextureImage==NULL) { GLC_LOGD("setFilteringEnabled called with mCurrentTextureImage == NULL"); } - if (needsRecompute && mCurrentTextureImage != nullptr) { + if (needsRecompute && mCurrentTextureImage != NULL) { computeCurrentTransformMatrixLocked(); } } @@ -820,34 +777,37 @@ void GLConsumer::computeCurrentTransformMatrixLocked() { void GLConsumer::computeTransformMatrix(float outTransform[16], const sp<GraphicBuffer>& buf, const Rect& cropRect, uint32_t transform, bool filtering) { - - float xform[16]; - for (int i = 0; i < 16; i++) { - xform[i] = mtxIdentity[i]; - } + // Transform matrices + static const mat4 mtxFlipH( + -1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 1, 0, 0, 1 + ); + static const mat4 mtxFlipV( + 1, 0, 0, 0, + 0, -1, 0, 0, + 0, 0, 1, 0, + 0, 1, 0, 1 + ); + static const mat4 mtxRot90( + 0, 1, 0, 0, + -1, 0, 0, 0, + 0, 0, 1, 0, + 1, 0, 0, 1 + ); + + mat4 xform; if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { - float result[16]; - mtxMul(result, xform, mtxFlipH); - for (int i = 0; i < 16; i++) { - xform[i] = result[i]; - } + xform *= mtxFlipH; } if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { - float result[16]; - mtxMul(result, xform, mtxFlipV); - for (int i = 0; i < 16; i++) { - xform[i] = result[i]; - } + xform *= mtxFlipV; } if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) { - float result[16]; - mtxMul(result, xform, mtxRot90); - for (int i = 0; i < 16; i++) { - xform[i] = result[i]; - } + xform *= mtxRot90; } - float mtxBeforeFlipV[16]; if (!cropRect.isEmpty()) { float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f; float bufferWidth = buf->getWidth(); @@ -893,25 +853,63 @@ void GLConsumer::computeTransformMatrix(float outTransform[16], sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) / bufferHeight; } - float crop[16] = { + + mat4 crop( sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, 1, 0, - tx, ty, 0, 1, - }; - - mtxMul(mtxBeforeFlipV, crop, xform); - } else { - for (int i = 0; i < 16; i++) { - mtxBeforeFlipV[i] = xform[i]; - } + tx, ty, 0, 1 + ); + xform = crop * xform; } // SurfaceFlinger expects the top of its window textures to be at a Y // coordinate of 0, so GLConsumer must behave the same way. We don't // want to expose this to applications, however, so we must add an // additional vertical flip to the transform after all the other transforms. - mtxMul(outTransform, mtxFlipV, mtxBeforeFlipV); + xform = mtxFlipV * xform; + + memcpy(outTransform, xform.asArray(), sizeof(xform)); +} + +Rect GLConsumer::scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight) { + Rect outCrop = crop; + + uint32_t newWidth = static_cast<uint32_t>(crop.width()); + uint32_t newHeight = static_cast<uint32_t>(crop.height()); + + if (newWidth * bufferHeight > newHeight * bufferWidth) { + newWidth = newHeight * bufferWidth / bufferHeight; + ALOGV("too wide: newWidth = %d", newWidth); + } else if (newWidth * bufferHeight < newHeight * bufferWidth) { + newHeight = newWidth * bufferHeight / bufferWidth; + ALOGV("too tall: newHeight = %d", newHeight); + } + + uint32_t currentWidth = static_cast<uint32_t>(crop.width()); + uint32_t currentHeight = static_cast<uint32_t>(crop.height()); + + // The crop is too wide + if (newWidth < currentWidth) { + uint32_t dw = currentWidth - newWidth; + auto halfdw = dw / 2; + outCrop.left += halfdw; + // Not halfdw because it would subtract 1 too few when dw is odd + outCrop.right -= (dw - halfdw); + // The crop is too tall + } else if (newHeight < currentHeight) { + uint32_t dh = currentHeight - newHeight; + auto halfdh = dh / 2; + outCrop.top += halfdh; + // Not halfdh because it would subtract 1 too few when dh is odd + outCrop.bottom -= (dh - halfdh); + } + + ALOGV("getCurrentCrop final crop [%d,%d,%d,%d]", + outCrop.left, outCrop.top, + outCrop.right,outCrop.bottom); + + return outCrop; } nsecs_t GLConsumer::getTimestamp() { @@ -940,50 +938,14 @@ sp<GraphicBuffer> GLConsumer::getCurrentBuffer(int* outSlot) const { } return (mCurrentTextureImage == nullptr) ? - nullptr : mCurrentTextureImage->graphicBuffer(); + NULL : mCurrentTextureImage->graphicBuffer(); } Rect GLConsumer::getCurrentCrop() const { Mutex::Autolock lock(mMutex); - - Rect outCrop = mCurrentCrop; - if (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) { - uint32_t newWidth = static_cast<uint32_t>(mCurrentCrop.width()); - uint32_t newHeight = static_cast<uint32_t>(mCurrentCrop.height()); - - if (newWidth * mDefaultHeight > newHeight * mDefaultWidth) { - newWidth = newHeight * mDefaultWidth / mDefaultHeight; - GLC_LOGV("too wide: newWidth = %d", newWidth); - } else if (newWidth * mDefaultHeight < newHeight * mDefaultWidth) { - newHeight = newWidth * mDefaultHeight / mDefaultWidth; - GLC_LOGV("too tall: newHeight = %d", newHeight); - } - - uint32_t currentWidth = static_cast<uint32_t>(mCurrentCrop.width()); - uint32_t currentHeight = static_cast<uint32_t>(mCurrentCrop.height()); - - // The crop is too wide - if (newWidth < currentWidth) { - uint32_t dw = currentWidth - newWidth; - auto halfdw = dw / 2; - outCrop.left += halfdw; - // Not halfdw because it would subtract 1 too few when dw is odd - outCrop.right -= (dw - halfdw); - // The crop is too tall - } else if (newHeight < currentHeight) { - uint32_t dh = currentHeight - newHeight; - auto halfdh = dh / 2; - outCrop.top += halfdh; - // Not halfdh because it would subtract 1 too few when dh is odd - outCrop.bottom -= (dh - halfdh); - } - - GLC_LOGV("getCurrentCrop final crop [%d,%d,%d,%d]", - outCrop.left, outCrop.top, - outCrop.right,outCrop.bottom); - } - - return outCrop; + return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) + ? scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight) + : mCurrentCrop; } uint32_t GLConsumer::getCurrentTransform() const { @@ -1006,11 +968,6 @@ std::shared_ptr<FenceTime> GLConsumer::getCurrentFenceTime() const { return mCurrentFenceTime; } -status_t GLConsumer::doGLFenceWait() const { - Mutex::Autolock lock(mMutex); - return doGLFenceWaitLocked(); -} - status_t GLConsumer::doGLFenceWaitLocked() const { EGLDisplay dpy = eglGetCurrentDisplay(); @@ -1027,7 +984,8 @@ status_t GLConsumer::doGLFenceWaitLocked() const { } if (mCurrentFence->isValid()) { - if (SyncFeatures::getInstance().useWaitSync()) { + if (SyncFeatures::getInstance().useWaitSync() && + SyncFeatures::getInstance().useNativeFenceSync()) { // Create an EGLSyncKHR from the current fence. int fenceFd = mCurrentFence->dup(); if (fenceFd == -1) { @@ -1086,61 +1044,8 @@ void GLConsumer::abandonLocked() { ConsumerBase::abandonLocked(); } -void GLConsumer::setName(const String8& name) { - Mutex::Autolock _l(mMutex); - if (mAbandoned) { - GLC_LOGE("setName: GLConsumer is abandoned!"); - return; - } - mName = name; - mConsumer->setConsumerName(name); -} - -status_t GLConsumer::setDefaultBufferFormat(PixelFormat defaultFormat) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - GLC_LOGE("setDefaultBufferFormat: GLConsumer is abandoned!"); - return NO_INIT; - } - return mConsumer->setDefaultBufferFormat(defaultFormat); -} - -status_t GLConsumer::setDefaultBufferDataSpace( - android_dataspace defaultDataSpace) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - GLC_LOGE("setDefaultBufferDataSpace: GLConsumer is abandoned!"); - return NO_INIT; - } - return mConsumer->setDefaultBufferDataSpace(defaultDataSpace); -} - status_t GLConsumer::setConsumerUsageBits(uint64_t usage) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - GLC_LOGE("setConsumerUsageBits: GLConsumer is abandoned!"); - return NO_INIT; - } - usage |= DEFAULT_USAGE_FLAGS; - return mConsumer->setConsumerUsageBits(usage); -} - -status_t GLConsumer::setTransformHint(uint32_t hint) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - GLC_LOGE("setTransformHint: GLConsumer is abandoned!"); - return NO_INIT; - } - return mConsumer->setTransformHint(hint); -} - -status_t GLConsumer::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - GLC_LOGE("setMaxAcquiredBufferCount: GLConsumer is abandoned!"); - return NO_INIT; - } - return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers); + return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS); } void GLConsumer::dumpLocked(String8& result, const char* prefix) const @@ -1155,28 +1060,6 @@ void GLConsumer::dumpLocked(String8& result, const char* prefix) const ConsumerBase::dumpLocked(result, prefix); } -static void mtxMul(float out[16], const float a[16], const float b[16]) { - out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3]; - out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3]; - out[2] = a[2]*b[0] + a[6]*b[1] + a[10]*b[2] + a[14]*b[3]; - out[3] = a[3]*b[0] + a[7]*b[1] + a[11]*b[2] + a[15]*b[3]; - - out[4] = a[0]*b[4] + a[4]*b[5] + a[8]*b[6] + a[12]*b[7]; - out[5] = a[1]*b[4] + a[5]*b[5] + a[9]*b[6] + a[13]*b[7]; - out[6] = a[2]*b[4] + a[6]*b[5] + a[10]*b[6] + a[14]*b[7]; - out[7] = a[3]*b[4] + a[7]*b[5] + a[11]*b[6] + a[15]*b[7]; - - out[8] = a[0]*b[8] + a[4]*b[9] + a[8]*b[10] + a[12]*b[11]; - out[9] = a[1]*b[8] + a[5]*b[9] + a[9]*b[10] + a[13]*b[11]; - out[10] = a[2]*b[8] + a[6]*b[9] + a[10]*b[10] + a[14]*b[11]; - out[11] = a[3]*b[8] + a[7]*b[9] + a[11]*b[10] + a[15]*b[11]; - - out[12] = a[0]*b[12] + a[4]*b[13] + a[8]*b[14] + a[12]*b[15]; - out[13] = a[1]*b[12] + a[5]*b[13] + a[9]*b[14] + a[13]*b[15]; - out[14] = a[2]*b[12] + a[6]*b[13] + a[10]*b[14] + a[14]*b[15]; - out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15]; -} - GLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer) : mGraphicBuffer(graphicBuffer), mEglImage(EGL_NO_IMAGE_KHR), @@ -1267,7 +1150,7 @@ EGLImageKHR GLConsumer::EglImage::createImage(EGLDisplay dpy, attrs[3] = attrs[11]; attrs[4] = EGL_NONE; } - eglInitialize(dpy, nullptr, nullptr); + eglInitialize(dpy, 0, 0); EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs); if (image == EGL_NO_IMAGE_KHR) { diff --git a/libs/gui/HdrMetadata.cpp b/libs/gui/HdrMetadata.cpp new file mode 100644 index 0000000000..b715e431d5 --- /dev/null +++ b/libs/gui/HdrMetadata.cpp @@ -0,0 +1,97 @@ +/* + * Copyright 2018 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. + */ + +#include <gui/HdrMetadata.h> + +namespace android { + +size_t HdrMetadata::getFlattenedSize() const { + size_t size = sizeof(validTypes); + if (validTypes & SMPTE2086) { + size += sizeof(smpte2086); + } + if (validTypes & CTA861_3) { + size += sizeof(cta8613); + } + return size; +} + +status_t HdrMetadata::flatten(void* buffer, size_t size) const { + if (size < getFlattenedSize()) { + return NO_MEMORY; + } + + FlattenableUtils::write(buffer, size, validTypes); + if (validTypes & SMPTE2086) { + FlattenableUtils::write(buffer, size, smpte2086); + } + if (validTypes & CTA861_3) { + FlattenableUtils::write(buffer, size, cta8613); + } + + return NO_ERROR; +} + +status_t HdrMetadata::unflatten(void const* buffer, size_t size) { + if (size < sizeof(validTypes)) { + return NO_MEMORY; + } + FlattenableUtils::read(buffer, size, validTypes); + if (validTypes & SMPTE2086) { + if (size < sizeof(smpte2086)) { + return NO_MEMORY; + } + FlattenableUtils::read(buffer, size, smpte2086); + } + if (validTypes & CTA861_3) { + if (size < sizeof(cta8613)) { + return NO_MEMORY; + } + FlattenableUtils::read(buffer, size, cta8613); + } + + return NO_ERROR; +} + +bool HdrMetadata::operator==(const HdrMetadata& rhs) const { + if (validTypes != rhs.validTypes) return false; + + if ((validTypes & SMPTE2086) == SMPTE2086) { + if (smpte2086.displayPrimaryRed.x != rhs.smpte2086.displayPrimaryRed.x || + smpte2086.displayPrimaryRed.y != rhs.smpte2086.displayPrimaryRed.y || + smpte2086.displayPrimaryGreen.x != rhs.smpte2086.displayPrimaryGreen.x || + smpte2086.displayPrimaryGreen.y != rhs.smpte2086.displayPrimaryGreen.y || + smpte2086.displayPrimaryBlue.x != rhs.smpte2086.displayPrimaryBlue.x || + smpte2086.displayPrimaryBlue.y != rhs.smpte2086.displayPrimaryBlue.y || + smpte2086.whitePoint.x != rhs.smpte2086.whitePoint.x || + smpte2086.whitePoint.y != rhs.smpte2086.whitePoint.y || + smpte2086.maxLuminance != rhs.smpte2086.maxLuminance || + smpte2086.minLuminance != rhs.smpte2086.minLuminance) { + return false; + } + } + + if ((validTypes & CTA861_3) == CTA861_3) { + if (cta8613.maxFrameAverageLightLevel != rhs.cta8613.maxFrameAverageLightLevel || + cta8613.maxContentLightLevel != rhs.cta8613.maxContentLightLevel) { + return false; + } + } + + return true; +} + +} // namespace android diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 23e9ddc014..0749fde1ad 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -27,6 +27,9 @@ #include <binder/Parcel.h> #include <binder/IInterface.h> +#ifndef NO_BUFFERHUB +#include <gui/BufferHubProducer.h> +#endif #include <gui/BufferQueueDefs.h> #include <gui/IGraphicBufferProducer.h> #include <gui/IProducerListener.h> @@ -187,10 +190,10 @@ public: virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) { - if (outBuffer == nullptr) { + if (outBuffer == NULL) { ALOGE("detachNextBuffer: outBuffer must not be NULL"); return BAD_VALUE; - } else if (outFence == nullptr) { + } else if (outFence == NULL) { ALOGE("detachNextBuffer: outFence must not be NULL"); return BAD_VALUE; } @@ -298,7 +301,7 @@ public: int api, bool producerControlledByApp, QueueBufferOutput* output) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); - if (listener != nullptr) { + if (listener != NULL) { data.writeInt32(1); data.writeStrongBinder(IInterface::asBinder(listener)); } else { @@ -653,6 +656,79 @@ IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer, HGraphicBufferProducer, // ---------------------------------------------------------------------- +status_t IGraphicBufferProducer::exportToParcel(Parcel* parcel) { + status_t res = OK; + res = parcel->writeUint32(USE_BUFFER_QUEUE); + if (res != NO_ERROR) { + ALOGE("exportToParcel: Cannot write magic, res=%d.", res); + return res; + } + + return parcel->writeStrongBinder(IInterface::asBinder(this)); +} + +/* static */ +status_t IGraphicBufferProducer::exportToParcel(const sp<IGraphicBufferProducer>& producer, + Parcel* parcel) { + if (parcel == nullptr) { + ALOGE("exportToParcel: Invalid parcel object."); + return BAD_VALUE; + } + + if (producer == nullptr) { + status_t res = OK; + res = parcel->writeUint32(IGraphicBufferProducer::USE_BUFFER_QUEUE); + if (res != NO_ERROR) return res; + return parcel->writeStrongBinder(nullptr); + } else { + return producer->exportToParcel(parcel); + } +} + +/* static */ +sp<IGraphicBufferProducer> IGraphicBufferProducer::createFromParcel(const Parcel* parcel) { + uint32_t outMagic = 0; + status_t res = NO_ERROR; + + res = parcel->readUint32(&outMagic); + if (res != NO_ERROR) { + ALOGE("createFromParcel: Failed to read magic, error=%d.", res); + return nullptr; + } + + switch (outMagic) { + case USE_BUFFER_QUEUE: { + sp<IBinder> binder; + res = parcel->readNullableStrongBinder(&binder); + if (res != NO_ERROR) { + ALOGE("createFromParcel: Can't read strong binder."); + return nullptr; + } + return interface_cast<IGraphicBufferProducer>(binder); + } + case USE_BUFFER_HUB: { + ALOGE("createFromParcel: BufferHub not implemented."); +#ifndef NO_BUFFERHUB + dvr::ProducerQueueParcelable producerParcelable; + res = producerParcelable.readFromParcel(parcel); + if (res != NO_ERROR) { + ALOGE("createFromParcel: Failed to read from parcel, error=%d", res); + return nullptr; + } + return BufferHubProducer::Create(std::move(producerParcelable)); +#else + return nullptr; +#endif + } + default: { + ALOGE("createFromParcel: Unexpected mgaic: 0x%x.", outMagic); + return nullptr; + } + } +} + +// ---------------------------------------------------------------------------- + status_t BnGraphicBufferProducer::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { @@ -662,8 +738,8 @@ status_t BnGraphicBufferProducer::onTransact( int bufferIdx = data.readInt32(); sp<GraphicBuffer> buffer; int result = requestBuffer(bufferIdx, &buffer); - reply->writeInt32(buffer != nullptr); - if (buffer != nullptr) { + reply->writeInt32(buffer != 0); + if (buffer != 0) { reply->write(*buffer); } reply->writeInt32(result); @@ -721,12 +797,12 @@ status_t BnGraphicBufferProducer::onTransact( int32_t result = detachNextBuffer(&buffer, &fence); reply->writeInt32(result); if (result == NO_ERROR) { - reply->writeInt32(buffer != nullptr); - if (buffer != nullptr) { + reply->writeInt32(buffer != NULL); + if (buffer != NULL) { reply->write(*buffer); } - reply->writeInt32(fence != nullptr); - if (fence != nullptr) { + reply->writeInt32(fence != NULL); + if (fence != NULL) { reply->write(*fence); } } @@ -951,7 +1027,8 @@ constexpr size_t IGraphicBufferProducer::QueueBufferInput::minFlattenedSize() { size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const { return minFlattenedSize() + fence->getFlattenedSize() + - surfaceDamage.getFlattenedSize(); + surfaceDamage.getFlattenedSize() + + hdrMetadata.getFlattenedSize(); } size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const { @@ -978,7 +1055,12 @@ status_t IGraphicBufferProducer::QueueBufferInput::flatten( if (result != NO_ERROR) { return result; } - return surfaceDamage.flatten(buffer, size); + result = surfaceDamage.flatten(buffer, size); + if (result != NO_ERROR) { + return result; + } + FlattenableUtils::advance(buffer, size, surfaceDamage.getFlattenedSize()); + return hdrMetadata.flatten(buffer, size); } status_t IGraphicBufferProducer::QueueBufferInput::unflatten( @@ -1002,7 +1084,12 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten( if (result != NO_ERROR) { return result; } - return surfaceDamage.unflatten(buffer, size); + result = surfaceDamage.unflatten(buffer, size); + if (result != NO_ERROR) { + return result; + } + FlattenableUtils::advance(buffer, size, surfaceDamage.getFlattenedSize()); + return hdrMetadata.unflatten(buffer, size); } // ---------------------------------------------------------------------------- diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 8e7f814313..e22bc708c9 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -29,8 +29,7 @@ #include <gui/ISurfaceComposer.h> #include <gui/ISurfaceComposerClient.h> #include <gui/LayerDebugInfo.h> - -#include <private/gui/LayerState.h> +#include <gui/LayerState.h> #include <system/graphics.h> @@ -44,6 +43,8 @@ namespace android { +using ui::ColorMode; + class BpSurfaceComposer : public BpInterface<ISurfaceComposer> { public: @@ -101,17 +102,13 @@ public: remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply); } - virtual status_t captureScreen(const sp<IBinder>& display, - const sp<IGraphicBufferProducer>& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, - ISurfaceComposer::Rotation rotation) - { + virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer, + Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, + int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform, + ISurfaceComposer::Rotation rotation) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); - data.writeStrongBinder(IInterface::asBinder(producer)); data.write(sourceCrop); data.writeUint32(reqWidth); data.writeUint32(reqHeight); @@ -119,8 +116,46 @@ public: data.writeInt32(maxLayerZ); data.writeInt32(static_cast<int32_t>(useIdentityTransform)); data.writeInt32(static_cast<int32_t>(rotation)); - remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply); - return reply.readInt32(); + status_t err = remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply); + + if (err != NO_ERROR) { + return err; + } + + err = reply.readInt32(); + if (err != NO_ERROR) { + return err; + } + + *outBuffer = new GraphicBuffer(); + reply.read(**outBuffer); + return err; + } + + virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder, + sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop, + float frameScale, bool childrenOnly) { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + data.writeStrongBinder(layerHandleBinder); + data.write(sourceCrop); + data.writeFloat(frameScale); + data.writeBool(childrenOnly); + status_t err = remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply); + + if (err != NO_ERROR) { + return err; + } + + err = reply.readInt32(); + if (err != NO_ERROR) { + return err; + } + + *outBuffer = new GraphicBuffer(); + reply.read(**outBuffer); + + return err; } virtual bool authenticateSurfaceTexture( @@ -317,7 +352,7 @@ public: } virtual status_t getDisplayColorModes(const sp<IBinder>& display, - Vector<android_color_mode_t>* outColorModes) { + Vector<ColorMode>* outColorModes) { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -340,34 +375,34 @@ public: outColorModes->clear(); outColorModes->resize(numModes); for (size_t i = 0; i < numModes; ++i) { - outColorModes->replaceAt(static_cast<android_color_mode_t>(reply.readInt32()), i); + outColorModes->replaceAt(static_cast<ColorMode>(reply.readInt32()), i); } } return result; } - virtual android_color_mode_t getActiveColorMode(const sp<IBinder>& display) { + virtual ColorMode getActiveColorMode(const sp<IBinder>& display) { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { ALOGE("getActiveColorMode failed to writeInterfaceToken: %d", result); - return static_cast<android_color_mode_t>(result); + return static_cast<ColorMode>(result); } result = data.writeStrongBinder(display); if (result != NO_ERROR) { ALOGE("getActiveColorMode failed to writeStrongBinder: %d", result); - return static_cast<android_color_mode_t>(result); + return static_cast<ColorMode>(result); } result = remote()->transact(BnSurfaceComposer::GET_ACTIVE_COLOR_MODE, data, &reply); if (result != NO_ERROR) { ALOGE("getActiveColorMode failed to transact: %d", result); - return static_cast<android_color_mode_t>(result); + return static_cast<ColorMode>(result); } - return static_cast<android_color_mode_t>(reply.readInt32()); + return static_cast<ColorMode>(reply.readInt32()); } virtual status_t setActiveColorMode(const sp<IBinder>& display, - android_color_mode_t colorMode) { + ColorMode colorMode) { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -379,7 +414,7 @@ public: ALOGE("setActiveColorMode failed to writeStrongBinder: %d", result); return result; } - result = data.writeInt32(colorMode); + result = data.writeInt32(static_cast<int32_t>(colorMode)); if (result != NO_ERROR) { ALOGE("setActiveColorMode failed to writeInt32: %d", result); return result; @@ -571,8 +606,7 @@ status_t BnSurfaceComposer::onTransact( case CAPTURE_SCREEN: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp<IBinder> display = data.readStrongBinder(); - sp<IGraphicBufferProducer> producer = - interface_cast<IGraphicBufferProducer>(data.readStrongBinder()); + sp<GraphicBuffer> outBuffer; Rect sourceCrop(Rect::EMPTY_RECT); data.read(sourceCrop); uint32_t reqWidth = data.readUint32(); @@ -582,11 +616,30 @@ status_t BnSurfaceComposer::onTransact( bool useIdentityTransform = static_cast<bool>(data.readInt32()); int32_t rotation = data.readInt32(); - status_t res = captureScreen(display, producer, - sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, - useIdentityTransform, - static_cast<ISurfaceComposer::Rotation>(rotation)); + status_t res = captureScreen(display, &outBuffer, sourceCrop, reqWidth, reqHeight, + minLayerZ, maxLayerZ, useIdentityTransform, + static_cast<ISurfaceComposer::Rotation>(rotation)); reply->writeInt32(res); + if (res == NO_ERROR) { + reply->write(*outBuffer); + } + return NO_ERROR; + } + case CAPTURE_LAYERS: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp<IBinder> layerHandleBinder = data.readStrongBinder(); + sp<GraphicBuffer> outBuffer; + Rect sourceCrop(Rect::EMPTY_RECT); + data.read(sourceCrop); + float frameScale = data.readFloat(); + bool childrenOnly = data.readBool(); + + status_t res = captureLayers(layerHandleBinder, &outBuffer, sourceCrop, frameScale, + childrenOnly); + reply->writeInt32(res); + if (res == NO_ERROR) { + reply->write(*outBuffer); + } return NO_ERROR; } case AUTHENTICATE_SURFACE: { @@ -688,7 +741,7 @@ status_t BnSurfaceComposer::onTransact( } case GET_DISPLAY_COLOR_MODES: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - Vector<android_color_mode_t> colorModes; + Vector<ColorMode> colorModes; sp<IBinder> display = nullptr; status_t result = data.readStrongBinder(&display); if (result != NO_ERROR) { @@ -700,7 +753,7 @@ status_t BnSurfaceComposer::onTransact( if (result == NO_ERROR) { reply->writeUint32(static_cast<uint32_t>(colorModes.size())); for (size_t i = 0; i < colorModes.size(); ++i) { - reply->writeInt32(colorModes[i]); + reply->writeInt32(static_cast<int32_t>(colorModes[i])); } } return NO_ERROR; @@ -713,7 +766,7 @@ status_t BnSurfaceComposer::onTransact( ALOGE("getActiveColorMode failed to readStrongBinder: %d", result); return result; } - android_color_mode_t colorMode = getActiveColorMode(display); + ColorMode colorMode = getActiveColorMode(display); result = reply->writeInt32(static_cast<int32_t>(colorMode)); return result; } @@ -732,7 +785,7 @@ status_t BnSurfaceComposer::onTransact( return result; } result = setActiveColorMode(display, - static_cast<android_color_mode_t>(colorModeInt)); + static_cast<ColorMode>(colorModeInt)); result = reply->writeInt32(result); return result; } diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp index 679f44b57b..a6890eeb19 100644 --- a/libs/gui/ISurfaceComposerClient.cpp +++ b/libs/gui/ISurfaceComposerClient.cpp @@ -47,8 +47,8 @@ public: ~BpSurfaceComposerClient() override; status_t createSurface(const String8& name, uint32_t width, uint32_t height, PixelFormat format, - uint32_t flags, const sp<IBinder>& parent, uint32_t windowType, - uint32_t ownerUid, sp<IBinder>* handle, + uint32_t flags, const sp<IBinder>& parent, int32_t windowType, + int32_t ownerUid, sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp) override { return callRemote<decltype(&ISurfaceComposerClient::createSurface)>(Tag::CREATE_SURFACE, name, width, height, diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp index 57ddde075a..d3dc16d30e 100644 --- a/libs/gui/LayerDebugInfo.cpp +++ b/libs/gui/LayerDebugInfo.cpp @@ -43,7 +43,10 @@ status_t LayerDebugInfo::writeToParcel(Parcel* parcel) const { RETURN_ON_ERROR(parcel->writeInt32(mHeight)); RETURN_ON_ERROR(parcel->write(mCrop)); RETURN_ON_ERROR(parcel->write(mFinalCrop)); - RETURN_ON_ERROR(parcel->writeFloat(mAlpha)); + RETURN_ON_ERROR(parcel->writeFloat(mColor.r)); + RETURN_ON_ERROR(parcel->writeFloat(mColor.g)); + RETURN_ON_ERROR(parcel->writeFloat(mColor.b)); + RETURN_ON_ERROR(parcel->writeFloat(mColor.a)); RETURN_ON_ERROR(parcel->writeUint32(mFlags)); RETURN_ON_ERROR(parcel->writeInt32(mPixelFormat)); RETURN_ON_ERROR(parcel->writeUint32(static_cast<uint32_t>(mDataSpace))); @@ -79,7 +82,14 @@ status_t LayerDebugInfo::readFromParcel(const Parcel* parcel) { RETURN_ON_ERROR(parcel->readInt32(&mHeight)); RETURN_ON_ERROR(parcel->read(mCrop)); RETURN_ON_ERROR(parcel->read(mFinalCrop)); - RETURN_ON_ERROR(parcel->readFloat(&mAlpha)); + mColor.r = parcel->readFloat(); + RETURN_ON_ERROR(parcel->errorCheck()); + mColor.g = parcel->readFloat(); + RETURN_ON_ERROR(parcel->errorCheck()); + mColor.b = parcel->readFloat(); + RETURN_ON_ERROR(parcel->errorCheck()); + mColor.a = parcel->readFloat(); + RETURN_ON_ERROR(parcel->errorCheck()); RETURN_ON_ERROR(parcel->readUint32(&mFlags)); RETURN_ON_ERROR(parcel->readInt32(&mPixelFormat)); // \todo [2017-07-25 kraita]: Static casting mDataSpace pointer to an uint32 does work. Better ways? @@ -116,8 +126,10 @@ std::string to_string(const LayerDebugInfo& info) { result.appendFormat("isOpaque=%1d, invalidate=%1d, ", info.mIsOpaque, info.mContentDirty); result.appendFormat("dataspace=%s, ", dataspaceDetails(info.mDataSpace).c_str()); result.appendFormat("pixelformat=%s, ", decodePixelFormat(info.mPixelFormat).c_str()); - result.appendFormat("alpha=%.3f, flags=0x%08x, ", - static_cast<double>(info.mAlpha), info.mFlags); + result.appendFormat("color=(%.3f,%.3f,%.3f,%.3f), flags=0x%08x, ", + static_cast<double>(info.mColor.r), static_cast<double>(info.mColor.g), + static_cast<double>(info.mColor.b), static_cast<double>(info.mColor.a), + info.mFlags); result.appendFormat("tr=[%.2f, %.2f][%.2f, %.2f]", static_cast<double>(info.mMatrix[0][0]), static_cast<double>(info.mMatrix[0][1]), static_cast<double>(info.mMatrix[1][0]), static_cast<double>(info.mMatrix[1][1])); diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 9b06e63610..01acc2de20 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -18,7 +18,7 @@ #include <binder/Parcel.h> #include <gui/ISurfaceComposerClient.h> #include <gui/IGraphicBufferProducer.h> -#include <private/gui/LayerState.h> +#include <gui/LayerState.h> namespace android { @@ -45,6 +45,10 @@ status_t layer_state_t::write(Parcel& output) const output.writeInt32(overrideScalingMode); output.writeStrongBinder(IInterface::asBinder(barrierGbp)); output.writeStrongBinder(relativeLayerHandle); + output.writeStrongBinder(parentHandleForChild); + output.writeFloat(color.r); + output.writeFloat(color.g); + output.writeFloat(color.b); output.write(transparentRegion); return NO_ERROR; } @@ -77,6 +81,10 @@ status_t layer_state_t::read(const Parcel& input) barrierGbp = interface_cast<IGraphicBufferProducer>(input.readStrongBinder()); relativeLayerHandle = input.readStrongBinder(); + parentHandleForChild = input.readStrongBinder(); + color.r = input.readFloat(); + color.g = input.readFloat(); + color.b = input.readFloat(); input.read(transparentRegion); return NO_ERROR; } @@ -128,5 +136,104 @@ status_t DisplayState::read(const Parcel& input) { return NO_ERROR; } +void DisplayState::merge(const DisplayState& other) { + if (other.what & eSurfaceChanged) { + what |= eSurfaceChanged; + surface = other.surface; + } + if (other.what & eLayerStackChanged) { + what |= eLayerStackChanged; + layerStack = other.layerStack; + } + if (other.what & eDisplayProjectionChanged) { + what |= eDisplayProjectionChanged; + orientation = other.orientation; + viewport = other.viewport; + frame = other.frame; + } + if (other.what & eDisplaySizeChanged) { + what |= eDisplaySizeChanged; + width = other.width; + height = other.height; + } +} + +void layer_state_t::merge(const layer_state_t& other) { + if (other.what & ePositionChanged) { + what |= ePositionChanged; + x = other.x; + y = other.y; + } + if (other.what & eLayerChanged) { + what |= eLayerChanged; + z = other.z; + } + if (other.what & eSizeChanged) { + what |= eSizeChanged; + w = other.w; + h = other.h; + } + if (other.what & eAlphaChanged) { + what |= eAlphaChanged; + alpha = other.alpha; + } + if (other.what & eMatrixChanged) { + what |= eMatrixChanged; + matrix = other.matrix; + } + if (other.what & eTransparentRegionChanged) { + what |= eTransparentRegionChanged; + transparentRegion = other.transparentRegion; + } + if (other.what & eFlagsChanged) { + what |= eFlagsChanged; + flags = other.flags; + mask = other.mask; + } + if (other.what & eLayerStackChanged) { + what |= eLayerStackChanged; + layerStack = other.layerStack; + } + if (other.what & eCropChanged) { + what |= eCropChanged; + crop = other.crop; + } + if (other.what & eDeferTransaction) { + what |= eDeferTransaction; + barrierHandle = other.barrierHandle; + barrierGbp = other.barrierGbp; + frameNumber = other.frameNumber; + } + if (other.what & eFinalCropChanged) { + what |= eFinalCropChanged; + finalCrop = other.finalCrop; + } + if (other.what & eOverrideScalingModeChanged) { + what |= eOverrideScalingModeChanged; + overrideScalingMode = other.overrideScalingMode; + } + if (other.what & eGeometryAppliesWithResize) { + what |= eGeometryAppliesWithResize; + } + if (other.what & eReparentChildren) { + what |= eReparentChildren; + reparentHandle = other.reparentHandle; + } + if (other.what & eDetachChildren) { + what |= eDetachChildren; + } + if (other.what & eRelativeLayerChanged) { + what |= eRelativeLayerChanged; + z = other.z; + relativeLayerHandle = other.relativeLayerHandle; + } + if (other.what & eReparent) { + what |= eReparent; + parentHandleForChild = other.parentHandleForChild; + } + if (other.what & eDestroySurface) { + what |= eDestroySurface; + } +} }; // namespace android diff --git a/libs/gui/StreamSplitter.cpp b/libs/gui/StreamSplitter.cpp index 2f8e104ea0..52c906775e 100644 --- a/libs/gui/StreamSplitter.cpp +++ b/libs/gui/StreamSplitter.cpp @@ -38,11 +38,11 @@ namespace android { status_t StreamSplitter::createSplitter( const sp<IGraphicBufferConsumer>& inputQueue, sp<StreamSplitter>* outSplitter) { - if (inputQueue == nullptr) { + if (inputQueue == NULL) { ALOGE("createSplitter: inputQueue must not be NULL"); return BAD_VALUE; } - if (outSplitter == nullptr) { + if (outSplitter == NULL) { ALOGE("createSplitter: outSplitter must not be NULL"); return BAD_VALUE; } @@ -74,7 +74,7 @@ StreamSplitter::~StreamSplitter() { status_t StreamSplitter::addOutput( const sp<IGraphicBufferProducer>& outputQueue) { - if (outputQueue == nullptr) { + if (outputQueue == NULL) { ALOGE("addOutput: outputQueue must not be NULL"); return BAD_VALUE; } diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index e55e6e415a..339bd0fa4e 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -44,6 +44,9 @@ namespace android { +using ui::ColorMode; +using ui::Dataspace; + Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp) : mGraphicBufferProducer(bufferProducer), mCrop(Rect::EMPTY_RECT), @@ -78,7 +81,7 @@ Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controll mReqFormat = 0; mReqUsage = 0; mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO; - mDataSpace = HAL_DATASPACE_UNKNOWN; + mDataSpace = Dataspace::UNKNOWN; mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; mTransform = 0; mStickyTransform = 0; @@ -153,7 +156,7 @@ status_t Surface::getDisplayRefreshCycleDuration(nsecs_t* outRefreshDuration) { ATRACE_CALL(); DisplayStatInfo stats; - status_t result = composerService()->getDisplayStats(nullptr, &stats); + status_t result = composerService()->getDisplayStats(NULL, &stats); if (result != NO_ERROR) { return result; } @@ -326,7 +329,7 @@ status_t Surface::getWideColorSupport(bool* supported) { sp<IBinder> display( composerService()->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - Vector<android_color_mode_t> colorModes; + Vector<ColorMode> colorModes; status_t err = composerService()->getDisplayColorModes(display, &colorModes); @@ -338,11 +341,11 @@ status_t Surface::getWideColorSupport(bool* supported) { &ISurfaceFlingerConfigs::hasWideColorDisplay>(false); *supported = false; - for (android_color_mode_t colorMode : colorModes) { + for (ColorMode colorMode : colorModes) { switch (colorMode) { - case HAL_COLOR_MODE_DISPLAY_P3: - case HAL_COLOR_MODE_ADOBE_RGB: - case HAL_COLOR_MODE_DCI_P3: + case ColorMode::DISPLAY_P3: + case ColorMode::ADOBE_RGB: + case ColorMode::DCI_P3: if (wideColorBoardConfig) { *supported = true; } @@ -494,7 +497,7 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { if (mSharedBufferMode && mAutoRefresh && mSharedBufferSlot != BufferItem::INVALID_BUFFER_SLOT) { sp<GraphicBuffer>& gbuf(mSlots[mSharedBufferSlot].buffer); - if (gbuf != nullptr) { + if (gbuf != NULL) { *buffer = gbuf.get(); *fenceFd = -1; return OK; @@ -534,7 +537,7 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { sp<GraphicBuffer>& gbuf(mSlots[buf].buffer); // this should never happen - ALOGE_IF(fence == nullptr, "Surface::dequeueBuffer: received null Fence! buf=%d", buf); + ALOGE_IF(fence == NULL, "Surface::dequeueBuffer: received null Fence! buf=%d", buf); if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) { freeAllBuffers(); @@ -612,7 +615,7 @@ int Surface::cancelBuffer(android_native_buffer_t* buffer, int Surface::getSlotFromBufferLocked( android_native_buffer_t* buffer) const { for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].buffer != nullptr && + if (mSlots[i].buffer != NULL && mSlots[i].buffer->handle == buffer->handle) { return i; } @@ -664,8 +667,12 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); IGraphicBufferProducer::QueueBufferOutput output; IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp, - mDataSpace, crop, mScalingMode, mTransform ^ mStickyTransform, - fence, mStickyTransform, mEnableFrameTimestamps); + static_cast<android_dataspace>(mDataSpace), crop, mScalingMode, + mTransform ^ mStickyTransform, fence, mStickyTransform, + mEnableFrameTimestamps); + + // we should send HDR metadata as needed if this becomes a bottleneck + input.setHdrMetadata(mHdrMetadata); if (mConnectedToCpu || mDirtyRegion.bounds() == Rect::INVALID_RECT) { input.setSurfaceDamage(Region::INVALID_REGION); @@ -878,6 +885,10 @@ int Surface::query(int what, int* value) const { *value = mGraphicBufferProducer != nullptr ? 1 : 0; return NO_ERROR; } + case NATIVE_WINDOW_DATASPACE: { + *value = static_cast<int>(mDataSpace); + return NO_ERROR; + } } } return mGraphicBufferProducer->query(what, value); @@ -944,6 +955,12 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_SET_BUFFERS_DATASPACE: res = dispatchSetBuffersDataSpace(args); break; + case NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA: + res = dispatchSetBuffersSmpte2086Metadata(args); + break; + case NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA: + res = dispatchSetBuffersCta8613Metadata(args); + break; case NATIVE_WINDOW_SET_SURFACE_DAMAGE: res = dispatchSetSurfaceDamage(args); break; @@ -1083,11 +1100,22 @@ int Surface::dispatchSetSidebandStream(va_list args) { } int Surface::dispatchSetBuffersDataSpace(va_list args) { - android_dataspace dataspace = - static_cast<android_dataspace>(va_arg(args, int)); + Dataspace dataspace = static_cast<Dataspace>(va_arg(args, int)); return setBuffersDataSpace(dataspace); } +int Surface::dispatchSetBuffersSmpte2086Metadata(va_list args) { + const android_smpte2086_metadata* metadata = + va_arg(args, const android_smpte2086_metadata*); + return setBuffersSmpte2086Metadata(metadata); +} + +int Surface::dispatchSetBuffersCta8613Metadata(va_list args) { + const android_cta861_3_metadata* metadata = + va_arg(args, const android_cta861_3_metadata*); + return setBuffersCta8613Metadata(metadata); +} + int Surface::dispatchSetSurfaceDamage(va_list args) { android_native_rect_t* rects = va_arg(args, android_native_rect_t*); size_t numRects = va_arg(args, size_t); @@ -1236,7 +1264,7 @@ int Surface::detachNextBuffer(sp<GraphicBuffer>* outBuffer, ATRACE_CALL(); ALOGV("Surface::detachNextBuffer"); - if (outBuffer == nullptr || outFence == nullptr) { + if (outBuffer == NULL || outFence == NULL) { return BAD_VALUE; } @@ -1245,8 +1273,8 @@ int Surface::detachNextBuffer(sp<GraphicBuffer>* outBuffer, mRemovedBuffers.clear(); } - sp<GraphicBuffer> buffer(nullptr); - sp<Fence> fence(nullptr); + sp<GraphicBuffer> buffer(NULL); + sp<Fence> fence(NULL); status_t result = mGraphicBufferProducer->detachNextBuffer( &buffer, &fence); if (result != NO_ERROR) { @@ -1254,19 +1282,19 @@ int Surface::detachNextBuffer(sp<GraphicBuffer>* outBuffer, } *outBuffer = buffer; - if (fence != nullptr && fence->isValid()) { + if (fence != NULL && fence->isValid()) { *outFence = fence; } else { *outFence = Fence::NO_FENCE; } for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].buffer != nullptr && + if (mSlots[i].buffer != NULL && mSlots[i].buffer->getId() == buffer->getId()) { if (mReportRemovedBuffers) { mRemovedBuffers.push_back(mSlots[i].buffer); } - mSlots[i].buffer = nullptr; + mSlots[i].buffer = NULL; } } @@ -1317,7 +1345,7 @@ int Surface::setCrop(Rect const* rect) ATRACE_CALL(); Rect realRect(Rect::EMPTY_RECT); - if (rect == nullptr || rect->isEmpty()) { + if (rect == NULL || rect->isEmpty()) { realRect.clear(); } else { realRect = *rect; @@ -1504,7 +1532,7 @@ int Surface::setBuffersTimestamp(int64_t timestamp) return NO_ERROR; } -int Surface::setBuffersDataSpace(android_dataspace dataSpace) +int Surface::setBuffersDataSpace(Dataspace dataSpace) { ALOGV("Surface::setBuffersDataSpace"); Mutex::Autolock lock(mMutex); @@ -1512,9 +1540,39 @@ int Surface::setBuffersDataSpace(android_dataspace dataSpace) return NO_ERROR; } +int Surface::setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metadata) { + ALOGV("Surface::setBuffersSmpte2086Metadata"); + Mutex::Autolock lock(mMutex); + if (metadata) { + mHdrMetadata.smpte2086 = *metadata; + mHdrMetadata.validTypes |= HdrMetadata::SMPTE2086; + } else { + mHdrMetadata.validTypes &= ~HdrMetadata::SMPTE2086; + } + return NO_ERROR; +} + +int Surface::setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata) { + ALOGV("Surface::setBuffersCta8613Metadata"); + Mutex::Autolock lock(mMutex); + if (metadata) { + mHdrMetadata.cta8613 = *metadata; + mHdrMetadata.validTypes |= HdrMetadata::CTA861_3; + } else { + mHdrMetadata.validTypes &= ~HdrMetadata::CTA861_3; + } + return NO_ERROR; +} + +Dataspace Surface::getBuffersDataSpace() { + ALOGV("Surface::getBuffersDataSpace"); + Mutex::Autolock lock(mMutex); + return mDataSpace; +} + void Surface::freeAllBuffers() { for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - mSlots[i].buffer = nullptr; + mSlots[i].buffer = 0; } } @@ -1554,12 +1612,12 @@ static status_t copyBlt( // src and dst with, height and format must be identical. no verification // is done here. status_t err; - uint8_t* src_bits = nullptr; + uint8_t* src_bits = NULL; err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), reinterpret_cast<void**>(&src_bits)); ALOGE_IF(err, "error locking src buffer %s", strerror(-err)); - uint8_t* dst_bits = nullptr; + uint8_t* dst_bits = NULL; err = dst->lockAsync(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), reinterpret_cast<void**>(&dst_bits), *dstFenceFd); ALOGE_IF(err, "error locking dst buffer %s", strerror(-err)); @@ -1607,7 +1665,7 @@ static status_t copyBlt( status_t Surface::lock( ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds) { - if (mLockedBuffer != nullptr) { + if (mLockedBuffer != 0) { ALOGE("Surface::lock failed, already locked"); return INVALID_OPERATION; } @@ -1639,7 +1697,7 @@ status_t Surface::lock( // figure out if we can copy the frontbuffer back const sp<GraphicBuffer>& frontBuffer(mPostedBuffer); - const bool canCopyBack = (frontBuffer != nullptr && + const bool canCopyBack = (frontBuffer != 0 && backBuffer->width == frontBuffer->width && backBuffer->height == frontBuffer->height && backBuffer->format == frontBuffer->format); @@ -1701,7 +1759,7 @@ status_t Surface::lock( status_t Surface::unlockAndPost() { - if (mLockedBuffer == nullptr) { + if (mLockedBuffer == 0) { ALOGE("Surface::unlockAndPost failed, no locked buffer"); return INVALID_OPERATION; } @@ -1715,7 +1773,7 @@ status_t Surface::unlockAndPost() mLockedBuffer->handle, strerror(-err)); mPostedBuffer = mLockedBuffer; - mLockedBuffer = nullptr; + mLockedBuffer = 0; return err; } @@ -1754,4 +1812,25 @@ status_t Surface::getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out) return OK; } +status_t Surface::attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffer) { + if (buffer == nullptr) { + return BAD_VALUE; + } + int err = static_cast<ANativeWindow*>(surface)->perform(surface, NATIVE_WINDOW_API_CONNECT, + NATIVE_WINDOW_API_CPU); + if (err != OK) { + return err; + } + err = surface->attachBuffer(buffer->getNativeBuffer()); + if (err != OK) { + return err; + } + err = static_cast<ANativeWindow*>(surface)->queueBuffer(surface, buffer->getNativeBuffer(), -1); + if (err != OK) { + return err; + } + err = surface->disconnect(NATIVE_WINDOW_API_CPU); + return err; +} + }; // namespace android diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 053b9afb86..63560c4b89 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -21,7 +21,6 @@ #include <utils/Errors.h> #include <utils/Log.h> -#include <utils/Singleton.h> #include <utils/SortedVector.h> #include <utils/String8.h> #include <utils/threads.h> @@ -37,13 +36,15 @@ #include <gui/IGraphicBufferProducer.h> #include <gui/ISurfaceComposer.h> #include <gui/ISurfaceComposerClient.h> +#include <gui/LayerState.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> #include <private/gui/ComposerService.h> -#include <private/gui/LayerState.h> namespace android { + +using ui::ColorMode; // --------------------------------------------------------------------------- ANDROID_SINGLETON_STATIC_INSTANCE(ComposerService); @@ -80,7 +81,7 @@ void ComposerService::connectLocked() { /*static*/ sp<ISurfaceComposer> ComposerService::getComposerService() { ComposerService& instance = ComposerService::getInstance(); Mutex::Autolock _l(instance.mLock); - if (instance.mComposerService == nullptr) { + if (instance.mComposerService == NULL) { ComposerService::getInstance().connectLocked(); assert(instance.mComposerService != NULL); ALOGD("ComposerService reconnected"); @@ -91,239 +92,150 @@ void ComposerService::connectLocked() { void ComposerService::composerServiceDied() { Mutex::Autolock _l(mLock); - mComposerService = nullptr; - mDeathObserver = nullptr; + mComposerService = NULL; + mDeathObserver = NULL; } // --------------------------------------------------------------------------- -static inline -int compare_type(const ComposerState& lhs, const ComposerState& rhs) { - if (lhs.client < rhs.client) return -1; - if (lhs.client > rhs.client) return 1; - if (lhs.state.surface < rhs.state.surface) return -1; - if (lhs.state.surface > rhs.state.surface) return 1; - return 0; -} - -static inline -int compare_type(const DisplayState& lhs, const DisplayState& rhs) { - return compare_type(lhs.token, rhs.token); -} - -class Composer : public Singleton<Composer> -{ - friend class Singleton<Composer>; - - mutable Mutex mLock; - SortedVector<ComposerState> mComposerStates; - SortedVector<DisplayState > mDisplayStates; - uint32_t mForceSynchronous; - uint32_t mTransactionNestCount; - bool mAnimation; - - Composer() : Singleton<Composer>(), - mForceSynchronous(0), mTransactionNestCount(0), - mAnimation(false) - { } - - void openGlobalTransactionImpl(); - void closeGlobalTransactionImpl(bool synchronous); - void setAnimationTransactionImpl(); - status_t enableVSyncInjectionsImpl(bool enable); - status_t injectVSyncImpl(nsecs_t when); - - layer_state_t* getLayerStateLocked( - const sp<SurfaceComposerClient>& client, const sp<IBinder>& id); - - DisplayState& getDisplayStateLocked(const sp<IBinder>& token); - -public: - sp<IBinder> createDisplay(const String8& displayName, bool secure); - void destroyDisplay(const sp<IBinder>& display); - sp<IBinder> getBuiltInDisplay(int32_t id); - - status_t setPosition(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - float x, float y); - status_t setSize(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - uint32_t w, uint32_t h); - status_t setLayer(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - int32_t z); - status_t setRelativeLayer(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - const sp<IBinder>& relativeTo, int32_t z); - status_t setFlags(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - uint32_t flags, uint32_t mask); - status_t setTransparentRegionHint( - const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - const Region& transparentRegion); - status_t setAlpha(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - float alpha); - status_t setMatrix(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - float dsdx, float dtdx, float dtdy, float dsdy); - status_t setOrientation(int orientation); - status_t setCrop(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - const Rect& crop); - status_t setFinalCrop(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, const Rect& crop); - status_t setLayerStack(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, uint32_t layerStack); - status_t deferTransactionUntil(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, const sp<IBinder>& handle, - uint64_t frameNumber); - status_t deferTransactionUntil(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, const sp<Surface>& barrierSurface, - uint64_t frameNumber); - status_t reparentChildren(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, - const sp<IBinder>& newParentHandle); - status_t detachChildren(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id); - status_t setOverrideScalingMode(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, int32_t overrideScalingMode); - status_t setGeometryAppliesWithResize(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id); - - status_t setDisplaySurface(const sp<IBinder>& token, - sp<IGraphicBufferProducer> bufferProducer); - void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack); - void setDisplayProjection(const sp<IBinder>& token, - uint32_t orientation, - const Rect& layerStackRect, - const Rect& displayRect); - void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height); - - static void setAnimationTransaction() { - Composer::getInstance().setAnimationTransactionImpl(); - } - - static void openGlobalTransaction() { - Composer::getInstance().openGlobalTransactionImpl(); +SurfaceComposerClient::Transaction::Transaction(const Transaction& other) : + mForceSynchronous(other.mForceSynchronous), + mTransactionNestCount(other.mTransactionNestCount), + mAnimation(other.mAnimation), + mEarlyWakeup(other.mEarlyWakeup) { + mDisplayStates = other.mDisplayStates; + mComposerStates = other.mComposerStates; +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) { + for (auto const& kv : other.mComposerStates) { + if (mComposerStates.count(kv.first) == 0) { + mComposerStates[kv.first] = kv.second; + } else { + mComposerStates[kv.first].state.merge(kv.second.state); + } } + other.mComposerStates.clear(); - static void closeGlobalTransaction(bool synchronous) { - Composer::getInstance().closeGlobalTransactionImpl(synchronous); + for (auto const& state : other.mDisplayStates) { + ssize_t index = mDisplayStates.indexOf(state); + if (index < 0) { + mDisplayStates.add(state); + } else { + mDisplayStates.editItemAt(static_cast<size_t>(index)).merge(state); + } } + other.mDisplayStates.clear(); - static status_t enableVSyncInjections(bool enable) { - return Composer::getInstance().enableVSyncInjectionsImpl(enable); - } + return *this; +} - static status_t injectVSync(nsecs_t when) { - return Composer::getInstance().injectVSyncImpl(when); +status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { + if (mStatus != NO_ERROR) { + return mStatus; } -}; - -ANDROID_SINGLETON_STATIC_INSTANCE(Composer); - -// --------------------------------------------------------------------------- -sp<IBinder> Composer::createDisplay(const String8& displayName, bool secure) { - return ComposerService::getComposerService()->createDisplay(displayName, - secure); -} + sp<ISurfaceComposer> sf(ComposerService::getComposerService()); -void Composer::destroyDisplay(const sp<IBinder>& display) { - return ComposerService::getComposerService()->destroyDisplay(display); -} + Vector<ComposerState> composerStates; + Vector<DisplayState> displayStates; + uint32_t flags = 0; -sp<IBinder> Composer::getBuiltInDisplay(int32_t id) { - return ComposerService::getComposerService()->getBuiltInDisplay(id); -} + mForceSynchronous |= synchronous; -void Composer::openGlobalTransactionImpl() { - { // scope for the lock - Mutex::Autolock _l(mLock); - mTransactionNestCount += 1; + for (auto const& kv : mComposerStates){ + composerStates.add(kv.second); } -} -void Composer::closeGlobalTransactionImpl(bool synchronous) { - sp<ISurfaceComposer> sm(ComposerService::getComposerService()); - - Vector<ComposerState> transaction; - Vector<DisplayState> displayTransaction; - uint32_t flags = 0; + mComposerStates.clear(); - { // scope for the lock - Mutex::Autolock _l(mLock); - mForceSynchronous |= synchronous; - if (!mTransactionNestCount) { - ALOGW("At least one call to closeGlobalTransaction() was not matched by a prior " - "call to openGlobalTransaction()."); - } else if (--mTransactionNestCount) { - return; - } + displayStates = mDisplayStates; + mDisplayStates.clear(); - transaction = mComposerStates; - mComposerStates.clear(); + if (mForceSynchronous) { + flags |= ISurfaceComposer::eSynchronous; + } + if (mAnimation) { + flags |= ISurfaceComposer::eAnimation; + } + if (mEarlyWakeup) { + flags |= ISurfaceComposer::eEarlyWakeup; + } - displayTransaction = mDisplayStates; - mDisplayStates.clear(); + mForceSynchronous = false; + mAnimation = false; + mEarlyWakeup = false; - if (mForceSynchronous) { - flags |= ISurfaceComposer::eSynchronous; - } - if (mAnimation) { - flags |= ISurfaceComposer::eAnimation; - } + sf->setTransactionState(composerStates, displayStates, flags); + mStatus = NO_ERROR; + return NO_ERROR; +} - mForceSynchronous = false; - mAnimation = false; - } +// --------------------------------------------------------------------------- - sm->setTransactionState(transaction, displayTransaction, flags); +sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName, bool secure) { + return ComposerService::getComposerService()->createDisplay(displayName, + secure); } -status_t Composer::enableVSyncInjectionsImpl(bool enable) { - sp<ISurfaceComposer> sm(ComposerService::getComposerService()); - return sm->enableVSyncInjections(enable); +void SurfaceComposerClient::destroyDisplay(const sp<IBinder>& display) { + return ComposerService::getComposerService()->destroyDisplay(display); } -status_t Composer::injectVSyncImpl(nsecs_t when) { - sp<ISurfaceComposer> sm(ComposerService::getComposerService()); - return sm->injectVSync(when); +sp<IBinder> SurfaceComposerClient::getBuiltInDisplay(int32_t id) { + return ComposerService::getComposerService()->getBuiltInDisplay(id); } -void Composer::setAnimationTransactionImpl() { - Mutex::Autolock _l(mLock); +void SurfaceComposerClient::Transaction::setAnimationTransaction() { mAnimation = true; } -layer_state_t* Composer::getLayerStateLocked( - const sp<SurfaceComposerClient>& client, const sp<IBinder>& id) { - - ComposerState s; - s.client = client->mClient; - s.state.surface = id; +void SurfaceComposerClient::Transaction::setEarlyWakeup() { + mEarlyWakeup = true; +} - ssize_t index = mComposerStates.indexOf(s); - if (index < 0) { +layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<SurfaceControl>& sc) { + if (mComposerStates.count(sc) == 0) { // we don't have it, add an initialized layer_state to our list - index = mComposerStates.add(s); + ComposerState s; + s.client = sc->getClient()->mClient; + s.state.surface = sc->getHandle(); + mComposerStates[sc] = s; } - ComposerState* const out = mComposerStates.editArray(); - return &(out[index].state); + return &(mComposerStates[sc].state); } -status_t Composer::setPosition(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, float x, float y) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setPosition( + const sp<SurfaceControl>& sc, float x, float y) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::ePositionChanged; s->x = x; s->y = y; - return NO_ERROR; + return *this; } -status_t Composer::setSize(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, uint32_t w, uint32_t h) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::show( + const sp<SurfaceControl>& sc) { + return setFlags(sc, 0, layer_state_t::eLayerHidden); +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::hide( + const sp<SurfaceControl>& sc) { + return setFlags(sc, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden); +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSize( + const sp<SurfaceControl>& sc, uint32_t w, uint32_t h) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eSizeChanged; s->w = w; s->h = h; @@ -331,41 +243,41 @@ status_t Composer::setSize(const sp<SurfaceComposerClient>& client, // Resizing a surface makes the transaction synchronous. mForceSynchronous = true; - return NO_ERROR; + return *this; } -status_t Composer::setLayer(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, int32_t z) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayer( + const sp<SurfaceControl>& sc, int32_t z) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eLayerChanged; s->z = z; - return NO_ERROR; + return *this; } -status_t Composer::setRelativeLayer(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, const sp<IBinder>& relativeTo, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setRelativeLayer(const sp<SurfaceControl>& sc, const sp<IBinder>& relativeTo, int32_t z) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); + layer_state_t* s = getLayerState(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; } s->what |= layer_state_t::eRelativeLayerChanged; s->relativeLayerHandle = relativeTo; s->z = z; - return NO_ERROR; + return *this; } -status_t Composer::setFlags(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, uint32_t flags, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFlags( + const sp<SurfaceControl>& sc, uint32_t flags, uint32_t mask) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } if ((mask & layer_state_t::eLayerOpaque) || (mask & layer_state_t::eLayerHidden) || (mask & layer_state_t::eLayerSecure)) { @@ -374,50 +286,54 @@ status_t Composer::setFlags(const sp<SurfaceComposerClient>& client, s->flags &= ~mask; s->flags |= (flags & mask); s->mask |= mask; - return NO_ERROR; + return *this; } -status_t Composer::setTransparentRegionHint( - const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTransparentRegionHint( + const sp<SurfaceControl>& sc, const Region& transparentRegion) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eTransparentRegionChanged; s->transparentRegion = transparentRegion; - return NO_ERROR; + return *this; } -status_t Composer::setAlpha(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, float alpha) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAlpha( + const sp<SurfaceControl>& sc, float alpha) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eAlphaChanged; s->alpha = alpha; - return NO_ERROR; + return *this; } -status_t Composer::setLayerStack(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, uint32_t layerStack) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayerStack( + const sp<SurfaceControl>& sc, uint32_t layerStack) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eLayerStackChanged; s->layerStack = layerStack; - return NO_ERROR; + return *this; } -status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, float dsdx, float dtdx, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setMatrix( + const sp<SurfaceControl>& sc, float dsdx, float dtdx, float dtdy, float dsdy) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eMatrixChanged; layer_state_t::matrix22_t matrix; matrix.dsdx = dsdx; @@ -425,93 +341,115 @@ status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client, matrix.dsdy = dsdy; matrix.dtdy = dtdy; s->matrix = matrix; - return NO_ERROR; + return *this; } -status_t Composer::setCrop(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, const Rect& crop) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop( + const sp<SurfaceControl>& sc, const Rect& crop) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eCropChanged; s->crop = crop; - return NO_ERROR; + return *this; } -status_t Composer::setFinalCrop(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, const Rect& crop) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFinalCrop(const sp<SurfaceControl>& sc, const Rect& crop) { + layer_state_t* s = getLayerState(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eFinalCropChanged; s->finalCrop = crop; - return NO_ERROR; + return *this; } -status_t Composer::deferTransactionUntil( - const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::deferTransactionUntil( + const sp<SurfaceControl>& sc, const sp<IBinder>& handle, uint64_t frameNumber) { - Mutex::Autolock lock(mLock); - layer_state_t* s = getLayerStateLocked(client, id); + layer_state_t* s = getLayerState(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eDeferTransaction; s->barrierHandle = handle; s->frameNumber = frameNumber; - return NO_ERROR; + return *this; } -status_t Composer::deferTransactionUntil( - const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::deferTransactionUntil( + const sp<SurfaceControl>& sc, const sp<Surface>& barrierSurface, uint64_t frameNumber) { - Mutex::Autolock lock(mLock); - layer_state_t* s = getLayerStateLocked(client, id); + layer_state_t* s = getLayerState(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eDeferTransaction; s->barrierGbp = barrierSurface->getIGraphicBufferProducer(); s->frameNumber = frameNumber; - return NO_ERROR; + return *this; } -status_t Composer::reparentChildren( - const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparentChildren( + const sp<SurfaceControl>& sc, const sp<IBinder>& newParentHandle) { - Mutex::Autolock lock(mLock); - layer_state_t* s = getLayerStateLocked(client, id); + layer_state_t* s = getLayerState(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eReparentChildren; s->reparentHandle = newParentHandle; - return NO_ERROR; + return *this; } -status_t Composer::detachChildren( - const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id) { - Mutex::Autolock lock(mLock); - layer_state_t* s = getLayerStateLocked(client, id); +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparent( + const sp<SurfaceControl>& sc, + const sp<IBinder>& newParentHandle) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eReparent; + s->parentHandleForChild = newParentHandle; + return *this; +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColor( + const sp<SurfaceControl>& sc, + const half3& color) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eColorChanged; + s->color = color; + return *this; +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::detachChildren( + const sp<SurfaceControl>& sc) { + layer_state_t* s = getLayerState(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; } s->what |= layer_state_t::eDetachChildren; - return NO_ERROR; + return *this; } -status_t Composer::setOverrideScalingMode( - const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, int32_t overrideScalingMode) { - Mutex::Autolock lock(mLock); - layer_state_t* s = getLayerStateLocked(client, id); +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setOverrideScalingMode( + const sp<SurfaceControl>& sc, int32_t overrideScalingMode) { + layer_state_t* s = getLayerState(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; + return *this; } switch (overrideScalingMode) { @@ -524,29 +462,40 @@ status_t Composer::setOverrideScalingMode( default: ALOGE("unknown scaling mode: %d", overrideScalingMode); - return BAD_VALUE; + mStatus = BAD_VALUE; + return *this; } s->what |= layer_state_t::eOverrideScalingModeChanged; s->overrideScalingMode = overrideScalingMode; - return NO_ERROR; + return *this; } -status_t Composer::setGeometryAppliesWithResize( - const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id) { - Mutex::Autolock lock(mLock); - layer_state_t* s = getLayerStateLocked(client, id); +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setGeometryAppliesWithResize( + const sp<SurfaceControl>& sc) { + layer_state_t* s = getLayerState(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eGeometryAppliesWithResize; - return NO_ERROR; + return *this; +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::destroySurface( + const sp<SurfaceControl>& sc) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eDestroySurface; + return *this; } // --------------------------------------------------------------------------- -DisplayState& Composer::getDisplayStateLocked(const sp<IBinder>& token) { +DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) { DisplayState s; s.token = token; ssize_t index = mDisplayStates.indexOf(s); @@ -558,8 +507,8 @@ DisplayState& Composer::getDisplayStateLocked(const sp<IBinder>& token) { return mDisplayStates.editItemAt(static_cast<size_t>(index)); } -status_t Composer::setDisplaySurface(const sp<IBinder>& token, - sp<IGraphicBufferProducer> bufferProducer) { +status_t SurfaceComposerClient::Transaction::setDisplaySurface(const sp<IBinder>& token, + const sp<IGraphicBufferProducer>& bufferProducer) { if (bufferProducer.get() != nullptr) { // Make sure that composition can never be stalled by a virtual display // consumer that isn't processing buffers fast enough. @@ -571,27 +520,24 @@ status_t Composer::setDisplaySurface(const sp<IBinder>& token, return err; } } - Mutex::Autolock _l(mLock); - DisplayState& s(getDisplayStateLocked(token)); + DisplayState& s(getDisplayState(token)); s.surface = bufferProducer; s.what |= DisplayState::eSurfaceChanged; return NO_ERROR; } -void Composer::setDisplayLayerStack(const sp<IBinder>& token, +void SurfaceComposerClient::Transaction::setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack) { - Mutex::Autolock _l(mLock); - DisplayState& s(getDisplayStateLocked(token)); + DisplayState& s(getDisplayState(token)); s.layerStack = layerStack; s.what |= DisplayState::eLayerStackChanged; } -void Composer::setDisplayProjection(const sp<IBinder>& token, +void SurfaceComposerClient::Transaction::setDisplayProjection(const sp<IBinder>& token, uint32_t orientation, const Rect& layerStackRect, const Rect& displayRect) { - Mutex::Autolock _l(mLock); - DisplayState& s(getDisplayStateLocked(token)); + DisplayState& s(getDisplayState(token)); s.orientation = orientation; s.viewport = layerStackRect; s.frame = displayRect; @@ -599,9 +545,8 @@ void Composer::setDisplayProjection(const sp<IBinder>& token, mForceSynchronous = true; // TODO: do we actually still need this? } -void Composer::setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height) { - Mutex::Autolock _l(mLock); - DisplayState& s(getDisplayStateLocked(token)); +void SurfaceComposerClient::Transaction::setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height) { + DisplayState& s(getDisplayState(token)); s.width = width; s.height = height; s.what |= DisplayState::eDisplaySizeChanged; @@ -610,23 +555,28 @@ void Composer::setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t // --------------------------------------------------------------------------- SurfaceComposerClient::SurfaceComposerClient() - : mStatus(NO_INIT), mComposer(Composer::getInstance()) + : mStatus(NO_INIT) { } SurfaceComposerClient::SurfaceComposerClient(const sp<IGraphicBufferProducer>& root) - : mStatus(NO_INIT), mComposer(Composer::getInstance()), mParent(root) + : mStatus(NO_INIT), mParent(root) +{ +} + +SurfaceComposerClient::SurfaceComposerClient(const sp<ISurfaceComposerClient>& client) + : mStatus(NO_ERROR), mClient(client) { } void SurfaceComposerClient::onFirstRef() { - sp<ISurfaceComposer> sm(ComposerService::getComposerService()); - if (sm != nullptr) { + sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + if (sf != 0 && mStatus == NO_INIT) { auto rootProducer = mParent.promote(); sp<ISurfaceComposerClient> conn; - conn = (rootProducer != nullptr) ? sm->createScopedConnection(rootProducer) : - sm->createConnection(); - if (conn != nullptr) { + conn = (rootProducer != nullptr) ? sf->createScopedConnection(rootProducer) : + sf->createConnection(); + if (conn != 0) { mClient = conn; mStatus = NO_ERROR; } @@ -648,15 +598,15 @@ sp<IBinder> SurfaceComposerClient::connection() const { status_t SurfaceComposerClient::linkToComposerDeath( const sp<IBinder::DeathRecipient>& recipient, void* cookie, uint32_t flags) { - sp<ISurfaceComposer> sm(ComposerService::getComposerService()); - return IInterface::asBinder(sm)->linkToDeath(recipient, cookie, flags); + sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + return IInterface::asBinder(sf)->linkToDeath(recipient, cookie, flags); } void SurfaceComposerClient::dispose() { // this can be called more than once. sp<ISurfaceComposerClient> client; Mutex::Autolock _lm(mLock); - if (mClient != nullptr) { + if (mClient != 0) { client = mClient; // hold ref while lock is held mClient.clear(); } @@ -670,10 +620,28 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface( PixelFormat format, uint32_t flags, SurfaceControl* parent, - uint32_t windowType, - uint32_t ownerUid) + int32_t windowType, + int32_t ownerUid) +{ + sp<SurfaceControl> s; + createSurfaceChecked(name, w, h, format, &s, flags, parent, windowType, ownerUid); + return s; +} + +status_t SurfaceComposerClient::createSurfaceChecked( + const String8& name, + uint32_t w, + uint32_t h, + PixelFormat format, + sp<SurfaceControl>* outSurface, + uint32_t flags, + SurfaceControl* parent, + int32_t windowType, + int32_t ownerUid) { sp<SurfaceControl> sur; + status_t err = mStatus; + if (mStatus == NO_ERROR) { sp<IBinder> handle; sp<IBinder> parentHandle; @@ -682,27 +650,14 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface( if (parent != nullptr) { parentHandle = parent->getHandle(); } - status_t err = mClient->createSurface(name, w, h, format, flags, parentHandle, + err = mClient->createSurface(name, w, h, format, flags, parentHandle, windowType, ownerUid, &handle, &gbp); ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err)); if (err == NO_ERROR) { - sur = new SurfaceControl(this, handle, gbp); + *outSurface = new SurfaceControl(this, handle, gbp, true /* owned */); } } - return sur; -} - -sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName, - bool secure) { - return Composer::getInstance().createDisplay(displayName, secure); -} - -void SurfaceComposerClient::destroyDisplay(const sp<IBinder>& display) { - Composer::getInstance().destroyDisplay(display); -} - -sp<IBinder> SurfaceComposerClient::getBuiltInDisplay(int32_t id) { - return Composer::getInstance().getBuiltInDisplay(id); + return err; } status_t SurfaceComposerClient::destroySurface(const sp<IBinder>& sid) { @@ -727,152 +682,18 @@ status_t SurfaceComposerClient::getLayerFrameStats(const sp<IBinder>& token, return mClient->getLayerFrameStats(token, outStats); } -inline Composer& SurfaceComposerClient::getComposer() { - return mComposer; -} - // ---------------------------------------------------------------------------- -void SurfaceComposerClient::openGlobalTransaction() { - Composer::openGlobalTransaction(); -} - -void SurfaceComposerClient::closeGlobalTransaction(bool synchronous) { - Composer::closeGlobalTransaction(synchronous); -} - -void SurfaceComposerClient::setAnimationTransaction() { - Composer::setAnimationTransaction(); -} - status_t SurfaceComposerClient::enableVSyncInjections(bool enable) { - return Composer::enableVSyncInjections(enable); + sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + return sf->enableVSyncInjections(enable); } status_t SurfaceComposerClient::injectVSync(nsecs_t when) { - return Composer::injectVSync(when); -} - -// ---------------------------------------------------------------------------- - -status_t SurfaceComposerClient::setCrop(const sp<IBinder>& id, const Rect& crop) { - return getComposer().setCrop(this, id, crop); -} - -status_t SurfaceComposerClient::setFinalCrop(const sp<IBinder>& id, - const Rect& crop) { - return getComposer().setFinalCrop(this, id, crop); -} - -status_t SurfaceComposerClient::setPosition(const sp<IBinder>& id, float x, float y) { - return getComposer().setPosition(this, id, x, y); -} - -status_t SurfaceComposerClient::setSize(const sp<IBinder>& id, uint32_t w, uint32_t h) { - return getComposer().setSize(this, id, w, h); -} - -status_t SurfaceComposerClient::setLayer(const sp<IBinder>& id, int32_t z) { - return getComposer().setLayer(this, id, z); -} - -status_t SurfaceComposerClient::setRelativeLayer(const sp<IBinder>& id, - const sp<IBinder>& relativeTo, int32_t z) { - return getComposer().setRelativeLayer(this, id, relativeTo, z); -} - -status_t SurfaceComposerClient::hide(const sp<IBinder>& id) { - return getComposer().setFlags(this, id, - layer_state_t::eLayerHidden, - layer_state_t::eLayerHidden); -} - -status_t SurfaceComposerClient::show(const sp<IBinder>& id) { - return getComposer().setFlags(this, id, - 0, - layer_state_t::eLayerHidden); -} - -status_t SurfaceComposerClient::setFlags(const sp<IBinder>& id, uint32_t flags, - uint32_t mask) { - return getComposer().setFlags(this, id, flags, mask); -} - -status_t SurfaceComposerClient::setTransparentRegionHint(const sp<IBinder>& id, - const Region& transparentRegion) { - return getComposer().setTransparentRegionHint(this, id, transparentRegion); -} - -status_t SurfaceComposerClient::setAlpha(const sp<IBinder>& id, float alpha) { - return getComposer().setAlpha(this, id, alpha); -} - -status_t SurfaceComposerClient::setLayerStack(const sp<IBinder>& id, uint32_t layerStack) { - return getComposer().setLayerStack(this, id, layerStack); -} - -status_t SurfaceComposerClient::setMatrix(const sp<IBinder>& id, float dsdx, float dtdx, - float dtdy, float dsdy) { - return getComposer().setMatrix(this, id, dsdx, dtdx, dtdy, dsdy); -} - -status_t SurfaceComposerClient::deferTransactionUntil(const sp<IBinder>& id, - const sp<IBinder>& handle, uint64_t frameNumber) { - return getComposer().deferTransactionUntil(this, id, handle, frameNumber); -} - -status_t SurfaceComposerClient::deferTransactionUntil(const sp<IBinder>& id, - const sp<Surface>& barrierSurface, uint64_t frameNumber) { - return getComposer().deferTransactionUntil(this, id, barrierSurface, frameNumber); -} - -status_t SurfaceComposerClient::reparentChildren(const sp<IBinder>& id, - const sp<IBinder>& newParentHandle) { - return getComposer().reparentChildren(this, id, newParentHandle); -} - -status_t SurfaceComposerClient::detachChildren(const sp<IBinder>& id) { - return getComposer().detachChildren(this, id); -} - -status_t SurfaceComposerClient::setOverrideScalingMode( - const sp<IBinder>& id, int32_t overrideScalingMode) { - return getComposer().setOverrideScalingMode( - this, id, overrideScalingMode); + sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + return sf->injectVSync(when); } -status_t SurfaceComposerClient::setGeometryAppliesWithResize( - const sp<IBinder>& id) { - return getComposer().setGeometryAppliesWithResize(this, id); -} - -// ---------------------------------------------------------------------------- - -status_t SurfaceComposerClient::setDisplaySurface(const sp<IBinder>& token, - sp<IGraphicBufferProducer> bufferProducer) { - return Composer::getInstance().setDisplaySurface(token, bufferProducer); -} - -void SurfaceComposerClient::setDisplayLayerStack(const sp<IBinder>& token, - uint32_t layerStack) { - Composer::getInstance().setDisplayLayerStack(token, layerStack); -} - -void SurfaceComposerClient::setDisplayProjection(const sp<IBinder>& token, - uint32_t orientation, - const Rect& layerStackRect, - const Rect& displayRect) { - Composer::getInstance().setDisplayProjection(token, orientation, - layerStackRect, displayRect); -} - -void SurfaceComposerClient::setDisplaySize(const sp<IBinder>& token, - uint32_t width, uint32_t height) { - Composer::getInstance().setDisplaySize(token, width, height); -} - -// ---------------------------------------------------------------------------- - status_t SurfaceComposerClient::getDisplayConfigs( const sp<IBinder>& display, Vector<DisplayInfo>* configs) { @@ -906,16 +727,16 @@ status_t SurfaceComposerClient::setActiveConfig(const sp<IBinder>& display, int } status_t SurfaceComposerClient::getDisplayColorModes(const sp<IBinder>& display, - Vector<android_color_mode_t>* outColorModes) { + Vector<ColorMode>* outColorModes) { return ComposerService::getComposerService()->getDisplayColorModes(display, outColorModes); } -android_color_mode_t SurfaceComposerClient::getActiveColorMode(const sp<IBinder>& display) { +ColorMode SurfaceComposerClient::getActiveColorMode(const sp<IBinder>& display) { return ComposerService::getComposerService()->getActiveColorMode(display); } status_t SurfaceComposerClient::setActiveColorMode(const sp<IBinder>& display, - android_color_mode_t colorMode) { + ColorMode colorMode) { return ComposerService::getComposerService()->setActiveColorMode(display, colorMode); } @@ -940,149 +761,37 @@ status_t SurfaceComposerClient::getHdrCapabilities(const sp<IBinder>& display, // ---------------------------------------------------------------------------- -status_t ScreenshotClient::capture( - const sp<IBinder>& display, - const sp<IGraphicBufferProducer>& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform) { - sp<ISurfaceComposer> s(ComposerService::getComposerService()); - if (s == nullptr) return NO_INIT; - return s->captureScreen(display, producer, sourceCrop, - reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform); -} - -status_t ScreenshotClient::captureToBuffer(const sp<IBinder>& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform, - uint32_t rotation, - sp<GraphicBuffer>* outBuffer) { +status_t ScreenshotClient::capture(const sp<IBinder>& display, Rect sourceCrop, uint32_t reqWidth, + uint32_t reqHeight, int32_t minLayerZ, int32_t maxLayerZ, + bool useIdentityTransform, uint32_t rotation, + sp<GraphicBuffer>* outBuffer) { sp<ISurfaceComposer> s(ComposerService::getComposerService()); - if (s == nullptr) return NO_INIT; - - sp<IGraphicBufferConsumer> gbpConsumer; - sp<IGraphicBufferProducer> producer; - BufferQueue::createBufferQueue(&producer, &gbpConsumer); - sp<BufferItemConsumer> consumer(new BufferItemConsumer(gbpConsumer, - GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_NEVER, - 1, true)); - - status_t ret = s->captureScreen(display, producer, sourceCrop, reqWidth, reqHeight, - minLayerZ, maxLayerZ, useIdentityTransform, - static_cast<ISurfaceComposer::Rotation>(rotation)); + if (s == NULL) return NO_INIT; + status_t ret = s->captureScreen(display, outBuffer, sourceCrop, reqWidth, reqHeight, minLayerZ, + maxLayerZ, useIdentityTransform, + static_cast<ISurfaceComposer::Rotation>(rotation)); if (ret != NO_ERROR) { return ret; } - BufferItem b; - consumer->acquireBuffer(&b, 0, true); - *outBuffer = b.mGraphicBuffer; return ret; } -ScreenshotClient::ScreenshotClient() - : mHaveBuffer(false) { - memset(&mBuffer, 0, sizeof(mBuffer)); -} - -ScreenshotClient::~ScreenshotClient() { - ScreenshotClient::release(); -} - -sp<CpuConsumer> ScreenshotClient::getCpuConsumer() const { - if (mCpuConsumer == nullptr) { - sp<IGraphicBufferConsumer> consumer; - BufferQueue::createBufferQueue(&mProducer, &consumer); - mCpuConsumer = new CpuConsumer(consumer, 1); - mCpuConsumer->setName(String8("ScreenshotClient")); - } - return mCpuConsumer; -} - -status_t ScreenshotClient::update(const sp<IBinder>& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, uint32_t rotation) { +status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle, Rect sourceCrop, + float frameScale, sp<GraphicBuffer>* outBuffer) { sp<ISurfaceComposer> s(ComposerService::getComposerService()); - if (s == nullptr) return NO_INIT; - sp<CpuConsumer> cpuConsumer = getCpuConsumer(); - - if (mHaveBuffer) { - mCpuConsumer->unlockBuffer(mBuffer); - memset(&mBuffer, 0, sizeof(mBuffer)); - mHaveBuffer = false; - } - - status_t err = s->captureScreen(display, mProducer, sourceCrop, - reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform, - static_cast<ISurfaceComposer::Rotation>(rotation)); - - if (err == NO_ERROR) { - err = mCpuConsumer->lockNextBuffer(&mBuffer); - if (err == NO_ERROR) { - mHaveBuffer = true; - } - } - return err; -} - -status_t ScreenshotClient::update(const sp<IBinder>& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform) { - - return ScreenshotClient::update(display, sourceCrop, reqWidth, reqHeight, - minLayerZ, maxLayerZ, useIdentityTransform, ISurfaceComposer::eRotateNone); -} - -status_t ScreenshotClient::update(const sp<IBinder>& display, Rect sourceCrop, - bool useIdentityTransform) { - return ScreenshotClient::update(display, sourceCrop, 0, 0, - INT32_MIN, INT32_MAX, - useIdentityTransform, ISurfaceComposer::eRotateNone); -} - -status_t ScreenshotClient::update(const sp<IBinder>& display, Rect sourceCrop, - uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform) { - return ScreenshotClient::update(display, sourceCrop, reqWidth, reqHeight, - INT32_MIN, INT32_MAX, - useIdentityTransform, ISurfaceComposer::eRotateNone); -} - -void ScreenshotClient::release() { - if (mHaveBuffer) { - mCpuConsumer->unlockBuffer(mBuffer); - memset(&mBuffer, 0, sizeof(mBuffer)); - mHaveBuffer = false; - } - mCpuConsumer.clear(); -} - -void const* ScreenshotClient::getPixels() const { - return mBuffer.data; -} - -uint32_t ScreenshotClient::getWidth() const { - return mBuffer.width; -} - -uint32_t ScreenshotClient::getHeight() const { - return mBuffer.height; -} - -PixelFormat ScreenshotClient::getFormat() const { - return mBuffer.format; -} - -uint32_t ScreenshotClient::getStride() const { - return mBuffer.stride; -} - -size_t ScreenshotClient::getSize() const { - return mBuffer.stride * mBuffer.height * bytesPerPixel(mBuffer.format); + if (s == NULL) return NO_INIT; + status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale, + false /* childrenOnly */); + return ret; } -android_dataspace ScreenshotClient::getDataSpace() const { - return mBuffer.dataSpace; +status_t ScreenshotClient::captureChildLayers(const sp<IBinder>& layerHandle, Rect sourceCrop, + float frameScale, sp<GraphicBuffer>* outBuffer) { + sp<ISurfaceComposer> s(ComposerService::getComposerService()); + if (s == NULL) return NO_INIT; + status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale, + true /* childrenOnly */); + return ret; } - // ---------------------------------------------------------------------------- }; // namespace android diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index 08e3b60f6c..5eafbb3555 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -48,8 +48,9 @@ namespace android { SurfaceControl::SurfaceControl( const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle, - const sp<IGraphicBufferProducer>& gbp) - : mClient(client), mHandle(handle), mGraphicBufferProducer(gbp) + const sp<IGraphicBufferProducer>& gbp, + bool owned) + : mClient(client), mHandle(handle), mGraphicBufferProducer(gbp), mOwned(owned) { } @@ -60,7 +61,9 @@ SurfaceControl::~SurfaceControl() void SurfaceControl::destroy() { - if (isValid()) { + // Avoid destroying the server-side surface if we are not the owner of it, meaning that we + // retrieved it from another process. + if (isValid() && mOwned) { mClient->destroySurface(mHandle); } // clear all references and trigger an IPC now, to make sure things @@ -83,7 +86,7 @@ void SurfaceControl::clear() } void SurfaceControl::disconnect() { - if (mGraphicBufferProducer != nullptr) { + if (mGraphicBufferProducer != NULL) { mGraphicBufferProducer->disconnect( BufferQueueCore::CURRENTLY_CONNECTED_API); } @@ -92,117 +95,11 @@ void SurfaceControl::disconnect() { bool SurfaceControl::isSameSurface( const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs) { - if (lhs == nullptr || rhs == nullptr) + if (lhs == 0 || rhs == 0) return false; return lhs->mHandle == rhs->mHandle; } -status_t SurfaceControl::setLayerStack(uint32_t layerStack) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setLayerStack(mHandle, layerStack); -} - -status_t SurfaceControl::setLayer(int32_t layer) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setLayer(mHandle, layer); -} - -status_t SurfaceControl::setRelativeLayer(const sp<IBinder>& relativeTo, int32_t layer) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setRelativeLayer(mHandle, relativeTo, layer); -} - -status_t SurfaceControl::setPosition(float x, float y) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setPosition(mHandle, x, y); -} -status_t SurfaceControl::setGeometryAppliesWithResize() { - status_t err = validate(); - if (err < 0) return err; - return mClient->setGeometryAppliesWithResize(mHandle); -} -status_t SurfaceControl::setSize(uint32_t w, uint32_t h) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setSize(mHandle, w, h); -} -status_t SurfaceControl::hide() { - status_t err = validate(); - if (err < 0) return err; - return mClient->hide(mHandle); -} -status_t SurfaceControl::show() { - status_t err = validate(); - if (err < 0) return err; - return mClient->show(mHandle); -} -status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setFlags(mHandle, flags, mask); -} -status_t SurfaceControl::setTransparentRegionHint(const Region& transparent) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setTransparentRegionHint(mHandle, transparent); -} -status_t SurfaceControl::setAlpha(float alpha) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setAlpha(mHandle, alpha); -} -status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dtdy, float dsdy) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setMatrix(mHandle, dsdx, dtdx, dtdy, dsdy); -} -status_t SurfaceControl::setCrop(const Rect& crop) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setCrop(mHandle, crop); -} -status_t SurfaceControl::setFinalCrop(const Rect& crop) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setFinalCrop(mHandle, crop); -} - -status_t SurfaceControl::deferTransactionUntil(const sp<IBinder>& handle, - uint64_t frameNumber) { - status_t err = validate(); - if (err < 0) return err; - return mClient->deferTransactionUntil(mHandle, handle, frameNumber); -} - -status_t SurfaceControl::deferTransactionUntil(const sp<Surface>& handle, - uint64_t frameNumber) { - status_t err = validate(); - if (err < 0) return err; - return mClient->deferTransactionUntil(mHandle, handle, frameNumber); -} - -status_t SurfaceControl::reparentChildren(const sp<IBinder>& newParentHandle) { - status_t err = validate(); - if (err < 0) return err; - return mClient->reparentChildren(mHandle, newParentHandle); -} - -status_t SurfaceControl::detachChildren() { - status_t err = validate(); - if (err < 0) return err; - return mClient->detachChildren(mHandle); -} - -status_t SurfaceControl::setOverrideScalingMode(int32_t overrideScalingMode) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setOverrideScalingMode(mHandle, overrideScalingMode); -} - status_t SurfaceControl::clearLayerFrameStats() const { status_t err = validate(); if (err < 0) return err; @@ -219,7 +116,7 @@ status_t SurfaceControl::getLayerFrameStats(FrameStats* outStats) const { status_t SurfaceControl::validate() const { - if (mHandle==nullptr || mClient==nullptr) { + if (mHandle==0 || mClient==0) { ALOGE("invalid handle (%p) or client (%p)", mHandle.get(), mClient.get()); return NO_INIT; @@ -231,7 +128,7 @@ status_t SurfaceControl::writeSurfaceToParcel( const sp<SurfaceControl>& control, Parcel* parcel) { sp<IGraphicBufferProducer> bp; - if (control != nullptr) { + if (control != NULL) { bp = control->mGraphicBufferProducer; } return parcel->writeStrongBinder(IInterface::asBinder(bp)); @@ -249,7 +146,7 @@ sp<Surface> SurfaceControl::generateSurfaceLocked() const sp<Surface> SurfaceControl::getSurface() const { Mutex::Autolock _l(mLock); - if (mSurfaceData == nullptr) { + if (mSurfaceData == 0) { return generateSurfaceLocked(); } return mSurfaceData; @@ -267,5 +164,35 @@ sp<IBinder> SurfaceControl::getHandle() const return mHandle; } +sp<SurfaceComposerClient> SurfaceControl::getClient() const +{ + return mClient; +} + +void SurfaceControl::writeToParcel(Parcel* parcel) +{ + parcel->writeStrongBinder(ISurfaceComposerClient::asBinder(mClient->getClient())); + parcel->writeStrongBinder(mHandle); + parcel->writeStrongBinder(IGraphicBufferProducer::asBinder(mGraphicBufferProducer)); +} + +sp<SurfaceControl> SurfaceControl::readFromParcel(Parcel* parcel) +{ + sp<IBinder> client = parcel->readStrongBinder(); + sp<IBinder> handle = parcel->readStrongBinder(); + if (client == nullptr || handle == nullptr) + { + ALOGE("Invalid parcel"); + return nullptr; + } + sp<IBinder> gbp; + parcel->readNullableStrongBinder(&gbp); + + // We aren't the original owner of the surface. + return new SurfaceControl(new SurfaceComposerClient( + interface_cast<ISurfaceComposerClient>(client)), + handle.get(), interface_cast<IGraphicBufferProducer>(gbp), false /* owned */); +} + // ---------------------------------------------------------------------------- }; // namespace android diff --git a/libs/gui/SyncFeatures.cpp b/libs/gui/SyncFeatures.cpp index fcae05c8ad..afa15c5cda 100644 --- a/libs/gui/SyncFeatures.cpp +++ b/libs/gui/SyncFeatures.cpp @@ -41,7 +41,7 @@ SyncFeatures::SyncFeatures() : Singleton<SyncFeatures>(), // This can only be called after EGL has been initialized; otherwise the // check below will abort. const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS); - LOG_ALWAYS_FATAL_IF(exts == nullptr, "eglQueryStringImplementationANDROID failed"); + LOG_ALWAYS_FATAL_IF(exts == NULL, "eglQueryStringImplementationANDROID failed"); if (strstr(exts, "EGL_ANDROID_native_fence_sync")) { // This makes GLConsumer use the EGL_ANDROID_native_fence_sync // extension to create Android native fences to signal when all diff --git a/libs/gui/include/gui/BufferHubConsumer.h b/libs/gui/include/gui/BufferHubConsumer.h new file mode 100644 index 0000000000..d38077014b --- /dev/null +++ b/libs/gui/include/gui/BufferHubConsumer.h @@ -0,0 +1,112 @@ +/* + * Copyright 2018 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. + */ + +#ifndef ANDROID_GUI_BUFFERHUBCONSUMER_H_ +#define ANDROID_GUI_BUFFERHUBCONSUMER_H_ + +#include <gui/IGraphicBufferConsumer.h> +#include <private/dvr/buffer_hub_queue_client.h> +#include <private/dvr/buffer_hub_queue_parcelable.h> + +namespace android { + +class BufferHubConsumer : public IGraphicBufferConsumer { +public: + // Creates a BufferHubConsumer instance by importing an existing producer queue. + static sp<BufferHubConsumer> Create(const std::shared_ptr<dvr::ConsumerQueue>& queue); + + // Creates a BufferHubConsumer instance by importing an existing producer + // parcelable. Note that this call takes the ownership of the parcelable + // object and is guaranteed to succeed if parcelable object is valid. + static sp<BufferHubConsumer> Create(dvr::ConsumerQueueParcelable parcelable); + + // See |IGraphicBufferConsumer::acquireBuffer| + status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen, + uint64_t maxFrameNumber = 0) override; + + // See |IGraphicBufferConsumer::detachBuffer| + status_t detachBuffer(int slot) override; + + // See |IGraphicBufferConsumer::attachBuffer| + status_t attachBuffer(int* outSlot, const sp<GraphicBuffer>& buffer) override; + + // See |IGraphicBufferConsumer::releaseBuffer| + status_t releaseBuffer(int buf, uint64_t frameNumber, EGLDisplay display, EGLSyncKHR fence, + const sp<Fence>& releaseFence) override; + + // See |IGraphicBufferConsumer::consumerConnect| + status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) override; + + // See |IGraphicBufferConsumer::consumerDisconnect| + status_t consumerDisconnect() override; + + // See |IGraphicBufferConsumer::getReleasedBuffers| + status_t getReleasedBuffers(uint64_t* slotMask) override; + + // See |IGraphicBufferConsumer::setDefaultBufferSize| + status_t setDefaultBufferSize(uint32_t w, uint32_t h) override; + + // See |IGraphicBufferConsumer::setMaxBufferCount| + status_t setMaxBufferCount(int bufferCount) override; + + // See |IGraphicBufferConsumer::setMaxAcquiredBufferCount| + status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) override; + + // See |IGraphicBufferConsumer::setConsumerName| + status_t setConsumerName(const String8& name) override; + + // See |IGraphicBufferConsumer::setDefaultBufferFormat| + status_t setDefaultBufferFormat(PixelFormat defaultFormat) override; + + // See |IGraphicBufferConsumer::setDefaultBufferDataSpace| + status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace) override; + + // See |IGraphicBufferConsumer::setConsumerUsageBits| + status_t setConsumerUsageBits(uint64_t usage) override; + + // See |IGraphicBufferConsumer::setConsumerIsProtected| + status_t setConsumerIsProtected(bool isProtected) override; + + // See |IGraphicBufferConsumer::setTransformHint| + status_t setTransformHint(uint32_t hint) override; + + // See |IGraphicBufferConsumer::getSidebandStream| + status_t getSidebandStream(sp<NativeHandle>* outStream) const override; + + // See |IGraphicBufferConsumer::getOccupancyHistory| + status_t getOccupancyHistory(bool forceFlush, + std::vector<OccupancyTracker::Segment>* outHistory) override; + + // See |IGraphicBufferConsumer::discardFreeBuffers| + status_t discardFreeBuffers() override; + + // See |IGraphicBufferConsumer::dumpState| + status_t dumpState(const String8& prefix, String8* outResult) const override; + + // BufferHubConsumer provides its own logic to cast to a binder object. + IBinder* onAsBinder() override; + +private: + // Private constructor to force use of |Create|. + BufferHubConsumer() = default; + + // Concrete implementation backed by BufferHubBuffer. + std::shared_ptr<dvr::ConsumerQueue> mQueue; +}; + +} // namespace android + +#endif // ANDROID_GUI_BUFFERHUBCONSUMER_H_ diff --git a/libs/gui/include/gui/BufferHubProducer.h b/libs/gui/include/gui/BufferHubProducer.h new file mode 100644 index 0000000000..23c9909826 --- /dev/null +++ b/libs/gui/include/gui/BufferHubProducer.h @@ -0,0 +1,219 @@ +/* + * Copyright 2018 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. + */ + +#ifndef ANDROID_GUI_BUFFERHUBPRODUCER_H_ +#define ANDROID_GUI_BUFFERHUBPRODUCER_H_ + +#include <gui/BufferSlot.h> +#include <gui/IGraphicBufferProducer.h> +#include <private/dvr/buffer_hub_queue_client.h> +#include <private/dvr/buffer_hub_queue_parcelable.h> + +namespace android { + +class BufferHubProducer : public IGraphicBufferProducer { +public: + static constexpr int kNoConnectedApi = -1; + + // TODO(b/36187402) The actual implementation of BufferHubQueue's consumer + // side logic doesn't limit the number of buffer it can acquire + // simultaneously. We need a way for consumer logic to configure and enforce + // that. + static constexpr int kDefaultUndequeuedBuffers = 1; + + // Creates a BufferHubProducer instance by importing an existing prodcuer + // queue. + static sp<BufferHubProducer> Create(const std::shared_ptr<dvr::ProducerQueue>& producer); + + // Creates a BufferHubProducer instance by importing an existing prodcuer + // parcelable. Note that this call takes the ownership of the parcelable + // object and is guaranteed to succeed if parcelable object is valid. + static sp<BufferHubProducer> Create(dvr::ProducerQueueParcelable parcelable); + + // See |IGraphicBufferProducer::requestBuffer| + status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override; + + // For the BufferHub based implementation. All buffers in the queue are + // allowed to be dequeued from the consumer side. It call always returns + // 0 for |NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS| query. Thus setting + // |max_dequeued_buffers| here can be considered the same as setting queue + // capacity. + // + // See |IGraphicBufferProducer::setMaxDequeuedBufferCount| for more info + status_t setMaxDequeuedBufferCount(int max_dequeued_buffers) override; + + // See |IGraphicBufferProducer::setAsyncMode| + status_t setAsyncMode(bool async) override; + + // See |IGraphicBufferProducer::dequeueBuffer| + status_t dequeueBuffer(int* out_slot, sp<Fence>* out_fence, uint32_t width, uint32_t height, + PixelFormat format, uint64_t usage, uint64_t* outBufferAge, + FrameEventHistoryDelta* outTimestamps) override; + + // See |IGraphicBufferProducer::detachBuffer| + status_t detachBuffer(int slot) override; + + // See |IGraphicBufferProducer::detachNextBuffer| + status_t detachNextBuffer(sp<GraphicBuffer>* out_buffer, sp<Fence>* out_fence) override; + + // See |IGraphicBufferProducer::attachBuffer| + status_t attachBuffer(int* out_slot, const sp<GraphicBuffer>& buffer) override; + + // See |IGraphicBufferProducer::queueBuffer| + status_t queueBuffer(int slot, const QueueBufferInput& input, + QueueBufferOutput* output) override; + + // See |IGraphicBufferProducer::cancelBuffer| + status_t cancelBuffer(int slot, const sp<Fence>& fence) override; + + // See |IGraphicBufferProducer::query| + status_t query(int what, int* out_value) override; + + // See |IGraphicBufferProducer::connect| + status_t connect(const sp<IProducerListener>& listener, int api, + bool producer_controlled_by_app, QueueBufferOutput* output) override; + + // See |IGraphicBufferProducer::disconnect| + status_t disconnect(int api, DisconnectMode mode = DisconnectMode::Api) override; + + // See |IGraphicBufferProducer::setSidebandStream| + status_t setSidebandStream(const sp<NativeHandle>& stream) override; + + // See |IGraphicBufferProducer::allocateBuffers| + void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format, + uint64_t usage) override; + + // See |IGraphicBufferProducer::allowAllocation| + status_t allowAllocation(bool allow) override; + + // See |IGraphicBufferProducer::setGenerationNumber| + status_t setGenerationNumber(uint32_t generation_number) override; + + // See |IGraphicBufferProducer::getConsumerName| + String8 getConsumerName() const override; + + // See |IGraphicBufferProducer::setSharedBufferMode| + status_t setSharedBufferMode(bool shared_buffer_mode) override; + + // See |IGraphicBufferProducer::setAutoRefresh| + status_t setAutoRefresh(bool auto_refresh) override; + + // See |IGraphicBufferProducer::setDequeueTimeout| + status_t setDequeueTimeout(nsecs_t timeout) override; + + // See |IGraphicBufferProducer::getLastQueuedBuffer| + status_t getLastQueuedBuffer(sp<GraphicBuffer>* out_buffer, sp<Fence>* out_fence, + float out_transform_matrix[16]) override; + + // See |IGraphicBufferProducer::getFrameTimestamps| + void getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) override; + + // See |IGraphicBufferProducer::getUniqueId| + status_t getUniqueId(uint64_t* out_id) const override; + + // See |IGraphicBufferProducer::getConsumerUsage| + status_t getConsumerUsage(uint64_t* out_usage) const override; + + // Takes out the current producer as a binder parcelable object. Note that the + // producer must be disconnected to be exportable. After successful export, + // the producer queue can no longer be connected again. Returns NO_ERROR when + // takeout is successful and out_parcelable will hold the new parcelable + // object. Also note that out_parcelable cannot be NULL and must points to an + // invalid parcelable. + status_t TakeAsParcelable(dvr::ProducerQueueParcelable* out_parcelable); + + IBinder* onAsBinder() override; + +protected: + // See |IGraphicBufferProducer::exportToParcel| + status_t exportToParcel(Parcel* parcel) override; + +private: + using LocalHandle = pdx::LocalHandle; + + // Private constructor to force use of |Create|. + BufferHubProducer() {} + + static uint64_t genUniqueId() { + static std::atomic<uint32_t> counter{0}; + static uint64_t id = static_cast<uint64_t>(getpid()) << 32; + return id | counter++; + } + + // Allocate new buffer through BufferHub and add it into |queue_| for + // bookkeeping. + status_t AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count, + PixelFormat format, uint64_t usage); + + // Remove a buffer via BufferHubRPC. + status_t RemoveBuffer(size_t slot); + + // Free all buffers which are owned by the prodcuer. Note that if graphic + // buffers are acquired by the consumer, we can't . + status_t FreeAllBuffers(); + + // Concreate implementation backed by BufferHubBuffer. + std::shared_ptr<dvr::ProducerQueue> queue_; + + // Mutex for thread safety. + std::mutex mutex_; + + // Connect client API, should be one of the NATIVE_WINDOW_API_* flags. + int connected_api_{kNoConnectedApi}; + + // |max_buffer_count_| sets the capacity of the underlying buffer queue. + int32_t max_buffer_count_{dvr::BufferHubQueue::kMaxQueueCapacity}; + + // |max_dequeued_buffer_count_| set the maximum number of buffers that can + // be dequeued at the same momment. + int32_t max_dequeued_buffer_count_{1}; + + // Sets how long dequeueBuffer or attachBuffer will block if a buffer or + // slot is not yet available. The timeout is stored in milliseconds. + int dequeue_timeout_ms_{dvr::BufferHubQueue::kNoTimeOut}; + + // |generation_number_| stores the current generation number of the attached + // producer. Any attempt to attach a buffer with a different generation + // number will fail. + // TOOD(b/38137191) Currently not used as we don't support + // IGraphicBufferProducer::detachBuffer. + uint32_t generation_number_{0}; + + // |buffers_| stores the buffers that have been dequeued from + // |dvr::BufferHubQueue|, It is initialized to invalid buffers, and gets + // filled in with the result of |Dequeue|. + // TODO(jwcai) The buffer allocated to a slot will also be replaced if the + // requested buffer usage or geometry differs from that of the buffer + // allocated to a slot. + struct BufferHubSlot : public BufferSlot { + BufferHubSlot() : mBufferProducer(nullptr), mIsReallocating(false) {} + // BufferSlot comes from android framework, using m prefix to comply with + // the name convention with the reset of data fields from BufferSlot. + std::shared_ptr<dvr::BufferProducer> mBufferProducer; + bool mIsReallocating; + }; + BufferHubSlot buffers_[dvr::BufferHubQueue::kMaxQueueCapacity]; + + // A uniqueId used by IGraphicBufferProducer interface. + const uint64_t unique_id_{genUniqueId()}; + + // A pending parcelable object which keeps the bufferhub channel alive. + dvr::ProducerQueueParcelable pending_producer_parcelable_; +}; + +} // namespace android + +#endif // ANDROID_GUI_BUFFERHUBPRODUCER_H_ diff --git a/libs/gui/include/gui/BufferItem.h b/libs/gui/include/gui/BufferItem.h index 55637a9be4..218bb424fb 100644 --- a/libs/gui/include/gui/BufferItem.h +++ b/libs/gui/include/gui/BufferItem.h @@ -17,6 +17,8 @@ #ifndef ANDROID_GUI_BUFFERITEM_H #define ANDROID_GUI_BUFFERITEM_H +#include <gui/HdrMetadata.h> + #include <ui/FenceTime.h> #include <ui/Rect.h> #include <ui/Region.h> @@ -86,6 +88,9 @@ class BufferItem : public Flattenable<BufferItem> { // dataSpace is format-dependent. android_dataspace mDataSpace; + // mHdrMetadata is the HDR metadata associated with this buffer slot. + HdrMetadata mHdrMetadata; + // mFrameNumber is the number of the queued frame for this slot. uint64_t mFrameNumber; @@ -122,6 +127,9 @@ class BufferItem : public Flattenable<BufferItem> { // Indicates that this BufferItem contains a stale buffer which has already // been released by the BufferQueue. bool mIsStale; + + // Indicates the API (NATIVE_WINDOW_API_xxx) that queues the buffer. + int mApi; }; } // namespace android diff --git a/libs/gui/include/gui/BufferItemConsumer.h b/libs/gui/include/gui/BufferItemConsumer.h index d9c57757f5..a905610ee2 100644 --- a/libs/gui/include/gui/BufferItemConsumer.h +++ b/libs/gui/include/gui/BufferItemConsumer.h @@ -57,10 +57,6 @@ class BufferItemConsumer: public ConsumerBase ~BufferItemConsumer() override; - // set the name of the BufferItemConsumer that will be used to identify it in - // log messages. - void setName(const String8& name); - // setBufferFreedListener sets the listener object that will be notified // when an old buffer is being freed. void setBufferFreedListener(const wp<BufferFreedListener>& listener); diff --git a/libs/gui/include/gui/BufferQueue.h b/libs/gui/include/gui/BufferQueue.h index ba5cbf7eb4..da952744f3 100644 --- a/libs/gui/include/gui/BufferQueue.h +++ b/libs/gui/include/gui/BufferQueue.h @@ -79,6 +79,12 @@ public: sp<IGraphicBufferConsumer>* outConsumer, bool consumerIsSurfaceFlinger = false); +#ifndef NO_BUFFERHUB + // Creates an IGraphicBufferProducer and IGraphicBufferConsumer pair backed by BufferHub. + static void createBufferHubQueue(sp<IGraphicBufferProducer>* outProducer, + sp<IGraphicBufferConsumer>* outConsumer); +#endif + BufferQueue() = delete; // Create through createBufferQueue }; diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h index e9fc8fd1ea..366ced380b 100644 --- a/libs/gui/include/gui/ConsumerBase.h +++ b/libs/gui/include/gui/ConsumerBase.h @@ -89,6 +89,18 @@ public: // See IGraphicBufferConsumer::setDefaultBufferDataSpace status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace); + // See IGraphicBufferConsumer::setConsumerUsageBits + status_t setConsumerUsageBits(uint64_t usage); + + // See IGraphicBufferConsumer::setTransformHint + status_t setTransformHint(uint32_t hint); + + // See IGraphicBufferConsumer::setMaxAcquiredBufferCount + status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); + + // See IGraphicBufferConsumer::getSidebandStream + sp<NativeHandle> getSidebandStream() const; + // See IGraphicBufferConsumer::getOccupancyHistory status_t getOccupancyHistory(bool forceFlush, std::vector<OccupancyTracker::Segment>* outHistory); @@ -187,7 +199,7 @@ protected: // ConsumerBase::releaseBufferLocked. virtual status_t releaseBufferLocked(int slot, const sp<GraphicBuffer> graphicBuffer, - EGLDisplay display, EGLSyncKHR eglFence); + EGLDisplay display = EGL_NO_DISPLAY, EGLSyncKHR eglFence = EGL_NO_SYNC_KHR); // returns true iff the slot still has the graphicBuffer in it. bool stillTracking(int slot, const sp<GraphicBuffer> graphicBuffer); diff --git a/libs/gui/include/gui/CpuConsumer.h b/libs/gui/include/gui/CpuConsumer.h index 58602bf321..d375611e5b 100644 --- a/libs/gui/include/gui/CpuConsumer.h +++ b/libs/gui/include/gui/CpuConsumer.h @@ -94,12 +94,6 @@ class CpuConsumer : public ConsumerBase CpuConsumer(const sp<IGraphicBufferConsumer>& bq, size_t maxLockedBuffers, bool controlledByApp = false); - virtual ~CpuConsumer(); - - // set the name of the CpuConsumer that will be used to identify it in - // log messages. - void setName(const String8& name); - // Gets the next graphics buffer from the producer and locks it for CPU use, // filling out the passed-in locked buffer structure with the native pointer // and metadata. Returns BAD_VALUE if no new buffer is available, and @@ -119,31 +113,39 @@ class CpuConsumer : public ConsumerBase private: // Maximum number of buffers that can be locked at a time - size_t mMaxLockedBuffers; - - status_t releaseAcquiredBufferLocked(size_t lockedIdx); - - virtual void freeBufferLocked(int slotIndex); + const size_t mMaxLockedBuffers; // Tracking for buffers acquired by the user struct AcquiredBuffer { + static constexpr uintptr_t kUnusedId = 0; + // Need to track the original mSlot index and the buffer itself because // the mSlot entry may be freed/reused before the acquired buffer is // released. int mSlot; sp<GraphicBuffer> mGraphicBuffer; - void *mBufferPointer; + uintptr_t mLockedBufferId; AcquiredBuffer() : mSlot(BufferQueue::INVALID_BUFFER_SLOT), - mBufferPointer(NULL) { + mLockedBufferId(kUnusedId) { + } + + void reset() { + mSlot = BufferQueue::INVALID_BUFFER_SLOT; + mGraphicBuffer.clear(); + mLockedBufferId = kUnusedId; } }; + + size_t findAcquiredBufferLocked(uintptr_t id) const; + + status_t lockBufferItem(const BufferItem& item, LockedBuffer* outBuffer) const; + Vector<AcquiredBuffer> mAcquiredBuffers; // Count of currently locked buffers size_t mCurrentLockedBuffers; - }; } // namespace android diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h index 75f2ccaaea..71ed3bf239 100644 --- a/libs/gui/include/gui/GLConsumer.h +++ b/libs/gui/include/gui/GLConsumer.h @@ -138,6 +138,10 @@ public: const sp<GraphicBuffer>& buf, const Rect& cropRect, uint32_t transform, bool filtering); + // Scale the crop down horizontally or vertically such that it has the + // same aspect ratio as the buffer does. + static Rect scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight); + // getTimestamp retrieves the timestamp associated with the texture image // set by the most recent call to updateTexImage. // @@ -197,22 +201,9 @@ public: // buffer is ready to be read from. std::shared_ptr<FenceTime> getCurrentFenceTime() const; - // doGLFenceWait inserts a wait command into the OpenGL ES command stream - // to ensure that it is safe for future OpenGL ES commands to access the - // current texture buffer. - status_t doGLFenceWait() const; - - // set the name of the GLConsumer that will be used to identify it in - // log messages. - void setName(const String8& name); - - // These functions call the corresponding BufferQueue implementation - // so the refactoring can proceed smoothly - status_t setDefaultBufferFormat(PixelFormat defaultFormat); - status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace); + // setConsumerUsageBits overrides the ConsumerBase method to OR + // DEFAULT_USAGE_FLAGS to usage. status_t setConsumerUsageBits(uint64_t usage); - status_t setTransformHint(uint32_t hint); - status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); // detachFromContext detaches the GLConsumer from the calling thread's // current OpenGL ES context. This context must be the same as the context @@ -267,8 +258,6 @@ protected: return releaseBufferLocked(slot, graphicBuffer, mEglDisplay, eglFence); } - static bool isExternalFormat(PixelFormat format); - struct PendingRelease { PendingRelease() : isPending(false), currentTexture(-1), graphicBuffer(), display(nullptr), fence(nullptr) {} diff --git a/libs/gui/include/gui/HdrMetadata.h b/libs/gui/include/gui/HdrMetadata.h new file mode 100644 index 0000000000..9800602d6c --- /dev/null +++ b/libs/gui/include/gui/HdrMetadata.h @@ -0,0 +1,45 @@ +/* + * Copyright 2018 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. + */ + +#pragma once + +#include <stdint.h> + +#include <system/graphics.h> +#include <utils/Flattenable.h> + +namespace android { + +struct HdrMetadata : public LightFlattenable<HdrMetadata> { + enum Type : uint32_t { + SMPTE2086 = 1 << 0, + CTA861_3 = 1 << 1, + }; + uint32_t validTypes{0}; + + android_smpte2086_metadata smpte2086{}; + android_cta861_3_metadata cta8613{}; + + // LightFlattenable + bool isFixedSize() const { return false; } + size_t getFlattenedSize() const; + status_t flatten(void* buffer, size_t size) const; + status_t unflatten(void const* buffer, size_t size); + + bool operator==(const HdrMetadata& rhs) const; +}; + +} // namespace android diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 039dc0d657..887654e05b 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -31,6 +31,7 @@ #include <ui/Region.h> #include <gui/FrameTimestamps.h> +#include <gui/HdrMetadata.h> #include <hidl/HybridInterface.h> #include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h> @@ -72,6 +73,14 @@ public: RELEASE_ALL_BUFFERS = 0x2, }; + enum { + // A parcelable magic indicates using Binder BufferQueue as transport + // backend. + USE_BUFFER_QUEUE = 0x62717565, // 'bque' + // A parcelable magic indicates using BufferHub as transport backend. + USE_BUFFER_HUB = 0x62687562, // 'bhub' + }; + // requestBuffer requests a new buffer for the given index. The server (i.e. // the IGraphicBufferProducer implementation) assigns the newly created // buffer to the given slot index, and the client is expected to mirror the @@ -354,6 +363,9 @@ public: const Region& getSurfaceDamage() const { return surfaceDamage; } void setSurfaceDamage(const Region& damage) { surfaceDamage = damage; } + const HdrMetadata& getHdrMetadata() const { return hdrMetadata; } + void setHdrMetadata(const HdrMetadata& metadata) { hdrMetadata = metadata; } + private: int64_t timestamp{0}; int isAutoTimestamp{0}; @@ -365,6 +377,7 @@ public: sp<Fence> fence; Region surfaceDamage; bool getFrameTimestamps{false}; + HdrMetadata hdrMetadata; }; struct QueueBufferOutput : public Flattenable<QueueBufferOutput> { @@ -599,6 +612,24 @@ public: // returned by querying the now deprecated // NATIVE_WINDOW_CONSUMER_USAGE_BITS attribute. virtual status_t getConsumerUsage(uint64_t* outUsage) const = 0; + + // Static method exports any IGraphicBufferProducer object to a parcel. It + // handles null producer as well. + static status_t exportToParcel(const sp<IGraphicBufferProducer>& producer, + Parcel* parcel); + + // Factory method that creates a new IBGP instance from the parcel. + static sp<IGraphicBufferProducer> createFromParcel(const Parcel* parcel); + +protected: + // Exports the current producer as a binder parcelable object. Note that the + // producer must be disconnected to be exportable. After successful export, + // the producer queue can no longer be connected again. Returns NO_ERROR + // when the export is successful and writes an implementation defined + // parcelable object into the parcel. For traditional Android BufferQueue, + // it writes a strong binder object; for BufferHub, it writes a + // ProducerQueueParcelable object. + virtual status_t exportToParcel(Parcel* parcel); }; // ---------------------------------------------------------------------------- diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index b2267426a8..e40157206d 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -29,6 +29,8 @@ #include <ui/FrameStats.h> #include <ui/PixelFormat.h> +#include <ui/GraphicBuffer.h> +#include <ui/GraphicTypes.h> #include <vector> @@ -59,6 +61,11 @@ public: enum { eSynchronous = 0x01, eAnimation = 0x02, + + // Indicates that this transaction will likely result in a lot of layers being composed, and + // thus, SurfaceFlinger should wake-up earlier to avoid missing frame deadlines. In this + // case SurfaceFlinger will wake up at (sf vsync offset - debug.sf.early_phase_offset_ns) + eEarlyWakeup = 0x04 }; enum { @@ -159,20 +166,25 @@ public: virtual status_t setActiveConfig(const sp<IBinder>& display, int id) = 0; virtual status_t getDisplayColorModes(const sp<IBinder>& display, - Vector<android_color_mode_t>* outColorModes) = 0; - virtual android_color_mode_t getActiveColorMode(const sp<IBinder>& display) = 0; + Vector<ui::ColorMode>* outColorModes) = 0; + virtual ui::ColorMode getActiveColorMode(const sp<IBinder>& display) = 0; virtual status_t setActiveColorMode(const sp<IBinder>& display, - android_color_mode_t colorMode) = 0; + ui::ColorMode colorMode) = 0; /* Capture the specified screen. requires READ_FRAME_BUFFER permission * This function will fail if there is a secure window on screen. */ - virtual status_t captureScreen(const sp<IBinder>& display, - const sp<IGraphicBufferProducer>& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, - Rotation rotation = eRotateNone) = 0; + virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer, + Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, + int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform, + Rotation rotation = eRotateNone) = 0; + + /** + * Capture a subtree of the layer hierarchy, potentially ignoring the root node. + */ + virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder, + sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop, + float frameScale = 1.0, bool childrenOnly = false) = 0; /* Clears the frame statistics for animations. * @@ -226,6 +238,7 @@ public: SET_ACTIVE_CONFIG, CONNECT_DISPLAY, CAPTURE_SCREEN, + CAPTURE_LAYERS, CLEAR_ANIMATION_FRAME_STATS, GET_ANIMATION_FRAME_STATS, SET_POWER_MODE, diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h index 2c613ea8c5..8dfc99a4b7 100644 --- a/libs/gui/include/gui/ISurfaceComposerClient.h +++ b/libs/gui/include/gui/ISurfaceComposerClient.h @@ -41,7 +41,7 @@ public: eCursorWindow = 0x00002000, eFXSurfaceNormal = 0x00000000, - eFXSurfaceDim = 0x00020000, + eFXSurfaceColor = 0x00020000, eFXSurfaceMask = 0x000F0000, }; @@ -49,8 +49,8 @@ public: * Requires ACCESS_SURFACE_FLINGER permission */ virtual status_t createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format, - uint32_t flags, const sp<IBinder>& parent, uint32_t windowType, - uint32_t ownerUid, sp<IBinder>* handle, + uint32_t flags, const sp<IBinder>& parent, int32_t windowType, + int32_t ownerUid, sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp) = 0; /* diff --git a/libs/gui/include/gui/LayerDebugInfo.h b/libs/gui/include/gui/LayerDebugInfo.h index 8453e043ef..92bd8c5b28 100644 --- a/libs/gui/include/gui/LayerDebugInfo.h +++ b/libs/gui/include/gui/LayerDebugInfo.h @@ -22,6 +22,7 @@ #include <ui/Region.h> #include <string> +#include <math/vec4.h> namespace android { @@ -52,7 +53,7 @@ public: int32_t mHeight = -1; Rect mCrop = Rect::INVALID_RECT; Rect mFinalCrop = Rect::INVALID_RECT; - float mAlpha = 0.f; + half4 mColor = half4(1.0_hf, 1.0_hf, 1.0_hf, 0.0_hf); uint32_t mFlags = 0; PixelFormat mPixelFormat = PIXEL_FORMAT_NONE; android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN; diff --git a/libs/gui/include/private/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 307c764702..788962e490 100644 --- a/libs/gui/include/private/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -25,6 +25,7 @@ #include <ui/Region.h> #include <ui/Rect.h> #include <gui/IGraphicBufferProducer.h> +#include <math/vec3.h> namespace android { @@ -59,7 +60,10 @@ struct layer_state_t { eGeometryAppliesWithResize = 0x00001000, eReparentChildren = 0x00002000, eDetachChildren = 0x00004000, - eRelativeLayerChanged = 0x00008000 + eRelativeLayerChanged = 0x00008000, + eReparent = 0x00010000, + eColorChanged = 0x00020000, + eDestroySurface = 0x00040000 }; layer_state_t() @@ -74,6 +78,7 @@ struct layer_state_t { matrix.dsdy = matrix.dtdx = 0.0f; } + void merge(const layer_state_t& other); status_t write(Parcel& output) const; status_t read(const Parcel& input); @@ -107,6 +112,10 @@ struct layer_state_t { sp<IBinder> relativeLayerHandle; + sp<IBinder> parentHandleForChild; + + half3 color; + // non POD must be last. see write/read Region transparentRegion; }; @@ -137,6 +146,7 @@ struct DisplayState { }; DisplayState(); + void merge(const DisplayState& other); uint32_t what; sp<IBinder> token; @@ -150,6 +160,20 @@ struct DisplayState { status_t read(const Parcel& input); }; +static inline +int compare_type(const ComposerState& lhs, const ComposerState& rhs) { + if (lhs.client < rhs.client) return -1; + if (lhs.client > rhs.client) return 1; + if (lhs.state.surface < rhs.state.surface) return -1; + if (lhs.state.surface > rhs.state.surface) return 1; + return 0; +} + +static inline +int compare_type(const DisplayState& lhs, const DisplayState& rhs) { + return compare_type(lhs.token, rhs.token); +} + }; // namespace android #endif // ANDROID_SF_LAYER_STATE_H diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 55dd6bf067..9aeafae198 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -17,10 +17,12 @@ #ifndef ANDROID_GUI_SURFACE_H #define ANDROID_GUI_SURFACE_H -#include <gui/IGraphicBufferProducer.h> #include <gui/BufferQueueDefs.h> +#include <gui/HdrMetadata.h> +#include <gui/IGraphicBufferProducer.h> #include <ui/ANativeObjectBase.h> +#include <ui/GraphicTypes.h> #include <ui/Region.h> #include <utils/Condition.h> @@ -214,6 +216,8 @@ private: int dispatchUnlockAndPost(va_list args); int dispatchSetSidebandStream(va_list args); int dispatchSetBuffersDataSpace(va_list args); + int dispatchSetBuffersSmpte2086Metadata(va_list args); + int dispatchSetBuffersCta8613Metadata(va_list args); int dispatchSetSurfaceDamage(va_list args); int dispatchSetSharedBufferMode(va_list args); int dispatchSetAutoRefresh(va_list args); @@ -242,7 +246,9 @@ protected: virtual int setBuffersTransform(uint32_t transform); virtual int setBuffersStickyTransform(uint32_t transform); virtual int setBuffersTimestamp(int64_t timestamp); - virtual int setBuffersDataSpace(android_dataspace dataSpace); + virtual int setBuffersDataSpace(ui::Dataspace dataSpace); + virtual int setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metadata); + virtual int setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata); virtual int setCrop(Rect const* rect); virtual int setUsage(uint64_t reqUsage); virtual void setSurfaceDamage(android_native_rect_t* rects, size_t numRects); @@ -281,6 +287,10 @@ public: // detachNextBuffer, or attachBuffer call. status_t getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out); + ui::Dataspace getBuffersDataSpace(); + + static status_t attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffer); + protected: enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS }; enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 }; @@ -331,9 +341,13 @@ protected: int64_t mTimestamp; // mDataSpace is the buffer dataSpace that will be used for the next buffer - // queue operation. It defaults to HAL_DATASPACE_UNKNOWN, which + // queue operation. It defaults to Dataspace::UNKNOWN, which // means that the buffer contains some type of color data. - android_dataspace mDataSpace; + ui::Dataspace mDataSpace; + + // mHdrMetadata is the HDR metadata that will be used for the next buffer + // queue operation. There is no HDR metadata by default. + HdrMetadata mHdrMetadata; // mCrop is the crop rectangle that will be used for the next buffer // that gets queued. It is set by calling setCrop. diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 145c0597bd..377fe68c41 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -19,6 +19,7 @@ #include <stdint.h> #include <sys/types.h> +#include <unordered_map> #include <binder/IBinder.h> @@ -28,17 +29,19 @@ #include <utils/threads.h> #include <ui/FrameStats.h> +#include <ui/GraphicTypes.h> #include <ui/PixelFormat.h> #include <gui/CpuConsumer.h> #include <gui/SurfaceControl.h> +#include <math/vec3.h> +#include <gui/LayerState.h> namespace android { // --------------------------------------------------------------------------- struct DisplayInfo; -class Composer; class HdrCapabilities; class ISurfaceComposerClient; class IGraphicBufferProducer; @@ -51,6 +54,7 @@ class SurfaceComposerClient : public RefBase friend class Composer; public: SurfaceComposerClient(); + SurfaceComposerClient(const sp<ISurfaceComposerClient>& client); SurfaceComposerClient(const sp<IGraphicBufferProducer>& parent); virtual ~SurfaceComposerClient(); @@ -85,13 +89,14 @@ public: // Gets the list of supported color modes for the given display static status_t getDisplayColorModes(const sp<IBinder>& display, - Vector<android_color_mode_t>* outColorModes); + Vector<ui::ColorMode>* outColorModes); // Gets the active color mode for the given display - static android_color_mode_t getActiveColorMode(const sp<IBinder>& display); + static ui::ColorMode getActiveColorMode(const sp<IBinder>& display); // Sets the active color mode for the given display - static status_t setActiveColorMode(const sp<IBinder>& display, android_color_mode_t colorMode); + static status_t setActiveColorMode(const sp<IBinder>& display, + ui::ColorMode colorMode); /* Triggers screen on/off or low power mode and waits for it to complete */ static void setDisplayPowerMode(const sp<IBinder>& display, int mode); @@ -107,8 +112,20 @@ public: PixelFormat format, // pixel-format desired uint32_t flags = 0, // usage flags SurfaceControl* parent = nullptr, // parent - uint32_t windowType = 0, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.) - uint32_t ownerUid = 0 // UID of the task + int32_t windowType = -1, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.) + int32_t ownerUid = -1 // UID of the task + ); + + status_t createSurfaceChecked( + const String8& name,// name of the surface + uint32_t w, // width in pixel + uint32_t h, // height in pixel + PixelFormat format, // pixel-format desired + sp<SurfaceControl>* outSurface, + uint32_t flags = 0, // usage flags + SurfaceControl* parent = nullptr, // parent + int32_t windowType = -1, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.) + int32_t ownerUid = -1 // UID of the task ); //! Create a virtual display @@ -121,157 +138,185 @@ public: //! Possible values for id are eDisplayIdMain and eDisplayIdHdmi. static sp<IBinder> getBuiltInDisplay(int32_t id); - // ------------------------------------------------------------------------ - // Composer parameters - // All composer parameters must be changed within a transaction - // several surfaces can be updated in one transaction, all changes are - // committed at once when the transaction is closed. - // closeGlobalTransaction() requires an IPC with the server. - - //! Open a composer transaction on all active SurfaceComposerClients. - static void openGlobalTransaction(); - - //! Close a composer transaction on all active SurfaceComposerClients. - static void closeGlobalTransaction(bool synchronous = false); - static status_t enableVSyncInjections(bool enable); static status_t injectVSync(nsecs_t when); - //! Flag the currently open transaction as an animation transaction. - static void setAnimationTransaction(); - - status_t hide(const sp<IBinder>& id); - status_t show(const sp<IBinder>& id); - status_t setFlags(const sp<IBinder>& id, uint32_t flags, uint32_t mask); - status_t setTransparentRegionHint(const sp<IBinder>& id, const Region& transparent); - status_t setLayer(const sp<IBinder>& id, int32_t layer); - status_t setRelativeLayer(const sp<IBinder>& id, - const sp<IBinder>& relativeTo, int32_t layer); - status_t setAlpha(const sp<IBinder>& id, float alpha=1.0f); - status_t setMatrix(const sp<IBinder>& id, float dsdx, float dtdx, float dtdy, float dsdy); - status_t setPosition(const sp<IBinder>& id, float x, float y); - status_t setSize(const sp<IBinder>& id, uint32_t w, uint32_t h); - status_t setCrop(const sp<IBinder>& id, const Rect& crop); - status_t setFinalCrop(const sp<IBinder>& id, const Rect& crop); - status_t setLayerStack(const sp<IBinder>& id, uint32_t layerStack); - status_t deferTransactionUntil(const sp<IBinder>& id, - const sp<IBinder>& handle, uint64_t frameNumber); - status_t deferTransactionUntil(const sp<IBinder>& id, - const sp<Surface>& handle, uint64_t frameNumber); - status_t reparentChildren(const sp<IBinder>& id, - const sp<IBinder>& newParentHandle); - status_t detachChildren(const sp<IBinder>& id); - status_t setOverrideScalingMode(const sp<IBinder>& id, - int32_t overrideScalingMode); - status_t setGeometryAppliesWithResize(const sp<IBinder>& id); + struct SCHash { + std::size_t operator()(const sp<SurfaceControl>& sc) const { + return std::hash<SurfaceControl *>{}(sc.get()); + } + }; + + class Transaction { + std::unordered_map<sp<SurfaceControl>, ComposerState, SCHash> mComposerStates; + SortedVector<DisplayState > mDisplayStates; + uint32_t mForceSynchronous = 0; + uint32_t mTransactionNestCount = 0; + bool mAnimation = false; + bool mEarlyWakeup = false; + + int mStatus = NO_ERROR; + + layer_state_t* getLayerState(const sp<SurfaceControl>& sc); + DisplayState& getDisplayState(const sp<IBinder>& token); + + public: + Transaction() = default; + virtual ~Transaction() = default; + Transaction(Transaction const& other); + + status_t apply(bool synchronous = false); + // Merge another transaction in to this one, clearing other + // as if it had been applied. + Transaction& merge(Transaction&& other); + Transaction& show(const sp<SurfaceControl>& sc); + Transaction& hide(const sp<SurfaceControl>& sc); + Transaction& setPosition(const sp<SurfaceControl>& sc, + float x, float y); + Transaction& setSize(const sp<SurfaceControl>& sc, + uint32_t w, uint32_t h); + Transaction& setLayer(const sp<SurfaceControl>& sc, + int32_t z); + + // Sets a Z order relative to the Surface specified by "relativeTo" but + // without becoming a full child of the relative. Z-ordering works exactly + // as if it were a child however. + // + // As a nod to sanity, only non-child surfaces may have a relative Z-order. + // + // This overrides any previous call and is overriden by any future calls + // to setLayer. + // + // If the relative is removed, the Surface will have no layer and be + // invisible, until the next time set(Relative)Layer is called. + Transaction& setRelativeLayer(const sp<SurfaceControl>& sc, + const sp<IBinder>& relativeTo, int32_t z); + Transaction& setFlags(const sp<SurfaceControl>& sc, + uint32_t flags, uint32_t mask); + Transaction& setTransparentRegionHint(const sp<SurfaceControl>& sc, + const Region& transparentRegion); + Transaction& setAlpha(const sp<SurfaceControl>& sc, + float alpha); + Transaction& setMatrix(const sp<SurfaceControl>& sc, + float dsdx, float dtdx, float dtdy, float dsdy); + Transaction& setCrop(const sp<SurfaceControl>& sc, const Rect& crop); + Transaction& setFinalCrop(const sp<SurfaceControl>& sc, const Rect& crop); + Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack); + // Defers applying any changes made in this transaction until the Layer + // identified by handle reaches the given frameNumber. If the Layer identified + // by handle is removed, then we will apply this transaction regardless of + // what frame number has been reached. + Transaction& deferTransactionUntil(const sp<SurfaceControl>& sc, + const sp<IBinder>& handle, + uint64_t frameNumber); + // A variant of deferTransactionUntil which identifies the Layer we wait for by + // Surface instead of Handle. Useful for clients which may not have the + // SurfaceControl for some of their Surfaces. Otherwise behaves identically. + Transaction& deferTransactionUntil(const sp<SurfaceControl>& sc, + const sp<Surface>& barrierSurface, + uint64_t frameNumber); + // Reparents all children of this layer to the new parent handle. + Transaction& reparentChildren(const sp<SurfaceControl>& sc, + const sp<IBinder>& newParentHandle); + + /// Reparents the current layer to the new parent handle. The new parent must not be null. + // This can be used instead of reparentChildren if the caller wants to + // only re-parent a specific child. + Transaction& reparent(const sp<SurfaceControl>& sc, + const sp<IBinder>& newParentHandle); + + Transaction& setColor(const sp<SurfaceControl>& sc, const half3& color); + + // Detaches all child surfaces (and their children recursively) + // from their SurfaceControl. + // The child SurfaceControls will not throw exceptions or return errors, + // but transactions will have no effect. + // The child surfaces will continue to follow their parent surfaces, + // and remain eligible for rendering, but their relative state will be + // frozen. We use this in the WindowManager, in app shutdown/relaunch + // scenarios, where the app would otherwise clean up its child Surfaces. + // Sometimes the WindowManager needs to extend their lifetime slightly + // in order to perform an exit animation or prevent flicker. + Transaction& detachChildren(const sp<SurfaceControl>& sc); + // Set an override scaling mode as documented in <system/window.h> + // the override scaling mode will take precedence over any client + // specified scaling mode. -1 will clear the override scaling mode. + Transaction& setOverrideScalingMode(const sp<SurfaceControl>& sc, + int32_t overrideScalingMode); + + // If the size changes in this transaction, all geometry updates specified + // in this transaction will not complete until a buffer of the new size + // arrives. As some elements normally apply immediately, this enables + // freezing the total geometry of a surface until a resize is completed. + Transaction& setGeometryAppliesWithResize(const sp<SurfaceControl>& sc); + + Transaction& destroySurface(const sp<SurfaceControl>& sc); + + status_t setDisplaySurface(const sp<IBinder>& token, + const sp<IGraphicBufferProducer>& bufferProducer); + + void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack); + + /* setDisplayProjection() defines the projection of layer stacks + * to a given display. + * + * - orientation defines the display's orientation. + * - layerStackRect defines which area of the window manager coordinate + * space will be used. + * - displayRect defines where on the display will layerStackRect be + * mapped to. displayRect is specified post-orientation, that is + * it uses the orientation seen by the end-user. + */ + void setDisplayProjection(const sp<IBinder>& token, + uint32_t orientation, + const Rect& layerStackRect, + const Rect& displayRect); + void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height); + void setAnimationTransaction(); + void setEarlyWakeup(); + }; status_t destroySurface(const sp<IBinder>& id); status_t clearLayerFrameStats(const sp<IBinder>& token) const; status_t getLayerFrameStats(const sp<IBinder>& token, FrameStats* outStats) const; - static status_t clearAnimationFrameStats(); static status_t getAnimationFrameStats(FrameStats* outStats); static status_t getHdrCapabilities(const sp<IBinder>& display, HdrCapabilities* outCapabilities); - static status_t setDisplaySurface(const sp<IBinder>& token, - sp<IGraphicBufferProducer> bufferProducer); - static void setDisplayLayerStack(const sp<IBinder>& token, - uint32_t layerStack); - static void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height); - - /* setDisplayProjection() defines the projection of layer stacks - * to a given display. - * - * - orientation defines the display's orientation. - * - layerStackRect defines which area of the window manager coordinate - * space will be used. - * - displayRect defines where on the display will layerStackRect be - * mapped to. displayRect is specified post-orientation, that is - * it uses the orientation seen by the end-user. - */ static void setDisplayProjection(const sp<IBinder>& token, uint32_t orientation, const Rect& layerStackRect, const Rect& displayRect); + inline sp<ISurfaceComposerClient> getClient() { return mClient; } + private: virtual void onFirstRef(); - Composer& getComposer(); mutable Mutex mLock; status_t mStatus; sp<ISurfaceComposerClient> mClient; - Composer& mComposer; wp<IGraphicBufferProducer> mParent; }; // --------------------------------------------------------------------------- -class ScreenshotClient -{ +class ScreenshotClient { public: // if cropping isn't required, callers may pass in a default Rect, e.g.: // capture(display, producer, Rect(), reqWidth, ...); - static status_t capture( - const sp<IBinder>& display, - const sp<IGraphicBufferProducer>& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform); - static status_t captureToBuffer( - const sp<IBinder>& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, - uint32_t rotation, - sp<GraphicBuffer>* outbuffer); -private: - mutable sp<CpuConsumer> mCpuConsumer; - mutable sp<IGraphicBufferProducer> mProducer; - CpuConsumer::LockedBuffer mBuffer; - bool mHaveBuffer; - -public: - ScreenshotClient(); - ~ScreenshotClient(); - - // frees the previous screenshot and captures a new one - // if cropping isn't required, callers may pass in a default Rect, e.g.: - // update(display, Rect(), useIdentityTransform); - status_t update(const sp<IBinder>& display, - Rect sourceCrop, bool useIdentityTransform); - status_t update(const sp<IBinder>& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - bool useIdentityTransform); - status_t update(const sp<IBinder>& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform); - status_t update(const sp<IBinder>& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, uint32_t rotation); - - sp<CpuConsumer> getCpuConsumer() const; - - // release memory occupied by the screenshot - void release(); - - // pixels are valid until this object is freed or - // release() or update() is called - void const* getPixels() const; - - uint32_t getWidth() const; - uint32_t getHeight() const; - PixelFormat getFormat() const; - uint32_t getStride() const; - // size of allocated memory in bytes - size_t getSize() const; - android_dataspace getDataSpace() const; + static status_t capture(const sp<IBinder>& display, Rect sourceCrop, uint32_t reqWidth, + uint32_t reqHeight, int32_t minLayerZ, int32_t maxLayerZ, + bool useIdentityTransform, uint32_t rotation, + sp<GraphicBuffer>* outBuffer); + static status_t captureLayers(const sp<IBinder>& layerHandle, Rect sourceCrop, float frameScale, + sp<GraphicBuffer>* outBuffer); + static status_t captureChildLayers(const sp<IBinder>& layerHandle, Rect sourceCrop, + float frameScale, sp<GraphicBuffer>* outBuffer); }; // --------------------------------------------------------------------------- diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h index c15209d32c..bd987dd638 100644 --- a/libs/gui/include/gui/SurfaceControl.h +++ b/libs/gui/include/gui/SurfaceControl.h @@ -29,6 +29,7 @@ #include <ui/Region.h> #include <gui/ISurfaceComposerClient.h> +#include <math/vec3.h> namespace android { @@ -43,6 +44,9 @@ class SurfaceComposerClient; class SurfaceControl : public RefBase { public: + static sp<SurfaceControl> readFromParcel(Parcel* parcel); + void writeToParcel(Parcel* parcel); + static bool isValid(const sp<SurfaceControl>& surface) { return (surface != 0) && surface->isValid(); } @@ -60,87 +64,6 @@ public: // disconnect any api that's connected void disconnect(); - status_t setLayerStack(uint32_t layerStack); - status_t setLayer(int32_t layer); - - // Sets a Z order relative to the Surface specified by "relativeTo" but - // without becoming a full child of the relative. Z-ordering works exactly - // as if it were a child however. - // - // As a nod to sanity, only non-child surfaces may have a relative Z-order. - // - // This overrides any previous and is overriden by any future calls - // to setLayer. - // - // If the relative dissapears, the Surface will have no layer and be - // invisible, until the next time set(Relative)Layer is called. - // - // TODO: This is probably a hack. Currently it exists only to work around - // some framework usage of the hidden APPLICATION_MEDIA_OVERLAY window type - // which allows inserting a window between a SurfaceView and it's main application - // window. However, since we are using child windows for the SurfaceView, but not using - // child windows elsewhere in O, the WindowManager can't set the layer appropriately. - // This is only used by the "TvInputService" and following the port of ViewRootImpl - // to child surfaces, we can then port this and remove this method. - status_t setRelativeLayer(const sp<IBinder>& relativeTo, int32_t layer); - status_t setPosition(float x, float y); - status_t setSize(uint32_t w, uint32_t h); - status_t hide(); - status_t show(); - status_t setFlags(uint32_t flags, uint32_t mask); - status_t setTransparentRegionHint(const Region& transparent); - status_t setAlpha(float alpha=1.0f); - - // Experimentarily it appears that the matrix transforms the - // on-screen rectangle and it's contents before the position is - // applied. - // - // TODO: Test with other combinations to find approximate transformation rules. - // - // For example: - // Layer sized (W,H) set to position (x,y) with matrix M=[-1, 0, 0, 1] (Horizontal flip) gives - // [((0, 0), (W, H)) x M] + (x,y) = ((-W, 0), (0, H)) + (x,y) = ((-W + x, y), (x, H+y)) - status_t setMatrix(float dsdx, float dtdx, float dtdy, float dsdy); - status_t setCrop(const Rect& crop); - status_t setFinalCrop(const Rect& crop); - - // If the size changes in this transaction, all geometry updates specified - // in this transaction will not complete until a buffer of the new size - // arrives. As some elements normally apply immediately, this enables - // freezing the total geometry of a surface until a resize is completed. - status_t setGeometryAppliesWithResize(); - - // Defers applying any changes made in this transaction until the Layer - // identified by handle reaches the given frameNumber. If the Layer identified - // by handle is removed, then we will apply this transaction regardless of - // what frame number has been reached. - status_t deferTransactionUntil(const sp<IBinder>& handle, uint64_t frameNumber); - - // A variant of deferTransactionUntil which identifies the Layer we wait for by - // Surface instead of Handle. Useful for clients which may not have the - // SurfaceControl for some of their Surfaces. Otherwise behaves identically. - status_t deferTransactionUntil(const sp<Surface>& barrier, uint64_t frameNumber); - - // Reparents all children of this layer to the new parent handle. - status_t reparentChildren(const sp<IBinder>& newParentHandle); - - // Detaches all child surfaces (and their children recursively) - // from their SurfaceControl. - // The child SurfaceControl's will not throw exceptions or return errors, - // but transactions will have no effect. - // The child surfaces will continue to follow their parent surfaces, - // and remain eligible for rendering, but their relative state will be - // frozen. We use this in the WindowManager, in app shutdown/relaunch - // scenarios, where the app would otherwise clean up its child Surfaces. - // Sometimes the WindowManager needs to extend their lifetime slightly - // in order to perform an exit animation or prevent flicker. - status_t detachChildren(); - - // Set an override scaling mode as documented in <system/window.h> - // the override scaling mode will take precedence over any client - // specified scaling mode. -1 will clear the override scaling mode. - status_t setOverrideScalingMode(int32_t overrideScalingMode); - static status_t writeSurfaceToParcel( const sp<SurfaceControl>& control, Parcel* parcel); @@ -151,6 +74,8 @@ public: status_t clearLayerFrameStats() const; status_t getLayerFrameStats(FrameStats* outStats) const; + sp<SurfaceComposerClient> getClient() const; + private: // can't be copied SurfaceControl& operator = (SurfaceControl& rhs); @@ -162,7 +87,8 @@ private: SurfaceControl( const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle, - const sp<IGraphicBufferProducer>& gbp); + const sp<IGraphicBufferProducer>& gbp, + bool owned); ~SurfaceControl(); @@ -175,6 +101,7 @@ private: sp<IGraphicBufferProducer> mGraphicBufferProducer; mutable Mutex mLock; mutable sp<Surface> mSurfaceData; + bool mOwned; }; }; // namespace android diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index 908959ce1a..01e90e0eb8 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -49,3 +49,35 @@ cc_test { "libnativewindow" ], } + +// Build a separate binary for each source file to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE) +cc_test { + name: "libgui_separate_binary_test", + test_suites: ["device-tests"], + + clang: true, + cflags: [ + "-Wall", + "-Werror", + ], + + test_per_src: true, + srcs: [ + "SurfaceParcelable_test.cpp", + ], + + shared_libs: [ + "liblog", + "libbinder", + "libcutils", + "libgui", + "libui", + "libutils", + "libbufferhubqueue", // TODO(b/70046255): Remove these once BufferHub is integrated into libgui. + "libpdx_default_transport", + ], + + header_libs: [ + "libdvr_headers", + ], +} diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp index 588e54142f..36be7d9368 100644 --- a/libs/gui/tests/CpuConsumer_test.cpp +++ b/libs/gui/tests/CpuConsumer_test.cpp @@ -33,6 +33,7 @@ #include <utils/Mutex.h> #include <utils/Condition.h> +#include <thread> #include <vector> #define CPU_CONSUMER_TEST_FORMAT_RAW 0 #define CPU_CONSUMER_TEST_FORMAT_Y8 0 @@ -681,6 +682,70 @@ TEST_P(CpuConsumerTest, FromCpuLockMax) { } } +TEST_P(CpuConsumerTest, FromCpuInvalid) { + status_t err = mCC->lockNextBuffer(nullptr); + ASSERT_EQ(BAD_VALUE, err) << "lockNextBuffer did not fail"; + + CpuConsumer::LockedBuffer b; + err = mCC->unlockBuffer(b); + ASSERT_EQ(BAD_VALUE, err) << "unlockBuffer did not fail"; +} + +TEST_P(CpuConsumerTest, FromCpuMultiThread) { + CpuConsumerTestParams params = GetParam(); + ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, params.maxLockedBuffers + 1)); + + for (int i = 0; i < 10; i++) { + std::atomic<int> threadReadyCount(0); + auto lockAndUnlock = [&]() { + threadReadyCount++; + // busy wait + while (threadReadyCount < params.maxLockedBuffers + 1); + + CpuConsumer::LockedBuffer b; + status_t err = mCC->lockNextBuffer(&b); + if (err == NO_ERROR) { + usleep(1000); + err = mCC->unlockBuffer(b); + ASSERT_NO_ERROR(err, "Could not unlock buffer: "); + } else if (err == NOT_ENOUGH_DATA) { + // there are params.maxLockedBuffers+1 threads so one of the + // threads might get this error + } else { + FAIL() << "Could not lock buffer"; + } + }; + + // produce buffers + for (int j = 0; j < params.maxLockedBuffers + 1; j++) { + const int64_t time = 1234L; + uint32_t stride; + ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time, &stride)); + } + + // spawn threads + std::vector<std::thread> threads; + for (int j = 0; j < params.maxLockedBuffers + 1; j++) { + threads.push_back(std::thread(lockAndUnlock)); + } + + // join threads + for (auto& thread : threads) { + thread.join(); + } + + // we produced N+1 buffers, but the threads might only consume N + CpuConsumer::LockedBuffer b; + if (mCC->lockNextBuffer(&b) == NO_ERROR) { + mCC->unlockBuffer(b); + } + + if (HasFatalFailure()) { + break; + } + } +} + CpuConsumerTestParams y8TestSets[] = { { 512, 512, 1, HAL_PIXEL_FORMAT_Y8}, { 512, 512, 3, HAL_PIXEL_FORMAT_Y8}, diff --git a/libs/gui/tests/GLTest.cpp b/libs/gui/tests/GLTest.cpp index 1739d9c7ca..a91552f7fe 100644 --- a/libs/gui/tests/GLTest.cpp +++ b/libs/gui/tests/GLTest.cpp @@ -22,6 +22,8 @@ namespace android { +using Transaction = SurfaceComposerClient::Transaction; + static int abs(int value) { return value > 0 ? value : -value; } @@ -68,10 +70,10 @@ void GLTest::SetUp() { ASSERT_TRUE(mSurfaceControl != NULL); ASSERT_TRUE(mSurfaceControl->isValid()); - SurfaceComposerClient::openGlobalTransaction(); - ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF)); - ASSERT_EQ(NO_ERROR, mSurfaceControl->show()); - SurfaceComposerClient::closeGlobalTransaction(); + Transaction t; + ASSERT_EQ(NO_ERROR, t.setLayer(mSurfaceControl, 0x7FFFFFFF) + .show(mSurfaceControl) + .apply()); sp<ANativeWindow> window = mSurfaceControl->getSurface(); mEglSurface = createWindowSurface(mEglDisplay, mGlConfig, window); diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp index dd23bd4cb2..a35cf11174 100644 --- a/libs/gui/tests/IGraphicBufferProducer_test.cpp +++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp @@ -42,6 +42,10 @@ #define TEST_CONTROLLED_BY_APP false #define TEST_PRODUCER_USAGE_BITS (0) +#ifndef USE_BUFFER_HUB_AS_BUFFER_QUEUE +#define USE_BUFFER_HUB_AS_BUFFER_QUEUE 0 +#endif + namespace android { namespace { @@ -66,9 +70,15 @@ namespace { const int QUEUE_BUFFER_INPUT_SCALING_MODE = 0; const int QUEUE_BUFFER_INPUT_TRANSFORM = 0; const sp<Fence> QUEUE_BUFFER_INPUT_FENCE = Fence::NO_FENCE; + + // Enums to control which IGraphicBufferProducer backend to test. + enum IGraphicBufferProducerTestCode { + USE_BUFFER_QUEUE_PRODUCER = 0, + USE_BUFFER_HUB_PRODUCER, + }; }; // namespace anonymous -class IGraphicBufferProducerTest : public ::testing::Test { +class IGraphicBufferProducerTest : public ::testing::TestWithParam<uint32_t> { protected: IGraphicBufferProducerTest() {} @@ -81,10 +91,27 @@ protected: mDC = new DummyConsumer; - BufferQueue::createBufferQueue(&mProducer, &mConsumer); + switch (GetParam()) { + case USE_BUFFER_QUEUE_PRODUCER: { + BufferQueue::createBufferQueue(&mProducer, &mConsumer); + break; + } + case USE_BUFFER_HUB_PRODUCER: { + BufferQueue::createBufferHubQueue(&mProducer, &mConsumer); + break; + } + default: { + // Should never reach here. + LOG_ALWAYS_FATAL("Invalid test params: %u", GetParam()); + break; + } + } // Test check: Can't connect producer if no consumer yet - ASSERT_EQ(NO_INIT, TryConnectProducer()); + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/73267953): Make BufferHub honor producer and consumer connection. + ASSERT_EQ(NO_INIT, TryConnectProducer()); + } // Must connect consumer before producer connects will succeed. ASSERT_OK(mConsumer->consumerConnect(mDC, /*controlledByApp*/false)); @@ -229,7 +256,7 @@ protected: // accessible from test body sp<IGraphicBufferConsumer> mConsumer; }; -TEST_F(IGraphicBufferProducerTest, ConnectFirst_ReturnsError) { +TEST_P(IGraphicBufferProducerTest, ConnectFirst_ReturnsError) { IGraphicBufferProducer::QueueBufferOutput output; // NULL output returns BAD_VALUE @@ -247,7 +274,7 @@ TEST_F(IGraphicBufferProducerTest, ConnectFirst_ReturnsError) { // TODO: get a token from a dead process somehow } -TEST_F(IGraphicBufferProducerTest, ConnectAgain_ReturnsError) { +TEST_P(IGraphicBufferProducerTest, ConnectAgain_ReturnsError) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); // Can't connect when there is already a producer connected @@ -259,20 +286,23 @@ TEST_F(IGraphicBufferProducerTest, ConnectAgain_ReturnsError) { ASSERT_OK(mConsumer->consumerDisconnect()); // Can't connect when IGBP is abandoned - EXPECT_EQ(NO_INIT, mProducer->connect(TEST_TOKEN, - TEST_API, - TEST_CONTROLLED_BY_APP, - &output)); + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/73267953): Make BufferHub honor producer and consumer connection. + EXPECT_EQ(NO_INIT, mProducer->connect(TEST_TOKEN, + TEST_API, + TEST_CONTROLLED_BY_APP, + &output)); + } } -TEST_F(IGraphicBufferProducerTest, Disconnect_Succeeds) { +TEST_P(IGraphicBufferProducerTest, Disconnect_Succeeds) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); ASSERT_OK(mProducer->disconnect(TEST_API)); } -TEST_F(IGraphicBufferProducerTest, Disconnect_ReturnsError) { +TEST_P(IGraphicBufferProducerTest, Disconnect_ReturnsError) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); // Must disconnect with same API number @@ -283,7 +313,7 @@ TEST_F(IGraphicBufferProducerTest, Disconnect_ReturnsError) { // TODO: somehow kill mProducer so that this returns DEAD_OBJECT } -TEST_F(IGraphicBufferProducerTest, Query_Succeeds) { +TEST_P(IGraphicBufferProducerTest, Query_Succeeds) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); int32_t value = -1; @@ -308,7 +338,7 @@ TEST_F(IGraphicBufferProducerTest, Query_Succeeds) { } -TEST_F(IGraphicBufferProducerTest, Query_ReturnsError) { +TEST_P(IGraphicBufferProducerTest, Query_ReturnsError) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); // One past the end of the last 'query' enum value. Update this if we add more enums. @@ -334,14 +364,17 @@ TEST_F(IGraphicBufferProducerTest, Query_ReturnsError) { ASSERT_OK(mConsumer->consumerDisconnect()); // BQ was abandoned - EXPECT_EQ(NO_INIT, mProducer->query(NATIVE_WINDOW_FORMAT, &value)); + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/73267953): Make BufferHub honor producer and consumer connection. + EXPECT_EQ(NO_INIT, mProducer->query(NATIVE_WINDOW_FORMAT, &value)); + } // TODO: other things in window.h that are supported by Surface::query // but not by BufferQueue::query } // TODO: queue under more complicated situations not involving just a single buffer -TEST_F(IGraphicBufferProducerTest, Queue_Succeeds) { +TEST_P(IGraphicBufferProducerTest, Queue_Succeeds) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); int dequeuedSlot = -1; @@ -371,16 +404,21 @@ TEST_F(IGraphicBufferProducerTest, Queue_Succeeds) { EXPECT_EQ(DEFAULT_WIDTH, output.width); EXPECT_EQ(DEFAULT_HEIGHT, output.height); EXPECT_EQ(DEFAULT_TRANSFORM_HINT, output.transformHint); + // Since queueBuffer was called exactly once - EXPECT_EQ(1u, output.numPendingBuffers); - EXPECT_EQ(2u, output.nextFrameNumber); + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/70041889): BufferHubProducer need to support metadata: numPendingBuffers + EXPECT_EQ(1u, output.numPendingBuffers); + // TODO(b/70041952): BufferHubProducer need to support metadata: nextFrameNumber + EXPECT_EQ(2u, output.nextFrameNumber); + } } // Buffer was not in the dequeued state EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(dequeuedSlot, input, &output)); } -TEST_F(IGraphicBufferProducerTest, Queue_ReturnsError) { +TEST_P(IGraphicBufferProducerTest, Queue_ReturnsError) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); // Invalid slot number @@ -463,15 +501,16 @@ TEST_F(IGraphicBufferProducerTest, Queue_ReturnsError) { ASSERT_OK(mConsumer->consumerDisconnect()); // The buffer queue has been abandoned. - { + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); IGraphicBufferProducer::QueueBufferOutput output; + // TODO(b/73267953): Make BufferHub honor producer and consumer connection. EXPECT_EQ(NO_INIT, mProducer->queueBuffer(dequeuedSlot, input, &output)); } } -TEST_F(IGraphicBufferProducerTest, CancelBuffer_DoesntCrash) { +TEST_P(IGraphicBufferProducerTest, CancelBuffer_DoesntCrash) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); int dequeuedSlot = -1; @@ -488,7 +527,7 @@ TEST_F(IGraphicBufferProducerTest, CancelBuffer_DoesntCrash) { mProducer->cancelBuffer(dequeuedSlot, dequeuedFence); } -TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Succeeds) { +TEST_P(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Succeeds) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); int minUndequeuedBuffers; ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, @@ -540,7 +579,7 @@ TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Succeeds) { ASSERT_OK(mProducer->setMaxDequeuedBufferCount(maxBuffers-1)); } -TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Fails) { +TEST_P(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Fails) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); int minUndequeuedBuffers; ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, @@ -578,12 +617,19 @@ TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Fails) { ASSERT_OK(mConsumer->consumerDisconnect()); // Fail because the buffer queue was abandoned - EXPECT_EQ(NO_INIT, mProducer->setMaxDequeuedBufferCount(minBuffers)) - << "bufferCount: " << minBuffers; - + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/73267953): Make BufferHub honor producer and consumer connection. + EXPECT_EQ(NO_INIT, mProducer->setMaxDequeuedBufferCount(minBuffers)) + << "bufferCount: " << minBuffers; + } } -TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Succeeds) { +TEST_P(IGraphicBufferProducerTest, SetAsyncMode_Succeeds) { + if (GetParam() == USE_BUFFER_HUB_PRODUCER) { + // TODO(b/36724099): Add support for BufferHubProducer::setAsyncMode(true) + return; + } + ASSERT_OK(mConsumer->setMaxAcquiredBufferCount(1)) << "maxAcquire: " << 1; ASSERT_NO_FATAL_FAILURE(ConnectProducer()); ASSERT_OK(mProducer->setAsyncMode(true)) << "async mode: " << true; @@ -609,7 +655,7 @@ TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Succeeds) { } } -TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Fails) { +TEST_P(IGraphicBufferProducerTest, SetAsyncMode_Fails) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); // Prerequisite to fail out a valid setBufferCount call { @@ -628,11 +674,13 @@ TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Fails) { ASSERT_OK(mConsumer->consumerDisconnect()); // Fail because the buffer queue was abandoned - EXPECT_EQ(NO_INIT, mProducer->setAsyncMode(false)) << "asyncMode: " - << false; + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/36724099): Make BufferHub honor producer and consumer connection. + EXPECT_EQ(NO_INIT, mProducer->setAsyncMode(false)) << "asyncMode: " << false; + } } -TEST_F(IGraphicBufferProducerTest, +TEST_P(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_dequeueBuffer) { int slot = -1; sp<Fence> fence; @@ -642,15 +690,18 @@ TEST_F(IGraphicBufferProducerTest, TEST_PRODUCER_USAGE_BITS, nullptr, nullptr)); } -TEST_F(IGraphicBufferProducerTest, +TEST_P(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_detachNextBuffer) { sp<Fence> fence; sp<GraphicBuffer> buffer; - ASSERT_EQ(NO_INIT, mProducer->detachNextBuffer(&buffer, &fence)); + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/38137191): Implement BufferHubProducer::detachBuffer + ASSERT_EQ(NO_INIT, mProducer->detachNextBuffer(&buffer, &fence)); + } } -TEST_F(IGraphicBufferProducerTest, +TEST_P(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_requestBuffer) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); @@ -674,7 +725,7 @@ TEST_F(IGraphicBufferProducerTest, } -TEST_F(IGraphicBufferProducerTest, +TEST_P(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_detachBuffer) { int slot = -1; sp<Fence> fence; @@ -684,10 +735,13 @@ TEST_F(IGraphicBufferProducerTest, ASSERT_OK(mProducer->disconnect(TEST_API)); - ASSERT_EQ(NO_INIT, mProducer->detachBuffer(slot)); + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/38137191): Implement BufferHubProducer::detachBuffer + ASSERT_EQ(NO_INIT, mProducer->detachBuffer(slot)); + } } -TEST_F(IGraphicBufferProducerTest, +TEST_P(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_queueBuffer) { int slot = -1; sp<Fence> fence; @@ -704,7 +758,7 @@ TEST_F(IGraphicBufferProducerTest, ASSERT_EQ(NO_INIT, mProducer->queueBuffer(slot, input, &output)); } -TEST_F(IGraphicBufferProducerTest, +TEST_P(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_cancelBuffer) { int slot = -1; sp<Fence> fence; @@ -717,7 +771,7 @@ TEST_F(IGraphicBufferProducerTest, ASSERT_EQ(NO_INIT, mProducer->cancelBuffer(slot, fence)); } -TEST_F(IGraphicBufferProducerTest, +TEST_P(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_attachBuffer) { int slot = -1; sp<Fence> fence; @@ -725,11 +779,27 @@ TEST_F(IGraphicBufferProducerTest, setupDequeueRequestBuffer(&slot, &fence, &buffer); - ASSERT_OK(mProducer->detachBuffer(slot)); + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/38137191): Implement BufferHubProducer::detachBuffer + ASSERT_OK(mProducer->detachBuffer(slot)); + } ASSERT_OK(mProducer->disconnect(TEST_API)); - ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer)); + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/69981968): Implement BufferHubProducer::attachBuffer + ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer)); + } } +#if USE_BUFFER_HUB_AS_BUFFER_QUEUE +INSTANTIATE_TEST_CASE_P(IGraphicBufferProducerBackends, IGraphicBufferProducerTest, + ::testing::Values(USE_BUFFER_QUEUE_PRODUCER, USE_BUFFER_HUB_PRODUCER)); +#else +// TODO(b/70046255): Remove the #ifdef here and always tests both backends once BufferHubQueue can +// pass all existing libgui tests. +INSTANTIATE_TEST_CASE_P(IGraphicBufferProducerBackends, IGraphicBufferProducerTest, + ::testing::Values(USE_BUFFER_QUEUE_PRODUCER)); +#endif + } // namespace android diff --git a/libs/gui/tests/SurfaceParcelable_test.cpp b/libs/gui/tests/SurfaceParcelable_test.cpp new file mode 100644 index 0000000000..686dc82f3e --- /dev/null +++ b/libs/gui/tests/SurfaceParcelable_test.cpp @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2018 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 "SurfaceParcelable_test" + +#include <gtest/gtest.h> + +#include <binder/IServiceManager.h> +#include <binder/ProcessState.h> +#include <gui/BufferHubProducer.h> +#include <gui/BufferQueue.h> +#include <gui/view/Surface.h> +#include <utils/Log.h> + +namespace android { + +static const String16 kTestServiceName = String16("SurfaceParcelableTestService"); +static const String16 kSurfaceName = String16("TEST_SURFACE"); +static const uint32_t kBufferWidth = 100; +static const uint32_t kBufferHeight = 1; +static const uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB; + +enum SurfaceParcelableTestServiceCode { + CREATE_BUFFER_QUEUE_SURFACE = IBinder::FIRST_CALL_TRANSACTION, + CREATE_BUFFER_HUB_SURFACE, +}; + +class SurfaceParcelableTestService : public BBinder { +public: + SurfaceParcelableTestService() { + // BufferQueue + BufferQueue::createBufferQueue(&mBufferQueueProducer, &mBufferQueueConsumer); + + // BufferHub + dvr::ProducerQueueConfigBuilder configBuilder; + mProducerQueue = dvr::ProducerQueue::Create(configBuilder.SetDefaultWidth(kBufferWidth) + .SetDefaultHeight(kBufferHeight) + .SetDefaultFormat(kBufferFormat) + .Build(), + dvr::UsagePolicy{}); + mBufferHubProducer = BufferHubProducer::Create(mProducerQueue); + } + + ~SurfaceParcelableTestService() = default; + + virtual status_t onTransact(uint32_t code, const Parcel& /*data*/, Parcel* reply, + uint32_t /*flags*/ = 0) { + switch (code) { + case CREATE_BUFFER_QUEUE_SURFACE: { + view::Surface surfaceShim; + surfaceShim.name = kSurfaceName; + surfaceShim.graphicBufferProducer = mBufferQueueProducer; + return surfaceShim.writeToParcel(reply); + } + case CREATE_BUFFER_HUB_SURFACE: { + view::Surface surfaceShim; + surfaceShim.name = kSurfaceName; + surfaceShim.graphicBufferProducer = mBufferHubProducer; + return surfaceShim.writeToParcel(reply); + } + default: + return UNKNOWN_TRANSACTION; + }; + } + +protected: + sp<IGraphicBufferProducer> mBufferQueueProducer; + sp<IGraphicBufferConsumer> mBufferQueueConsumer; + + std::shared_ptr<dvr::ProducerQueue> mProducerQueue; + sp<IGraphicBufferProducer> mBufferHubProducer; +}; + +static int runBinderServer() { + ProcessState::self()->startThreadPool(); + + sp<IServiceManager> sm = defaultServiceManager(); + sp<SurfaceParcelableTestService> service = new SurfaceParcelableTestService; + sm->addService(kTestServiceName, service, false); + + ALOGI("Binder server running..."); + + while (true) { + int stat, retval; + retval = wait(&stat); + if (retval == -1 && errno == ECHILD) { + break; + } + } + + ALOGI("Binder server exiting..."); + return 0; +} + +class SurfaceParcelableTest : public ::testing::TestWithParam<uint32_t> { +protected: + virtual void SetUp() { + mService = defaultServiceManager()->getService(kTestServiceName); + if (mService == nullptr) { + ALOGE("Failed to connect to the test service."); + return; + } + + ALOGI("Binder service is ready for client."); + } + + status_t GetSurface(view::Surface* surfaceShim) { + ALOGI("...Test: %d", GetParam()); + + uint32_t opCode = GetParam(); + Parcel data; + Parcel reply; + status_t error = mService->transact(opCode, data, &reply); + if (error != NO_ERROR) { + ALOGE("Failed to get surface over binder, error=%d.", error); + return error; + } + + error = surfaceShim->readFromParcel(&reply); + if (error != NO_ERROR) { + ALOGE("Failed to get surface from parcel, error=%d.", error); + return error; + } + + return NO_ERROR; + } + +private: + sp<IBinder> mService; +}; + +TEST_P(SurfaceParcelableTest, SendOverBinder) { + view::Surface surfaceShim; + EXPECT_EQ(GetSurface(&surfaceShim), NO_ERROR); + EXPECT_EQ(surfaceShim.name, kSurfaceName); + EXPECT_FALSE(surfaceShim.graphicBufferProducer == nullptr); +} + +INSTANTIATE_TEST_CASE_P(SurfaceBackends, SurfaceParcelableTest, + ::testing::Values(CREATE_BUFFER_QUEUE_SURFACE, CREATE_BUFFER_HUB_SURFACE)); + +} // namespace android + +int main(int argc, char** argv) { + pid_t pid = fork(); + if (pid == 0) { + android::ProcessState::self()->startThreadPool(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); + + } else { + ALOGI("Test process pid: %d.", pid); + return android::runBinderServer(); + } +} diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index ca43c68f92..2c02ba657d 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -22,6 +22,7 @@ #include <binder/ProcessState.h> #include <configstore/Utils.h> #include <cutils/properties.h> +#include <inttypes.h> #include <gui/BufferItemConsumer.h> #include <gui/IDisplayEventConnection.h> #include <gui/IProducerListener.h> @@ -41,10 +42,16 @@ using namespace std::chrono_literals; // retrieve wide-color and hdr settings from configstore using namespace android::hardware::configstore; using namespace android::hardware::configstore::V1_0; +using ui::ColorMode; + +using Transaction = SurfaceComposerClient::Transaction; static bool hasWideColorDisplay = getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false); +static bool hasHdrDisplay = + getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(false); + class FakeSurfaceComposer; class FakeProducerFrameEventHistory; @@ -52,7 +59,6 @@ static constexpr uint64_t NO_FRAME_INDEX = std::numeric_limits<uint64_t>::max(); class SurfaceTest : public ::testing::Test { protected: - SurfaceTest() { ProcessState::self()->startThreadPool(); } @@ -69,10 +75,10 @@ protected: ASSERT_TRUE(mSurfaceControl != NULL); ASSERT_TRUE(mSurfaceControl->isValid()); - SurfaceComposerClient::openGlobalTransaction(); - ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7fffffff)); - ASSERT_EQ(NO_ERROR, mSurfaceControl->show()); - SurfaceComposerClient::closeGlobalTransaction(); + Transaction t; + ASSERT_EQ(NO_ERROR, t.setLayer(mSurfaceControl, 0x7fffffff) + .show(mSurfaceControl) + .apply()); mSurface = mSurfaceControl->getSurface(); ASSERT_TRUE(mSurface != NULL); @@ -87,6 +93,16 @@ protected: sp<SurfaceControl> mSurfaceControl; }; +TEST_F(SurfaceTest, CreateSurfaceReturnsErrorBadClient) { + mComposerClient->dispose(); + ASSERT_EQ(NO_INIT, mComposerClient->initCheck()); + + sp<SurfaceControl> sc; + status_t err = mComposerClient->createSurfaceChecked( + String8("Test Surface"), 32, 32, PIXEL_FORMAT_RGBA_8888, &sc, 0); + ASSERT_EQ(NO_INIT, err); +} + TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenVisible) { sp<ANativeWindow> anw(mSurface); int result = -123; @@ -114,14 +130,11 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { sp<ANativeWindow> anw(mSurface); // Verify the screenshot works with no protected buffers. - sp<IGraphicBufferProducer> producer; - sp<IGraphicBufferConsumer> consumer; - BufferQueue::createBufferQueue(&producer, &consumer); - sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1); sp<ISurfaceComposer> sf(ComposerService::getComposerService()); sp<IBinder> display(sf->getBuiltInDisplay( ISurfaceComposer::eDisplayIdMain)); - ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(), + sp<GraphicBuffer> outBuffer; + ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &outBuffer, Rect(), 64, 64, 0, 0x7fffffff, false)); ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(), @@ -152,7 +165,7 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { &buf)); ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1)); } - ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(), + ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &outBuffer, Rect(), 64, 64, 0, 0x7fffffff, false)); } @@ -295,6 +308,68 @@ TEST_F(SurfaceTest, GetWideColorSupport) { ASSERT_EQ(hasWideColorDisplay, supported); } +TEST_F(SurfaceTest, GetHdrSupport) { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp<DummyConsumer> dummyConsumer(new DummyConsumer); + consumer->consumerConnect(dummyConsumer, false); + consumer->setConsumerName(String8("TestConsumer")); + + sp<Surface> surface = new Surface(producer); + sp<ANativeWindow> window(surface); + native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU); + + bool supported; + status_t result = surface->getHdrSupport(&supported); + ASSERT_EQ(NO_ERROR, result); + + // NOTE: This is not a CTS test. + // This test verifies that when the BoardConfig TARGET_HAS_HDR_DISPLAY + // is TRUE, getHdrSupport is also true. + // TODO: Add check for an HDR color mode on the primary display. + ASSERT_EQ(hasHdrDisplay, supported); +} + +TEST_F(SurfaceTest, SetHdrMetadata) { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp<DummyConsumer> dummyConsumer(new DummyConsumer); + consumer->consumerConnect(dummyConsumer, false); + consumer->setConsumerName(String8("TestConsumer")); + + sp<Surface> surface = new Surface(producer); + sp<ANativeWindow> window(surface); + native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU); + + bool supported; + status_t result = surface->getHdrSupport(&supported); + ASSERT_EQ(NO_ERROR, result); + + if (!hasHdrDisplay || !supported) { + return; + } + const android_smpte2086_metadata smpte2086 = { + {0.680, 0.320}, + {0.265, 0.690}, + {0.150, 0.060}, + {0.3127, 0.3290}, + 100.0, + 0.1, + }; + const android_cta861_3_metadata cta861_3 = { + 78.0, + 62.0, + }; + int error = native_window_set_buffers_smpte2086_metadata(window.get(), &smpte2086); + ASSERT_EQ(error, NO_ERROR); + error = native_window_set_buffers_cta861_3_metadata(window.get(), &cta861_3); + ASSERT_EQ(error, NO_ERROR); +} + TEST_F(SurfaceTest, DynamicSetBufferCount) { sp<IGraphicBufferProducer> producer; sp<IGraphicBufferConsumer> consumer; @@ -512,21 +587,26 @@ public: return NO_ERROR; } status_t getDisplayColorModes(const sp<IBinder>& /*display*/, - Vector<android_color_mode_t>* /*outColorModes*/) override { + Vector<ColorMode>* /*outColorModes*/) override { return NO_ERROR; } - android_color_mode_t getActiveColorMode(const sp<IBinder>& /*display*/) + ColorMode getActiveColorMode(const sp<IBinder>& /*display*/) override { - return HAL_COLOR_MODE_NATIVE; + return ColorMode::NATIVE; } status_t setActiveColorMode(const sp<IBinder>& /*display*/, - android_color_mode_t /*colorMode*/) override { return NO_ERROR; } + ColorMode /*colorMode*/) override { return NO_ERROR; } status_t captureScreen(const sp<IBinder>& /*display*/, - const sp<IGraphicBufferProducer>& /*producer*/, + sp<GraphicBuffer>* /*outBuffer*/, Rect /*sourceCrop*/, uint32_t /*reqWidth*/, uint32_t /*reqHeight*/, int32_t /*minLayerZ*/, int32_t /*maxLayerZ*/, bool /*useIdentityTransform*/, Rotation /*rotation*/) override { return NO_ERROR; } + virtual status_t captureLayers(const sp<IBinder>& /*parentHandle*/, + sp<GraphicBuffer>* /*outBuffer*/, const Rect& /*sourceCrop*/, + float /*frameScale*/, bool /*childrenOnly*/) override { + return NO_ERROR; + } status_t clearAnimationFrameStats() override { return NO_ERROR; } status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override { return NO_ERROR; @@ -800,7 +880,7 @@ protected: (iOldFrame == NO_FRAME_INDEX) ? nullptr : &mFrames[iOldFrame]; FrameEvents* newFrame = &mFrames[iNewFrame]; - uint64_t nOldFrame = iOldFrame + 1; + uint64_t nOldFrame = (iOldFrame == NO_FRAME_INDEX) ? 0 : iOldFrame + 1; uint64_t nNewFrame = iNewFrame + 1; // Latch, Composite, and Release the frames in a plausible order. diff --git a/libs/gui/view/Surface.cpp b/libs/gui/view/Surface.cpp index 5ed3d3bebb..d64dfd55be 100644 --- a/libs/gui/view/Surface.cpp +++ b/libs/gui/view/Surface.cpp @@ -45,10 +45,7 @@ status_t Surface::writeToParcel(Parcel* parcel, bool nameAlreadyWritten) const { if (res != OK) return res; } - res = parcel->writeStrongBinder( - IGraphicBufferProducer::asBinder(graphicBufferProducer)); - - return res; + return IGraphicBufferProducer::exportToParcel(graphicBufferProducer, parcel); } status_t Surface::readFromParcel(const Parcel* parcel) { @@ -70,16 +67,7 @@ status_t Surface::readFromParcel(const Parcel* parcel, bool nameAlreadyRead) { } } - sp<IBinder> binder; - - res = parcel->readNullableStrongBinder(&binder); - if (res != OK) { - ALOGE("%s: Can't read strong binder", __FUNCTION__); - return res; - } - - graphicBufferProducer = interface_cast<IGraphicBufferProducer>(binder); - + graphicBufferProducer = IGraphicBufferProducer::createFromParcel(parcel); return OK; } diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 905d336bfe..aa0bf17ca3 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -99,34 +99,34 @@ size_t InputMessage::size() const { // --- InputChannel --- -InputChannel::InputChannel(const String8& name, int fd) : +InputChannel::InputChannel(const std::string& name, int fd) : mName(name), mFd(fd) { #if DEBUG_CHANNEL_LIFECYCLE ALOGD("Input channel constructed: name='%s', fd=%d", - mName.string(), fd); + mName.c_str(), fd); #endif int result = fcntl(mFd, F_SETFL, O_NONBLOCK); LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket " - "non-blocking. errno=%d", mName.string(), errno); + "non-blocking. errno=%d", mName.c_str(), errno); } InputChannel::~InputChannel() { #if DEBUG_CHANNEL_LIFECYCLE ALOGD("Input channel destroyed: name='%s', fd=%d", - mName.string(), mFd); + mName.c_str(), mFd); #endif ::close(mFd); } -status_t InputChannel::openInputChannelPair(const String8& name, +status_t InputChannel::openInputChannelPair(const std::string& name, sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) { int sockets[2]; if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) { status_t result = -errno; ALOGE("channel '%s' ~ Could not create socket pair. errno=%d", - name.string(), errno); + name.c_str(), errno); outServerChannel.clear(); outClientChannel.clear(); return result; @@ -138,12 +138,12 @@ status_t InputChannel::openInputChannelPair(const String8& name, setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)); setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)); - String8 serverChannelName = name; - serverChannelName.append(" (server)"); + std::string serverChannelName = name; + serverChannelName += " (server)"; outServerChannel = new InputChannel(serverChannelName, sockets[0]); - String8 clientChannelName = name; - clientChannelName.append(" (client)"); + std::string clientChannelName = name; + clientChannelName += " (client)"; outClientChannel = new InputChannel(clientChannelName, sockets[1]); return OK; } @@ -158,7 +158,7 @@ status_t InputChannel::sendMessage(const InputMessage* msg) { if (nWrite < 0) { int error = errno; #if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.string(), + ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.c_str(), msg->header.type, error); #endif if (error == EAGAIN || error == EWOULDBLOCK) { @@ -173,13 +173,13 @@ status_t InputChannel::sendMessage(const InputMessage* msg) { if (size_t(nWrite) != msgLength) { #if DEBUG_CHANNEL_MESSAGES ALOGD("channel '%s' ~ error sending message type %d, send was incomplete", - mName.string(), msg->header.type); + mName.c_str(), msg->header.type); #endif return DEAD_OBJECT; } #if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ sent message of type %d", mName.string(), msg->header.type); + ALOGD("channel '%s' ~ sent message of type %d", mName.c_str(), msg->header.type); #endif return OK; } @@ -193,7 +193,7 @@ status_t InputChannel::receiveMessage(InputMessage* msg) { if (nRead < 0) { int error = errno; #if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.string(), errno); + ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.c_str(), errno); #endif if (error == EAGAIN || error == EWOULDBLOCK) { return WOULD_BLOCK; @@ -206,20 +206,20 @@ status_t InputChannel::receiveMessage(InputMessage* msg) { if (nRead == 0) { // check for EOF #if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.string()); + ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.c_str()); #endif return DEAD_OBJECT; } if (!msg->isValid(nRead)) { #if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ received invalid message", mName.string()); + ALOGD("channel '%s' ~ received invalid message", mName.c_str()); #endif return BAD_VALUE; } #if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ received message of type %d", mName.string(), msg->header.type); + ALOGD("channel '%s' ~ received message of type %d", mName.c_str(), msg->header.type); #endif return OK; } @@ -254,8 +254,8 @@ status_t InputPublisher::publishKeyEvent( #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, " "action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d," - "downTime=%lld, eventTime=%lld", - mChannel->getName().string(), seq, + "downTime=%" PRId64 ", eventTime=%" PRId64, + mChannel->getName().c_str(), seq, deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount, downTime, eventTime); #endif @@ -305,9 +305,9 @@ status_t InputPublisher::publishMotionEvent( ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, " "action=0x%x, actionButton=0x%08x, flags=0x%x, edgeFlags=0x%x, " "metaState=0x%x, buttonState=0x%x, xOffset=%f, yOffset=%f, " - "xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, " + "xPrecision=%f, yPrecision=%f, downTime=%" PRId64 ", eventTime=%" PRId64 ", " "pointerCount=%" PRIu32, - mChannel->getName().string(), seq, + mChannel->getName().c_str(), seq, deviceId, source, action, actionButton, flags, edgeFlags, metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount); #endif @@ -319,7 +319,7 @@ status_t InputPublisher::publishMotionEvent( if (pointerCount > MAX_POINTERS || pointerCount < 1) { ALOGE("channel '%s' publisher ~ Invalid number of pointers provided: %" PRIu32 ".", - mChannel->getName().string(), pointerCount); + mChannel->getName().c_str(), pointerCount); return BAD_VALUE; } @@ -352,7 +352,7 @@ status_t InputPublisher::publishMotionEvent( status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) { #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' publisher ~ receiveFinishedSignal", - mChannel->getName().string()); + mChannel->getName().c_str()); #endif InputMessage msg; @@ -364,7 +364,7 @@ status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandle } if (msg.header.type != InputMessage::TYPE_FINISHED) { ALOGE("channel '%s' publisher ~ Received unexpected message of type %d from consumer", - mChannel->getName().string(), msg.header.type); + mChannel->getName().c_str(), msg.header.type); return UNKNOWN_ERROR; } *outSeq = msg.body.finished.seq; @@ -401,8 +401,8 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId) { #if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%lld", - mChannel->getName().string(), consumeBatches ? "true" : "false", frameTime); + ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%" PRId64, + mChannel->getName().c_str(), consumeBatches ? "true" : "false", frameTime); #endif *outSeq = 0; @@ -426,7 +426,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, if (*outEvent) { #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u", - mChannel->getName().string(), *outSeq); + mChannel->getName().c_str(), *outSeq); #endif break; } @@ -445,7 +445,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, *outEvent = keyEvent; #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ consumed key event, seq=%u", - mChannel->getName().string(), *outSeq); + mChannel->getName().c_str(), *outSeq); #endif break; } @@ -458,7 +458,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, batch.samples.push(mMsg); #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ appended to batch event", - mChannel->getName().string()); + mChannel->getName().c_str()); #endif break; } else { @@ -474,7 +474,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ consumed batch event and " "deferred current event, seq=%u", - mChannel->getName().string(), *outSeq); + mChannel->getName().c_str(), *outSeq); #endif break; } @@ -488,7 +488,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, batch.samples.push(mMsg); #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ started batch event", - mChannel->getName().string()); + mChannel->getName().c_str()); #endif break; } @@ -503,14 +503,14 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, *displayId = mMsg.body.motion.displayId; #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u", - mChannel->getName().string(), *outSeq); + mChannel->getName().c_str(), *outSeq); #endif break; } default: ALOGE("channel '%s' consumer ~ Received unexpected message of type %d", - mChannel->getName().string(), mMsg.header.type); + mChannel->getName().c_str(), mMsg.header.type); return UNKNOWN_ERROR; } } @@ -841,7 +841,7 @@ bool InputConsumer::shouldResampleTool(int32_t toolType) { status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) { #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ sendFinishedSignal: seq=%u, handled=%s", - mChannel->getName().string(), seq, handled ? "true" : "false"); + mChannel->getName().c_str(), seq, handled ? "true" : "false"); #endif if (!seq) { diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp index 0627ca6d6f..cba1111606 100644 --- a/libs/input/KeyCharacterMap.cpp +++ b/libs/input/KeyCharacterMap.cpp @@ -824,6 +824,9 @@ status_t KeyCharacterMap::Parser::parseType() { } else if (typeToken == "FULL") { type = KEYBOARD_TYPE_FULL; } else if (typeToken == "SPECIAL_FUNCTION") { + ALOGW("The SPECIAL_FUNCTION type is now declared in the device's IDC file, please set " + "the property 'keyboard.specialFunction' to '1' there instead."); + // TODO: return BAD_VALUE here in Q type = KEYBOARD_TYPE_SPECIAL_FUNCTION; } else if (typeToken == "OVERLAY") { type = KEYBOARD_TYPE_OVERLAY; diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp index 07f2289785..11842ee7ff 100644 --- a/libs/input/Keyboard.cpp +++ b/libs/input/Keyboard.cpp @@ -148,9 +148,19 @@ String8 KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier, // --- Global functions --- +bool isKeyboardSpecialFunction(const PropertyMap* config) { + if (config == nullptr) { + return false; + } + bool isSpecialFunction = false; + config->tryGetProperty(String8("keyboard.specialFunction"), isSpecialFunction); + return isSpecialFunction; +} + bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier, const PropertyMap* deviceConfiguration, const KeyMap* keyMap) { - if (!keyMap->haveKeyCharacterMap() + // TODO: remove the third OR statement (SPECIAL_FUNCTION) in Q + if (!keyMap->haveKeyCharacterMap() || isKeyboardSpecialFunction(deviceConfiguration) || keyMap->keyCharacterMap->getKeyboardType() == KeyCharacterMap::KEYBOARD_TYPE_SPECIAL_FUNCTION) { return false; diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp index 62acea360e..c07a81245a 100644 --- a/libs/input/VelocityTracker.cpp +++ b/libs/input/VelocityTracker.cpp @@ -75,7 +75,9 @@ static std::string vectorToString(const float* a, uint32_t m) { str += " ]"; return str; } +#endif +#if DEBUG_STRATEGY static std::string matrixToString(const float* a, uint32_t m, uint32_t n, bool rowMajor) { std::string str; str = "["; @@ -141,6 +143,11 @@ bool VelocityTracker::configureStrategy(const char* strategy) { } VelocityTrackerStrategy* VelocityTracker::createStrategy(const char* strategy) { + if (!strcmp("impulse", strategy)) { + // Physical model of pushing an object. Quality: VERY GOOD. + // Works with duplicate coordinates, unclean finger liftoff. + return new ImpulseVelocityTrackerStrategy(); + } if (!strcmp("lsq1", strategy)) { // 1st order least squares. Quality: POOR. // Frequently underfits the touch data especially when the finger accelerates @@ -318,8 +325,8 @@ void VelocityTracker::addMovement(const MotionEvent* event) { eventTime = event->getHistoricalEventTime(h); for (size_t i = 0; i < pointerCount; i++) { uint32_t index = pointerIndex[i]; - positions[index].x = event->getHistoricalX(i, h); - positions[index].y = event->getHistoricalY(i, h); + positions[index].x = event->getHistoricalRawX(i, h); + positions[index].y = event->getHistoricalRawY(i, h); } addMovement(eventTime, idBits, positions); } @@ -327,8 +334,8 @@ void VelocityTracker::addMovement(const MotionEvent* event) { eventTime = event->getEventTime(); for (size_t i = 0; i < pointerCount; i++) { uint32_t index = pointerIndex[i]; - positions[index].x = event->getX(i); - positions[index].y = event->getY(i); + positions[index].x = event->getRawX(i); + positions[index].y = event->getRawY(i); } addMovement(eventTime, idBits, positions); } @@ -352,9 +359,6 @@ bool VelocityTracker::getEstimator(uint32_t id, Estimator* outEstimator) const { // --- LeastSquaresVelocityTrackerStrategy --- -const nsecs_t LeastSquaresVelocityTrackerStrategy::HORIZON; -const uint32_t LeastSquaresVelocityTrackerStrategy::HISTORY_SIZE; - LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy( uint32_t degree, Weighting weighting) : mDegree(degree), mWeighting(weighting) { @@ -863,10 +867,6 @@ void IntegratingVelocityTrackerStrategy::populateEstimator(const State& state, // --- LegacyVelocityTrackerStrategy --- -const nsecs_t LegacyVelocityTrackerStrategy::HORIZON; -const uint32_t LegacyVelocityTrackerStrategy::HISTORY_SIZE; -const nsecs_t LegacyVelocityTrackerStrategy::MIN_DURATION; - LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() { clear(); } @@ -979,4 +979,194 @@ bool LegacyVelocityTrackerStrategy::getEstimator(uint32_t id, return true; } +// --- ImpulseVelocityTrackerStrategy --- + +ImpulseVelocityTrackerStrategy::ImpulseVelocityTrackerStrategy() { + clear(); +} + +ImpulseVelocityTrackerStrategy::~ImpulseVelocityTrackerStrategy() { +} + +void ImpulseVelocityTrackerStrategy::clear() { + mIndex = 0; + mMovements[0].idBits.clear(); +} + +void ImpulseVelocityTrackerStrategy::clearPointers(BitSet32 idBits) { + BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value); + mMovements[mIndex].idBits = remainingIdBits; +} + +void ImpulseVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits, + const VelocityTracker::Position* positions) { + if (++mIndex == HISTORY_SIZE) { + mIndex = 0; + } + + Movement& movement = mMovements[mIndex]; + movement.eventTime = eventTime; + movement.idBits = idBits; + uint32_t count = idBits.count(); + for (uint32_t i = 0; i < count; i++) { + movement.positions[i] = positions[i]; + } +} + +/** + * Calculate the total impulse provided to the screen and the resulting velocity. + * + * The touchscreen is modeled as a physical object. + * Initial condition is discussed below, but for now suppose that v(t=0) = 0 + * + * The kinetic energy of the object at the release is E=0.5*m*v^2 + * Then vfinal = sqrt(2E/m). The goal is to calculate E. + * + * The kinetic energy at the release is equal to the total work done on the object by the finger. + * The total work W is the sum of all dW along the path. + * + * dW = F*dx, where dx is the piece of path traveled. + * Force is change of momentum over time, F = dp/dt = m dv/dt. + * Then substituting: + * dW = m (dv/dt) * dx = m * v * dv + * + * Summing along the path, we get: + * W = sum(dW) = sum(m * v * dv) = m * sum(v * dv) + * Since the mass stays constant, the equation for final velocity is: + * vfinal = sqrt(2*sum(v * dv)) + * + * Here, + * dv : change of velocity = (v[i+1]-v[i]) + * dx : change of distance = (x[i+1]-x[i]) + * dt : change of time = (t[i+1]-t[i]) + * v : instantaneous velocity = dx/dt + * + * The final formula is: + * vfinal = sqrt(2) * sqrt(sum((v[i]-v[i-1])*|v[i]|)) for all i + * The absolute value is needed to properly account for the sign. If the velocity over a + * particular segment descreases, then this indicates braking, which means that negative + * work was done. So for two positive, but decreasing, velocities, this contribution would be + * negative and will cause a smaller final velocity. + * + * Initial condition + * There are two ways to deal with initial condition: + * 1) Assume that v(0) = 0, which would mean that the screen is initially at rest. + * This is not entirely accurate. We are only taking the past X ms of touch data, where X is + * currently equal to 100. However, a touch event that created a fling probably lasted for longer + * than that, which would mean that the user has already been interacting with the touchscreen + * and it has probably already been moving. + * 2) Assume that the touchscreen has already been moving at a certain velocity, calculate this + * initial velocity and the equivalent energy, and start with this initial energy. + * Consider an example where we have the following data, consisting of 3 points: + * time: t0, t1, t2 + * x : x0, x1, x2 + * v : 0 , v1, v2 + * Here is what will happen in each of these scenarios: + * 1) By directly applying the formula above with the v(0) = 0 boundary condition, we will get + * vfinal = sqrt(2*(|v1|*(v1-v0) + |v2|*(v2-v1))). This can be simplified since v0=0 + * vfinal = sqrt(2*(|v1|*v1 + |v2|*(v2-v1))) = sqrt(2*(v1^2 + |v2|*(v2 - v1))) + * since velocity is a real number + * 2) If we treat the screen as already moving, then it must already have an energy (per mass) + * equal to 1/2*v1^2. Then the initial energy should be 1/2*v1*2, and only the second segment + * will contribute to the total kinetic energy (since we can effectively consider that v0=v1). + * This will give the following expression for the final velocity: + * vfinal = sqrt(2*(1/2*v1^2 + |v2|*(v2-v1))) + * This analysis can be generalized to an arbitrary number of samples. + * + * + * Comparing the two equations above, we see that the only mathematical difference + * is the factor of 1/2 in front of the first velocity term. + * This boundary condition would allow for the "proper" calculation of the case when all of the + * samples are equally spaced in time and distance, which should suggest a constant velocity. + * + * Note that approach 2) is sensitive to the proper ordering of the data in time, since + * the boundary condition must be applied to the oldest sample to be accurate. + */ +static float kineticEnergyToVelocity(float work) { + static constexpr float sqrt2 = 1.41421356237; + return (work < 0 ? -1.0 : 1.0) * sqrtf(fabsf(work)) * sqrt2; +} + +static float calculateImpulseVelocity(const nsecs_t* t, const float* x, size_t count) { + // The input should be in reversed time order (most recent sample at index i=0) + // t[i] is in nanoseconds, but due to FP arithmetic, convert to seconds inside this function + static constexpr float SECONDS_PER_NANO = 1E-9; + + if (count < 2) { + return 0; // if 0 or 1 points, velocity is zero + } + if (t[1] > t[0]) { // Algorithm will still work, but not perfectly + ALOGE("Samples provided to calculateImpulseVelocity in the wrong order"); + } + if (count == 2) { // if 2 points, basic linear calculation + if (t[1] == t[0]) { + ALOGE("Events have identical time stamps t=%" PRId64 ", setting velocity = 0", t[0]); + return 0; + } + return (x[1] - x[0]) / (SECONDS_PER_NANO * (t[1] - t[0])); + } + // Guaranteed to have at least 3 points here + float work = 0; + for (size_t i = count - 1; i > 0 ; i--) { // start with the oldest sample and go forward in time + if (t[i] == t[i-1]) { + ALOGE("Events have identical time stamps t=%" PRId64 ", skipping sample", t[i]); + continue; + } + float vprev = kineticEnergyToVelocity(work); // v[i-1] + float vcurr = (x[i] - x[i-1]) / (SECONDS_PER_NANO * (t[i] - t[i-1])); // v[i] + work += (vcurr - vprev) * fabsf(vcurr); + if (i == count - 1) { + work *= 0.5; // initial condition, case 2) above + } + } + return kineticEnergyToVelocity(work); +} + +bool ImpulseVelocityTrackerStrategy::getEstimator(uint32_t id, + VelocityTracker::Estimator* outEstimator) const { + outEstimator->clear(); + + // Iterate over movement samples in reverse time order and collect samples. + float x[HISTORY_SIZE]; + float y[HISTORY_SIZE]; + nsecs_t time[HISTORY_SIZE]; + size_t m = 0; // number of points that will be used for fitting + size_t index = mIndex; + const Movement& newestMovement = mMovements[mIndex]; + do { + const Movement& movement = mMovements[index]; + if (!movement.idBits.hasBit(id)) { + break; + } + + nsecs_t age = newestMovement.eventTime - movement.eventTime; + if (age > HORIZON) { + break; + } + + const VelocityTracker::Position& position = movement.getPosition(id); + x[m] = position.x; + y[m] = position.y; + time[m] = movement.eventTime; + index = (index == 0 ? HISTORY_SIZE : index) - 1; + } while (++m < HISTORY_SIZE); + + if (m == 0) { + return false; // no data + } + outEstimator->xCoeff[0] = 0; + outEstimator->yCoeff[0] = 0; + outEstimator->xCoeff[1] = calculateImpulseVelocity(time, x, m); + outEstimator->yCoeff[1] = calculateImpulseVelocity(time, y, m); + outEstimator->xCoeff[2] = 0; + outEstimator->yCoeff[2] = 0; + outEstimator->time = newestMovement.eventTime; + outEstimator->degree = 2; // similar results to 2nd degree fit + outEstimator->confidence = 1; +#if DEBUG_STRATEGY + ALOGD("velocity: (%f, %f)", outEstimator->xCoeff[1], outEstimator->yCoeff[1]); +#endif + return true; +} + } // namespace android diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp index 8137e3dbf6..aca9521c76 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -6,6 +6,7 @@ cc_test { "InputChannel_test.cpp", "InputEvent_test.cpp", "InputPublisherAndConsumer_test.cpp", + "VelocityTracker_test.cpp", ], cflags: [ "-Wall", @@ -19,6 +20,7 @@ cc_test { "libutils", "libbinder", "libui", + "libbase", ] } diff --git a/libs/input/tests/InputChannel_test.cpp b/libs/input/tests/InputChannel_test.cpp index e71ebe2a1d..96c165cac2 100644 --- a/libs/input/tests/InputChannel_test.cpp +++ b/libs/input/tests/InputChannel_test.cpp @@ -41,9 +41,9 @@ TEST_F(InputChannelTest, ConstructorAndDestructor_TakesOwnershipOfFileDescriptor // of a pipe and to check for EPIPE on the other end after the channel is destroyed. Pipe pipe; - sp<InputChannel> inputChannel = new InputChannel(String8("channel name"), pipe.sendFd); + sp<InputChannel> inputChannel = new InputChannel("channel name", pipe.sendFd); - EXPECT_STREQ("channel name", inputChannel->getName().string()) + EXPECT_STREQ("channel name", inputChannel->getName().c_str()) << "channel should have provided name"; EXPECT_EQ(pipe.sendFd, inputChannel->getFd()) << "channel should have provided fd"; @@ -60,16 +60,16 @@ TEST_F(InputChannelTest, ConstructorAndDestructor_TakesOwnershipOfFileDescriptor TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) { sp<InputChannel> serverChannel, clientChannel; - status_t result = InputChannel::openInputChannelPair(String8("channel name"), + status_t result = InputChannel::openInputChannelPair("channel name", serverChannel, clientChannel); ASSERT_EQ(OK, result) << "should have successfully opened a channel pair"; // Name - EXPECT_STREQ("channel name (server)", serverChannel->getName().string()) + EXPECT_STREQ("channel name (server)", serverChannel->getName().c_str()) << "server channel should have suffixed name"; - EXPECT_STREQ("channel name (client)", clientChannel->getName().string()) + EXPECT_STREQ("channel name (client)", clientChannel->getName().c_str()) << "client channel should have suffixed name"; // Server->Client communication @@ -111,7 +111,7 @@ TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) { TEST_F(InputChannelTest, ReceiveSignal_WhenNoSignalPresent_ReturnsAnError) { sp<InputChannel> serverChannel, clientChannel; - status_t result = InputChannel::openInputChannelPair(String8("channel name"), + status_t result = InputChannel::openInputChannelPair("channel name", serverChannel, clientChannel); ASSERT_EQ(OK, result) @@ -125,7 +125,7 @@ TEST_F(InputChannelTest, ReceiveSignal_WhenNoSignalPresent_ReturnsAnError) { TEST_F(InputChannelTest, ReceiveSignal_WhenPeerClosed_ReturnsAnError) { sp<InputChannel> serverChannel, clientChannel; - status_t result = InputChannel::openInputChannelPair(String8("channel name"), + status_t result = InputChannel::openInputChannelPair("channel name", serverChannel, clientChannel); ASSERT_EQ(OK, result) @@ -141,7 +141,7 @@ TEST_F(InputChannelTest, ReceiveSignal_WhenPeerClosed_ReturnsAnError) { TEST_F(InputChannelTest, SendSignal_WhenPeerClosed_ReturnsAnError) { sp<InputChannel> serverChannel, clientChannel; - status_t result = InputChannel::openInputChannelPair(String8("channel name"), + status_t result = InputChannel::openInputChannelPair("channel name", serverChannel, clientChannel); ASSERT_EQ(OK, result) diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index 34c52d03d1..c5322414fd 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -36,7 +36,7 @@ protected: PreallocatedInputEventFactory mEventFactory; virtual void SetUp() { - status_t result = InputChannel::openInputChannelPair(String8("channel name"), + status_t result = InputChannel::openInputChannelPair("channel name", serverChannel, clientChannel); mPublisher = new InputPublisher(serverChannel); @@ -254,19 +254,36 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_EndToEnd) { ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent()); } +TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenSequenceNumberIsZero_ReturnsError) { + status_t status; + const size_t pointerCount = 1; + PointerProperties pointerProperties[pointerCount]; + PointerCoords pointerCoords[pointerCount]; + for (size_t i = 0; i < pointerCount; i++) { + pointerProperties[i].clear(); + pointerCoords[i].clear(); + } + + status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + pointerCount, pointerProperties, pointerCoords); + ASSERT_EQ(BAD_VALUE, status) + << "publisher publishMotionEvent should return BAD_VALUE"; +} + TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessThan1_ReturnsError) { status_t status; const size_t pointerCount = 0; PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; - status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } -TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreaterThanMax_ReturnsError) { +TEST_F(InputPublisherAndConsumerTest, + PublishMotionEvent_WhenPointerCountGreaterThanMax_ReturnsError) { status_t status; const size_t pointerCount = MAX_POINTERS + 1; PointerProperties pointerProperties[pointerCount]; @@ -276,7 +293,7 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreater pointerCoords[i].clear(); } - status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp new file mode 100644 index 0000000000..43b6012e0d --- /dev/null +++ b/libs/input/tests/VelocityTracker_test.cpp @@ -0,0 +1,664 @@ +/* + * Copyright (C) 2017 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 "VelocityTracker_test" + +#include <math.h> + +#include <android-base/stringprintf.h> +#include <gtest/gtest.h> +#include <input/VelocityTracker.h> + +using android::base::StringPrintf; + +namespace android { + +constexpr int32_t DEFAULT_POINTER_ID = 0; // pointer ID used for manually defined tests + +// velocity must be in the range (1-tol)*EV <= velocity <= (1+tol)*EV +// here EV = expected value, tol = VELOCITY_TOLERANCE +constexpr float VELOCITY_TOLERANCE = 0.2; + +// --- VelocityTrackerTest --- +class VelocityTrackerTest : public testing::Test { }; + +static void checkVelocity(float Vactual, float Vtarget) { + // Compare directions + if ((Vactual > 0 && Vtarget <= 0) || (Vactual < 0 && Vtarget >= 0)) { + FAIL() << StringPrintf("Velocity %f does not have the same direction" + " as the target velocity %f", Vactual, Vtarget); + } + + // Compare magnitudes + const float Vlower = fabsf(Vtarget * (1 - VELOCITY_TOLERANCE)); + const float Vupper = fabsf(Vtarget * (1 + VELOCITY_TOLERANCE)); + if (fabsf(Vactual) < Vlower) { + FAIL() << StringPrintf("Velocity %f is more than %.0f%% below target velocity %f", + Vactual, VELOCITY_TOLERANCE * 100, Vtarget); + } + if (fabsf(Vactual) > Vupper) { + FAIL() << StringPrintf("Velocity %f is more than %.0f%% above target velocity %f", + Vactual, VELOCITY_TOLERANCE * 100, Vtarget); + } + SUCCEED() << StringPrintf("Velocity %f within %.0f%% of target %f)", + Vactual, VELOCITY_TOLERANCE * 100, Vtarget); +} + +void failWithMessage(std::string message) { + FAIL() << message; // cannot do this directly from a non-void function +} + +struct Position { + nsecs_t time; + float x; + float y; +}; + + +MotionEvent* createSimpleMotionEvent(const Position* positions, size_t numSamples) { + /** + * Only populate the basic fields of a MotionEvent, such as time and a single axis + * Designed for use with manually-defined tests. + * Create a new MotionEvent on the heap, caller responsible for destroying the object. + */ + if (numSamples < 1) { + failWithMessage(StringPrintf("Need at least 1 sample to create a MotionEvent." + " Received numSamples=%zu", numSamples)); + } + + MotionEvent* event = new MotionEvent(); + PointerCoords coords; + PointerProperties properties[1]; + + properties[0].id = DEFAULT_POINTER_ID; + properties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + + // First sample added separately with initialize + coords.setAxisValue(AMOTION_EVENT_AXIS_X, positions[0].x); + coords.setAxisValue(AMOTION_EVENT_AXIS_Y, positions[0].y); + event->initialize(0, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, positions[0].time, 1, properties, &coords); + + for (size_t i = 1; i < numSamples; i++) { + coords.setAxisValue(AMOTION_EVENT_AXIS_X, positions[i].x); + coords.setAxisValue(AMOTION_EVENT_AXIS_Y, positions[i].y); + event->addSample(positions[i].time, &coords); + } + return event; +} + +static void computeAndCheckVelocity(const Position* positions, size_t numSamples, + int32_t axis, float targetVelocity) { + VelocityTracker vt(nullptr); + float Vx, Vy; + + MotionEvent* event = createSimpleMotionEvent(positions, numSamples); + vt.addMovement(event); + + vt.getVelocity(DEFAULT_POINTER_ID, &Vx, &Vy); + + switch (axis) { + case AMOTION_EVENT_AXIS_X: + checkVelocity(Vx, targetVelocity); + break; + case AMOTION_EVENT_AXIS_Y: + checkVelocity(Vy, targetVelocity); + break; + default: + FAIL() << "Axis must be either AMOTION_EVENT_AXIS_X or AMOTION_EVENT_AXIS_Y"; + } + delete event; +} + +/* + * ================== VelocityTracker tests generated manually ===================================== + */ + // @todo Currently disabled, enable when switching away from lsq2 VelocityTrackerStrategy +TEST_F(VelocityTrackerTest, DISABLED_ThreePointsPositiveVelocityTest) { + // Same coordinate is reported 2 times in a row + // It is difficult to determine the correct answer here, but at least the direction + // of the reported velocity should be positive. + Position values[] = { + { 0, 273, NAN }, + { 12585000, 293, NAN }, + { 14730000, 293, NAN }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 1600); +} + +TEST_F(VelocityTrackerTest, ThreePointsZeroVelocityTest) { + // Same coordinate is reported 3 times in a row + Position values[] = { + { 0, 293, NAN }, + { 6132000, 293, NAN }, + { 11283000, 293, NAN }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 0); +} + +TEST_F(VelocityTrackerTest, ThreePointsLinearVelocityTest) { + // Fixed velocity at 5 points per 10 milliseconds + Position values[] = { + { 0, 0, NAN }, + { 10000000, 5, NAN }, + { 20000000, 10, NAN }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 500); +} + + +/** + * ================== VelocityTracker tests generated by recording real events ===================== + * + * To add a test, record the input coordinates and event times to all calls + * to void VelocityTracker::addMovement(const MotionEvent* event). + * Also record all calls to VelocityTracker::clear(). + * Finally, record the output of VelocityTracker::getVelocity(...) + * This will give you the necessary data to create a new test. + */ + +// --------------- Recorded by hand on swordfish --------------------------------------------------- +// @todo Currently disabled, enable when switching away from lsq2 VelocityTrackerStrategy +TEST_F(VelocityTrackerTest, DISABLED_SwordfishFlingDown) { + // Recording of a fling on Swordfish that could cause a fling in the wrong direction + Position values[] = { + { 0, 271, 96 }, + { 16071042, 269.786346, 106.922775 }, + { 35648403, 267.983063, 156.660034 }, + { 52313925, 262.638397, 220.339081 }, + { 68976522, 266.138824, 331.581116 }, + { 85639375, 274.79245, 428.113159 }, + { 96948871, 274.79245, 428.113159 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 623.577637); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 8523.348633); +} + +// --------------- Recorded by hand on sailfish, generated by a script ----------------------------- +// For some of these tests, the X-direction velocity checking has been removed, because the lsq2 +// and the impulse VelocityTrackerStrategies did not agree within 20%. +// Since the flings were recorded in the Y-direction, the intentional user action should only +// be relevant for the Y axis. +// There have been also cases where lsq2 and impulse disagreed more than 20% in the Y-direction. +// Those recordings have been discarded because we didn't feel one strategy's interpretation was +// more correct than another's but didn't want to increase the tolerance for the entire test suite. +// +// There are 18 tests total below: 9 in the positive Y direction and 9 in the opposite. +// The recordings were loosely binned into 3 categories - slow, faster, and fast, which roughly +// characterizes the velocity of the finger motion. +// These can be treated approximately as: +// slow - less than 1 page gets scrolled +// faster - more than 1 page gets scrolled, but less than 3 +// fast - entire list is scrolled (fling is done as hard as possible) + +TEST_F(VelocityTrackerTest, SailfishFlingUpSlow1) { + // Sailfish - fling up - slow - 1 + Position values[] = { + { 235089067457000, 528.00, 983.00 }, + { 235089084684000, 527.00, 981.00 }, + { 235089093349000, 527.00, 977.00 }, + { 235089095677625, 527.00, 975.93 }, + { 235089101859000, 527.00, 970.00 }, + { 235089110378000, 528.00, 960.00 }, + { 235089112497111, 528.25, 957.51 }, + { 235089118760000, 531.00, 946.00 }, + { 235089126686000, 535.00, 931.00 }, + { 235089129316820, 536.33, 926.02 }, + { 235089135199000, 540.00, 914.00 }, + { 235089144297000, 546.00, 896.00 }, + { 235089146136443, 547.21, 892.36 }, + { 235089152923000, 553.00, 877.00 }, + { 235089160784000, 559.00, 851.00 }, + { 235089162955851, 560.66, 843.82 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 872.794617); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 951.698181); // lsq2 + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3604.819336); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3044.966064); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingUpSlow2) { + // Sailfish - fling up - slow - 2 + Position values[] = { + { 235110560704000, 522.00, 1107.00 }, + { 235110575764000, 522.00, 1107.00 }, + { 235110584385000, 522.00, 1107.00 }, + { 235110588421179, 521.52, 1106.52 }, + { 235110592830000, 521.00, 1106.00 }, + { 235110601385000, 520.00, 1104.00 }, + { 235110605088160, 519.14, 1102.27 }, + { 235110609952000, 518.00, 1100.00 }, + { 235110618353000, 517.00, 1093.00 }, + { 235110621755146, 516.60, 1090.17 }, + { 235110627010000, 517.00, 1081.00 }, + { 235110634785000, 518.00, 1063.00 }, + { 235110638422450, 518.87, 1052.58 }, + { 235110643161000, 520.00, 1039.00 }, + { 235110651767000, 524.00, 1011.00 }, + { 235110655089581, 525.54, 1000.19 }, + { 235110660368000, 530.00, 980.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -4096.583008); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3455.094238); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingUpSlow3) { + // Sailfish - fling up - slow - 3 + Position values[] = { + { 792536237000, 580.00, 1317.00 }, + { 792541538987, 580.63, 1311.94 }, + { 792544613000, 581.00, 1309.00 }, + { 792552301000, 583.00, 1295.00 }, + { 792558362309, 585.13, 1282.92 }, + { 792560828000, 586.00, 1278.00 }, + { 792569446000, 589.00, 1256.00 }, + { 792575185095, 591.54, 1241.41 }, + { 792578491000, 593.00, 1233.00 }, + { 792587044000, 597.00, 1211.00 }, + { 792592008172, 600.28, 1195.92 }, + { 792594616000, 602.00, 1188.00 }, + { 792603129000, 607.00, 1167.00 }, + { 792608831290, 609.48, 1155.83 }, + { 792612321000, 611.00, 1149.00 }, + { 792620768000, 615.00, 1131.00 }, + { 792625653873, 617.32, 1121.73 }, + { 792629200000, 619.00, 1115.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 574.33429); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 617.40564); // lsq2 + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -2361.982666); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -2500.055664); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingUpFaster1) { + // Sailfish - fling up - faster - 1 + Position values[] = { + { 235160420675000, 610.00, 1042.00 }, + { 235160428220000, 609.00, 1026.00 }, + { 235160436544000, 609.00, 1024.00 }, + { 235160441852394, 609.64, 1020.82 }, + { 235160444878000, 610.00, 1019.00 }, + { 235160452673000, 613.00, 1006.00 }, + { 235160458519743, 617.18, 992.06 }, + { 235160461061000, 619.00, 986.00 }, + { 235160469798000, 627.00, 960.00 }, + { 235160475186713, 632.22, 943.02 }, + { 235160478051000, 635.00, 934.00 }, + { 235160486489000, 644.00, 906.00 }, + { 235160491853697, 649.56, 890.56 }, + { 235160495177000, 653.00, 881.00 }, + { 235160504148000, 662.00, 858.00 }, + { 235160509231495, 666.81, 845.37 }, + { 235160512603000, 670.00, 837.00 }, + { 235160520366000, 679.00, 814.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 1274.141724); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 1438.53186); // lsq2 + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3877.35498); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3695.859619); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingUpFaster2) { + // Sailfish - fling up - faster - 2 + Position values[] = { + { 847153808000, 576.00, 1264.00 }, + { 847171174000, 576.00, 1262.00 }, + { 847179640000, 576.00, 1257.00 }, + { 847185187540, 577.41, 1249.22 }, + { 847187487000, 578.00, 1246.00 }, + { 847195710000, 581.00, 1227.00 }, + { 847202027059, 583.93, 1209.40 }, + { 847204324000, 585.00, 1203.00 }, + { 847212672000, 590.00, 1176.00 }, + { 847218861395, 594.36, 1157.11 }, + { 847221190000, 596.00, 1150.00 }, + { 847230484000, 602.00, 1124.00 }, + { 847235701400, 607.56, 1103.83 }, + { 847237986000, 610.00, 1095.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -4280.07959); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -4241.004395); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingUpFaster3) { + // Sailfish - fling up - faster - 3 + Position values[] = { + { 235200532789000, 507.00, 1084.00 }, + { 235200549221000, 507.00, 1083.00 }, + { 235200557841000, 507.00, 1081.00 }, + { 235200558051189, 507.00, 1080.95 }, + { 235200566314000, 507.00, 1078.00 }, + { 235200574876586, 508.97, 1070.12 }, + { 235200575006000, 509.00, 1070.00 }, + { 235200582900000, 514.00, 1054.00 }, + { 235200591276000, 525.00, 1023.00 }, + { 235200591701829, 525.56, 1021.42 }, + { 235200600064000, 542.00, 976.00 }, + { 235200608519000, 563.00, 911.00 }, + { 235200608527086, 563.02, 910.94 }, + { 235200616933000, 590.00, 844.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -8715.686523); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -7639.026367); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingUpFast1) { + // Sailfish - fling up - fast - 1 + Position values[] = { + { 920922149000, 561.00, 1412.00 }, + { 920930185000, 559.00, 1377.00 }, + { 920930262463, 558.98, 1376.66 }, + { 920938547000, 559.00, 1371.00 }, + { 920947096857, 562.91, 1342.68 }, + { 920947302000, 563.00, 1342.00 }, + { 920955502000, 577.00, 1272.00 }, + { 920963931021, 596.87, 1190.54 }, + { 920963987000, 597.00, 1190.00 }, + { 920972530000, 631.00, 1093.00 }, + { 920980765511, 671.31, 994.68 }, + { 920980906000, 672.00, 993.00 }, + { 920989261000, 715.00, 903.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 5670.329102); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 5991.866699); // lsq2 + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -13021.101562); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -15093.995117); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingUpFast2) { + // Sailfish - fling up - fast - 2 + Position values[] = { + { 235247153233000, 518.00, 1168.00 }, + { 235247170452000, 517.00, 1167.00 }, + { 235247178908000, 515.00, 1159.00 }, + { 235247179556213, 514.85, 1158.39 }, + { 235247186821000, 515.00, 1125.00 }, + { 235247195265000, 521.00, 1051.00 }, + { 235247196389476, 521.80, 1041.15 }, + { 235247203649000, 538.00, 932.00 }, + { 235247212253000, 571.00, 794.00 }, + { 235247213222491, 574.72, 778.45 }, + { 235247220736000, 620.00, 641.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -20286.958984); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -20494.587891); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingUpFast3) { + // Sailfish - fling up - fast - 3 + Position values[] = { + { 235302568736000, 529.00, 1167.00 }, + { 235302576644000, 523.00, 1140.00 }, + { 235302579395063, 520.91, 1130.61 }, + { 235302585140000, 522.00, 1130.00 }, + { 235302593615000, 527.00, 1065.00 }, + { 235302596207444, 528.53, 1045.12 }, + { 235302602102000, 559.00, 872.00 }, + { 235302610545000, 652.00, 605.00 }, + { 235302613019881, 679.26, 526.73 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -39295.941406); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -36461.421875); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingDownSlow1) { + // Sailfish - fling down - slow - 1 + Position values[] = { + { 235655749552755, 582.00, 432.49 }, + { 235655750638000, 582.00, 433.00 }, + { 235655758865000, 582.00, 440.00 }, + { 235655766221523, 581.16, 448.43 }, + { 235655767594000, 581.00, 450.00 }, + { 235655776044000, 580.00, 462.00 }, + { 235655782890696, 579.18, 474.35 }, + { 235655784360000, 579.00, 477.00 }, + { 235655792795000, 578.00, 496.00 }, + { 235655799559531, 576.27, 515.04 }, + { 235655800612000, 576.00, 518.00 }, + { 235655809535000, 574.00, 542.00 }, + { 235655816988015, 572.17, 564.86 }, + { 235655817685000, 572.00, 567.00 }, + { 235655825981000, 569.00, 595.00 }, + { 235655833808653, 566.26, 620.60 }, + { 235655834541000, 566.00, 623.00 }, + { 235655842893000, 563.00, 649.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -419.749695); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -398.303894); // lsq2 + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 3309.016357); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 3969.099854); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingDownSlow2) { + // Sailfish - fling down - slow - 2 + Position values[] = { + { 235671152083370, 485.24, 558.28 }, + { 235671154126000, 485.00, 559.00 }, + { 235671162497000, 484.00, 566.00 }, + { 235671168750511, 483.27, 573.29 }, + { 235671171071000, 483.00, 576.00 }, + { 235671179390000, 482.00, 588.00 }, + { 235671185417210, 481.31, 598.98 }, + { 235671188173000, 481.00, 604.00 }, + { 235671196371000, 480.00, 624.00 }, + { 235671202084196, 479.27, 639.98 }, + { 235671204235000, 479.00, 646.00 }, + { 235671212554000, 478.00, 673.00 }, + { 235671219471011, 476.39, 697.12 }, + { 235671221159000, 476.00, 703.00 }, + { 235671229592000, 474.00, 734.00 }, + { 235671236281462, 472.43, 758.38 }, + { 235671238098000, 472.00, 765.00 }, + { 235671246532000, 470.00, 799.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -262.80426); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -243.665344); // lsq2 + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4215.682129); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4587.986816); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingDownSlow3) { + // Sailfish - fling down - slow - 3 + Position values[] = { + { 170983201000, 557.00, 533.00 }, + { 171000668000, 556.00, 534.00 }, + { 171007359750, 554.73, 535.27 }, + { 171011197000, 554.00, 536.00 }, + { 171017660000, 552.00, 540.00 }, + { 171024201831, 549.97, 544.73 }, + { 171027333000, 549.00, 547.00 }, + { 171034603000, 545.00, 557.00 }, + { 171041043371, 541.98, 567.55 }, + { 171043147000, 541.00, 571.00 }, + { 171051052000, 536.00, 586.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -723.413513); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -651.038452); // lsq2 + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 2091.502441); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 1934.517456); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingDownFaster1) { + // Sailfish - fling down - faster - 1 + Position values[] = { + { 235695280333000, 558.00, 451.00 }, + { 235695283971237, 558.43, 454.45 }, + { 235695289038000, 559.00, 462.00 }, + { 235695297388000, 561.00, 478.00 }, + { 235695300638465, 561.83, 486.25 }, + { 235695305265000, 563.00, 498.00 }, + { 235695313591000, 564.00, 521.00 }, + { 235695317305492, 564.43, 532.68 }, + { 235695322181000, 565.00, 548.00 }, + { 235695330709000, 565.00, 577.00 }, + { 235695333972227, 565.00, 588.10 }, + { 235695339250000, 565.00, 609.00 }, + { 235695347839000, 565.00, 642.00 }, + { 235695351313257, 565.00, 656.18 }, + { 235695356412000, 565.00, 677.00 }, + { 235695364899000, 563.00, 710.00 }, + { 235695368118682, 562.24, 722.52 }, + { 235695373403000, 564.00, 744.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4254.639648); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4698.415039); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingDownFaster2) { + // Sailfish - fling down - faster - 2 + Position values[] = { + { 235709624766000, 535.00, 579.00 }, + { 235709642256000, 534.00, 580.00 }, + { 235709643350278, 533.94, 580.06 }, + { 235709650760000, 532.00, 584.00 }, + { 235709658615000, 530.00, 593.00 }, + { 235709660170495, 529.60, 594.78 }, + { 235709667095000, 527.00, 606.00 }, + { 235709675616000, 524.00, 628.00 }, + { 235709676983261, 523.52, 631.53 }, + { 235709684289000, 521.00, 652.00 }, + { 235709692763000, 518.00, 682.00 }, + { 235709693804993, 517.63, 685.69 }, + { 235709701438000, 515.00, 709.00 }, + { 235709709830000, 512.00, 739.00 }, + { 235709710626776, 511.72, 741.85 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -430.440247); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -447.600311); // lsq2 + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 3953.859375); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4316.155273); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingDownFaster3) { + // Sailfish - fling down - faster - 3 + Position values[] = { + { 235727628927000, 540.00, 440.00 }, + { 235727636810000, 537.00, 454.00 }, + { 235727646176000, 536.00, 454.00 }, + { 235727653586628, 535.12, 456.65 }, + { 235727654557000, 535.00, 457.00 }, + { 235727663024000, 534.00, 465.00 }, + { 235727670410103, 533.04, 479.45 }, + { 235727670691000, 533.00, 480.00 }, + { 235727679255000, 531.00, 501.00 }, + { 235727687233704, 529.09, 526.73 }, + { 235727687628000, 529.00, 528.00 }, + { 235727696113000, 526.00, 558.00 }, + { 235727704057546, 523.18, 588.98 }, + { 235727704576000, 523.00, 591.00 }, + { 235727713099000, 520.00, 626.00 }, + { 235727720880776, 516.33, 655.36 }, + { 235727721580000, 516.00, 658.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4484.617676); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4927.92627); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingDownFast1) { + // Sailfish - fling down - fast - 1 + Position values[] = { + { 235762352849000, 467.00, 286.00 }, + { 235762360250000, 443.00, 344.00 }, + { 235762362787412, 434.77, 363.89 }, + { 235762368807000, 438.00, 359.00 }, + { 235762377220000, 425.00, 423.00 }, + { 235762379608561, 421.31, 441.17 }, + { 235762385698000, 412.00, 528.00 }, + { 235762394133000, 406.00, 648.00 }, + { 235762396429369, 404.37, 680.67 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 19084.931641); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 16064.685547); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingDownFast2) { + // Sailfish - fling down - fast - 2 + Position values[] = { + { 235772487188000, 576.00, 204.00 }, + { 235772495159000, 553.00, 236.00 }, + { 235772503568000, 551.00, 240.00 }, + { 235772508192247, 545.55, 254.17 }, + { 235772512051000, 541.00, 266.00 }, + { 235772520794000, 520.00, 337.00 }, + { 235772525015263, 508.92, 394.43 }, + { 235772529174000, 498.00, 451.00 }, + { 235772537635000, 484.00, 589.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 18660.048828); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 16918.439453); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingDownFast3) { + // Sailfish - fling down - fast - 3 + Position values[] = { + { 507650295000, 628.00, 233.00 }, + { 507658234000, 605.00, 269.00 }, + { 507666784000, 601.00, 274.00 }, + { 507669660483, 599.65, 275.68 }, + { 507675427000, 582.00, 308.00 }, + { 507683740000, 541.00, 404.00 }, + { 507686506238, 527.36, 435.95 }, + { 507692220000, 487.00, 581.00 }, + { 507700707000, 454.00, 792.00 }, + { 507703352649, 443.71, 857.77 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -6772.508301); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -6388.48877); // lsq2 + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 29765.908203); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 28354.796875); // lsq2 +} + + +} // namespace android diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp index ed292e7bae..49ffc8f221 100644 --- a/libs/nativewindow/AHardwareBuffer.cpp +++ b/libs/nativewindow/AHardwareBuffer.cpp @@ -29,7 +29,7 @@ #include <system/graphics.h> #include <private/android/AHardwareBufferHelpers.h> -#include <android/hardware/graphics/common/1.0/types.h> +#include <android/hardware/graphics/common/1.1/types.h> static constexpr int kFdBufferSize = 128 * sizeof(int); // 128 ints @@ -60,6 +60,13 @@ int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc, AHardwareBuffer** return BAD_VALUE; } + if ((desc->usage & (AHARDWAREBUFFER_USAGE_CPU_READ_MASK | AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK)) && + (desc->usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT)) { + ALOGE("AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT requires AHARDWAREBUFFER_USAGE_CPU_READ_NEVER " + "and AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER"); + return BAD_VALUE; + } + uint64_t usage = AHardwareBuffer_convertToGrallocUsageBits(desc->usage); sp<GraphicBuffer> gbuffer(new GraphicBuffer( desc->width, desc->height, format, desc->layers, usage, @@ -311,6 +318,18 @@ bool AHardwareBuffer_isValidPixelFormat(uint32_t format) { "HAL and AHardwareBuffer pixel format don't match"); static_assert(HAL_PIXEL_FORMAT_BLOB == AHARDWAREBUFFER_FORMAT_BLOB, "HAL and AHardwareBuffer pixel format don't match"); + static_assert(HAL_PIXEL_FORMAT_DEPTH_16 == AHARDWAREBUFFER_FORMAT_D16_UNORM, + "HAL and AHardwareBuffer pixel format don't match"); + static_assert(HAL_PIXEL_FORMAT_DEPTH_24 == AHARDWAREBUFFER_FORMAT_D24_UNORM, + "HAL and AHardwareBuffer pixel format don't match"); + static_assert(HAL_PIXEL_FORMAT_DEPTH_24_STENCIL_8 == AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT, + "HAL and AHardwareBuffer pixel format don't match"); + static_assert(HAL_PIXEL_FORMAT_DEPTH_32F == AHARDWAREBUFFER_FORMAT_D32_FLOAT, + "HAL and AHardwareBuffer pixel format don't match"); + static_assert(HAL_PIXEL_FORMAT_DEPTH_32F_STENCIL_8 == AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT, + "HAL and AHardwareBuffer pixel format don't match"); + static_assert(HAL_PIXEL_FORMAT_STENCIL_8 == AHARDWAREBUFFER_FORMAT_S8_UINT, + "HAL and AHardwareBuffer pixel format don't match"); static_assert(HAL_PIXEL_FORMAT_BGRA_8888 == AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM, "HAL and AHardwareBuffer pixel format don't match"); static_assert(HAL_PIXEL_FORMAT_YV12 == AHARDWAREBUFFER_FORMAT_YV12, @@ -331,14 +350,6 @@ bool AHardwareBuffer_isValidPixelFormat(uint32_t format) { "HAL and AHardwareBuffer pixel format don't match"); static_assert(HAL_PIXEL_FORMAT_YCBCR_420_888 == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420, "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_YCBCR_422_888 == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_422, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_YCBCR_444_888 == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_444, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_FLEX_RGB_888 == AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_FLEX_RGBA_8888 == AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8A8, - "HAL and AHardwareBuffer pixel format don't match"); static_assert(HAL_PIXEL_FORMAT_YCBCR_422_SP == AHARDWAREBUFFER_FORMAT_YCbCr_422_SP, "HAL and AHardwareBuffer pixel format don't match"); static_assert(HAL_PIXEL_FORMAT_YCRCB_420_SP == AHARDWAREBUFFER_FORMAT_YCrCb_420_SP, @@ -354,6 +365,12 @@ bool AHardwareBuffer_isValidPixelFormat(uint32_t format) { case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT: case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM: case AHARDWAREBUFFER_FORMAT_BLOB: + case AHARDWAREBUFFER_FORMAT_D16_UNORM: + case AHARDWAREBUFFER_FORMAT_D24_UNORM: + case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT: + case AHARDWAREBUFFER_FORMAT_D32_FLOAT: + case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT: + case AHARDWAREBUFFER_FORMAT_S8_UINT: // VNDK formats only -- unfortunately we can't differentiate from where we're called case AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM: case AHARDWAREBUFFER_FORMAT_YV12: @@ -365,10 +382,6 @@ bool AHardwareBuffer_isValidPixelFormat(uint32_t format) { case AHARDWAREBUFFER_FORMAT_RAW_OPAQUE: case AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED: case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420: - case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_422: - case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_444: - case AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8: - case AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8A8: case AHARDWAREBUFFER_FORMAT_YCbCr_422_SP: case AHARDWAREBUFFER_FORMAT_YCrCb_420_SP: case AHARDWAREBUFFER_FORMAT_YCbCr_422_I: @@ -388,7 +401,7 @@ uint32_t AHardwareBuffer_convertToPixelFormat(uint32_t ahardwarebuffer_format) { } uint64_t AHardwareBuffer_convertToGrallocUsageBits(uint64_t usage) { - using android::hardware::graphics::common::V1_0::BufferUsage; + using android::hardware::graphics::common::V1_1::BufferUsage; static_assert(AHARDWAREBUFFER_USAGE_CPU_READ_NEVER == (uint64_t)BufferUsage::CPU_READ_NEVER, "gralloc and AHardwareBuffer flags don't match"); static_assert(AHARDWAREBUFFER_USAGE_CPU_READ_RARELY == (uint64_t)BufferUsage::CPU_READ_RARELY, @@ -413,6 +426,10 @@ uint64_t AHardwareBuffer_convertToGrallocUsageBits(uint64_t usage) { "gralloc and AHardwareBuffer flags don't match"); static_assert(AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA == (uint64_t)BufferUsage::SENSOR_DIRECT_DATA, "gralloc and AHardwareBuffer flags don't match"); + static_assert(AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP == (uint64_t)BufferUsage::GPU_CUBE_MAP, + "gralloc and AHardwareBuffer flags don't match"); + static_assert(AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE == (uint64_t)BufferUsage::GPU_MIPMAP_COMPLETE, + "gralloc and AHardwareBuffer flags don't match"); return usage; } diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index c6994c30b4..765dcd9973 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -33,6 +33,27 @@ static int32_t query(ANativeWindow* window, int what) { return res < 0 ? res : value; } +static bool isDataSpaceValid(ANativeWindow* window, int32_t dataSpace) { + bool supported = false; + switch (dataSpace) { + case HAL_DATASPACE_UNKNOWN: + case HAL_DATASPACE_V0_SRGB: + return true; + // These data space need wide gamut support. + case HAL_DATASPACE_V0_SCRGB_LINEAR: + case HAL_DATASPACE_V0_SCRGB: + case HAL_DATASPACE_DISPLAY_P3: + native_window_get_wide_color_support(window, &supported); + return supported; + // These data space need HDR support. + case HAL_DATASPACE_BT2020_PQ: + native_window_get_hdr_support(window, &supported); + return supported; + default: + return false; + } +} + /************************************************************************************************** * NDK **************************************************************************************************/ @@ -92,7 +113,10 @@ int32_t ANativeWindow_setBuffersTransform(ANativeWindow* window, int32_t transfo constexpr int32_t kAllTransformBits = ANATIVEWINDOW_TRANSFORM_MIRROR_HORIZONTAL | ANATIVEWINDOW_TRANSFORM_MIRROR_VERTICAL | - ANATIVEWINDOW_TRANSFORM_ROTATE_90; + ANATIVEWINDOW_TRANSFORM_ROTATE_90 | + // We don't expose INVERSE_DISPLAY as an NDK constant, but someone could have read it + // from a buffer already set by Camera framework, so we allow it to be forwarded. + NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) return -EINVAL; if ((transform & ~kAllTransformBits) != 0) @@ -101,6 +125,28 @@ int32_t ANativeWindow_setBuffersTransform(ANativeWindow* window, int32_t transfo return native_window_set_buffers_transform(window, transform); } +int32_t ANativeWindow_setBuffersDataSpace(ANativeWindow* window, int32_t dataSpace) { + static_assert(ADATASPACE_UNKNOWN == HAL_DATASPACE_UNKNOWN); + static_assert(ADATASPACE_SCRGB_LINEAR == HAL_DATASPACE_V0_SCRGB_LINEAR); + static_assert(ADATASPACE_SRGB == HAL_DATASPACE_V0_SRGB); + static_assert(ADATASPACE_SCRGB == HAL_DATASPACE_V0_SCRGB); + static_assert(ADATASPACE_DISPLAY_P3 == HAL_DATASPACE_DISPLAY_P3); + static_assert(ADATASPACE_BT2020_PQ == HAL_DATASPACE_BT2020_PQ); + + if (!window || !query(window, NATIVE_WINDOW_IS_VALID) || + !isDataSpaceValid(window, dataSpace)) { + return -EINVAL; + } + return native_window_set_buffers_data_space(window, + static_cast<android_dataspace_t>(dataSpace)); +} + +int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) { + if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) + return -EINVAL; + return query(window, NATIVE_WINDOW_DATASPACE); +} + /************************************************************************************************** * vndk-stable **************************************************************************************************/ @@ -209,10 +255,6 @@ int ANativeWindow_setBuffersTimestamp(ANativeWindow* window, int64_t timestamp) return native_window_set_buffers_timestamp(window, timestamp); } -int ANativeWindow_setBufferDataSpace(ANativeWindow* window, android_dataspace_t dataSpace) { - return native_window_set_buffers_data_space(window, dataSpace); -} - int ANativeWindow_setSharedBufferMode(ANativeWindow* window, bool sharedBufferMode) { return native_window_set_shared_buffer_mode(window, sharedBufferMode); } diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp index 29555fde9d..5fbb3b2f87 100644 --- a/libs/nativewindow/Android.bp +++ b/libs/nativewindow/Android.bp @@ -60,7 +60,7 @@ cc_library { "liblog", "libutils", "libui", - "android.hardware.graphics.common@1.0", + "android.hardware.graphics.common@1.1", ], static_libs: [ diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h new file mode 100644 index 0000000000..3ac1c58ea9 --- /dev/null +++ b/libs/nativewindow/include/android/data_space.h @@ -0,0 +1,108 @@ +/* + * Copyright 2018 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. + */ + +/** + * @file data_space.h + */ + +#ifndef ANDROID_DATA_SPACE_H +#define ANDROID_DATA_SPACE_H + +#include <inttypes.h> + +#include <sys/cdefs.h> + +__BEGIN_DECLS + +/** + * ADataSpace. + */ +enum ADataSpace { + /** + * Default-assumption data space, when not explicitly specified. + * + * It is safest to assume the buffer is an image with sRGB primaries and + * encoding ranges, but the consumer and/or the producer of the data may + * simply be using defaults. No automatic gamma transform should be + * expected, except for a possible display gamma transform when drawn to a + * screen. + */ + ADATASPACE_UNKNOWN = 0, + + /** + * scRGB linear encoding: + * + * The red, green, and blue components are stored in extended sRGB space, + * but are linear, not gamma-encoded. + * The RGB primaries and the white point are the same as BT.709. + * + * The values are floating point. + * A pixel value of 1.0, 1.0, 1.0 corresponds to sRGB white (D65) at 80 nits. + * Values beyond the range [0.0 - 1.0] would correspond to other colors + * spaces and/or HDR content. + */ + ADATASPACE_SCRGB_LINEAR = 406913024, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_EXTENDED + + /** + * sRGB gamma encoding: + * + * The red, green and blue components are stored in sRGB space, and + * converted to linear space when read, using the SRGB transfer function + * for each of the R, G and B components. When written, the inverse + * transformation is performed. + * + * The alpha component, if present, is always stored in linear space and + * is left unmodified when read or written. + * + * Use full range and BT.709 standard. + */ + ADATASPACE_SRGB = 142671872, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_FULL + + /** + * scRGB: + * + * The red, green, and blue components are stored in extended sRGB space, + * but are linear, not gamma-encoded. + * The RGB primaries and the white point are the same as BT.709. + * + * The values are floating point. + * A pixel value of 1.0, 1.0, 1.0 corresponds to sRGB white (D65) at 80 nits. + * Values beyond the range [0.0 - 1.0] would correspond to other colors + * spaces and/or HDR content. + */ + ADATASPACE_SCRGB = 411107328, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_EXTENDED + + /** + * Display P3 + * + * Use same primaries and white-point as DCI-P3 + * but sRGB transfer function. + */ + ADATASPACE_DISPLAY_P3 = 143261696, // STANDARD_DCI_P3 | TRANSFER_SRGB | RANGE_FULL + + /** + * ITU-R Recommendation 2020 (BT.2020) + * + * Ultra High-definition television + * + * Use full range, SMPTE 2084 (PQ) transfer and BT2020 standard + */ + ADATASPACE_BT2020_PQ = 163971072, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_FULL +}; + +__END_DECLS + +#endif // ANDROID_DATA_SPACE_H diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h index ef4875aea1..32b926644e 100644 --- a/libs/nativewindow/include/android/hardware_buffer.h +++ b/libs/nativewindow/include/android/hardware_buffer.h @@ -46,9 +46,11 @@ enum { AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM = 1, /** + * 32 bits per pixel, 8 bits per channel format where alpha values are + * ignored (always opaque). * Corresponding formats: * Vulkan: VK_FORMAT_R8G8B8A8_UNORM - * OpenGL ES: GL_RGBA8 + * OpenGL ES: GL_RGB8 */ AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM = 2, @@ -85,39 +87,94 @@ enum { * the buffer size in bytes. */ AHARDWAREBUFFER_FORMAT_BLOB = 0x21, + + /** + * Corresponding formats: + * Vulkan: VK_FORMAT_D16_UNORM + * OpenGL ES: GL_DEPTH_COMPONENT16 + */ + AHARDWAREBUFFER_FORMAT_D16_UNORM = 0x30, + + /** + * Corresponding formats: + * Vulkan: VK_FORMAT_X8_D24_UNORM_PACK32 + * OpenGL ES: GL_DEPTH_COMPONENT24 + */ + AHARDWAREBUFFER_FORMAT_D24_UNORM = 0x31, + + /** + * Corresponding formats: + * Vulkan: VK_FORMAT_D24_UNORM_S8_UINT + * OpenGL ES: GL_DEPTH24_STENCIL8 + */ + AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT = 0x32, + + /** + * Corresponding formats: + * Vulkan: VK_FORMAT_D32_SFLOAT + * OpenGL ES: GL_DEPTH_COMPONENT32F + */ + AHARDWAREBUFFER_FORMAT_D32_FLOAT = 0x33, + + /** + * Corresponding formats: + * Vulkan: VK_FORMAT_D32_SFLOAT_S8_UINT + * OpenGL ES: GL_DEPTH32F_STENCIL8 + */ + AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT = 0x34, + + /** + * Corresponding formats: + * Vulkan: VK_FORMAT_S8_UINT + * OpenGL ES: GL_STENCIL_INDEX8 + */ + AHARDWAREBUFFER_FORMAT_S8_UINT = 0x35, }; +/** + * Buffer usage flags, specifying how the buffer will be accessed. + */ enum { - /* The buffer will never be read by the CPU */ + /// The buffer will never be read by the CPU. AHARDWAREBUFFER_USAGE_CPU_READ_NEVER = 0UL, - /* The buffer will sometimes be read by the CPU */ + /// The buffer will sometimes be read by the CPU. AHARDWAREBUFFER_USAGE_CPU_READ_RARELY = 2UL, - /* The buffer will often be read by the CPU */ + /// The buffer will often be read by the CPU. AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN = 3UL, - /* CPU read value mask */ + /// CPU read value mask. AHARDWAREBUFFER_USAGE_CPU_READ_MASK = 0xFUL, - /* The buffer will never be written by the CPU */ + /// The buffer will never be written by the CPU. AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER = 0UL << 4, - /* The buffer will sometimes be written to by the CPU */ + /// The buffer will sometimes be written to by the CPU. AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY = 2UL << 4, - /* The buffer will often be written to by the CPU */ + /// The buffer will often be written to by the CPU. AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN = 3UL << 4, - /* CPU write value mask */ + /// CPU write value mask. AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK = 0xFUL << 4, - /* The buffer will be read from by the GPU */ + /// The buffer will be read from by the GPU as a texture. AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE = 1UL << 8, - /* The buffer will be written to by the GPU */ + /** + * The buffer will be written to by the GPU as a framebuffer attachment. + * Note that the name of this flag is somewhat misleading: it does not imply + * that the buffer contains a color format. A buffer with depth or stencil + * format that will be used as a framebuffer attachment should also have + * this flag. + */ AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT = 1UL << 9, - /* The buffer must not be used outside of a protected hardware path */ + /// The buffer must not be used outside of a protected hardware path. AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT = 1UL << 14, - /* The buffer will be read by a hardware video encoder */ + /// The buffer will be read by a hardware video encoder. AHARDWAREBUFFER_USAGE_VIDEO_ENCODE = 1UL << 16, - /** The buffer will be used for sensor direct data */ + /// The buffer will be used for direct writes from sensors. AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA = 1UL << 23, - /* The buffer will be used as a shader storage or uniform buffer object*/ + /// The buffer will be used as a shader storage or uniform buffer object. AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER = 1UL << 24, + /// The buffer will be used as a cube map texture. + AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP = 1UL << 25, + /// The buffer contains a complete mipmap hierarchy. + AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE = 1UL << 26, AHARDWAREBUFFER_USAGE_VENDOR_0 = 1ULL << 28, AHARDWAREBUFFER_USAGE_VENDOR_1 = 1ULL << 29, @@ -141,15 +198,19 @@ enum { AHARDWAREBUFFER_USAGE_VENDOR_19 = 1ULL << 63, }; +/** + * Buffer description. Used for allocating new buffers and querying parameters + * of existing ones. + */ typedef struct AHardwareBuffer_Desc { - uint32_t width; // width in pixels - uint32_t height; // height in pixels - uint32_t layers; // number of images - uint32_t format; // One of AHARDWAREBUFFER_FORMAT_* - uint64_t usage; // Combination of AHARDWAREBUFFER_USAGE_* - uint32_t stride; // Stride in pixels, ignored for AHardwareBuffer_allocate() - uint32_t rfu0; // Initialize to zero, reserved for future use - uint64_t rfu1; // Initialize to zero, reserved for future use + uint32_t width; ///< Width in pixels. + uint32_t height; ///< Height in pixels. + uint32_t layers; ///< Number of images in an image array. + uint32_t format; ///< One of AHARDWAREBUFFER_FORMAT_* + uint64_t usage; ///< Combination of AHARDWAREBUFFER_USAGE_* + uint32_t stride; ///< Row stride in pixels, ignored for AHardwareBuffer_allocate() + uint32_t rfu0; ///< Initialize to zero, reserved for future use. + uint64_t rfu1; ///< Initialize to zero, reserved for future use. } AHardwareBuffer_Desc; typedef struct AHardwareBuffer AHardwareBuffer; @@ -158,8 +219,8 @@ typedef struct AHardwareBuffer AHardwareBuffer; * Allocates a buffer that backs an AHardwareBuffer using the passed * AHardwareBuffer_Desc. * - * Returns NO_ERROR on success, or an error number of the allocation fails for - * any reason. + * \return 0 on success, or an error number of the allocation fails for + * any reason. The returned buffer has a reference count of 1. */ int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc, AHardwareBuffer** outBuffer); @@ -182,7 +243,7 @@ void AHardwareBuffer_release(AHardwareBuffer* buffer); void AHardwareBuffer_describe(const AHardwareBuffer* buffer, AHardwareBuffer_Desc* outDesc); -/* +/** * Lock the AHardwareBuffer for reading or writing, depending on the usage flags * passed. This call may block if the hardware needs to finish rendering or if * CPU caches need to be synchronized, or possibly for other implementation- @@ -190,16 +251,16 @@ void AHardwareBuffer_describe(const AHardwareBuffer* buffer, * descriptor that will be signaled when the buffer is locked, otherwise the * caller will block until the buffer is available. * - * If rect is not NULL, the caller promises to modify only data in the area + * If \a rect is not NULL, the caller promises to modify only data in the area * specified by rect. If rect is NULL, the caller may modify the contents of the * entire buffer. * * The content of the buffer outside of the specified rect is NOT modified * by this call. * - * The buffer usage may only specify AHARDWAREBUFFER_USAGE_CPU_*. If set, then - * outVirtualAddress is filled with the address of the buffer in virtual memory, - * otherwise this function will fail. + * The \a usage parameter may only specify AHARDWAREBUFFER_USAGE_CPU_*. If set, + * then outVirtualAddress is filled with the address of the buffer in virtual + * memory. * * THREADING CONSIDERATIONS: * @@ -211,38 +272,38 @@ void AHardwareBuffer_describe(const AHardwareBuffer* buffer, * may return an error or leave the buffer's content into an indeterminate * state. * - * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL or if the usage + * \return 0 on success, -EINVAL if \a buffer is NULL or if the usage * flags are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or an error * number of the lock fails for any reason. */ int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage, int32_t fence, const ARect* rect, void** outVirtualAddress); -/* +/** * Unlock the AHardwareBuffer; must be called after all changes to the buffer * are completed by the caller. If fence is not NULL then it will be set to a * file descriptor that is signaled when all pending work on the buffer is * completed. The caller is responsible for closing the fence when it is no * longer needed. * - * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL, or an error - * number of the lock fails for any reason. + * \return 0 on success, -EINVAL if \a buffer is NULL, or an error + * number if the unlock fails for any reason. */ int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence); -/* +/** * Send the AHardwareBuffer to an AF_UNIX socket. * - * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL, or an error - * number of the lock fails for any reason. + * \return 0 on success, -EINVAL if \a buffer is NULL, or an error + * number if the operation fails for any reason. */ int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer, int socketFd); -/* +/** * Receive the AHardwareBuffer from an AF_UNIX socket. * - * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL, or an error - * number of the lock fails for any reason. + * \return 0 on success, -EINVAL if \a outBuffer is NULL, or an error + * number if the operation fails for any reason. */ int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** outBuffer); diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h index 5290dd51cd..d5e5e9dd24 100644 --- a/libs/nativewindow/include/android/native_window.h +++ b/libs/nativewindow/include/android/native_window.h @@ -29,6 +29,7 @@ #include <sys/cdefs.h> +#include <android/data_space.h> #include <android/hardware_buffer.h> #include <android/rect.h> @@ -84,23 +85,23 @@ typedef struct ANativeWindow ANativeWindow; * A pointer can be obtained using {@link ANativeWindow_lock()}. */ typedef struct ANativeWindow_Buffer { - // The number of pixels that are show horizontally. + /// The number of pixels that are shown horizontally. int32_t width; - // The number of pixels that are shown vertically. + /// The number of pixels that are shown vertically. int32_t height; - // The number of *pixels* that a line in the buffer takes in - // memory. This may be >= width. + /// The number of *pixels* that a line in the buffer takes in + /// memory. This may be >= width. int32_t stride; - // The format of the buffer. One of AHARDWAREBUFFER_FORMAT_* + /// The format of the buffer. One of AHARDWAREBUFFER_FORMAT_* int32_t format; - // The actual bits. + /// The actual bits. void* bits; - // Do not touch. + /// Do not touch. uint32_t reserved[6]; } ANativeWindow_Buffer; @@ -189,6 +190,33 @@ int32_t ANativeWindow_setBuffersTransform(ANativeWindow* window, int32_t transfo #endif // __ANDROID_API__ >= __ANDROID_API_O__ +#if __ANDROID_API__ >= __ANDROID_API_P__ + +/** + * All buffers queued after this call will be associated with the dataSpace + * parameter specified. + * + * dataSpace specifies additional information about the buffer. + * For example, it can be used to convey the color space of the image data in + * the buffer, or it can be used to indicate that the buffers contain depth + * measurement data instead of color images. The default dataSpace is 0, + * ADATASPACE_UNKNOWN, unless it has been overridden by the producer. + * + * \param dataSpace data space of all buffers queued after this call. + * \return 0 for success, -EINVAL if window is invalid or the dataspace is not + * supported. + */ +int32_t ANativeWindow_setBuffersDataSpace(ANativeWindow* window, int32_t dataSpace); + +/** + * Get the dataspace of the buffers in window. + * \return the dataspace of buffers in window, ADATASPACE_UNKNOWN is returned if + * dataspace is unknown, or -EINVAL if window is invalid. + */ +int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window); + +#endif // __ANDROID_API__ >= __ANDROID_API_P__ + #ifdef __cplusplus }; #endif diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 64908049d6..197f73f3b1 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -179,6 +179,16 @@ enum { * with GRALLOC_USAGE_PROTECTED usage bits on. */ NATIVE_WINDOW_CONSUMER_IS_PROTECTED = 19, + + /* + * Returns data space for the buffers. + */ + NATIVE_WINDOW_DATASPACE = 20, + + /* + * Returns maxBufferCount set by BufferQueueConsumer + */ + NATIVE_WINDOW_MAX_BUFFER_COUNT = 21, }; /* Valid operations for the (*perform)() hook. @@ -225,6 +235,8 @@ enum { NATIVE_WINDOW_GET_HDR_SUPPORT = 29, NATIVE_WINDOW_SET_USAGE64 = 30, NATIVE_WINDOW_GET_CONSUMER_USAGE64 = 31, + NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA = 32, + NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA = 33, // clang-format on }; @@ -700,6 +712,42 @@ static inline int native_window_set_buffers_data_space( } /* + * native_window_set_buffers_smpte2086_metadata(..., metadata) + * All buffers queued after this call will be associated with the SMPTE + * ST.2086 metadata specified. + * + * metadata specifies additional information about the contents of the buffer + * that may affect how it's displayed. When it is nullptr, it means no such + * information is available. No SMPTE ST.2086 metadata is associated with the + * buffers by default. + */ +static inline int native_window_set_buffers_smpte2086_metadata( + struct ANativeWindow* window, + const struct android_smpte2086_metadata* metadata) +{ + return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA, + metadata); +} + +/* + * native_window_set_buffers_cta861_3_metadata(..., metadata) + * All buffers queued after this call will be associated with the CTA-861.3 + * metadata specified. + * + * metadata specifies additional information about the contents of the buffer + * that may affect how it's displayed. When it is nullptr, it means no such + * information is available. No CTA-861.3 metadata is associated with the + * buffers by default. + */ +static inline int native_window_set_buffers_cta861_3_metadata( + struct ANativeWindow* window, + const struct android_cta861_3_metadata* metadata) +{ + return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA, + metadata); +} + +/* * native_window_set_buffers_transform(..., int transform) * All buffers queued after this call will be displayed transformed according * to the transform parameter specified. diff --git a/libs/nativewindow/include/vndk/hardware_buffer.h b/libs/nativewindow/include/vndk/hardware_buffer.h index 802edcc17d..7a4b31f513 100644 --- a/libs/nativewindow/include/vndk/hardware_buffer.h +++ b/libs/nativewindow/include/vndk/hardware_buffer.h @@ -53,14 +53,6 @@ enum { AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED = 0x22, /* same as HAL_PIXEL_FORMAT_YCBCR_420_888 */ AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420 = 0x23, - /* same as HAL_PIXEL_FORMAT_YCBCR_422_888 */ - AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_422 = 0x27, - /* same as HAL_PIXEL_FORMAT_YCBCR_444_888 */ - AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_444 = 0x28, - /* same as HAL_PIXEL_FORMAT_FLEX_RGB_888 */ - AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8 = 0x29, - /* same as HAL_PIXEL_FORMAT_FLEX_RGBA_8888 */ - AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8A8 = 0x2A, /* same as HAL_PIXEL_FORMAT_YCBCR_422_SP */ AHARDWAREBUFFER_FORMAT_YCbCr_422_SP = 0x10, /* same as HAL_PIXEL_FORMAT_YCRCB_420_SP */ diff --git a/libs/nativewindow/include/vndk/window.h b/libs/nativewindow/include/vndk/window.h index a7b340aea3..995ba44d20 100644 --- a/libs/nativewindow/include/vndk/window.h +++ b/libs/nativewindow/include/vndk/window.h @@ -306,20 +306,6 @@ int ANativeWindow_setBuffersTimestamp(ANativeWindow* window, int64_t timestamp); /* - * All buffers queued after this call will be associated with the dataSpace - * parameter specified. - * - * dataSpace specifies additional information about the buffer that's dependent - * on the buffer format and the endpoints. For example, it can be used to convey - * the color space of the image data in the buffer, or it can be used to - * indicate that the buffers contain depth measurement data instead of color - * images. The default dataSpace is 0, HAL_DATASPACE_UNKNOWN, unless it has been - * overridden by the consumer. - */ -int ANativeWindow_setBufferDataSpace(ANativeWindow* window, android_dataspace_t dataSpace); - - -/* * Enable/disable shared buffer mode */ int ANativeWindow_setSharedBufferMode(ANativeWindow* window, bool sharedBufferMode); diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index 105d01b7b3..d2ba971458 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -15,6 +15,7 @@ LIBNATIVEWINDOW { ANativeWindow_acquire; ANativeWindow_cancelBuffer; # vndk ANativeWindow_dequeueBuffer; # vndk + ANativeWindow_getBuffersDataSpace; # introduced=28 ANativeWindow_getFormat; ANativeWindow_getHeight; ANativeWindow_getWidth; @@ -25,7 +26,7 @@ LIBNATIVEWINDOW { ANativeWindow_release; ANativeWindow_setAutoRefresh; # vndk ANativeWindow_setBufferCount; # vndk - ANativeWindow_setBufferDataSpace; # vndk + ANativeWindow_setBuffersDataSpace; # introduced=28 ANativeWindow_setBuffersDimensions; # vndk ANativeWindow_setBuffersFormat; # vndk ANativeWindow_setBuffersGeometry; diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp index efbbf7d826..5200545a53 100644 --- a/libs/sensor/ISensorServer.cpp +++ b/libs/sensor/ISensorServer.cpp @@ -27,6 +27,7 @@ #include <binder/Parcel.h> #include <binder/IInterface.h> +#include <binder/IResultReceiver.h> #include <sensor/Sensor.h> #include <sensor/ISensorEventConnection.h> @@ -227,6 +228,30 @@ status_t BnSensorServer::onTransact( reply->writeInt32(ret); return NO_ERROR; } + case SHELL_COMMAND_TRANSACTION: { + int in = data.readFileDescriptor(); + int out = data.readFileDescriptor(); + int err = data.readFileDescriptor(); + int argc = data.readInt32(); + Vector<String16> args; + for (int i = 0; i < argc && data.dataAvail() > 0; i++) { + args.add(data.readString16()); + } + sp<IBinder> unusedCallback; + sp<IResultReceiver> resultReceiver; + status_t status; + if ((status = data.readNullableStrongBinder(&unusedCallback)) != NO_ERROR) { + return status; + } + if ((status = data.readNullableStrongBinder(&resultReceiver)) != NO_ERROR) { + return status; + } + status = shellCommand(in, out, err, args); + if (resultReceiver != nullptr) { + resultReceiver->send(status); + } + return NO_ERROR; + } } return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/sensor/OWNERS b/libs/sensor/OWNERS new file mode 100644 index 0000000000..d4393d6a83 --- /dev/null +++ b/libs/sensor/OWNERS @@ -0,0 +1,2 @@ +arthuri@google.com +bduddie@google.com diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp index 6fe72a13ba..b9ae524ee8 100644 --- a/libs/sensor/SensorManager.cpp +++ b/libs/sensor/SensorManager.cpp @@ -27,6 +27,7 @@ #include <utils/Singleton.h> #include <binder/IBinder.h> +#include <binder/IPermissionController.h> #include <binder/IServiceManager.h> #include <sensor/ISensorServer.h> diff --git a/libs/sensor/include/sensor/ISensorServer.h b/libs/sensor/include/sensor/ISensorServer.h index edf3e0f4cf..402678f0fd 100644 --- a/libs/sensor/include/sensor/ISensorServer.h +++ b/libs/sensor/include/sensor/ISensorServer.h @@ -60,6 +60,9 @@ public: class BnSensorServer : public BnInterface<ISensorServer> { public: + virtual status_t shellCommand(int in, int out, int err, + Vector<String16>& args) = 0; + virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index 438fd2a0f7..d25ad1a46d 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -48,7 +48,7 @@ cc_library_shared { ], sanitize: { - //misc_undefined: ["integer"], + integer_overflow: true, }, srcs: [ @@ -74,7 +74,9 @@ cc_library_shared { shared_libs: [ "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.common@1.1", "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@2.1", "android.hardware.configstore@1.0", "android.hardware.configstore-utils", "libbase", @@ -89,6 +91,10 @@ cc_library_shared { "liblog", ], + export_shared_lib_headers: [ + "android.hardware.graphics.common@1.1", + ], + static_libs: [ "libarect", "libgrallocusage", @@ -96,20 +102,23 @@ cc_library_shared { ], header_libs: [ + "libbase_headers", "libnativebase_headers", "libhardware_headers", + "libui_headers", + "libpdx_headers", ], - export_include_dirs: ["include"], - export_static_lib_headers: [ "libarect", "libmath", ], export_header_lib_headers: [ + "libbase_headers", "libnativebase_headers", "libhardware_headers", + "libui_headers", ], } @@ -117,6 +126,11 @@ cc_library_headers { name: "libui_headers", export_include_dirs: ["include"], vendor_available: true, + target: { + vendor: { + override_export_include_dirs: ["include_vndk"], + }, + }, } subdirs = [ diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp index 2d72944665..61df02d41d 100644 --- a/libs/ui/DebugUtils.cpp +++ b/libs/ui/DebugUtils.cpp @@ -22,6 +22,8 @@ #include <string> using android::base::StringPrintf; +using android::ui::ColorMode; +using android::ui::RenderIntent; std::string decodeStandard(android_dataspace dataspace) { const uint32_t dataspaceSelect = (dataspace & HAL_DATASPACE_STANDARD_MASK); @@ -74,7 +76,7 @@ std::string decodeStandard(android_dataspace dataspace) { case HAL_DATASPACE_SRGB: return std::string("(deprecated) sRGB"); - case HAL_DATASPACE_V0_BT709: + case HAL_DATASPACE_BT709: return std::string("(deprecated) BT709"); case HAL_DATASPACE_ARBITRARY: @@ -84,7 +86,7 @@ std::string decodeStandard(android_dataspace dataspace) { // Fallthrough default: return android::base::StringPrintf("Unknown deprecated dataspace code %d", - dataspaceSelect); + dataspace); } } @@ -98,7 +100,7 @@ std::string decodeTransfer(android_dataspace dataspace) { case HAL_DATASPACE_JFIF: case HAL_DATASPACE_BT601_625: case HAL_DATASPACE_BT601_525: - case HAL_DATASPACE_V0_BT709: + case HAL_DATASPACE_BT709: return std::string("SMPTE_170M"); case HAL_DATASPACE_SRGB_LINEAR: @@ -159,8 +161,8 @@ std::string decodeRange(android_dataspace dataspace) { case HAL_DATASPACE_BT601_625: case HAL_DATASPACE_BT601_525: - case HAL_DATASPACE_V0_BT709: - return std::string("Limited range)"); + case HAL_DATASPACE_BT709: + return std::string("Limited range"); case HAL_DATASPACE_ARBITRARY: case HAL_DATASPACE_UNKNOWN: @@ -197,42 +199,78 @@ std::string dataspaceDetails(android_dataspace dataspace) { decodeRange(dataspace).c_str()); } -std::string decodeColorMode(android_color_mode colorMode) { +std::string decodeColorMode(ColorMode colorMode) { switch (colorMode) { - case HAL_COLOR_MODE_NATIVE: - return std::string("HAL_COLOR_MODE_NATIVE"); + case ColorMode::NATIVE: + return std::string("ColorMode::NATIVE"); - case HAL_COLOR_MODE_STANDARD_BT601_625: - return std::string("HAL_COLOR_MODE_BT601_625"); + case ColorMode::STANDARD_BT601_625: + return std::string("ColorMode::BT601_625"); - case HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED: - return std::string("HAL_COLOR_MODE_BT601_625_UNADJUSTED"); + case ColorMode::STANDARD_BT601_625_UNADJUSTED: + return std::string("ColorMode::BT601_625_UNADJUSTED"); - case HAL_COLOR_MODE_STANDARD_BT601_525: - return std::string("HAL_COLOR_MODE_BT601_525"); + case ColorMode::STANDARD_BT601_525: + return std::string("ColorMode::BT601_525"); - case HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED: - return std::string("HAL_COLOR_MODE_BT601_525_UNADJUSTED"); + case ColorMode::STANDARD_BT601_525_UNADJUSTED: + return std::string("ColorMode::BT601_525_UNADJUSTED"); - case HAL_COLOR_MODE_STANDARD_BT709: - return std::string("HAL_COLOR_MODE_BT709"); + case ColorMode::STANDARD_BT709: + return std::string("ColorMode::BT709"); - case HAL_COLOR_MODE_DCI_P3: - return std::string("HAL_COLOR_MODE_DCI_P3"); + case ColorMode::DCI_P3: + return std::string("ColorMode::DCI_P3"); - case HAL_COLOR_MODE_SRGB: - return std::string("HAL_COLOR_MODE_SRGB"); + case ColorMode::SRGB: + return std::string("ColorMode::SRGB"); - case HAL_COLOR_MODE_ADOBE_RGB: - return std::string("HAL_COLOR_MODE_ADOBE_RGB"); + case ColorMode::ADOBE_RGB: + return std::string("ColorMode::ADOBE_RGB"); - case HAL_COLOR_MODE_DISPLAY_P3: - return std::string("HAL_COLOR_MODE_DISPLAY_P3"); + case ColorMode::DISPLAY_P3: + return std::string("ColorMode::DISPLAY_P3"); + + case ColorMode::BT2020: + return std::string("ColorMode::BT2020"); + + case ColorMode::BT2100_PQ: + return std::string("ColorMode::BT2100_PQ"); + + case ColorMode::BT2100_HLG: + return std::string("ColorMode::BT2100_HLG"); } return android::base::StringPrintf("Unknown color mode %d", colorMode); } +std::string decodeColorTransform(android_color_transform colorTransform) { + switch (colorTransform) { + case HAL_COLOR_TRANSFORM_IDENTITY: + return std::string("Identity"); + + case HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX: + return std::string("Arbitrary matrix"); + + case HAL_COLOR_TRANSFORM_VALUE_INVERSE: + return std::string("Inverse value"); + + case HAL_COLOR_TRANSFORM_GRAYSCALE: + return std::string("Grayscale"); + + case HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA: + return std::string("Correct protanopia"); + + case HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA: + return std::string("Correct deuteranopia"); + + case HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA: + return std::string("Correct tritanopia"); + } + + return android::base::StringPrintf("Unknown color transform %d", colorTransform); +} + // Converts a PixelFormat to a human-readable string. Max 11 chars. // (Could use a table of prefab String8 objects.) std::string decodePixelFormat(android::PixelFormat format) { @@ -266,6 +304,20 @@ std::string decodePixelFormat(android::PixelFormat format) { } } +std::string decodeRenderIntent(RenderIntent renderIntent) { + switch(renderIntent) { + case RenderIntent::COLORIMETRIC: + return std::string("RenderIntent::COLORIMETRIC"); + case RenderIntent::ENHANCE: + return std::string("RenderIntent::ENHANCE"); + case RenderIntent::TONE_MAP_COLORIMETRIC: + return std::string("RenderIntent::TONE_MAP_COLORIMETRIC"); + case RenderIntent::TONE_MAP_ENHANCE: + return std::string("RenderIntent::TONE_MAP_ENHANCE"); + } + return std::string("Unknown RenderIntent"); +} + std::string to_string(const android::Rect& rect) { return StringPrintf("(%4d,%4d,%4d,%4d)", rect.left, rect.top, rect.right, rect.bottom); } diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp index eb88be117a..ed7ccb0bed 100644 --- a/libs/ui/Fence.cpp +++ b/libs/ui/Fence.cpp @@ -37,18 +37,12 @@ namespace android { const sp<Fence> Fence::NO_FENCE = sp<Fence>(new Fence); -Fence::Fence() : - mFenceFd(-1) { -} - Fence::Fence(int fenceFd) : mFenceFd(fenceFd) { } -Fence::~Fence() { - if (mFenceFd != -1) { - close(mFenceFd); - } +Fence::Fence(base::unique_fd fenceFd) : + mFenceFd(std::move(fenceFd)) { } status_t Fence::wait(int timeout) { @@ -68,7 +62,7 @@ status_t Fence::waitForever(const char* logname) { int warningTimeout = 3000; int err = sync_wait(mFenceFd, warningTimeout); if (err < 0 && errno == ETIME) { - ALOGE("%s: fence %d didn't signal in %u ms", logname, mFenceFd, + ALOGE("%s: fence %d didn't signal in %u ms", logname, mFenceFd.get(), warningTimeout); err = sync_wait(mFenceFd, TIMEOUT_NEVER); } @@ -94,7 +88,7 @@ sp<Fence> Fence::merge(const char* name, const sp<Fence>& f1, if (result == -1) { status_t err = -errno; ALOGE("merge: sync_merge(\"%s\", %d, %d) returned an error: %s (%d)", - name, f1->mFenceFd, f2->mFenceFd, + name, f1->mFenceFd.get(), f2->mFenceFd.get(), strerror(-err), err); return NO_FENCE; } @@ -117,7 +111,7 @@ nsecs_t Fence::getSignalTime() const { struct sync_file_info* finfo = sync_file_info(mFenceFd); if (finfo == NULL) { - ALOGE("sync_file_info returned NULL for fd %d", mFenceFd); + ALOGE("sync_file_info returned NULL for fd %d", mFenceFd.get()); return SIGNAL_TIME_INVALID; } if (finfo->status != 1) { @@ -181,7 +175,7 @@ status_t Fence::unflatten(void const*& buffer, size_t& size, int const*& fds, si } if (numFds) { - mFenceFd = *fds++; + mFenceFd.reset(*fds++); count--; } diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp index 0eb08e59a9..37cf617374 100644 --- a/libs/ui/Gralloc2.cpp +++ b/libs/ui/Gralloc2.cpp @@ -20,6 +20,7 @@ #include <hwbinder/IPCThreadState.h> #include <ui/Gralloc2.h> +#include <inttypes.h> #include <log/log.h> #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wzero-length-array" @@ -30,35 +31,104 @@ namespace android { namespace Gralloc2 { +namespace { + static constexpr Error kTransactionError = Error::NO_RESOURCES; +uint64_t getValid10UsageBits() { + static const uint64_t valid10UsageBits = []() -> uint64_t { + using hardware::graphics::common::V1_0::BufferUsage; + uint64_t bits = 0; + for (const auto bit : hardware::hidl_enum_range<BufferUsage>()) { + bits = bits | bit; + } + // TODO(b/72323293, b/72703005): Remove these additional bits + bits = bits | (1 << 10) | (1 << 13); + + return bits; + }(); + return valid10UsageBits; +} + +uint64_t getValid11UsageBits() { + static const uint64_t valid11UsageBits = []() -> uint64_t { + using hardware::graphics::common::V1_1::BufferUsage; + uint64_t bits = 0; + for (const auto bit : hardware::hidl_enum_range<BufferUsage>()) { + bits = bits | bit; + } + return bits; + }(); + return valid11UsageBits; +} + +} // anonymous namespace + void Mapper::preload() { android::hardware::preloadPassthroughService<hardware::graphics::mapper::V2_0::IMapper>(); } Mapper::Mapper() { - mMapper = IMapper::getService(); - if (mMapper == nullptr || mMapper->isRemote()) { + mMapper = hardware::graphics::mapper::V2_0::IMapper::getService(); + if (mMapper == nullptr) { + LOG_ALWAYS_FATAL("gralloc-mapper is missing"); + } + if (mMapper->isRemote()) { LOG_ALWAYS_FATAL("gralloc-mapper must be in passthrough mode"); } + + // IMapper 2.1 is optional + mMapperV2_1 = IMapper::castFrom(mMapper); +} + +Gralloc2::Error Mapper::validateBufferDescriptorInfo( + const IMapper::BufferDescriptorInfo& descriptorInfo) const { + uint64_t validUsageBits = getValid10UsageBits(); + if (mMapperV2_1 != nullptr) { + validUsageBits = validUsageBits | getValid11UsageBits(); + } + + if (descriptorInfo.usage & ~validUsageBits) { + ALOGE("buffer descriptor contains invalid usage bits 0x%" PRIx64, + descriptorInfo.usage & ~validUsageBits); + return Error::BAD_VALUE; + } + return Error::NONE; } Error Mapper::createDescriptor( const IMapper::BufferDescriptorInfo& descriptorInfo, BufferDescriptor* outDescriptor) const { - Error error; - auto ret = mMapper->createDescriptor(descriptorInfo, - [&](const auto& tmpError, const auto& tmpDescriptor) - { - error = tmpError; - if (error != Error::NONE) { - return; - } + Error error = validateBufferDescriptorInfo(descriptorInfo); + if (error != Error::NONE) { + return error; + } - *outDescriptor = tmpDescriptor; - }); + auto hidl_cb = [&](const auto& tmpError, const auto& tmpDescriptor) + { + error = tmpError; + if (error != Error::NONE) { + return; + } + + *outDescriptor = tmpDescriptor; + }; + + hardware::Return<void> ret; + if (mMapperV2_1 != nullptr) { + ret = mMapperV2_1->createDescriptor_2_1(descriptorInfo, hidl_cb); + } else { + const hardware::graphics::mapper::V2_0::IMapper::BufferDescriptorInfo info = { + descriptorInfo.width, + descriptorInfo.height, + descriptorInfo.layerCount, + static_cast<hardware::graphics::common::V1_0::PixelFormat>(descriptorInfo.format), + descriptorInfo.usage, + }; + ret = mMapper->createDescriptor(info, hidl_cb); + } return (ret.isOk()) ? error : kTransactionError; } @@ -91,6 +161,50 @@ void Mapper::freeBuffer(buffer_handle_t bufferHandle) const buffer, error); } +Error Mapper::validateBufferSize(buffer_handle_t bufferHandle, + const IMapper::BufferDescriptorInfo& descriptorInfo, + uint32_t stride) const +{ + if (mMapperV2_1 == nullptr) { + return Error::NONE; + } + + auto buffer = const_cast<native_handle_t*>(bufferHandle); + auto ret = mMapperV2_1->validateBufferSize(buffer, descriptorInfo, stride); + + return (ret.isOk()) ? static_cast<Error>(ret) : kTransactionError; +} + +void Mapper::getTransportSize(buffer_handle_t bufferHandle, + uint32_t* outNumFds, uint32_t* outNumInts) const +{ + *outNumFds = uint32_t(bufferHandle->numFds); + *outNumInts = uint32_t(bufferHandle->numInts); + + if (mMapperV2_1 == nullptr) { + return; + } + + Error error; + auto buffer = const_cast<native_handle_t*>(bufferHandle); + auto ret = mMapperV2_1->getTransportSize(buffer, + [&](const auto& tmpError, const auto& tmpNumFds, const auto& tmpNumInts) { + error = tmpError; + if (error != Error::NONE) { + return; + } + + *outNumFds = tmpNumFds; + *outNumInts = tmpNumInts; + }); + + if (!ret.isOk()) { + error = kTransactionError; + } + ALOGE_IF(error != Error::NONE, "getTransportSize(%p) failed with %d", + buffer, error); +} + Error Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const IMapper::Rect& accessRegion, int acquireFence, void** outData) const diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index c8805000a4..254038b0ad 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -22,6 +22,7 @@ #include <grallocusage/GrallocUsageConversion.h> +#include <ui/DetachedBufferHandle.h> #include <ui/Gralloc2.h> #include <ui/GraphicBufferAllocator.h> #include <ui/GraphicBufferMapper.h> @@ -170,6 +171,8 @@ status_t GraphicBuffer::initWithSize(uint32_t inWidth, uint32_t inHeight, inUsage, &handle, &outStride, mId, std::move(requestorName)); if (err == NO_ERROR) { + mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts); + width = static_cast<int>(inWidth); height = static_cast<int>(inHeight); format = inFormat; @@ -199,7 +202,8 @@ status_t GraphicBuffer::initWithHandle(const native_handle_t* handle, if (method == TAKE_UNREGISTERED_HANDLE || method == CLONE_HANDLE) { buffer_handle_t importedHandle; - status_t err = mBufferMapper.importBuffer(handle, &importedHandle); + status_t err = mBufferMapper.importBuffer(handle, width, height, + layerCount, format, usage, stride, &importedHandle); if (err != NO_ERROR) { initWithHandle(nullptr, WRAP_HANDLE, 0, 0, 0, 0, 0, 0); @@ -212,6 +216,7 @@ status_t GraphicBuffer::initWithHandle(const native_handle_t* handle, } handle = importedHandle; + mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts); } ANativeWindowBuffer::handle = handle; @@ -323,11 +328,11 @@ status_t GraphicBuffer::unlockAsync(int *fenceFd) } size_t GraphicBuffer::getFlattenedSize() const { - return static_cast<size_t>(13 + (handle ? handle->numInts : 0)) * sizeof(int); + return static_cast<size_t>(13 + (handle ? mTransportNumInts : 0)) * sizeof(int); } size_t GraphicBuffer::getFdCount() const { - return static_cast<size_t>(handle ? handle->numFds : 0); + return static_cast<size_t>(handle ? mTransportNumFds : 0); } status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const { @@ -353,18 +358,18 @@ status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& buf[12] = int(usage >> 32); // high 32-bits if (handle) { - buf[10] = handle->numFds; - buf[11] = handle->numInts; - memcpy(fds, handle->data, static_cast<size_t>(handle->numFds) * sizeof(int)); + buf[10] = int32_t(mTransportNumFds); + buf[11] = int32_t(mTransportNumInts); + memcpy(fds, handle->data, static_cast<size_t>(mTransportNumFds) * sizeof(int)); memcpy(buf + 13, handle->data + handle->numFds, - static_cast<size_t>(handle->numInts) * sizeof(int)); + static_cast<size_t>(mTransportNumInts) * sizeof(int)); } buffer = static_cast<void*>(static_cast<uint8_t*>(buffer) + sizeNeeded); size -= sizeNeeded; if (handle) { - fds += handle->numFds; - count -= static_cast<size_t>(handle->numFds); + fds += mTransportNumFds; + count -= static_cast<size_t>(mTransportNumFds); } return NO_ERROR; @@ -457,7 +462,8 @@ status_t GraphicBuffer::unflatten( if (handle != 0) { buffer_handle_t importedHandle; - status_t err = mBufferMapper.importBuffer(handle, &importedHandle); + status_t err = mBufferMapper.importBuffer(handle, uint32_t(width), uint32_t(height), + uint32_t(layerCount), format, usage, uint32_t(stride), &importedHandle); if (err != NO_ERROR) { width = height = stride = format = usage_deprecated = 0; layerCount = 0; @@ -470,6 +476,7 @@ status_t GraphicBuffer::unflatten( native_handle_close(handle); native_handle_delete(const_cast<native_handle_t*>(handle)); handle = importedHandle; + mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts); } buffer = static_cast<void const*>(static_cast<uint8_t const*>(buffer) + sizeNeeded); @@ -480,6 +487,24 @@ status_t GraphicBuffer::unflatten( return NO_ERROR; } +bool GraphicBuffer::isDetachedBuffer() const { + return mDetachedBufferHandle && mDetachedBufferHandle->isValid(); +} + +status_t GraphicBuffer::setDetachedBufferHandle(std::unique_ptr<DetachedBufferHandle> channel) { + if (isDetachedBuffer()) { + ALOGW("setDetachedBuffer: there is already a BufferHub channel associated with this " + "GraphicBuffer. Replacing the old one."); + } + + mDetachedBufferHandle = std::move(channel); + return NO_ERROR; +} + +std::unique_ptr<DetachedBufferHandle> GraphicBuffer::takeDetachedBufferHandle() { + return std::move(mDetachedBufferHandle); +} + // --------------------------------------------------------------------------- }; // namespace android diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp index d85448968a..2d8e5824b0 100644 --- a/libs/ui/GraphicBufferMapper.cpp +++ b/libs/ui/GraphicBufferMapper.cpp @@ -52,17 +52,43 @@ GraphicBufferMapper::GraphicBufferMapper() } status_t GraphicBufferMapper::importBuffer(buffer_handle_t rawHandle, + uint32_t width, uint32_t height, uint32_t layerCount, + PixelFormat format, uint64_t usage, uint32_t stride, buffer_handle_t* outHandle) { ATRACE_CALL(); + buffer_handle_t bufferHandle; Gralloc2::Error error = mMapper->importBuffer( - hardware::hidl_handle(rawHandle), outHandle); + hardware::hidl_handle(rawHandle), &bufferHandle); + if (error != Gralloc2::Error::NONE) { + ALOGW("importBuffer(%p) failed: %d", rawHandle, error); + return static_cast<status_t>(error); + } + + Gralloc2::IMapper::BufferDescriptorInfo info = {}; + info.width = width; + info.height = height; + info.layerCount = layerCount; + info.format = static_cast<Gralloc2::PixelFormat>(format); + info.usage = usage; + + error = mMapper->validateBufferSize(bufferHandle, info, stride); + if (error != Gralloc2::Error::NONE) { + ALOGE("validateBufferSize(%p) failed: %d", rawHandle, error); + freeBuffer(bufferHandle); + return static_cast<status_t>(error); + } - ALOGW_IF(error != Gralloc2::Error::NONE, "importBuffer(%p) failed: %d", - rawHandle, error); + *outHandle = bufferHandle; - return static_cast<status_t>(error); + return NO_ERROR; +} + +void GraphicBufferMapper::getTransportSize(buffer_handle_t handle, + uint32_t* outTransportNumFds, uint32_t* outTransportNumInts) +{ + mMapper->getTransportSize(handle, outTransportNumFds, outTransportNumInts); } status_t GraphicBufferMapper::freeBuffer(buffer_handle_t handle) diff --git a/libs/ui/HdrCapabilities.cpp b/libs/ui/HdrCapabilities.cpp index 755e60c82e..a36911d1cf 100644 --- a/libs/ui/HdrCapabilities.cpp +++ b/libs/ui/HdrCapabilities.cpp @@ -27,13 +27,12 @@ HdrCapabilities::~HdrCapabilities() = default; HdrCapabilities::HdrCapabilities(HdrCapabilities&& other) = default; HdrCapabilities& HdrCapabilities::operator=(HdrCapabilities&& other) = default; - size_t HdrCapabilities::getFlattenedSize() const { return sizeof(mMaxLuminance) + sizeof(mMaxAverageLuminance) + sizeof(mMinLuminance) + sizeof(int32_t) + - mSupportedHdrTypes.size() * sizeof(int32_t); + mSupportedHdrTypes.size() * sizeof(ui::Hdr); } status_t HdrCapabilities::flatten(void* buffer, size_t size) const { @@ -48,7 +47,7 @@ status_t HdrCapabilities::flatten(void* buffer, size_t size) const { reinterpret_cast<float&>(buf[2]) = mMinLuminance; buf[3] = static_cast<int32_t>(mSupportedHdrTypes.size()); for (size_t i = 0, c = mSupportedHdrTypes.size(); i < c; ++i) { - buf[4 + i] = mSupportedHdrTypes[i]; + buf[4 + i] = static_cast<int32_t>(mSupportedHdrTypes[i]); } return NO_ERROR; } @@ -78,7 +77,7 @@ status_t HdrCapabilities::unflatten(void const* buffer, size_t size) { if (itemCount) { mSupportedHdrTypes.resize(itemCount); for (size_t i = 0; i < itemCount; ++i) { - mSupportedHdrTypes[i] = buf[4 + i]; + mSupportedHdrTypes[i] = static_cast<ui::Hdr>(buf[4 + i]); } } return NO_ERROR; diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp index b53c563624..fe4ae6c414 100644 --- a/libs/ui/Region.cpp +++ b/libs/ui/Region.cpp @@ -513,6 +513,12 @@ void Region::rasterizer::flushSpan() bool Region::validate(const Region& reg, const char* name, bool silent) { + if (reg.mStorage.isEmpty()) { + ALOGE_IF(!silent, "%s: mStorage is empty, which is never valid", name); + // return immediately as the code below assumes mStorage is non-empty + return false; + } + bool result = true; const_iterator cur = reg.begin(); const_iterator const tail = reg.end(); @@ -832,6 +838,11 @@ Region::const_iterator Region::begin() const { } Region::const_iterator Region::end() const { + // Workaround for b/77643177 + // mStorage should never be empty, but somehow it is and it's causing + // an abort in ubsan + if (mStorage.isEmpty()) return mStorage.array(); + size_t numRects = isRect() ? 1 : mStorage.size() - 1; return mStorage.array() + numRects; } diff --git a/libs/ui/include/ui/DebugUtils.h b/libs/ui/include/ui/DebugUtils.h index dad9446b3a..92b2bfb282 100644 --- a/libs/ui/include/ui/DebugUtils.h +++ b/libs/ui/include/ui/DebugUtils.h @@ -16,7 +16,7 @@ #pragma once -#include <system/graphics.h> +#include <ui/GraphicTypes.h> #include <ui/PixelFormat.h> #include <string> @@ -29,6 +29,8 @@ std::string decodeStandard(android_dataspace dataspace); std::string decodeTransfer(android_dataspace dataspace); std::string decodeRange(android_dataspace dataspace); std::string dataspaceDetails(android_dataspace dataspace); -std::string decodeColorMode(android_color_mode colormode); +std::string decodeColorMode(android::ui::ColorMode colormode); +std::string decodeColorTransform(android_color_transform colorTransform); std::string decodePixelFormat(android::PixelFormat format); +std::string decodeRenderIntent(android::ui::RenderIntent renderIntent); std::string to_string(const android::Rect& rect); diff --git a/libs/ui/include/ui/DetachedBufferHandle.h b/libs/ui/include/ui/DetachedBufferHandle.h new file mode 100644 index 0000000000..f3c328d52b --- /dev/null +++ b/libs/ui/include/ui/DetachedBufferHandle.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef ANDROID_DETACHED_BUFFER_HUB_HANDLE_H +#define ANDROID_DETACHED_BUFFER_HUB_HANDLE_H + +#include <pdx/channel_handle.h> + +#include <memory> + +namespace android { + +// A wrapper that holds a pdx::LocalChannelHandle object. From the handle, a BufferHub buffer can be +// created. Current implementation assumes that the underlying transport is using libpdx (thus +// holding a pdx::LocalChannelHandle object), but future implementation can change it to a Binder +// backend if ever needed. +class DetachedBufferHandle { +public: + static std::unique_ptr<DetachedBufferHandle> Create(pdx::LocalChannelHandle handle) { + return std::unique_ptr<DetachedBufferHandle>(new DetachedBufferHandle(std::move(handle))); + } + + // Accessors to get or take the internal pdx::LocalChannelHandle. + pdx::LocalChannelHandle& handle() { return mHandle; } + const pdx::LocalChannelHandle& handle() const { return mHandle; } + + // Returns whether the DetachedBufferHandle holds a BufferHub channel. + bool isValid() const { return mHandle.valid(); } + +private: + // Constructs a DetachedBufferHandle from a pdx::LocalChannelHandle. + explicit DetachedBufferHandle(pdx::LocalChannelHandle handle) : mHandle(std::move(handle)) {} + + pdx::LocalChannelHandle mHandle; +}; + +} // namespace android + +#endif // ANDROID_DETACHED_BUFFER_HUB_HANDLE_H diff --git a/libs/ui/include/ui/Fence.h b/libs/ui/include/ui/Fence.h index 37811bcd7c..ec67fa972c 100644 --- a/libs/ui/include/ui/Fence.h +++ b/libs/ui/include/ui/Fence.h @@ -19,6 +19,7 @@ #include <stdint.h> +#include <android-base/unique_fd.h> #include <utils/Flattenable.h> #include <utils/RefBase.h> #include <utils/Timers.h> @@ -49,12 +50,13 @@ public: // Construct a new Fence object with an invalid file descriptor. This // should be done when the Fence object will be set up by unflattening // serialized data. - Fence(); + Fence() = default; // Construct a new Fence object to manage a given fence file descriptor. // When the new Fence object is destructed the file descriptor will be // closed. explicit Fence(int fenceFd); + explicit Fence(base::unique_fd fenceFd); // Not copyable or movable. Fence(const Fence& rhs) = delete; @@ -136,9 +138,9 @@ public: private: // Only allow instantiation using ref counting. friend class LightRefBase<Fence>; - ~Fence(); + ~Fence() = default; - int mFenceFd; + base::unique_fd mFenceFd; }; }; // namespace android diff --git a/libs/ui/include/ui/Gralloc2.h b/libs/ui/include/ui/Gralloc2.h index 8aee16033a..5a8dbda5d3 100644 --- a/libs/ui/include/ui/Gralloc2.h +++ b/libs/ui/include/ui/Gralloc2.h @@ -20,7 +20,9 @@ #include <string> #include <android/hardware/graphics/allocator/2.0/IAllocator.h> +#include <android/hardware/graphics/common/1.1/types.h> #include <android/hardware/graphics/mapper/2.0/IMapper.h> +#include <android/hardware/graphics/mapper/2.1/IMapper.h> #include <utils/StrongPointer.h> namespace android { @@ -28,11 +30,11 @@ namespace android { namespace Gralloc2 { using hardware::graphics::allocator::V2_0::IAllocator; -using hardware::graphics::common::V1_0::BufferUsage; -using hardware::graphics::common::V1_0::PixelFormat; +using hardware::graphics::common::V1_1::BufferUsage; +using hardware::graphics::common::V1_1::PixelFormat; +using hardware::graphics::mapper::V2_1::IMapper; using hardware::graphics::mapper::V2_0::BufferDescriptor; using hardware::graphics::mapper::V2_0::Error; -using hardware::graphics::mapper::V2_0::IMapper; using hardware::graphics::mapper::V2_0::YCbCrLayout; // A wrapper to IMapper @@ -55,6 +57,13 @@ public: void freeBuffer(buffer_handle_t bufferHandle) const; + Error validateBufferSize(buffer_handle_t bufferHandle, + const IMapper::BufferDescriptorInfo& descriptorInfo, + uint32_t stride) const; + + void getTransportSize(buffer_handle_t bufferHandle, + uint32_t* outNumFds, uint32_t* outNumInts) const; + // The ownership of acquireFence is always transferred to the callee, even // on errors. Error lock(buffer_handle_t bufferHandle, uint64_t usage, @@ -72,7 +81,12 @@ public: int unlock(buffer_handle_t bufferHandle) const; private: - sp<IMapper> mMapper; + // Determines whether the passed info is compatible with the mapper. + Error validateBufferDescriptorInfo( + const IMapper::BufferDescriptorInfo& descriptorInfo) const; + + sp<hardware::graphics::mapper::V2_0::IMapper> mMapper; + sp<IMapper> mMapperV2_1; }; // A wrapper to IAllocator diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h index 95c2d2272e..cc38982e64 100644 --- a/libs/ui/include/ui/GraphicBuffer.h +++ b/libs/ui/include/ui/GraphicBuffer.h @@ -34,6 +34,7 @@ namespace android { +class DetachedBufferHandle; class GraphicBufferMapper; // =========================================================================== @@ -190,6 +191,11 @@ public: status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const; status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count); + // Sets and takes DetachedBuffer. Should only be called from BufferHub. + bool isDetachedBuffer() const; + status_t setDetachedBufferHandle(std::unique_ptr<DetachedBufferHandle> detachedBuffer); + std::unique_ptr<DetachedBufferHandle> takeDetachedBufferHandle(); + private: ~GraphicBuffer(); @@ -230,12 +236,27 @@ private: GraphicBufferMapper& mBufferMapper; ssize_t mInitCheck; + // numbers of fds/ints in native_handle_t to flatten + uint32_t mTransportNumFds; + uint32_t mTransportNumInts; + uint64_t mId; // Stores the generation number of this buffer. If this number does not // match the BufferQueue's internal generation number (set through // IGBP::setGenerationNumber), attempts to attach the buffer will fail. uint32_t mGenerationNumber; + + // Stores a BufferHub handle that can be used to re-attach this GraphicBuffer back into a + // BufferHub producer/consumer set. In terms of GraphicBuffer's relationship with BufferHub, + // there are three different modes: + // 1. Legacy mode: GraphicBuffer is not backed by BufferHub and mDetachedBufferHandle must be + // invalid. + // 2. Detached mode: GraphicBuffer is backed by BufferHub, but not part of a producer/consumer + // set. In this mode, mDetachedBufferHandle must be valid. + // 3. Attached mode: GraphicBuffer is backed by BufferHub and it's part of a producer/consumer + // set. In this mode, mDetachedBufferHandle must be invalid. + std::unique_ptr<DetachedBufferHandle> mDetachedBufferHandle; }; }; // namespace android diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h index 06961b11b5..7cf003dcba 100644 --- a/libs/ui/include/ui/GraphicBufferMapper.h +++ b/libs/ui/include/ui/GraphicBufferMapper.h @@ -22,6 +22,7 @@ #include <memory> +#include <ui/PixelFormat.h> #include <utils/Singleton.h> @@ -49,10 +50,15 @@ public: // The imported outHandle must be freed with freeBuffer when no longer // needed. rawHandle is owned by the caller. status_t importBuffer(buffer_handle_t rawHandle, + uint32_t width, uint32_t height, uint32_t layerCount, + PixelFormat format, uint64_t usage, uint32_t stride, buffer_handle_t* outHandle); status_t freeBuffer(buffer_handle_t handle); + void getTransportSize(buffer_handle_t handle, + uint32_t* outTransportNumFds, uint32_t* outTransportNumInts); + status_t lock(buffer_handle_t handle, uint32_t usage, const Rect& bounds, void** vaddr); diff --git a/libs/ui/include/ui/GraphicTypes.h b/libs/ui/include/ui/GraphicTypes.h new file mode 100644 index 0000000000..0fa819dce8 --- /dev/null +++ b/libs/ui/include/ui/GraphicTypes.h @@ -0,0 +1,34 @@ +/* + * Copyright 2018 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. + */ + +#pragma once + +#include <android/hardware/graphics/common/1.1/types.h> +#include <system/graphics.h> + +// android::ui::* in this header file will alias different types as +// the HIDL interface is updated. +namespace android { +namespace ui { + +using android::hardware::graphics::common::V1_0::Hdr; +using android::hardware::graphics::common::V1_1::ColorMode; +using android::hardware::graphics::common::V1_1::Dataspace; +using android::hardware::graphics::common::V1_1::PixelFormat; +using android::hardware::graphics::common::V1_1::RenderIntent; + +} // namespace ui +} // namespace android diff --git a/libs/ui/include/ui/HdrCapabilities.h b/libs/ui/include/ui/HdrCapabilities.h index 925aa1b7b3..4e98c283d1 100644 --- a/libs/ui/include/ui/HdrCapabilities.h +++ b/libs/ui/include/ui/HdrCapabilities.h @@ -21,6 +21,7 @@ #include <vector> +#include <ui/GraphicTypes.h> #include <utils/Flattenable.h> namespace android { @@ -28,7 +29,7 @@ namespace android { class HdrCapabilities : public LightFlattenable<HdrCapabilities> { public: - HdrCapabilities(const std::vector<int32_t /*android_hdr_t*/>& types, + HdrCapabilities(const std::vector<ui::Hdr>& types, float maxLuminance, float maxAverageLuminance, float minLuminance) : mSupportedHdrTypes(types), mMaxLuminance(maxLuminance), @@ -47,7 +48,7 @@ public: ~HdrCapabilities(); - const std::vector<int32_t /*android_hdr_t*/>& getSupportedHdrTypes() const { + const std::vector<ui::Hdr>& getSupportedHdrTypes() const { return mSupportedHdrTypes; } float getDesiredMaxLuminance() const { return mMaxLuminance; } @@ -61,7 +62,7 @@ public: status_t unflatten(void const* buffer, size_t size); private: - std::vector<int32_t /*android_hdr_t*/> mSupportedHdrTypes; + std::vector<ui::Hdr> mSupportedHdrTypes; float mMaxLuminance; float mMaxAverageLuminance; float mMinLuminance; diff --git a/libs/ui/include/ui/Rect.h b/libs/ui/include/ui/Rect.h index c099a026aa..0bec0b7f78 100644 --- a/libs/ui/include/ui/Rect.h +++ b/libs/ui/include/ui/Rect.h @@ -95,15 +95,18 @@ public: } // rectangle's width + __attribute__((no_sanitize("signed-integer-overflow"))) inline int32_t getWidth() const { return right - left; } // rectangle's height + __attribute__((no_sanitize("signed-integer-overflow"))) inline int32_t getHeight() const { return bottom - top; } + __attribute__((no_sanitize("signed-integer-overflow"))) inline Rect getBounds() const { return Rect(right - left, bottom - top); } diff --git a/libs/ui/include_vndk/ui/ANativeObjectBase.h b/libs/ui/include_vndk/ui/ANativeObjectBase.h new file mode 120000 index 0000000000..4dab8d8b8b --- /dev/null +++ b/libs/ui/include_vndk/ui/ANativeObjectBase.h @@ -0,0 +1 @@ +../../include/ui/ANativeObjectBase.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/BufferQueueDefs.h b/libs/ui/include_vndk/ui/BufferQueueDefs.h new file mode 120000 index 0000000000..c886ed858e --- /dev/null +++ b/libs/ui/include_vndk/ui/BufferQueueDefs.h @@ -0,0 +1 @@ +../../include/ui/BufferQueueDefs.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/ColorSpace.h b/libs/ui/include_vndk/ui/ColorSpace.h new file mode 120000 index 0000000000..ddf70d5bdf --- /dev/null +++ b/libs/ui/include_vndk/ui/ColorSpace.h @@ -0,0 +1 @@ +../../include/ui/ColorSpace.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/DebugUtils.h b/libs/ui/include_vndk/ui/DebugUtils.h new file mode 120000 index 0000000000..8461bb39c3 --- /dev/null +++ b/libs/ui/include_vndk/ui/DebugUtils.h @@ -0,0 +1 @@ +../../include/ui/DebugUtils.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/DisplayInfo.h b/libs/ui/include_vndk/ui/DisplayInfo.h new file mode 120000 index 0000000000..75f14cf66d --- /dev/null +++ b/libs/ui/include_vndk/ui/DisplayInfo.h @@ -0,0 +1 @@ +../../include/ui/DisplayInfo.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/DisplayStatInfo.h b/libs/ui/include_vndk/ui/DisplayStatInfo.h new file mode 120000 index 0000000000..6689ad3162 --- /dev/null +++ b/libs/ui/include_vndk/ui/DisplayStatInfo.h @@ -0,0 +1 @@ +../../include/ui/DisplayStatInfo.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/Fence.h b/libs/ui/include_vndk/ui/Fence.h new file mode 120000 index 0000000000..b110201354 --- /dev/null +++ b/libs/ui/include_vndk/ui/Fence.h @@ -0,0 +1 @@ +../../include/ui/Fence.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/FenceTime.h b/libs/ui/include_vndk/ui/FenceTime.h new file mode 120000 index 0000000000..01a6ff21d1 --- /dev/null +++ b/libs/ui/include_vndk/ui/FenceTime.h @@ -0,0 +1 @@ +../../include/ui/FenceTime.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/FloatRect.h b/libs/ui/include_vndk/ui/FloatRect.h new file mode 120000 index 0000000000..a5262118f7 --- /dev/null +++ b/libs/ui/include_vndk/ui/FloatRect.h @@ -0,0 +1 @@ +../../include/ui/FloatRect.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/FrameStats.h b/libs/ui/include_vndk/ui/FrameStats.h new file mode 120000 index 0000000000..e68e5c843f --- /dev/null +++ b/libs/ui/include_vndk/ui/FrameStats.h @@ -0,0 +1 @@ +../../include/ui/FrameStats.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/Gralloc2.h b/libs/ui/include_vndk/ui/Gralloc2.h new file mode 120000 index 0000000000..66098c4edb --- /dev/null +++ b/libs/ui/include_vndk/ui/Gralloc2.h @@ -0,0 +1 @@ +../../include/ui/Gralloc2.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/GraphicBuffer.h b/libs/ui/include_vndk/ui/GraphicBuffer.h new file mode 120000 index 0000000000..445eae5395 --- /dev/null +++ b/libs/ui/include_vndk/ui/GraphicBuffer.h @@ -0,0 +1 @@ +../../include/ui/GraphicBuffer.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/GraphicBufferAllocator.h b/libs/ui/include_vndk/ui/GraphicBufferAllocator.h new file mode 120000 index 0000000000..96345330f1 --- /dev/null +++ b/libs/ui/include_vndk/ui/GraphicBufferAllocator.h @@ -0,0 +1 @@ +../../include/ui/GraphicBufferAllocator.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/GraphicBufferMapper.h b/libs/ui/include_vndk/ui/GraphicBufferMapper.h new file mode 120000 index 0000000000..c3b3a7c61d --- /dev/null +++ b/libs/ui/include_vndk/ui/GraphicBufferMapper.h @@ -0,0 +1 @@ +../../include/ui/GraphicBufferMapper.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/GraphicTypes.h b/libs/ui/include_vndk/ui/GraphicTypes.h new file mode 120000 index 0000000000..b1859e0f51 --- /dev/null +++ b/libs/ui/include_vndk/ui/GraphicTypes.h @@ -0,0 +1 @@ +../../include/ui/GraphicTypes.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/HdrCapabilities.h b/libs/ui/include_vndk/ui/HdrCapabilities.h new file mode 120000 index 0000000000..a240828c8c --- /dev/null +++ b/libs/ui/include_vndk/ui/HdrCapabilities.h @@ -0,0 +1 @@ +../../include/ui/HdrCapabilities.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/PixelFormat.h b/libs/ui/include_vndk/ui/PixelFormat.h new file mode 120000 index 0000000000..0aba056f58 --- /dev/null +++ b/libs/ui/include_vndk/ui/PixelFormat.h @@ -0,0 +1 @@ +../../include/ui/PixelFormat.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/Point.h b/libs/ui/include_vndk/ui/Point.h new file mode 120000 index 0000000000..0aeda3e97e --- /dev/null +++ b/libs/ui/include_vndk/ui/Point.h @@ -0,0 +1 @@ +../../include/ui/Point.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/Rect.h b/libs/ui/include_vndk/ui/Rect.h new file mode 120000 index 0000000000..01ed6891e9 --- /dev/null +++ b/libs/ui/include_vndk/ui/Rect.h @@ -0,0 +1 @@ +../../include/ui/Rect.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/Region.h b/libs/ui/include_vndk/ui/Region.h new file mode 120000 index 0000000000..3f829bfad0 --- /dev/null +++ b/libs/ui/include_vndk/ui/Region.h @@ -0,0 +1 @@ +../../include/ui/Region.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/UiConfig.h b/libs/ui/include_vndk/ui/UiConfig.h new file mode 120000 index 0000000000..f580ce1095 --- /dev/null +++ b/libs/ui/include_vndk/ui/UiConfig.h @@ -0,0 +1 @@ +../../include/ui/UiConfig.h
\ No newline at end of file diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp index 08067fcf5d..aef6428cc8 100644 --- a/libs/ui/tests/Android.bp +++ b/libs/ui/tests/Android.bp @@ -27,3 +27,10 @@ cc_test { srcs: ["colorspace_test.cpp"], cflags: ["-Wall", "-Werror"], } + +cc_test { + name: "GraphicBuffer_test", + shared_libs: ["libpdx_default_transport", "libui", "libutils"], + srcs: ["GraphicBuffer_test.cpp"], + cflags: ["-Wall", "-Werror"], +} diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp new file mode 100644 index 0000000000..eb679ac236 --- /dev/null +++ b/libs/ui/tests/GraphicBuffer_test.cpp @@ -0,0 +1,64 @@ +/* + * Copyright 2018 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 "GraphicBufferTest" + +#include <ui/DetachedBufferHandle.h> +#include <ui/GraphicBuffer.h> + +#include <gtest/gtest.h> + +namespace android { + +namespace { + +constexpr uint32_t kTestWidth = 1024; +constexpr uint32_t kTestHeight = 1; +constexpr uint32_t kTestFormat = HAL_PIXEL_FORMAT_BLOB; +constexpr uint32_t kTestLayerCount = 1; +constexpr uint64_t kTestUsage = GraphicBuffer::USAGE_SW_WRITE_OFTEN; + +} // namespace + +class GraphicBufferTest : public testing::Test {}; + +TEST_F(GraphicBufferTest, DetachedBuffer) { + sp<GraphicBuffer> buffer( + new GraphicBuffer(kTestWidth, kTestHeight, kTestFormat, kTestLayerCount, kTestUsage)); + + // Currently a newly allocated GraphicBuffer is in legacy mode, i.e. not associated with + // BufferHub. But this may change in the future. + EXPECT_FALSE(buffer->isDetachedBuffer()); + + pdx::LocalChannelHandle channel{nullptr, 1234}; + EXPECT_TRUE(channel.valid()); + + std::unique_ptr<DetachedBufferHandle> handle = DetachedBufferHandle::Create(std::move(channel)); + EXPECT_FALSE(channel.valid()); + EXPECT_TRUE(handle->isValid()); + EXPECT_TRUE(handle->handle().valid()); + + buffer->setDetachedBufferHandle(std::move(handle)); + EXPECT_TRUE(handle == nullptr); + EXPECT_TRUE(buffer->isDetachedBuffer()); + + handle = buffer->takeDetachedBufferHandle(); + EXPECT_TRUE(handle != nullptr); + EXPECT_TRUE(handle->isValid()); + EXPECT_FALSE(buffer->isDetachedBuffer()); +} + +} // namespace android diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp index a13160fa06..69b6422d1d 100644 --- a/libs/vr/libbufferhub/Android.bp +++ b/libs/vr/libbufferhub/Android.bp @@ -15,6 +15,7 @@ sourceFiles = [ "buffer_hub_client.cpp", "buffer_hub_rpc.cpp", + "detached_buffer.cpp", "ion_buffer.cpp", ] @@ -22,19 +23,16 @@ localIncludeFiles = [ "include", ] -staticLibraries = [ - "libdvrcommon", - "libpdx_default_transport", -] - sharedLibraries = [ "libbase", + "libbinder", "libcutils", "libhardware", "liblog", "libui", "libutils", - "libnativewindow" + "libnativewindow", + "libpdx_default_transport", ] headerLibraries = [ @@ -52,7 +50,6 @@ cc_library { "-Werror", ], export_include_dirs: localIncludeFiles, - static_libs: staticLibraries, shared_libs: sharedLibraries, header_libs: headerLibraries, name: "libbufferhub", @@ -62,9 +59,10 @@ cc_library { } cc_test { - srcs: ["bufferhub_tests.cpp"], - static_libs: ["libbufferhub"] + staticLibraries, + srcs: ["buffer_hub-test.cpp"], + static_libs: ["libbufferhub"], shared_libs: sharedLibraries, header_libs: headerLibraries, - name: "bufferhub_tests", + name: "buffer_hub-test", } + diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp new file mode 100644 index 0000000000..e24739845d --- /dev/null +++ b/libs/vr/libbufferhub/buffer_hub-test.cpp @@ -0,0 +1,947 @@ +#include <gtest/gtest.h> +#include <poll.h> +#include <private/dvr/buffer_hub_client.h> +#include <private/dvr/bufferhub_rpc.h> +#include <private/dvr/detached_buffer.h> +#include <sys/epoll.h> +#include <sys/eventfd.h> +#include <ui/DetachedBufferHandle.h> + +#include <mutex> +#include <thread> + +#define RETRY_EINTR(fnc_call) \ + ([&]() -> decltype(fnc_call) { \ + decltype(fnc_call) result; \ + do { \ + result = (fnc_call); \ + } while (result == -1 && errno == EINTR); \ + return result; \ + })() + +using android::GraphicBuffer; +using android::sp; +using android::dvr::BufferConsumer; +using android::dvr::BufferProducer; +using android::dvr::DetachedBuffer; +using android::dvr::BufferHubDefs::IsBufferAcquired; +using android::dvr::BufferHubDefs::IsBufferGained; +using android::dvr::BufferHubDefs::IsBufferPosted; +using android::dvr::BufferHubDefs::IsBufferReleased; +using android::dvr::BufferHubDefs::kConsumerStateMask; +using android::dvr::BufferHubDefs::kMetadataHeaderSize; +using android::dvr::BufferHubDefs::kProducerStateBit; +using android::pdx::LocalChannelHandle; +using android::pdx::LocalHandle; +using android::pdx::Status; + +const int kWidth = 640; +const int kHeight = 480; +const int kLayerCount = 1; +const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888; +const int kUsage = 0; +const size_t kUserMetadataSize = 0; +const uint64_t kContext = 42; +const size_t kMaxConsumerCount = 63; +const int kPollTimeoutMs = 100; + +using LibBufferHubTest = ::testing::Test; + +TEST_F(LibBufferHubTest, TestBasicUsage) { + std::unique_ptr<BufferProducer> p = BufferProducer::Create( + kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); + ASSERT_TRUE(p.get() != nullptr); + std::unique_ptr<BufferConsumer> c = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(c.get() != nullptr); + // Check that consumers can spawn other consumers. + std::unique_ptr<BufferConsumer> c2 = + BufferConsumer::Import(c->CreateConsumer()); + ASSERT_TRUE(c2.get() != nullptr); + + // Producer state mask is unique, i.e. 1. + EXPECT_EQ(p->buffer_state_bit(), kProducerStateBit); + // Consumer state mask cannot have producer bit on. + EXPECT_EQ(c->buffer_state_bit() & kProducerStateBit, 0U); + // Consumer state mask must be a single, i.e. power of 2. + EXPECT_NE(c->buffer_state_bit(), 0U); + EXPECT_EQ(c->buffer_state_bit() & (c->buffer_state_bit() - 1), 0U); + // Consumer state mask cannot have producer bit on. + EXPECT_EQ(c2->buffer_state_bit() & kProducerStateBit, 0U); + // Consumer state mask must be a single, i.e. power of 2. + EXPECT_NE(c2->buffer_state_bit(), 0U); + EXPECT_EQ(c2->buffer_state_bit() & (c2->buffer_state_bit() - 1), 0U); + // Each consumer should have unique bit. + EXPECT_EQ(c->buffer_state_bit() & c2->buffer_state_bit(), 0U); + + // Initial state: producer not available, consumers not available. + EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); + EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); + EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs))); + + EXPECT_EQ(0, p->Post(LocalHandle(), kContext)); + + // New state: producer not available, consumers available. + EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); + EXPECT_EQ(1, RETRY_EINTR(c->Poll(kPollTimeoutMs))); + EXPECT_EQ(1, RETRY_EINTR(c2->Poll(kPollTimeoutMs))); + + uint64_t context; + LocalHandle fence; + EXPECT_EQ(0, c->Acquire(&fence, &context)); + EXPECT_EQ(kContext, context); + EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); + EXPECT_EQ(1, RETRY_EINTR(c2->Poll(kPollTimeoutMs))); + + EXPECT_EQ(0, c2->Acquire(&fence, &context)); + EXPECT_EQ(kContext, context); + EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs))); + EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); + + EXPECT_EQ(0, c->Release(LocalHandle())); + EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); + EXPECT_EQ(0, c2->Discard()); + + EXPECT_EQ(1, RETRY_EINTR(p->Poll(kPollTimeoutMs))); + EXPECT_EQ(0, p->Gain(&fence)); + EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); + EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); + EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs))); +} + +TEST_F(LibBufferHubTest, TestEpoll) { + std::unique_ptr<BufferProducer> p = BufferProducer::Create( + kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); + ASSERT_TRUE(p.get() != nullptr); + std::unique_ptr<BufferConsumer> c = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(c.get() != nullptr); + + LocalHandle epoll_fd{epoll_create1(EPOLL_CLOEXEC)}; + ASSERT_TRUE(epoll_fd.IsValid()); + + epoll_event event; + std::array<epoll_event, 64> events; + + auto event_sources = p->GetEventSources(); + ASSERT_LT(event_sources.size(), events.size()); + + for (const auto& event_source : event_sources) { + event = {.events = event_source.event_mask | EPOLLET, + .data = {.fd = p->event_fd()}}; + ASSERT_EQ(0, epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, event_source.event_fd, + &event)); + } + + event_sources = c->GetEventSources(); + ASSERT_LT(event_sources.size(), events.size()); + + for (const auto& event_source : event_sources) { + event = {.events = event_source.event_mask | EPOLLET, + .data = {.fd = c->event_fd()}}; + ASSERT_EQ(0, epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, event_source.event_fd, + &event)); + } + + // No events should be signaled initially. + ASSERT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 0)); + + // Post the producer and check for consumer signal. + EXPECT_EQ(0, p->Post({}, kContext)); + ASSERT_EQ(1, epoll_wait(epoll_fd.Get(), events.data(), events.size(), + kPollTimeoutMs)); + ASSERT_TRUE(events[0].events & EPOLLIN); + ASSERT_EQ(c->event_fd(), events[0].data.fd); + + // Save the event bits to translate later. + event = events[0]; + + // Check for events again. Edge-triggered mode should prevent any. + EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), + kPollTimeoutMs)); + EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), + kPollTimeoutMs)); + EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), + kPollTimeoutMs)); + EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), + kPollTimeoutMs)); + + // Translate the events. + auto event_status = c->GetEventMask(event.events); + ASSERT_TRUE(event_status); + ASSERT_TRUE(event_status.get() & EPOLLIN); + + // Check for events again. Edge-triggered mode should prevent any. + EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), + kPollTimeoutMs)); +} + +TEST_F(LibBufferHubTest, TestStateMask) { + std::unique_ptr<BufferProducer> p = BufferProducer::Create( + kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); + ASSERT_TRUE(p.get() != nullptr); + + // It's ok to create up to kMaxConsumerCount consumer buffers. + uint64_t buffer_state_bits = p->buffer_state_bit(); + std::array<std::unique_ptr<BufferConsumer>, kMaxConsumerCount> cs; + for (size_t i = 0; i < kMaxConsumerCount; i++) { + cs[i] = BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(cs[i].get() != nullptr); + // Expect all buffers have unique state mask. + EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0U); + buffer_state_bits |= cs[i]->buffer_state_bit(); + } + EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask); + + // The 64th creation will fail with out-of-memory error. + auto state = p->CreateConsumer(); + EXPECT_EQ(state.error(), E2BIG); + + // Release any consumer should allow us to re-create. + for (size_t i = 0; i < kMaxConsumerCount; i++) { + buffer_state_bits &= ~cs[i]->buffer_state_bit(); + cs[i] = nullptr; + cs[i] = BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(cs[i].get() != nullptr); + // The released state mask will be reused. + EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0U); + buffer_state_bits |= cs[i]->buffer_state_bit(); + EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask); + } +} + +TEST_F(LibBufferHubTest, TestStateTransitions) { + std::unique_ptr<BufferProducer> p = BufferProducer::Create( + kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); + ASSERT_TRUE(p.get() != nullptr); + std::unique_ptr<BufferConsumer> c = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(c.get() != nullptr); + + uint64_t context; + LocalHandle fence; + + // The producer buffer starts in gained state. + + // Acquire, release, and gain in gained state should fail. + EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context)); + EXPECT_EQ(-EBUSY, c->Release(LocalHandle())); + EXPECT_EQ(-EALREADY, p->Gain(&fence)); + + // Post in gained state should succeed. + EXPECT_EQ(0, p->Post(LocalHandle(), kContext)); + + // Post, release, and gain in posted state should fail. + EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext)); + EXPECT_EQ(-EBUSY, c->Release(LocalHandle())); + EXPECT_EQ(-EBUSY, p->Gain(&fence)); + + // Acquire in posted state should succeed. + EXPECT_LE(0, c->Acquire(&fence, &context)); + + // Acquire, post, and gain in acquired state should fail. + EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context)); + EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext)); + EXPECT_EQ(-EBUSY, p->Gain(&fence)); + + // Release in acquired state should succeed. + EXPECT_EQ(0, c->Release(LocalHandle())); + EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); + + // Release, acquire, and post in released state should fail. + EXPECT_EQ(-EBUSY, c->Release(LocalHandle())); + EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context)); + EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext)); + + // Gain in released state should succeed. + EXPECT_EQ(0, p->Gain(&fence)); + + // Acquire, release, and gain in gained state should fail. + EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context)); + EXPECT_EQ(-EBUSY, c->Release(LocalHandle())); + EXPECT_EQ(-EALREADY, p->Gain(&fence)); +} + +TEST_F(LibBufferHubTest, TestAsyncStateTransitions) { + std::unique_ptr<BufferProducer> p = BufferProducer::Create( + kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); + ASSERT_TRUE(p.get() != nullptr); + std::unique_ptr<BufferConsumer> c = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(c.get() != nullptr); + + DvrNativeBufferMetadata metadata; + LocalHandle invalid_fence; + + // The producer buffer starts in gained state. + + // Acquire, release, and gain in gained state should fail. + EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence)); + EXPECT_FALSE(invalid_fence.IsValid()); + EXPECT_EQ(-EBUSY, c->ReleaseAsync(&metadata, invalid_fence)); + EXPECT_EQ(-EALREADY, p->GainAsync(&metadata, &invalid_fence)); + EXPECT_FALSE(invalid_fence.IsValid()); + + // Post in gained state should succeed. + EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence)); + EXPECT_EQ(p->buffer_state(), c->buffer_state()); + EXPECT_TRUE(IsBufferPosted(p->buffer_state())); + + // Post, release, and gain in posted state should fail. + EXPECT_EQ(-EBUSY, p->PostAsync(&metadata, invalid_fence)); + EXPECT_EQ(-EBUSY, c->ReleaseAsync(&metadata, invalid_fence)); + EXPECT_EQ(-EBUSY, p->GainAsync(&metadata, &invalid_fence)); + EXPECT_FALSE(invalid_fence.IsValid()); + + // Acquire in posted state should succeed. + EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); + EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence)); + EXPECT_FALSE(invalid_fence.IsValid()); + EXPECT_EQ(p->buffer_state(), c->buffer_state()); + EXPECT_TRUE(IsBufferAcquired(p->buffer_state())); + + // Acquire, post, and gain in acquired state should fail. + EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence)); + EXPECT_FALSE(invalid_fence.IsValid()); + EXPECT_EQ(-EBUSY, p->PostAsync(&metadata, invalid_fence)); + EXPECT_EQ(-EBUSY, p->GainAsync(&metadata, &invalid_fence)); + EXPECT_FALSE(invalid_fence.IsValid()); + + // Release in acquired state should succeed. + EXPECT_EQ(0, c->ReleaseAsync(&metadata, invalid_fence)); + EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); + EXPECT_EQ(p->buffer_state(), c->buffer_state()); + EXPECT_TRUE(IsBufferReleased(p->buffer_state())); + + // Release, acquire, and post in released state should fail. + EXPECT_EQ(-EBUSY, c->ReleaseAsync(&metadata, invalid_fence)); + EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence)); + EXPECT_FALSE(invalid_fence.IsValid()); + EXPECT_EQ(-EBUSY, p->PostAsync(&metadata, invalid_fence)); + + // Gain in released state should succeed. + EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence)); + EXPECT_FALSE(invalid_fence.IsValid()); + EXPECT_EQ(p->buffer_state(), c->buffer_state()); + EXPECT_TRUE(IsBufferGained(p->buffer_state())); + + // Acquire, release, and gain in gained state should fail. + EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence)); + EXPECT_FALSE(invalid_fence.IsValid()); + EXPECT_EQ(-EBUSY, c->ReleaseAsync(&metadata, invalid_fence)); + EXPECT_EQ(-EALREADY, p->GainAsync(&metadata, &invalid_fence)); + EXPECT_FALSE(invalid_fence.IsValid()); +} + +TEST_F(LibBufferHubTest, TestZeroConsumer) { + std::unique_ptr<BufferProducer> p = BufferProducer::Create( + kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); + ASSERT_TRUE(p.get() != nullptr); + + DvrNativeBufferMetadata metadata; + LocalHandle invalid_fence; + + // Newly created. + EXPECT_TRUE(IsBufferGained(p->buffer_state())); + EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence)); + EXPECT_TRUE(IsBufferPosted(p->buffer_state())); + + // The buffer should stay in posted stay until a consumer picks it up. + EXPECT_GE(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); + + // A new consumer should still be able to acquire the buffer immediately. + std::unique_ptr<BufferConsumer> c = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(c.get() != nullptr); + EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence)); + EXPECT_TRUE(IsBufferAcquired(c->buffer_state())); +} + +TEST_F(LibBufferHubTest, TestMaxConsumers) { + std::unique_ptr<BufferProducer> p = BufferProducer::Create( + kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); + ASSERT_TRUE(p.get() != nullptr); + + std::array<std::unique_ptr<BufferConsumer>, kMaxConsumerCount> cs; + for (size_t i = 0; i < kMaxConsumerCount; i++) { + cs[i] = BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(cs[i].get() != nullptr); + EXPECT_TRUE(IsBufferGained(cs[i]->buffer_state())); + } + + DvrNativeBufferMetadata metadata; + LocalHandle invalid_fence; + + // Post the producer should trigger all consumers to be available. + EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence)); + EXPECT_TRUE(IsBufferPosted(p->buffer_state())); + for (size_t i = 0; i < kMaxConsumerCount; i++) { + EXPECT_TRUE( + IsBufferPosted(cs[i]->buffer_state(), cs[i]->buffer_state_bit())); + EXPECT_LT(0, RETRY_EINTR(cs[i]->Poll(kPollTimeoutMs))); + EXPECT_EQ(0, cs[i]->AcquireAsync(&metadata, &invalid_fence)); + EXPECT_TRUE(IsBufferAcquired(p->buffer_state())); + } + + // All consumers have to release before the buffer is considered to be + // released. + for (size_t i = 0; i < kMaxConsumerCount; i++) { + EXPECT_FALSE(IsBufferReleased(p->buffer_state())); + EXPECT_EQ(0, cs[i]->ReleaseAsync(&metadata, invalid_fence)); + } + + EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); + EXPECT_TRUE(IsBufferReleased(p->buffer_state())); + + // Buffer state cross all clients must be consistent. + for (size_t i = 0; i < kMaxConsumerCount; i++) { + EXPECT_EQ(p->buffer_state(), cs[i]->buffer_state()); + } +} + +TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferGained) { + std::unique_ptr<BufferProducer> p = BufferProducer::Create( + kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); + ASSERT_TRUE(p.get() != nullptr); + EXPECT_TRUE(IsBufferGained(p->buffer_state())); + + std::unique_ptr<BufferConsumer> c = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(c.get() != nullptr); + EXPECT_TRUE(IsBufferGained(c->buffer_state())); + + DvrNativeBufferMetadata metadata; + LocalHandle invalid_fence; + + // Post the gained buffer should signal already created consumer. + EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence)); + EXPECT_TRUE(IsBufferPosted(p->buffer_state())); + EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); + EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence)); + EXPECT_TRUE(IsBufferAcquired(c->buffer_state())); +} + +TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferPosted) { + std::unique_ptr<BufferProducer> p = BufferProducer::Create( + kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); + ASSERT_TRUE(p.get() != nullptr); + EXPECT_TRUE(IsBufferGained(p->buffer_state())); + + DvrNativeBufferMetadata metadata; + LocalHandle invalid_fence; + + // Post the gained buffer before any consumer gets created. + EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence)); + EXPECT_TRUE(IsBufferPosted(p->buffer_state())); + + // Newly created consumer should be automatically sigalled. + std::unique_ptr<BufferConsumer> c = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(c.get() != nullptr); + EXPECT_TRUE(IsBufferPosted(c->buffer_state())); + EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence)); + EXPECT_TRUE(IsBufferAcquired(c->buffer_state())); +} + +TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferReleased) { + std::unique_ptr<BufferProducer> p = BufferProducer::Create( + kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); + ASSERT_TRUE(p.get() != nullptr); + + std::unique_ptr<BufferConsumer> c1 = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(c1.get() != nullptr); + + DvrNativeBufferMetadata metadata; + LocalHandle invalid_fence; + + // Post, acquire, and release the buffer.. + EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence)); + EXPECT_LT(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs))); + EXPECT_EQ(0, c1->AcquireAsync(&metadata, &invalid_fence)); + EXPECT_EQ(0, c1->ReleaseAsync(&metadata, invalid_fence)); + + // Note that the next PDX call is on the producer channel, which may be + // executed before Release impulse gets executed by bufferhubd. Thus, here we + // need to wait until the releasd is confirmed before creating another + // consumer. + EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); + EXPECT_TRUE(IsBufferReleased(p->buffer_state())); + + // Create another consumer immediately after the release, should not make the + // buffer un-released. + std::unique_ptr<BufferConsumer> c2 = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(c2.get() != nullptr); + + EXPECT_TRUE(IsBufferReleased(p->buffer_state())); + EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence)); + EXPECT_TRUE(IsBufferGained(p->buffer_state())); +} + +TEST_F(LibBufferHubTest, TestWithCustomMetadata) { + struct Metadata { + int64_t field1; + int64_t field2; + }; + std::unique_ptr<BufferProducer> p = BufferProducer::Create( + kWidth, kHeight, kFormat, kUsage, sizeof(Metadata)); + ASSERT_TRUE(p.get() != nullptr); + std::unique_ptr<BufferConsumer> c = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(c.get() != nullptr); + + Metadata m = {1, 3}; + EXPECT_EQ(0, p->Post(LocalHandle(), m)); + EXPECT_LE(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); + + LocalHandle fence; + Metadata m2 = {}; + EXPECT_EQ(0, c->Acquire(&fence, &m2)); + EXPECT_EQ(m.field1, m2.field1); + EXPECT_EQ(m.field2, m2.field2); + + EXPECT_EQ(0, c->Release(LocalHandle())); + EXPECT_LT(0, RETRY_EINTR(p->Poll(0))); +} + +TEST_F(LibBufferHubTest, TestPostWithWrongMetaSize) { + struct Metadata { + int64_t field1; + int64_t field2; + }; + struct OverSizedMetadata { + int64_t field1; + int64_t field2; + int64_t field3; + }; + std::unique_ptr<BufferProducer> p = BufferProducer::Create( + kWidth, kHeight, kFormat, kUsage, sizeof(Metadata)); + ASSERT_TRUE(p.get() != nullptr); + std::unique_ptr<BufferConsumer> c = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(c.get() != nullptr); + + // It is illegal to post metadata larger than originally requested during + // buffer allocation. + OverSizedMetadata evil_meta = {}; + EXPECT_NE(0, p->Post(LocalHandle(), evil_meta)); + EXPECT_GE(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); + + // It is ok to post metadata smaller than originally requested during + // buffer allocation. + int64_t sequence = 42; + EXPECT_EQ(0, p->Post(LocalHandle(), sequence)); +} + +TEST_F(LibBufferHubTest, TestAcquireWithWrongMetaSize) { + struct Metadata { + int64_t field1; + int64_t field2; + }; + struct OverSizedMetadata { + int64_t field1; + int64_t field2; + int64_t field3; + }; + std::unique_ptr<BufferProducer> p = BufferProducer::Create( + kWidth, kHeight, kFormat, kUsage, sizeof(Metadata)); + ASSERT_TRUE(p.get() != nullptr); + std::unique_ptr<BufferConsumer> c = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(c.get() != nullptr); + + Metadata m = {1, 3}; + EXPECT_EQ(0, p->Post(LocalHandle(), m)); + + LocalHandle fence; + int64_t sequence; + OverSizedMetadata e; + + // It is illegal to acquire metadata larger than originally requested during + // buffer allocation. + EXPECT_NE(0, c->Acquire(&fence, &e)); + + // It is ok to acquire metadata smaller than originally requested during + // buffer allocation. + EXPECT_EQ(0, c->Acquire(&fence, &sequence)); + EXPECT_EQ(m.field1, sequence); +} + +TEST_F(LibBufferHubTest, TestAcquireWithNoMeta) { + std::unique_ptr<BufferProducer> p = BufferProducer::Create( + kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); + ASSERT_TRUE(p.get() != nullptr); + std::unique_ptr<BufferConsumer> c = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(c.get() != nullptr); + + int64_t sequence = 3; + EXPECT_EQ(0, p->Post(LocalHandle(), sequence)); + + LocalHandle fence; + EXPECT_EQ(0, c->Acquire(&fence)); +} + +TEST_F(LibBufferHubTest, TestWithNoMeta) { + std::unique_ptr<BufferProducer> p = + BufferProducer::Create(kWidth, kHeight, kFormat, kUsage); + ASSERT_TRUE(p.get() != nullptr); + std::unique_ptr<BufferConsumer> c = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(c.get() != nullptr); + + LocalHandle fence; + + EXPECT_EQ(0, p->Post<void>(LocalHandle())); + EXPECT_EQ(0, c->Acquire(&fence)); +} + +TEST_F(LibBufferHubTest, TestFailureToPostMetaFromABufferWithoutMeta) { + std::unique_ptr<BufferProducer> p = + BufferProducer::Create(kWidth, kHeight, kFormat, kUsage); + ASSERT_TRUE(p.get() != nullptr); + std::unique_ptr<BufferConsumer> c = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(c.get() != nullptr); + + int64_t sequence = 3; + EXPECT_NE(0, p->Post(LocalHandle(), sequence)); +} + +namespace { + +int PollFd(int fd, int timeout_ms) { + pollfd p = {fd, POLLIN, 0}; + return poll(&p, 1, timeout_ms); +} + +} // namespace + +TEST_F(LibBufferHubTest, TestAcquireFence) { + std::unique_ptr<BufferProducer> p = BufferProducer::Create( + kWidth, kHeight, kFormat, kUsage, /*metadata_size=*/0); + ASSERT_TRUE(p.get() != nullptr); + std::unique_ptr<BufferConsumer> c = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(c.get() != nullptr); + + DvrNativeBufferMetadata meta; + LocalHandle f1(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); + + // Post with unsignaled fence. + EXPECT_EQ(0, p->PostAsync(&meta, f1)); + + // Should acquire a valid fence. + LocalHandle f2; + EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); + EXPECT_EQ(0, c->AcquireAsync(&meta, &f2)); + EXPECT_TRUE(f2.IsValid()); + // The original fence and acquired fence should have different fd number. + EXPECT_NE(f1.Get(), f2.Get()); + EXPECT_GE(0, PollFd(f2.Get(), 0)); + + // Signal the original fence will trigger the new fence. + eventfd_write(f1.Get(), 1); + // Now the original FD has been signaled. + EXPECT_LT(0, PollFd(f2.Get(), kPollTimeoutMs)); + + // Release the consumer with an invalid fence. + EXPECT_EQ(0, c->ReleaseAsync(&meta, LocalHandle())); + + // Should gain an invalid fence. + LocalHandle f3; + EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); + EXPECT_EQ(0, p->GainAsync(&meta, &f3)); + EXPECT_FALSE(f3.IsValid()); + + // Post with a signaled fence. + EXPECT_EQ(0, p->PostAsync(&meta, f1)); + + // Should acquire a valid fence and it's already signalled. + LocalHandle f4; + EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); + EXPECT_EQ(0, c->AcquireAsync(&meta, &f4)); + EXPECT_TRUE(f4.IsValid()); + EXPECT_LT(0, PollFd(f4.Get(), kPollTimeoutMs)); + + // Release with an unsignalled fence and signal it immediately after release + // without producer gainning. + LocalHandle f5(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); + EXPECT_EQ(0, c->ReleaseAsync(&meta, f5)); + eventfd_write(f5.Get(), 1); + + // Should gain a valid fence, which is already signaled. + LocalHandle f6; + EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); + EXPECT_EQ(0, p->GainAsync(&meta, &f6)); + EXPECT_TRUE(f6.IsValid()); + EXPECT_LT(0, PollFd(f6.Get(), kPollTimeoutMs)); +} + +TEST_F(LibBufferHubTest, TestOrphanedAcquire) { + std::unique_ptr<BufferProducer> p = BufferProducer::Create( + kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); + ASSERT_TRUE(p.get() != nullptr); + std::unique_ptr<BufferConsumer> c1 = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(c1.get() != nullptr); + const uint64_t consumer_state_bit1 = c1->buffer_state_bit(); + + DvrNativeBufferMetadata meta; + EXPECT_EQ(0, p->PostAsync(&meta, LocalHandle())); + + LocalHandle fence; + EXPECT_LT(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs))); + EXPECT_LE(0, c1->AcquireAsync(&meta, &fence)); + // Destroy the consumer now will make it orphaned and the buffer is still + // acquired. + c1 = nullptr; + EXPECT_GE(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); + + std::unique_ptr<BufferConsumer> c2 = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(c2.get() != nullptr); + const uint64_t consumer_state_bit2 = c2->buffer_state_bit(); + EXPECT_NE(consumer_state_bit1, consumer_state_bit2); + + // The new consumer is available for acquire. + EXPECT_LT(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs))); + EXPECT_LE(0, c2->AcquireAsync(&meta, &fence)); + // Releasing the consumer makes the buffer gainable. + EXPECT_EQ(0, c2->ReleaseAsync(&meta, LocalHandle())); + + // The buffer is now available for the producer to gain. + EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); + + // But if another consumer is created in released state. + std::unique_ptr<BufferConsumer> c3 = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(c3.get() != nullptr); + const uint64_t consumer_state_bit3 = c3->buffer_state_bit(); + EXPECT_NE(consumer_state_bit2, consumer_state_bit3); + // The consumer buffer is not acquirable. + EXPECT_GE(0, RETRY_EINTR(c3->Poll(kPollTimeoutMs))); + EXPECT_EQ(-EBUSY, c3->AcquireAsync(&meta, &fence)); + + // Producer should be able to gain no matter what. + EXPECT_EQ(0, p->GainAsync(&meta, &fence)); +} + +TEST_F(LibBufferHubTest, TestDetachBufferFromProducer) { + std::unique_ptr<BufferProducer> p = BufferProducer::Create( + kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); + std::unique_ptr<BufferConsumer> c = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(p.get() != nullptr); + ASSERT_TRUE(c.get() != nullptr); + + DvrNativeBufferMetadata metadata; + LocalHandle invalid_fence; + int p_id = p->id(); + + // Detach in posted state should fail. + EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence)); + EXPECT_GT(RETRY_EINTR(c->Poll(kPollTimeoutMs)), 0); + auto s1 = p->Detach(); + EXPECT_FALSE(s1); + + // Detach in acquired state should fail. + EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence)); + s1 = p->Detach(); + EXPECT_FALSE(s1); + + // Detach in released state should fail. + EXPECT_EQ(0, c->ReleaseAsync(&metadata, invalid_fence)); + EXPECT_GT(RETRY_EINTR(p->Poll(kPollTimeoutMs)), 0); + s1 = p->Detach(); + EXPECT_FALSE(s1); + + // Detach in gained state should succeed. + EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence)); + s1 = p->Detach(); + EXPECT_TRUE(s1); + + LocalChannelHandle handle = s1.take(); + EXPECT_TRUE(handle.valid()); + + // Both producer and consumer should have hangup. + EXPECT_GT(RETRY_EINTR(p->Poll(kPollTimeoutMs)), 0); + auto s2 = p->GetEventMask(POLLHUP); + EXPECT_TRUE(s2); + EXPECT_EQ(s2.get(), POLLHUP); + + EXPECT_GT(RETRY_EINTR(c->Poll(kPollTimeoutMs)), 0); + s2 = p->GetEventMask(POLLHUP); + EXPECT_TRUE(s2); + EXPECT_EQ(s2.get(), POLLHUP); + + auto s3 = p->CreateConsumer(); + EXPECT_FALSE(s3); + // Note that here the expected error code is EOPNOTSUPP as the socket towards + // ProducerChannel has been teared down. + EXPECT_EQ(s3.error(), EOPNOTSUPP); + + s3 = c->CreateConsumer(); + EXPECT_FALSE(s3); + // Note that here the expected error code is EPIPE returned from + // ConsumerChannel::HandleMessage as the socket is still open but the producer + // is gone. + EXPECT_EQ(s3.error(), EPIPE); + + // Detached buffer handle can be use to construct a new DetachedBuffer object. + auto d = DetachedBuffer::Import(std::move(handle)); + EXPECT_FALSE(handle.valid()); + EXPECT_TRUE(d->IsConnected()); + EXPECT_TRUE(d->IsValid()); + + ASSERT_TRUE(d->buffer() != nullptr); + EXPECT_EQ(d->buffer()->initCheck(), 0); + EXPECT_EQ(d->id(), p_id); +} + +TEST_F(LibBufferHubTest, TestCreateDetachedBufferFails) { + // Buffer Creation will fail: BLOB format requires height to be 1. + auto b1 = DetachedBuffer::Create(kWidth, /*height=2*/ 2, kLayerCount, + /*format=*/HAL_PIXEL_FORMAT_BLOB, kUsage, + kUserMetadataSize); + + EXPECT_FALSE(b1->IsConnected()); + EXPECT_FALSE(b1->IsValid()); + EXPECT_TRUE(b1->buffer() == nullptr); + + // Buffer Creation will fail: user metadata size too large. + auto b2 = DetachedBuffer::Create( + kWidth, kHeight, kLayerCount, kFormat, kUsage, + /*user_metadata_size=*/std::numeric_limits<size_t>::max()); + + EXPECT_FALSE(b2->IsConnected()); + EXPECT_FALSE(b2->IsValid()); + EXPECT_TRUE(b2->buffer() == nullptr); + + // Buffer Creation will fail: user metadata size too large. + auto b3 = DetachedBuffer::Create( + kWidth, kHeight, kLayerCount, kFormat, kUsage, + /*user_metadata_size=*/std::numeric_limits<size_t>::max() - + kMetadataHeaderSize); + + EXPECT_FALSE(b3->IsConnected()); + EXPECT_FALSE(b3->IsValid()); + EXPECT_TRUE(b3->buffer() == nullptr); +} + +TEST_F(LibBufferHubTest, TestCreateDetachedBuffer) { + auto b1 = DetachedBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, + kUsage, kUserMetadataSize); + int b1_id = b1->id(); + + EXPECT_TRUE(b1->IsConnected()); + EXPECT_TRUE(b1->IsValid()); + ASSERT_TRUE(b1->buffer() != nullptr); + EXPECT_NE(b1->id(), 0); + EXPECT_EQ(b1->buffer()->initCheck(), 0); + EXPECT_FALSE(b1->buffer()->isDetachedBuffer()); + + // Takes a standalone GraphicBuffer which still holds on an + // PDX::LocalChannelHandle towards BufferHub. + sp<GraphicBuffer> g1 = b1->TakeGraphicBuffer(); + ASSERT_TRUE(g1 != nullptr); + EXPECT_TRUE(g1->isDetachedBuffer()); + + EXPECT_FALSE(b1->IsConnected()); + EXPECT_FALSE(b1->IsValid()); + EXPECT_TRUE(b1->buffer() == nullptr); + + sp<GraphicBuffer> g2 = b1->TakeGraphicBuffer(); + ASSERT_TRUE(g2 == nullptr); + + auto h1 = g1->takeDetachedBufferHandle(); + ASSERT_TRUE(h1 != nullptr); + ASSERT_TRUE(h1->isValid()); + EXPECT_FALSE(g1->isDetachedBuffer()); + + auto b2 = DetachedBuffer::Import(std::move(h1->handle())); + ASSERT_FALSE(h1->isValid()); + EXPECT_TRUE(b2->IsConnected()); + EXPECT_TRUE(b2->IsValid()); + + ASSERT_TRUE(b2->buffer() != nullptr); + EXPECT_EQ(b2->buffer()->initCheck(), 0); + + // The newly created DetachedBuffer should share the original buffer_id. + EXPECT_EQ(b2->id(), b1_id); + EXPECT_FALSE(b2->buffer()->isDetachedBuffer()); +} + +TEST_F(LibBufferHubTest, TestPromoteDetachedBuffer) { + auto b1 = DetachedBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, + kUsage, kUserMetadataSize); + int b1_id = b1->id(); + EXPECT_TRUE(b1->IsValid()); + + auto status_or_handle = b1->Promote(); + EXPECT_TRUE(status_or_handle); + + // The detached buffer should have hangup. + EXPECT_GT(RETRY_EINTR(b1->Poll(kPollTimeoutMs)), 0); + auto status_or_int = b1->GetEventMask(POLLHUP); + EXPECT_TRUE(status_or_int.ok()); + EXPECT_EQ(status_or_int.get(), POLLHUP); + + // The buffer client is still considered as connected but invalid. + EXPECT_TRUE(b1->IsConnected()); + EXPECT_FALSE(b1->IsValid()); + + // Gets the channel handle for the producer. + LocalChannelHandle h1 = status_or_handle.take(); + EXPECT_TRUE(h1.valid()); + + std::unique_ptr<BufferProducer> p1 = BufferProducer::Import(std::move(h1)); + EXPECT_FALSE(h1.valid()); + ASSERT_TRUE(p1 != nullptr); + int p1_id = p1->id(); + + // A newly promoted ProducerBuffer should inherit the same buffer id. + EXPECT_EQ(b1_id, p1_id); + EXPECT_TRUE(IsBufferGained(p1->buffer_state())); +} + +TEST_F(LibBufferHubTest, TestDetachThenPromote) { + std::unique_ptr<BufferProducer> p1 = BufferProducer::Create( + kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); + ASSERT_TRUE(p1.get() != nullptr); + int p1_id = p1->id(); + + // Detached the producer. + auto status_or_handle = p1->Detach(); + EXPECT_TRUE(status_or_handle.ok()); + LocalChannelHandle h1 = status_or_handle.take(); + EXPECT_TRUE(h1.valid()); + + // Detached buffer handle can be use to construct a new DetachedBuffer object. + auto b1 = DetachedBuffer::Import(std::move(h1)); + EXPECT_FALSE(h1.valid()); + EXPECT_TRUE(b1->IsValid()); + int b1_id = b1->id(); + EXPECT_EQ(b1_id, p1_id); + + // Promote the detached buffer. + status_or_handle = b1->Promote(); + // The buffer client is still considered as connected but invalid. + EXPECT_TRUE(b1->IsConnected()); + EXPECT_FALSE(b1->IsValid()); + EXPECT_TRUE(status_or_handle.ok()); + + // Gets the channel handle for the producer. + LocalChannelHandle h2 = status_or_handle.take(); + EXPECT_TRUE(h2.valid()); + + std::unique_ptr<BufferProducer> p2 = BufferProducer::Import(std::move(h2)); + EXPECT_FALSE(h2.valid()); + ASSERT_TRUE(p2 != nullptr); + int p2_id = p2->id(); + + // A newly promoted ProducerBuffer should inherit the same buffer id. + EXPECT_EQ(b1_id, p2_id); + EXPECT_TRUE(IsBufferGained(p2->buffer_state())); +} diff --git a/libs/vr/libbufferhub/buffer_hub_client.cpp b/libs/vr/libbufferhub/buffer_hub_client.cpp index 97341b1477..159f2bd1b3 100644 --- a/libs/vr/libbufferhub/buffer_hub_client.cpp +++ b/libs/vr/libbufferhub/buffer_hub_client.cpp @@ -15,10 +15,30 @@ using android::pdx::LocalChannelHandle; using android::pdx::LocalHandle; using android::pdx::Status; +using android::pdx::default_transport::ClientChannel; +using android::pdx::default_transport::ClientChannelFactory; namespace android { namespace dvr { +BufferHubClient::BufferHubClient() + : Client(ClientChannelFactory::Create(BufferHubRPC::kClientPath)) {} + +BufferHubClient::BufferHubClient(LocalChannelHandle channel_handle) + : Client(ClientChannel::Create(std::move(channel_handle))) {} + +bool BufferHubClient::IsValid() const { + return IsConnected() && GetChannelHandle().valid(); +} + +LocalChannelHandle BufferHubClient::TakeChannelHandle() { + if (IsConnected()) { + return std::move(GetChannelHandle()); + } else { + return {}; + } +} + BufferHubBuffer::BufferHubBuffer(LocalChannelHandle channel_handle) : Client{pdx::default_transport::ClientChannel::Create( std::move(channel_handle))}, @@ -395,25 +415,16 @@ int BufferConsumer::SetIgnore(bool ignore) { } BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format, - uint32_t usage, size_t user_metadata_size) - : BufferProducer(width, height, format, usage, usage, user_metadata_size) {} - -BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format, - uint64_t producer_usage, uint64_t consumer_usage, - size_t user_metadata_size) + uint64_t usage, size_t user_metadata_size) : BASE(BufferHubRPC::kClientPath) { ATRACE_NAME("BufferProducer::BufferProducer"); ALOGD_IF(TRACE, "BufferProducer::BufferProducer: fd=%d width=%u height=%u format=%u " - "producer_usage=%" PRIx64 " consumer_usage=%" PRIx64 - " user_metadata_size=%zu", - event_fd(), width, height, format, producer_usage, consumer_usage, - user_metadata_size); + "usage=%" PRIx64 " user_metadata_size=%zu", + event_fd(), width, height, format, usage, user_metadata_size); - // (b/37881101) Deprecate producer/consumer usage auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>( - width, height, format, (producer_usage | consumer_usage), - user_metadata_size); + width, height, format, usage, user_metadata_size); if (!status) { ALOGE( "BufferProducer::BufferProducer: Failed to create producer buffer: %s", @@ -431,70 +442,18 @@ BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format, } } -BufferProducer::BufferProducer(const std::string& name, int user_id, - int group_id, uint32_t width, uint32_t height, - uint32_t format, uint32_t usage, - size_t user_metadata_size) - : BufferProducer(name, user_id, group_id, width, height, format, usage, - usage, user_metadata_size) {} - -BufferProducer::BufferProducer(const std::string& name, int user_id, - int group_id, uint32_t width, uint32_t height, - uint32_t format, uint64_t producer_usage, - uint64_t consumer_usage, - size_t user_metadata_size) +BufferProducer::BufferProducer(uint64_t usage, size_t size) : BASE(BufferHubRPC::kClientPath) { ATRACE_NAME("BufferProducer::BufferProducer"); - ALOGD_IF(TRACE, - "BufferProducer::BufferProducer: fd=%d name=%s user_id=%d " - "group_id=%d width=%u height=%u format=%u producer_usage=%" PRIx64 - " consumer_usage=%" PRIx64 " user_metadata_size=%zu", - event_fd(), name.c_str(), user_id, group_id, width, height, format, - producer_usage, consumer_usage, user_metadata_size); - - // (b/37881101) Deprecate producer/consumer usage - auto status = InvokeRemoteMethod<BufferHubRPC::CreatePersistentBuffer>( - name, user_id, group_id, width, height, format, - (producer_usage | consumer_usage), user_metadata_size); - if (!status) { - ALOGE( - "BufferProducer::BufferProducer: Failed to create/get persistent " - "buffer \"%s\": %s", - name.c_str(), status.GetErrorMessage().c_str()); - Close(-status.error()); - return; - } - - const int ret = ImportBuffer(); - if (ret < 0) { - ALOGE( - "BufferProducer::BufferProducer: Failed to import producer buffer " - "\"%s\": %s", - name.c_str(), strerror(-ret)); - Close(ret); - } -} - -BufferProducer::BufferProducer(uint32_t usage, size_t size) - : BufferProducer(usage, usage, size) {} - -BufferProducer::BufferProducer(uint64_t producer_usage, uint64_t consumer_usage, - size_t size) - : BASE(BufferHubRPC::kClientPath) { - ATRACE_NAME("BufferProducer::BufferProducer"); - ALOGD_IF(TRACE, - "BufferProducer::BufferProducer: producer_usage=%" PRIx64 - " consumer_usage=%" PRIx64 " size=%zu", - producer_usage, consumer_usage, size); + ALOGD_IF(TRACE, "BufferProducer::BufferProducer: usage=%" PRIx64 " size=%zu", + usage, size); const int width = static_cast<int>(size); const int height = 1; const int format = HAL_PIXEL_FORMAT_BLOB; const size_t user_metadata_size = 0; - // (b/37881101) Deprecate producer/consumer usage auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>( - width, height, format, (producer_usage | consumer_usage), - user_metadata_size); + width, height, format, usage, user_metadata_size); if (!status) { ALOGE("BufferProducer::BufferProducer: Failed to create blob: %s", status.GetErrorMessage().c_str()); @@ -511,73 +470,6 @@ BufferProducer::BufferProducer(uint64_t producer_usage, uint64_t consumer_usage, } } -BufferProducer::BufferProducer(const std::string& name, int user_id, - int group_id, uint32_t usage, size_t size) - : BufferProducer(name, user_id, group_id, usage, usage, size) {} - -BufferProducer::BufferProducer(const std::string& name, int user_id, - int group_id, uint64_t producer_usage, - uint64_t consumer_usage, size_t size) - : BASE(BufferHubRPC::kClientPath) { - ATRACE_NAME("BufferProducer::BufferProducer"); - ALOGD_IF(TRACE, - "BufferProducer::BufferProducer: name=%s user_id=%d group=%d " - "producer_usage=%" PRIx64 " consumer_usage=%" PRIx64 " size=%zu", - name.c_str(), user_id, group_id, producer_usage, consumer_usage, - size); - const int width = static_cast<int>(size); - const int height = 1; - const int format = HAL_PIXEL_FORMAT_BLOB; - const size_t user_metadata_size = 0; - - // (b/37881101) Deprecate producer/consumer usage - auto status = InvokeRemoteMethod<BufferHubRPC::CreatePersistentBuffer>( - name, user_id, group_id, width, height, format, - (producer_usage | consumer_usage), user_metadata_size); - if (!status) { - ALOGE( - "BufferProducer::BufferProducer: Failed to create persistent " - "buffer \"%s\": %s", - name.c_str(), status.GetErrorMessage().c_str()); - Close(-status.error()); - return; - } - - const int ret = ImportBuffer(); - if (ret < 0) { - ALOGE( - "BufferProducer::BufferProducer: Failed to import producer buffer " - "\"%s\": %s", - name.c_str(), strerror(-ret)); - Close(ret); - } -} - -BufferProducer::BufferProducer(const std::string& name) - : BASE(BufferHubRPC::kClientPath) { - ATRACE_NAME("BufferProducer::BufferProducer"); - ALOGD_IF(TRACE, "BufferProducer::BufferProducer: name=%s", name.c_str()); - - auto status = InvokeRemoteMethod<BufferHubRPC::GetPersistentBuffer>(name); - if (!status) { - ALOGE( - "BufferProducer::BufferProducer: Failed to get producer buffer by name " - "\"%s\": %s", - name.c_str(), status.GetErrorMessage().c_str()); - Close(-status.error()); - return; - } - - const int ret = ImportBuffer(); - if (ret < 0) { - ALOGE( - "BufferProducer::BufferProducer: Failed to import producer buffer " - "\"%s\": %s", - name.c_str(), strerror(-ret)); - Close(ret); - } -} - BufferProducer::BufferProducer(LocalChannelHandle channel) : BASE(std::move(channel)) { const int ret = ImportBuffer(); @@ -736,18 +628,22 @@ std::unique_ptr<BufferProducer> BufferProducer::Import( : LocalChannelHandle{nullptr, -status.error()}); } -int BufferProducer::MakePersistent(const std::string& name, int user_id, - int group_id) { - ATRACE_NAME("BufferProducer::MakePersistent"); - return ReturnStatusOrError( - InvokeRemoteMethod<BufferHubRPC::ProducerMakePersistent>(name, user_id, - group_id)); -} +Status<LocalChannelHandle> BufferProducer::Detach() { + uint64_t buffer_state = buffer_state_->load(); + if (!BufferHubDefs::IsBufferGained(buffer_state)) { + // Can only detach a BufferProducer when it's in gained state. + ALOGW("BufferProducer::Detach: The buffer (id=%d, state=0x%" PRIx64 + ") is not in gained state.", + id(), buffer_state); + return {}; + } -int BufferProducer::RemovePersistence() { - ATRACE_NAME("BufferProducer::RemovePersistence"); - return ReturnStatusOrError( - InvokeRemoteMethod<BufferHubRPC::ProducerRemovePersistence>()); + Status<LocalChannelHandle> status = + InvokeRemoteMethod<BufferHubRPC::ProducerBufferDetach>(); + ALOGE_IF(!status, + "BufferProducer::Detach: Failed to detach buffer (id=%d): %s.", id(), + status.GetErrorMessage().c_str()); + return status; } } // namespace dvr diff --git a/libs/vr/libbufferhub/bufferhub_tests.cpp b/libs/vr/libbufferhub/bufferhub_tests.cpp deleted file mode 100644 index d0d3a73574..0000000000 --- a/libs/vr/libbufferhub/bufferhub_tests.cpp +++ /dev/null @@ -1,558 +0,0 @@ -#include <gtest/gtest.h> -#include <poll.h> -#include <private/dvr/buffer_hub_client.h> -#include <private/dvr/bufferhub_rpc.h> -#include <sys/epoll.h> -#include <sys/eventfd.h> - -#include <mutex> -#include <thread> - -#define RETRY_EINTR(fnc_call) \ - ([&]() -> decltype(fnc_call) { \ - decltype(fnc_call) result; \ - do { \ - result = (fnc_call); \ - } while (result == -1 && errno == EINTR); \ - return result; \ - })() - -using android::dvr::BufferConsumer; -using android::dvr::BufferHubDefs::kConsumerStateMask; -using android::dvr::BufferHubDefs::kProducerStateBit; -using android::dvr::BufferProducer; -using android::pdx::LocalHandle; - -const int kWidth = 640; -const int kHeight = 480; -const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888; -const int kUsage = 0; -const uint64_t kContext = 42; - -using LibBufferHubTest = ::testing::Test; - -TEST_F(LibBufferHubTest, TestBasicUsage) { - std::unique_ptr<BufferProducer> p = BufferProducer::Create( - kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); - ASSERT_TRUE(p.get() != nullptr); - std::unique_ptr<BufferConsumer> c = - BufferConsumer::Import(p->CreateConsumer()); - ASSERT_TRUE(c.get() != nullptr); - // Check that consumers can spawn other consumers. - std::unique_ptr<BufferConsumer> c2 = - BufferConsumer::Import(c->CreateConsumer()); - ASSERT_TRUE(c2.get() != nullptr); - - // Producer state mask is unique, i.e. 1. - EXPECT_EQ(p->buffer_state_bit(), kProducerStateBit); - // Consumer state mask cannot have producer bit on. - EXPECT_EQ(c->buffer_state_bit() & kProducerStateBit, 0ULL); - // Consumer state mask must be a single, i.e. power of 2. - EXPECT_NE(c->buffer_state_bit(), 0ULL); - EXPECT_EQ(c->buffer_state_bit() & (c->buffer_state_bit() - 1), 0ULL); - // Consumer state mask cannot have producer bit on. - EXPECT_EQ(c2->buffer_state_bit() & kProducerStateBit, 0ULL); - // Consumer state mask must be a single, i.e. power of 2. - EXPECT_NE(c2->buffer_state_bit(), 0ULL); - EXPECT_EQ(c2->buffer_state_bit() & (c2->buffer_state_bit() - 1), 0ULL); - // Each consumer should have unique bit. - EXPECT_EQ(c->buffer_state_bit() & c2->buffer_state_bit(), 0ULL); - - // Initial state: producer not available, consumers not available. - EXPECT_EQ(0, RETRY_EINTR(p->Poll(100))); - EXPECT_EQ(0, RETRY_EINTR(c->Poll(100))); - EXPECT_EQ(0, RETRY_EINTR(c2->Poll(100))); - - EXPECT_EQ(0, p->Post(LocalHandle(), kContext)); - - // New state: producer not available, consumers available. - EXPECT_EQ(0, RETRY_EINTR(p->Poll(100))); - EXPECT_EQ(1, RETRY_EINTR(c->Poll(100))); - EXPECT_EQ(1, RETRY_EINTR(c2->Poll(100))); - - uint64_t context; - LocalHandle fence; - EXPECT_EQ(0, c->Acquire(&fence, &context)); - EXPECT_EQ(kContext, context); - EXPECT_EQ(0, RETRY_EINTR(c->Poll(100))); - EXPECT_EQ(1, RETRY_EINTR(c2->Poll(100))); - - EXPECT_EQ(0, c2->Acquire(&fence, &context)); - EXPECT_EQ(kContext, context); - EXPECT_EQ(0, RETRY_EINTR(c2->Poll(100))); - EXPECT_EQ(0, RETRY_EINTR(c->Poll(100))); - - EXPECT_EQ(0, c->Release(LocalHandle())); - EXPECT_EQ(0, RETRY_EINTR(p->Poll(100))); - EXPECT_EQ(0, c2->Discard()); - - EXPECT_EQ(1, RETRY_EINTR(p->Poll(100))); - EXPECT_EQ(0, p->Gain(&fence)); - EXPECT_EQ(0, RETRY_EINTR(p->Poll(100))); - EXPECT_EQ(0, RETRY_EINTR(c->Poll(100))); - EXPECT_EQ(0, RETRY_EINTR(c2->Poll(100))); -} - -TEST_F(LibBufferHubTest, TestEpoll) { - std::unique_ptr<BufferProducer> p = BufferProducer::Create( - kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); - ASSERT_TRUE(p.get() != nullptr); - std::unique_ptr<BufferConsumer> c = - BufferConsumer::Import(p->CreateConsumer()); - ASSERT_TRUE(c.get() != nullptr); - - LocalHandle epoll_fd{epoll_create1(EPOLL_CLOEXEC)}; - ASSERT_TRUE(epoll_fd.IsValid()); - - epoll_event event; - std::array<epoll_event, 64> events; - - auto event_sources = p->GetEventSources(); - ASSERT_LT(event_sources.size(), events.size()); - - for (const auto& event_source : event_sources) { - event = {.events = event_source.event_mask | EPOLLET, - .data = {.fd = p->event_fd()}}; - ASSERT_EQ(0, epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, event_source.event_fd, - &event)); - } - - event_sources = c->GetEventSources(); - ASSERT_LT(event_sources.size(), events.size()); - - for (const auto& event_source : event_sources) { - event = {.events = event_source.event_mask | EPOLLET, - .data = {.fd = c->event_fd()}}; - ASSERT_EQ(0, epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, event_source.event_fd, - &event)); - } - - // No events should be signaled initially. - ASSERT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 0)); - - // Post the producer and check for consumer signal. - EXPECT_EQ(0, p->Post({}, kContext)); - ASSERT_EQ(1, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100)); - ASSERT_TRUE(events[0].events & EPOLLIN); - ASSERT_EQ(c->event_fd(), events[0].data.fd); - - // Save the event bits to translate later. - event = events[0]; - - // Check for events again. Edge-triggered mode should prevent any. - EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100)); - EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100)); - EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100)); - EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100)); - - // Translate the events. - auto event_status = c->GetEventMask(event.events); - ASSERT_TRUE(event_status); - ASSERT_TRUE(event_status.get() & EPOLLIN); - - // Check for events again. Edge-triggered mode should prevent any. - EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100)); -} - -TEST_F(LibBufferHubTest, TestStateMask) { - std::unique_ptr<BufferProducer> p = BufferProducer::Create( - kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); - ASSERT_TRUE(p.get() != nullptr); - - // It's ok to create up to 63 consumer buffers. - uint64_t buffer_state_bits = p->buffer_state_bit(); - std::array<std::unique_ptr<BufferConsumer>, 63> cs; - for (size_t i = 0; i < 63; i++) { - cs[i] = BufferConsumer::Import(p->CreateConsumer()); - ASSERT_TRUE(cs[i].get() != nullptr); - // Expect all buffers have unique state mask. - EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0ULL); - buffer_state_bits |= cs[i]->buffer_state_bit(); - } - EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask); - - // The 64th creation will fail with out-of-memory error. - auto state = p->CreateConsumer(); - EXPECT_EQ(state.error(), E2BIG); - - // Release any consumer should allow us to re-create. - for (size_t i = 0; i < 63; i++) { - buffer_state_bits &= ~cs[i]->buffer_state_bit(); - cs[i] = nullptr; - cs[i] = BufferConsumer::Import(p->CreateConsumer()); - ASSERT_TRUE(cs[i].get() != nullptr); - // The released state mask will be reused. - EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0ULL); - buffer_state_bits |= cs[i]->buffer_state_bit(); - EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask); - } -} - -TEST_F(LibBufferHubTest, TestStateTransitions) { - std::unique_ptr<BufferProducer> p = BufferProducer::Create( - kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); - ASSERT_TRUE(p.get() != nullptr); - std::unique_ptr<BufferConsumer> c = - BufferConsumer::Import(p->CreateConsumer()); - ASSERT_TRUE(c.get() != nullptr); - - uint64_t context; - LocalHandle fence; - - // The producer buffer starts in gained state. - - // Acquire, release, and gain in gained state should fail. - EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context)); - EXPECT_EQ(-EBUSY, c->Release(LocalHandle())); - EXPECT_EQ(-EALREADY, p->Gain(&fence)); - - // Post in gained state should succeed. - EXPECT_EQ(0, p->Post(LocalHandle(), kContext)); - - // Post, release, and gain in posted state should fail. - EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext)); - EXPECT_EQ(-EBUSY, c->Release(LocalHandle())); - EXPECT_EQ(-EBUSY, p->Gain(&fence)); - - // Acquire in posted state should succeed. - EXPECT_LE(0, c->Acquire(&fence, &context)); - - // Acquire, post, and gain in acquired state should fail. - EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context)); - EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext)); - EXPECT_EQ(-EBUSY, p->Gain(&fence)); - - // Release in acquired state should succeed. - EXPECT_EQ(0, c->Release(LocalHandle())); - EXPECT_LT(0, RETRY_EINTR(p->Poll(10))); - - // Release, acquire, and post in released state should fail. - EXPECT_EQ(-EBUSY, c->Release(LocalHandle())); - EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context)); - EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext)); - - // Gain in released state should succeed. - EXPECT_EQ(0, p->Gain(&fence)); - - // Acquire, release, and gain in gained state should fail. - EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context)); - EXPECT_EQ(-EBUSY, c->Release(LocalHandle())); - EXPECT_EQ(-EALREADY, p->Gain(&fence)); -} - -TEST_F(LibBufferHubTest, TestWithCustomMetadata) { - struct Metadata { - int64_t field1; - int64_t field2; - }; - std::unique_ptr<BufferProducer> p = BufferProducer::Create( - kWidth, kHeight, kFormat, kUsage, sizeof(Metadata)); - ASSERT_TRUE(p.get() != nullptr); - std::unique_ptr<BufferConsumer> c = - BufferConsumer::Import(p->CreateConsumer()); - ASSERT_TRUE(c.get() != nullptr); - - Metadata m = {1, 3}; - EXPECT_EQ(0, p->Post(LocalHandle(), m)); - EXPECT_LE(0, RETRY_EINTR(c->Poll(10))); - - LocalHandle fence; - Metadata m2 = {}; - EXPECT_EQ(0, c->Acquire(&fence, &m2)); - EXPECT_EQ(m.field1, m2.field1); - EXPECT_EQ(m.field2, m2.field2); - - EXPECT_EQ(0, c->Release(LocalHandle())); - EXPECT_LT(0, RETRY_EINTR(p->Poll(0))); -} - -TEST_F(LibBufferHubTest, TestPostWithWrongMetaSize) { - struct Metadata { - int64_t field1; - int64_t field2; - }; - struct OverSizedMetadata { - int64_t field1; - int64_t field2; - int64_t field3; - }; - std::unique_ptr<BufferProducer> p = BufferProducer::Create( - kWidth, kHeight, kFormat, kUsage, sizeof(Metadata)); - ASSERT_TRUE(p.get() != nullptr); - std::unique_ptr<BufferConsumer> c = - BufferConsumer::Import(p->CreateConsumer()); - ASSERT_TRUE(c.get() != nullptr); - - // It is illegal to post metadata larger than originally requested during - // buffer allocation. - OverSizedMetadata evil_meta = {}; - EXPECT_NE(0, p->Post(LocalHandle(), evil_meta)); - EXPECT_GE(0, RETRY_EINTR(c->Poll(10))); - - // It is ok to post metadata smaller than originally requested during - // buffer allocation. - int64_t sequence = 42; - EXPECT_EQ(0, p->Post(LocalHandle(), sequence)); -} - -TEST_F(LibBufferHubTest, TestAcquireWithWrongMetaSize) { - struct Metadata { - int64_t field1; - int64_t field2; - }; - struct OverSizedMetadata { - int64_t field1; - int64_t field2; - int64_t field3; - }; - std::unique_ptr<BufferProducer> p = BufferProducer::Create( - kWidth, kHeight, kFormat, kUsage, sizeof(Metadata)); - ASSERT_TRUE(p.get() != nullptr); - std::unique_ptr<BufferConsumer> c = - BufferConsumer::Import(p->CreateConsumer()); - ASSERT_TRUE(c.get() != nullptr); - - Metadata m = {1, 3}; - EXPECT_EQ(0, p->Post(LocalHandle(), m)); - - LocalHandle fence; - int64_t sequence; - OverSizedMetadata e; - - // It is illegal to acquire metadata larger than originally requested during - // buffer allocation. - EXPECT_NE(0, c->Acquire(&fence, &e)); - - // It is ok to acquire metadata smaller than originally requested during - // buffer allocation. - EXPECT_EQ(0, c->Acquire(&fence, &sequence)); - EXPECT_EQ(m.field1, sequence); -} - -TEST_F(LibBufferHubTest, TestAcquireWithNoMeta) { - std::unique_ptr<BufferProducer> p = BufferProducer::Create( - kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); - ASSERT_TRUE(p.get() != nullptr); - std::unique_ptr<BufferConsumer> c = - BufferConsumer::Import(p->CreateConsumer()); - ASSERT_TRUE(c.get() != nullptr); - - int64_t sequence = 3; - EXPECT_EQ(0, p->Post(LocalHandle(), sequence)); - - LocalHandle fence; - EXPECT_EQ(0, c->Acquire(&fence)); -} - -TEST_F(LibBufferHubTest, TestWithNoMeta) { - std::unique_ptr<BufferProducer> p = - BufferProducer::Create(kWidth, kHeight, kFormat, kUsage); - ASSERT_TRUE(p.get() != nullptr); - std::unique_ptr<BufferConsumer> c = - BufferConsumer::Import(p->CreateConsumer()); - ASSERT_TRUE(c.get() != nullptr); - - LocalHandle fence; - - EXPECT_EQ(0, p->Post<void>(LocalHandle())); - EXPECT_EQ(0, c->Acquire(&fence)); -} - -TEST_F(LibBufferHubTest, TestFailureToPostMetaFromABufferWithoutMeta) { - std::unique_ptr<BufferProducer> p = - BufferProducer::Create(kWidth, kHeight, kFormat, kUsage); - ASSERT_TRUE(p.get() != nullptr); - std::unique_ptr<BufferConsumer> c = - BufferConsumer::Import(p->CreateConsumer()); - ASSERT_TRUE(c.get() != nullptr); - - int64_t sequence = 3; - EXPECT_NE(0, p->Post(LocalHandle(), sequence)); -} - -TEST_F(LibBufferHubTest, TestPersistentBufferPersistence) { - auto p = BufferProducer::Create("TestPersistentBuffer", -1, -1, kWidth, - kHeight, kFormat, kUsage); - ASSERT_NE(nullptr, p); - - // Record the original buffer id for later comparison. - const int buffer_id = p->id(); - - auto c = BufferConsumer::Import(p->CreateConsumer()); - ASSERT_NE(nullptr, c); - - EXPECT_EQ(0, p->Post<void>(LocalHandle())); - - // Close the connection to the producer. This should not affect the consumer. - p = nullptr; - - LocalHandle fence; - EXPECT_EQ(0, c->Acquire(&fence)); - EXPECT_EQ(0, c->Release(LocalHandle())); - - // Attempt to reconnect to the persistent buffer. - p = BufferProducer::Create("TestPersistentBuffer"); - ASSERT_NE(nullptr, p); - EXPECT_EQ(buffer_id, p->id()); - EXPECT_EQ(0, p->Gain(&fence)); -} - -TEST_F(LibBufferHubTest, TestPersistentBufferMismatchParams) { - auto p = BufferProducer::Create("TestPersistentBuffer", -1, -1, kWidth, - kHeight, kFormat, kUsage); - ASSERT_NE(nullptr, p); - - // Close the connection to the producer. - p = nullptr; - - // Mismatch the params. - p = BufferProducer::Create("TestPersistentBuffer", -1, -1, kWidth * 2, - kHeight, kFormat, kUsage); - ASSERT_EQ(nullptr, p); -} - -TEST_F(LibBufferHubTest, TestRemovePersistentBuffer) { - auto p = BufferProducer::Create("TestPersistentBuffer", -1, -1, kWidth, - kHeight, kFormat, kUsage); - ASSERT_NE(nullptr, p); - - LocalHandle fence; - auto c = BufferConsumer::Import(p->CreateConsumer()); - ASSERT_NE(nullptr, c); - EXPECT_EQ(0, p->Post<void>(LocalHandle())); - EXPECT_EQ(0, c->Acquire(&fence)); - EXPECT_EQ(0, c->Release(LocalHandle())); - EXPECT_LT(0, RETRY_EINTR(p->Poll(10))); - - // Test that removing persistence and closing the producer orphans the - // consumer. - EXPECT_EQ(0, p->Gain(&fence)); - EXPECT_EQ(0, p->Post<void>(LocalHandle())); - EXPECT_EQ(0, p->RemovePersistence()); - p = nullptr; - - // Orphaned consumer can acquire the posted buffer one more time in - // asynchronous manner. But synchronous call will fail. - DvrNativeBufferMetadata meta; - EXPECT_EQ(0, c->AcquireAsync(&meta, &fence)); - EXPECT_EQ(-EPIPE, c->Release(LocalHandle())); -} - -namespace { - -int PollFd(int fd, int timeout_ms) { - pollfd p = {fd, POLLIN, 0}; - return poll(&p, 1, timeout_ms); -} - -} // namespace - -TEST_F(LibBufferHubTest, TestAcquireFence) { - std::unique_ptr<BufferProducer> p = BufferProducer::Create( - kWidth, kHeight, kFormat, kUsage, /*metadata_size=*/0); - ASSERT_TRUE(p.get() != nullptr); - std::unique_ptr<BufferConsumer> c = - BufferConsumer::Import(p->CreateConsumer()); - ASSERT_TRUE(c.get() != nullptr); - - DvrNativeBufferMetadata meta; - LocalHandle f1(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); - - // Post with unsignaled fence. - EXPECT_EQ(0, p->PostAsync(&meta, f1)); - - // Should acquire a valid fence. - LocalHandle f2; - EXPECT_LT(0, RETRY_EINTR(c->Poll(10))); - EXPECT_EQ(0, c->AcquireAsync(&meta, &f2)); - EXPECT_TRUE(f2.IsValid()); - // The original fence and acquired fence should have different fd number. - EXPECT_NE(f1.Get(), f2.Get()); - EXPECT_GE(0, PollFd(f2.Get(), 0)); - - // Signal the original fence will trigger the new fence. - eventfd_write(f1.Get(), 1); - // Now the original FD has been signaled. - EXPECT_LT(0, PollFd(f2.Get(), 10)); - - // Release the consumer with an invalid fence. - EXPECT_EQ(0, c->ReleaseAsync(&meta, LocalHandle())); - - // Should gain an invalid fence. - LocalHandle f3; - EXPECT_LT(0, RETRY_EINTR(p->Poll(10))); - EXPECT_EQ(0, p->GainAsync(&meta, &f3)); - EXPECT_FALSE(f3.IsValid()); - - // Post with a signaled fence. - EXPECT_EQ(0, p->PostAsync(&meta, f1)); - - // Should acquire a valid fence and it's already signalled. - LocalHandle f4; - EXPECT_LT(0, RETRY_EINTR(c->Poll(10))); - EXPECT_EQ(0, c->AcquireAsync(&meta, &f4)); - EXPECT_TRUE(f4.IsValid()); - EXPECT_LT(0, PollFd(f4.Get(), 10)); - - // Release with an unsignalled fence and signal it immediately after release - // without producer gainning. - LocalHandle f5(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); - EXPECT_EQ(0, c->ReleaseAsync(&meta, f5)); - eventfd_write(f5.Get(), 1); - - // Should gain a valid fence, which is already signaled. - LocalHandle f6; - EXPECT_LT(0, RETRY_EINTR(p->Poll(10))); - EXPECT_EQ(0, p->GainAsync(&meta, &f6)); - EXPECT_TRUE(f6.IsValid()); - EXPECT_LT(0, PollFd(f6.Get(), 10)); -} - -TEST_F(LibBufferHubTest, TestOrphanedAcquire) { - std::unique_ptr<BufferProducer> p = BufferProducer::Create( - kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); - ASSERT_TRUE(p.get() != nullptr); - std::unique_ptr<BufferConsumer> c1 = - BufferConsumer::Import(p->CreateConsumer()); - ASSERT_TRUE(c1.get() != nullptr); - const uint64_t consumer_state_bit1 = c1->buffer_state_bit(); - - DvrNativeBufferMetadata meta; - EXPECT_EQ(0, p->PostAsync(&meta, LocalHandle())); - - LocalHandle fence; - EXPECT_LT(0, RETRY_EINTR(c1->Poll(10))); - EXPECT_LE(0, c1->AcquireAsync(&meta, &fence)); - // Destroy the consumer now will make it orphaned and the buffer is still - // acquired. - c1 = nullptr; - EXPECT_GE(0, RETRY_EINTR(p->Poll(10))); - - std::unique_ptr<BufferConsumer> c2 = - BufferConsumer::Import(p->CreateConsumer()); - ASSERT_TRUE(c2.get() != nullptr); - const uint64_t consumer_state_bit2 = c2->buffer_state_bit(); - EXPECT_NE(consumer_state_bit1, consumer_state_bit2); - - // The new consumer is available for acquire. - EXPECT_LT(0, RETRY_EINTR(c2->Poll(10))); - EXPECT_LE(0, c2->AcquireAsync(&meta, &fence)); - // Releasing the consumer makes the buffer gainable. - EXPECT_EQ(0, c2->ReleaseAsync(&meta, LocalHandle())); - - // The buffer is now available for the producer to gain. - EXPECT_LT(0, RETRY_EINTR(p->Poll(10))); - - // But if another consumer is created in released state. - std::unique_ptr<BufferConsumer> c3 = - BufferConsumer::Import(p->CreateConsumer()); - ASSERT_TRUE(c3.get() != nullptr); - const uint64_t consumer_state_bit3 = c3->buffer_state_bit(); - EXPECT_NE(consumer_state_bit2, consumer_state_bit3); - // The consumer buffer is not acquirable. - EXPECT_GE(0, RETRY_EINTR(c3->Poll(10))); - EXPECT_EQ(-EBUSY, c3->AcquireAsync(&meta, &fence)); - - // Producer should be able to gain no matter what. - EXPECT_EQ(0, p->GainAsync(&meta, &fence)); -} diff --git a/libs/vr/libbufferhub/detached_buffer.cpp b/libs/vr/libbufferhub/detached_buffer.cpp new file mode 100644 index 0000000000..6fae16d265 --- /dev/null +++ b/libs/vr/libbufferhub/detached_buffer.cpp @@ -0,0 +1,125 @@ +#include <private/dvr/detached_buffer.h> + +#include <pdx/file_handle.h> +#include <ui/DetachedBufferHandle.h> + +#include <poll.h> + +using android::pdx::LocalChannelHandle; +using android::pdx::LocalHandle; +using android::pdx::Status; + +namespace android { +namespace dvr { + +DetachedBuffer::DetachedBuffer(uint32_t width, uint32_t height, + uint32_t layer_count, uint32_t format, + uint64_t usage, size_t user_metadata_size) { + ATRACE_NAME("DetachedBuffer::DetachedBuffer"); + ALOGD_IF(TRACE, + "DetachedBuffer::DetachedBuffer: width=%u height=%u layer_count=%u, " + "format=%u usage=%" PRIx64 " user_metadata_size=%zu", + width, height, layer_count, format, usage, user_metadata_size); + + auto status = client_.InvokeRemoteMethod<DetachedBufferRPC::Create>( + width, height, layer_count, format, usage, user_metadata_size); + if (!status) { + ALOGE( + "DetachedBuffer::DetachedBuffer: Failed to create detached buffer: %s", + status.GetErrorMessage().c_str()); + client_.Close(-status.error()); + } + + const int ret = ImportGraphicBuffer(); + if (ret < 0) { + ALOGE("DetachedBuffer::DetachedBuffer: Failed to import buffer: %s", + strerror(-ret)); + client_.Close(ret); + } +} + +DetachedBuffer::DetachedBuffer(LocalChannelHandle channel_handle) + : client_(std::move(channel_handle)) { + const int ret = ImportGraphicBuffer(); + if (ret < 0) { + ALOGE("DetachedBuffer::DetachedBuffer: Failed to import buffer: %s", + strerror(-ret)); + client_.Close(ret); + } +} + +int DetachedBuffer::ImportGraphicBuffer() { + ATRACE_NAME("DetachedBuffer::DetachedBuffer"); + + auto status = client_.InvokeRemoteMethod<DetachedBufferRPC::Import>(); + if (!status) { + ALOGE("DetachedBuffer::DetachedBuffer: Failed to import GraphicBuffer: %s", + status.GetErrorMessage().c_str()); + return -status.error(); + } + + BufferDescription<LocalHandle> buffer_desc = status.take(); + if (buffer_desc.id() < 0) { + ALOGE("DetachedBuffer::DetachedBuffer: Received an invalid id!"); + return -EIO; + } + + // Stash the buffer id to replace the value in id_. + const int buffer_id = buffer_desc.id(); + + // Import the buffer. + IonBuffer ion_buffer; + ALOGD_IF(TRACE, "DetachedBuffer::DetachedBuffer: id=%d.", buffer_id); + + if (const int ret = buffer_desc.ImportBuffer(&ion_buffer)) { + ALOGE("Failed to import GraphicBuffer, error=%d", ret); + return ret; + } + + // If all imports succeed, replace the previous buffer and id. + id_ = buffer_id; + buffer_ = std::move(ion_buffer); + return 0; +} + +int DetachedBuffer::Poll(int timeout_ms) { + ATRACE_NAME("DetachedBuffer::Poll"); + pollfd p = {client_.event_fd(), POLLIN, 0}; + return poll(&p, 1, timeout_ms); +} + +Status<LocalChannelHandle> DetachedBuffer::Promote() { + ATRACE_NAME("DetachedBuffer::Promote"); + ALOGD_IF(TRACE, "DetachedBuffer::Promote: id=%d.", id_); + + auto status_or_handle = + client_.InvokeRemoteMethod<DetachedBufferRPC::Promote>(); + if (status_or_handle.ok()) { + // Invalidate the buffer. + buffer_ = {}; + } else { + ALOGE("DetachedBuffer::Promote: Failed to promote buffer (id=%d): %s.", id_, + status_or_handle.GetErrorMessage().c_str()); + } + return status_or_handle; +} + +sp<GraphicBuffer> DetachedBuffer::TakeGraphicBuffer() { + if (!client_.IsValid() || !buffer_.buffer()) { + ALOGE("DetachedBuffer::TakeGraphicBuffer: Invalid buffer."); + return nullptr; + } + + // Technically this should never happen. + LOG_FATAL_IF( + buffer_.buffer()->isDetachedBuffer(), + "DetachedBuffer::TakeGraphicBuffer: GraphicBuffer is already detached."); + + sp<GraphicBuffer> buffer = std::move(buffer_.buffer()); + buffer->setDetachedBufferHandle( + DetachedBufferHandle::Create(client_.TakeChannelHandle())); + return buffer; +} + +} // namespace dvr +} // namespace android diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h index 1186f9348d..0ea77c85fb 100644 --- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h +++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h @@ -16,6 +16,21 @@ namespace android { namespace dvr { +class BufferHubClient : public pdx::Client { + public: + BufferHubClient(); + explicit BufferHubClient(pdx::LocalChannelHandle channel_handle); + + bool IsValid() const; + pdx::LocalChannelHandle TakeChannelHandle(); + + using pdx::Client::Close; + using pdx::Client::GetChannel; + using pdx::Client::InvokeRemoteMethod; + using pdx::Client::IsConnected; + using pdx::Client::event_fd; +}; + class BufferHubBuffer : public pdx::Client { public: using LocalHandle = pdx::LocalHandle; @@ -94,6 +109,9 @@ class BufferHubBuffer : public pdx::Client { int id() const { return id_; } + // Returns the buffer buffer state. + uint64_t buffer_state() { return buffer_state_->load(); }; + // A state mask which is unique to a buffer hub client among all its siblings // sharing the same concrete graphic buffer. uint64_t buffer_state_bit() const { return buffer_state_bit_; } @@ -108,10 +126,6 @@ class BufferHubBuffer : public pdx::Client { uint32_t usage() const { return buffer_.usage(); } uint32_t layer_count() const { return buffer_.layer_count(); } - // TODO(b/37881101) Clean up producer/consumer usage. - uint64_t producer_usage() const { return buffer_.usage(); } - uint64_t consumer_usage() const { return buffer_.usage(); } - uint64_t GetQueueIndex() const { return metadata_header_->queue_index; } void SetQueueIndex(uint64_t index) { metadata_header_->queue_index = index; } @@ -218,18 +232,13 @@ class BufferProducer : public pdx::ClientBase<BufferProducer, BufferHubBuffer> { // succeeded, or a negative errno code if local error check fails. int GainAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence); - // Attaches the producer to |name| so that it becomes a persistent buffer that - // may be retrieved by name at a later time. This may be used in cases where a - // shared memory buffer should persist across the life of the producer process - // (i.e. the buffer may be held by clients across a service restart). The - // buffer may be associated with a user and/or group id to restrict access to - // the buffer. If user_id or group_id is -1 then checks for the respective id - // are disabled. If user_id or group_id is 0 then the respective id of the - // calling process is used instead. - int MakePersistent(const std::string& name, int user_id, int group_id); - - // Removes the persistence of the producer. - int RemovePersistence(); + // Detaches a ProducerBuffer from an existing producer/consumer set. Can only + // be called when a producer buffer has exclusive access to the buffer (i.e. + // in the gain'ed state). On the successful return of the IPC call, a new + // LocalChannelHandle representing a detached buffer will be returned and all + // existing producer and consumer channels will be closed. Further IPCs + // towards those channels will return error. + Status<LocalChannelHandle> Detach(); private: friend BASE; @@ -240,44 +249,10 @@ class BufferProducer : public pdx::ClientBase<BufferProducer, BufferHubBuffer> { // Constructs a buffer with the given geometry and parameters. BufferProducer(uint32_t width, uint32_t height, uint32_t format, - uint32_t usage, size_t metadata_size = 0); - BufferProducer(uint32_t width, uint32_t height, uint32_t format, - uint64_t producer_usage, uint64_t consumer_usage, - size_t metadata_size); - - // Constructs a persistent buffer with the given geometry and parameters and - // binds it to |name| in one shot. If a persistent buffer with the same name - // and settings already exists and matches the given geometry and parameters, - // that buffer is connected to this client instead of creating a new buffer. - // If the name matches but the geometry or settings do not match then - // construction fails and BufferProducer::Create() returns nullptr. - // - // Access to the persistent buffer may be restricted by |user_id| and/or - // |group_id|; these settings are established only when the buffer is first - // created and cannot be changed. A user or group id of -1 disables checks for - // that respective id. A user or group id of 0 is substituted with the - // effective user or group id of the calling process. - BufferProducer(const std::string& name, int user_id, int group_id, - uint32_t width, uint32_t height, uint32_t format, - uint32_t usage, size_t metadata_size = 0); - BufferProducer(const std::string& name, int user_id, int group_id, - uint32_t width, uint32_t height, uint32_t format, - uint64_t producer_usage, uint64_t consumer_usage, - size_t user_metadata_size); + uint64_t usage, size_t metadata_size = 0); // Constructs a blob (flat) buffer with the given usage flags. - BufferProducer(uint32_t usage, size_t size); - BufferProducer(uint64_t producer_usage, uint64_t consumer_usage, size_t size); - - // Constructs a persistent blob (flat) buffer and binds it to |name|. - BufferProducer(const std::string& name, int user_id, int group_id, - uint32_t usage, size_t size); - BufferProducer(const std::string& name, int user_id, int group_id, - uint64_t producer_usage, uint64_t consumer_usage, size_t size); - - // Constructs a channel to persistent buffer by name only. The buffer must - // have been previously created or made persistent. - explicit BufferProducer(const std::string& name); + BufferProducer(uint64_t usage, size_t size); // Imports the given file handle to a producer channel, taking ownership. explicit BufferProducer(LocalChannelHandle channel); diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h index f9fd42d7bb..f4918c497e 100644 --- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h +++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h @@ -2,8 +2,8 @@ #define ANDROID_DVR_BUFFERHUB_RPC_H_ #include <cutils/native_handle.h> -#include <gui/BufferQueueDefs.h> #include <sys/types.h> +#include <ui/BufferQueueDefs.h> #include <dvr/dvr_api.h> #include <pdx/channel_handle.h> @@ -366,23 +366,25 @@ struct BufferHubRPC { // Op codes. enum { kOpCreateBuffer = 0, - kOpCreatePersistentBuffer, - kOpGetPersistentBuffer, kOpGetBuffer, kOpNewConsumer, - kOpProducerMakePersistent, - kOpProducerRemovePersistence, kOpProducerPost, kOpProducerGain, kOpConsumerAcquire, kOpConsumerRelease, kOpConsumerSetIgnore, + kOpProducerBufferDetach, + kOpConsumerBufferDetach, + kOpDetachedBufferCreate, + kOpDetachedBufferPromote, kOpCreateProducerQueue, kOpCreateConsumerQueue, kOpGetQueueInfo, kOpProducerQueueAllocateBuffers, kOpProducerQueueRemoveBuffer, kOpConsumerQueueImportBuffers, + // TODO(b/77153033): Separate all those RPC operations into subclasses. + kOpDetachedBufferBase = 1000, }; // Aliases. @@ -394,19 +396,9 @@ struct BufferHubRPC { PDX_REMOTE_METHOD(CreateBuffer, kOpCreateBuffer, void(uint32_t width, uint32_t height, uint32_t format, uint64_t usage, size_t user_metadata_size)); - PDX_REMOTE_METHOD(CreatePersistentBuffer, kOpCreatePersistentBuffer, - void(const std::string& name, int user_id, int group_id, - uint32_t width, uint32_t height, uint32_t format, - uint64_t usage, size_t user_metadata_size)); - PDX_REMOTE_METHOD(GetPersistentBuffer, kOpGetPersistentBuffer, - void(const std::string& name)); PDX_REMOTE_METHOD(GetBuffer, kOpGetBuffer, BufferDescription<LocalHandle>(Void)); PDX_REMOTE_METHOD(NewConsumer, kOpNewConsumer, LocalChannelHandle(Void)); - PDX_REMOTE_METHOD(ProducerMakePersistent, kOpProducerMakePersistent, - void(const std::string& name, int user_id, int group_id)); - PDX_REMOTE_METHOD(ProducerRemovePersistence, kOpProducerRemovePersistence, - void(Void)); PDX_REMOTE_METHOD(ProducerPost, kOpProducerPost, void(LocalFence acquire_fence)); PDX_REMOTE_METHOD(ProducerGain, kOpProducerGain, LocalFence(Void)); @@ -414,6 +406,17 @@ struct BufferHubRPC { PDX_REMOTE_METHOD(ConsumerRelease, kOpConsumerRelease, void(LocalFence release_fence)); PDX_REMOTE_METHOD(ConsumerSetIgnore, kOpConsumerSetIgnore, void(bool ignore)); + PDX_REMOTE_METHOD(ProducerBufferDetach, kOpProducerBufferDetach, + LocalChannelHandle(Void)); + + // Detaches a ConsumerBuffer from an existing producer/consumer set. Can only + // be called when the consumer is the only consumer and it has exclusive + // access to the buffer (i.e. in the acquired'ed state). On the successful + // return of the IPC call, a new DetachedBufferChannel handle will be returned + // and all existing producer and consumer channels will be closed. Further + // IPCs towards those channels will return error. + PDX_REMOTE_METHOD(ConsumerBufferDetach, kOpConsumerBufferDetach, + LocalChannelHandle(Void)); // Buffer Queue Methods. PDX_REMOTE_METHOD(CreateProducerQueue, kOpCreateProducerQueue, @@ -433,6 +436,25 @@ struct BufferHubRPC { std::vector<std::pair<LocalChannelHandle, size_t>>(Void)); }; +struct DetachedBufferRPC final : public BufferHubRPC { + private: + enum { + kOpCreate = kOpDetachedBufferBase, + kOpImport, + kOpPromote, + }; + + public: + PDX_REMOTE_METHOD(Create, kOpCreate, + void(uint32_t width, uint32_t height, uint32_t layer_count, + uint32_t format, uint64_t usage, + size_t user_metadata_size)); + PDX_REMOTE_METHOD(Import, kOpImport, BufferDescription<LocalHandle>(Void)); + PDX_REMOTE_METHOD(Promote, kOpPromote, LocalChannelHandle(Void)); + + PDX_REMOTE_API(API, Create, Promote); +}; + } // namespace dvr } // namespace android diff --git a/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h b/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h new file mode 100644 index 0000000000..6d0b502271 --- /dev/null +++ b/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h @@ -0,0 +1,82 @@ +#ifndef ANDROID_DVR_DETACHED_BUFFER_H_ +#define ANDROID_DVR_DETACHED_BUFFER_H_ + +#include <private/dvr/buffer_hub_client.h> + +namespace android { +namespace dvr { + +class DetachedBuffer { + public: + // Allocates a standalone DetachedBuffer not associated with any producer + // consumer set. + static std::unique_ptr<DetachedBuffer> Create(uint32_t width, uint32_t height, + uint32_t layer_count, + uint32_t format, uint64_t usage, + size_t user_metadata_size) { + return std::unique_ptr<DetachedBuffer>(new DetachedBuffer( + width, height, layer_count, format, usage, user_metadata_size)); + } + + // Imports the given channel handle to a DetachedBuffer, taking ownership. + static std::unique_ptr<DetachedBuffer> Import( + pdx::LocalChannelHandle channel_handle) { + return std::unique_ptr<DetachedBuffer>( + new DetachedBuffer(std::move(channel_handle))); + } + + DetachedBuffer(const DetachedBuffer&) = delete; + void operator=(const DetachedBuffer&) = delete; + + const sp<GraphicBuffer>& buffer() const { return buffer_.buffer(); } + + int id() const { return id_; } + + // Returns true if the buffer holds an open PDX channels towards bufferhubd. + bool IsConnected() const { return client_.IsValid(); } + + // Returns true if the buffer holds an valid gralloc buffer handle that's + // availble for the client to read from and/or write into. + bool IsValid() const { return buffer_.IsValid(); } + + // Returns the event mask for all the events that are pending on this buffer + // (see sys/poll.h for all possible bits). + pdx::Status<int> GetEventMask(int events) { + if (auto* channel = client_.GetChannel()) { + return channel->GetEventMask(events); + } else { + return pdx::ErrorStatus(EINVAL); + } + } + + // Polls the fd for |timeout_ms| milliseconds (-1 for infinity). + int Poll(int timeout_ms); + + // Promotes a DetachedBuffer to become a ProducerBuffer. Once promoted the + // DetachedBuffer channel will be closed automatically on successful IPC + // return. Further IPCs towards this channel will return error. + pdx::Status<pdx::LocalChannelHandle> Promote(); + + // Takes the underlying graphic buffer out of this DetachedBuffer. This call + // immediately invalidates this DetachedBuffer object and transfers the + // underlying pdx::LocalChannelHandle into the GraphicBuffer. + sp<GraphicBuffer> TakeGraphicBuffer(); + + private: + DetachedBuffer(uint32_t width, uint32_t height, uint32_t layer_count, + uint32_t format, uint64_t usage, size_t user_metadata_size); + + DetachedBuffer(pdx::LocalChannelHandle channel_handle); + + int ImportGraphicBuffer(); + + // Global id for the buffer that is consistent across processes. + int id_; + IonBuffer buffer_; + BufferHubClient client_; +}; + +} // namespace dvr +} // namespace android + +#endif // ANDROID_DVR_DETACHED_BUFFER_H_ diff --git a/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h b/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h index 0d337f7b3b..f6bc5471f4 100644 --- a/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h +++ b/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h @@ -23,6 +23,9 @@ class IonBuffer { IonBuffer(IonBuffer&& other); IonBuffer& operator=(IonBuffer&& other); + // Returns check this IonBuffer holds a valid Gralloc buffer. + bool IsValid() const { return buffer_ && buffer_->initCheck() == NO_ERROR; } + // Frees the underlying native handle and leaves the instance initialized to // empty. void FreeHandle(); @@ -66,6 +69,7 @@ class IonBuffer { struct android_ycbcr* yuv); int Unlock(); + sp<GraphicBuffer>& buffer() { return buffer_; } const sp<GraphicBuffer>& buffer() const { return buffer_; } buffer_handle_t handle() const { return buffer_.get() ? buffer_->handle : nullptr; diff --git a/libs/vr/libbufferhub/include/private/dvr/native_buffer.h b/libs/vr/libbufferhub/include/private/dvr/native_buffer.h deleted file mode 100644 index 140ffc5a5a..0000000000 --- a/libs/vr/libbufferhub/include/private/dvr/native_buffer.h +++ /dev/null @@ -1,179 +0,0 @@ -#ifndef ANDROID_DVR_NATIVE_BUFFER_H_ -#define ANDROID_DVR_NATIVE_BUFFER_H_ - -#include <EGL/egl.h> -#include <EGL/eglext.h> -#include <log/log.h> -#include <ui/ANativeObjectBase.h> -#include <utils/RefBase.h> -#include <nativebase/nativebase.h> - -#include <private/dvr/buffer_hub_client.h> - -namespace android { -namespace dvr { - -// ANativeWindowBuffer is the abstraction Android HALs and frameworks use to -// pass around hardware graphics buffers. The following classes implement this -// abstraction with different DVR backing buffers, all of which provide -// different semantics on top of ion/gralloc buffers. - -// An implementation of ANativeWindowBuffer backed by an IonBuffer. -class NativeBuffer - : public android::ANativeObjectBase<ANativeWindowBuffer, NativeBuffer, - android::LightRefBase<NativeBuffer>> { - public: - static constexpr int kEmptyFence = -1; - - explicit NativeBuffer(const std::shared_ptr<IonBuffer>& buffer) - : BASE(), buffer_(buffer), fence_(kEmptyFence) { - ANativeWindowBuffer::width = buffer->width(); - ANativeWindowBuffer::height = buffer->height(); - ANativeWindowBuffer::stride = buffer->stride(); - ANativeWindowBuffer::format = buffer->format(); - ANativeWindowBuffer::usage = buffer->usage(); - handle = buffer_->handle(); - } - - virtual ~NativeBuffer() {} - - std::shared_ptr<IonBuffer> buffer() { return buffer_; } - int fence() const { return fence_.Get(); } - - void SetFence(int fence) { fence_.Reset(fence); } - - private: - friend class android::LightRefBase<NativeBuffer>; - - std::shared_ptr<IonBuffer> buffer_; - pdx::LocalHandle fence_; - - NativeBuffer(const NativeBuffer&) = delete; - void operator=(NativeBuffer&) = delete; -}; - -class NativeBufferProducer : public android::ANativeObjectBase< - ANativeWindowBuffer, NativeBufferProducer, - android::LightRefBase<NativeBufferProducer>> { - public: - static constexpr int kEmptyFence = -1; - - NativeBufferProducer(const std::shared_ptr<BufferProducer>& buffer, - EGLDisplay display, uint32_t surface_buffer_index) - : BASE(), - buffer_(buffer), - surface_buffer_index_(surface_buffer_index), - display_(display) { - ANativeWindowBuffer::width = buffer_->width(); - ANativeWindowBuffer::height = buffer_->height(); - ANativeWindowBuffer::stride = buffer_->stride(); - ANativeWindowBuffer::format = buffer_->format(); - ANativeWindowBuffer::usage = buffer_->usage(); - ANativeWindowBuffer::handle = buffer_->native_handle(); - if (display_) { - image_khr_ = - eglCreateImageKHR(display_, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, - static_cast<ANativeWindowBuffer*>(this), nullptr); - } else { - image_khr_ = EGL_NO_IMAGE_KHR; - } - } - - explicit NativeBufferProducer(const std::shared_ptr<BufferProducer>& buffer) - : NativeBufferProducer(buffer, nullptr, 0) {} - - virtual ~NativeBufferProducer() { - if (image_khr_ != EGL_NO_IMAGE_KHR) - eglDestroyImageKHR(display_, image_khr_); - } - - EGLImageKHR image_khr() const { return image_khr_; } - std::shared_ptr<BufferProducer> buffer() const { return buffer_; } - int release_fence() const { return release_fence_.Get(); } - uint32_t surface_buffer_index() const { return surface_buffer_index_; } - - // Return the release fence, passing ownership to the caller. - pdx::LocalHandle ClaimReleaseFence() { return std::move(release_fence_); } - - // Post the buffer consumer, closing the acquire and release fences. - int Post(int acquire_fence, uint64_t sequence) { - release_fence_.Close(); - return buffer_->Post(pdx::LocalHandle(acquire_fence), sequence); - } - - // Gain the buffer producer, closing the previous release fence if valid. - int Gain() { return buffer_->Gain(&release_fence_); } - - // Asynchronously gain the buffer, closing the previous release fence. - int GainAsync() { - release_fence_.Close(); - return buffer_->GainAsync(); - } - - private: - friend class android::LightRefBase<NativeBufferProducer>; - - std::shared_ptr<BufferProducer> buffer_; - pdx::LocalHandle release_fence_; - EGLImageKHR image_khr_; - uint32_t surface_buffer_index_; - EGLDisplay display_; - - NativeBufferProducer(const NativeBufferProducer&) = delete; - void operator=(NativeBufferProducer&) = delete; -}; - -// NativeBufferConsumer is an implementation of ANativeWindowBuffer backed by a -// BufferConsumer. -class NativeBufferConsumer : public android::ANativeObjectBase< - ANativeWindowBuffer, NativeBufferConsumer, - android::LightRefBase<NativeBufferConsumer>> { - public: - static constexpr int kEmptyFence = -1; - - explicit NativeBufferConsumer(const std::shared_ptr<BufferConsumer>& buffer) - : BASE(), buffer_(buffer), acquire_fence_(kEmptyFence), sequence_(0) { - ANativeWindowBuffer::width = buffer_->width(); - ANativeWindowBuffer::height = buffer_->height(); - ANativeWindowBuffer::stride = buffer_->stride(); - ANativeWindowBuffer::format = buffer_->format(); - ANativeWindowBuffer::usage = buffer_->usage(); - handle = buffer_->native_handle(); - } - - virtual ~NativeBufferConsumer() {} - - std::shared_ptr<BufferConsumer> buffer() const { return buffer_; } - int acquire_fence() const { return acquire_fence_.Get(); } - uint64_t sequence() const { return sequence_; } - - // Return the acquire fence, passing ownership to the caller. - pdx::LocalHandle ClaimAcquireFence() { return std::move(acquire_fence_); } - - // Acquire the underlying buffer consumer, closing the previous acquire fence - // if valid. - int Acquire() { return buffer_->Acquire(&acquire_fence_, &sequence_); } - - // Release the buffer consumer, closing the acquire and release fences if - // valid. - int Release(int release_fence) { - acquire_fence_.Close(); - sequence_ = 0; - return buffer_->Release(pdx::LocalHandle(release_fence)); - } - - private: - friend class android::LightRefBase<NativeBufferConsumer>; - - std::shared_ptr<BufferConsumer> buffer_; - pdx::LocalHandle acquire_fence_; - uint64_t sequence_; - - NativeBufferConsumer(const NativeBufferConsumer&) = delete; - void operator=(NativeBufferConsumer&) = delete; -}; - -} // namespace dvr -} // namespace android - -#endif // ANDROID_DVR_NATIVE_BUFFER_H_ diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp index b279875309..9f72c05f0c 100644 --- a/libs/vr/libbufferhubqueue/Android.bp +++ b/libs/vr/libbufferhubqueue/Android.bp @@ -14,7 +14,7 @@ sourceFiles = [ "buffer_hub_queue_client.cpp", - "buffer_hub_queue_producer.cpp", + "buffer_hub_queue_parcelable.cpp", ] includeFiles = [ @@ -23,8 +23,6 @@ includeFiles = [ staticLibraries = [ "libbufferhub", - "libdvrcommon", - "libpdx_default_transport", ] sharedLibraries = [ @@ -35,7 +33,7 @@ sharedLibraries = [ "liblog", "libui", "libutils", - "libgui", + "libpdx_default_transport", ] headerLibraries = [ @@ -43,7 +41,7 @@ headerLibraries = [ "libnativebase_headers", ] -cc_library { +cc_library_shared { name: "libbufferhubqueue", cflags: [ "-DLOG_TAG=\"libbufferhubqueue\"", @@ -63,4 +61,4 @@ cc_library { header_libs: headerLibraries, } -subdirs = ["tests"] +subdirs = ["benchmarks", "tests"] diff --git a/libs/vr/libbufferhubqueue/benchmarks/Android.bp b/libs/vr/libbufferhubqueue/benchmarks/Android.bp new file mode 100644 index 0000000000..5089b8754e --- /dev/null +++ b/libs/vr/libbufferhubqueue/benchmarks/Android.bp @@ -0,0 +1,26 @@ + +cc_benchmark { + srcs: ["buffer_transport_benchmark.cpp"], + shared_libs: [ + "libbase", + "libbinder", + "libcutils", + "libdvr", + "libgui", + "liblog", + "libhardware", + "libui", + "libutils", + "libnativewindow", + "libbufferhubqueue", + "libpdx_default_transport", + ], + cflags: [ + "-DLOG_TAG=\"buffer_transport_benchmark\"", + "-DTRACE=0", + "-O2", + "-Wall", + "-Werror", + ], + name: "buffer_transport_benchmark", +} diff --git a/libs/vr/libbufferhubqueue/benchmarks/buffer_transport_benchmark.cpp b/libs/vr/libbufferhubqueue/benchmarks/buffer_transport_benchmark.cpp new file mode 100644 index 0000000000..4ca8671f24 --- /dev/null +++ b/libs/vr/libbufferhubqueue/benchmarks/buffer_transport_benchmark.cpp @@ -0,0 +1,589 @@ +#include <android-base/logging.h> +#include <android/native_window.h> +#include <benchmark/benchmark.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <dvr/dvr_api.h> +#include <gui/BufferItem.h> +#include <gui/BufferItemConsumer.h> +#include <gui/Surface.h> +#include <private/dvr/epoll_file_descriptor.h> +#include <utils/Trace.h> + +#include <chrono> +#include <functional> +#include <iostream> +#include <thread> +#include <vector> + +#include <dlfcn.h> +#include <poll.h> +#include <sys/epoll.h> +#include <sys/wait.h> + +// Use ALWAYS at the tag level. Control is performed manually during command +// line processing. +#ifdef ATRACE_TAG +#undef ATRACE_TAG +#endif +#define ATRACE_TAG ATRACE_TAG_ALWAYS + +using namespace android; +using ::benchmark::State; + +static const String16 kBinderService = String16("bufferTransport"); +static const uint32_t kBufferWidth = 100; +static const uint32_t kBufferHeight = 1; +static const uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB; +static const uint64_t kBufferUsage = + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN; +static const uint32_t kBufferLayer = 1; +static const int kMaxAcquiredImages = 1; +static const int kQueueDepth = 2; // We are double buffering for this test. +static const size_t kMaxQueueCounts = 128; +static const int kInvalidFence = -1; + +enum BufferTransportServiceCode { + CREATE_BUFFER_QUEUE = IBinder::FIRST_CALL_TRANSACTION, +}; + +// A binder services that minics a compositor that consumes buffers. It provides +// one Binder interface to create a new Surface for buffer producer to write +// into; while itself will carry out no-op buffer consuming by acquiring then +// releasing the buffer immediately. +class BufferTransportService : public BBinder { + public: + BufferTransportService() = default; + ~BufferTransportService() = default; + + virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, + uint32_t flags = 0) { + (void)flags; + (void)data; + switch (code) { + case CREATE_BUFFER_QUEUE: { + auto new_queue = std::make_shared<BufferQueueHolder>(this); + reply->writeStrongBinder( + IGraphicBufferProducer::asBinder(new_queue->producer)); + buffer_queues_.push_back(new_queue); + return NO_ERROR; + } + default: + return UNKNOWN_TRANSACTION; + }; + } + + private: + struct FrameListener : public ConsumerBase::FrameAvailableListener { + public: + FrameListener(BufferTransportService* /*service*/, + sp<BufferItemConsumer> buffer_item_consumer) + : buffer_item_consumer_(buffer_item_consumer) {} + + void onFrameAvailable(const BufferItem& /*item*/) override { + BufferItem buffer; + status_t ret = 0; + { + ATRACE_NAME("AcquireBuffer"); + ret = buffer_item_consumer_->acquireBuffer(&buffer, /*presentWhen=*/0, + /*waitForFence=*/false); + } + + if (ret != NO_ERROR) { + LOG(ERROR) << "Failed to acquire next buffer."; + return; + } + + { + ATRACE_NAME("ReleaseBuffer"); + ret = buffer_item_consumer_->releaseBuffer(buffer); + } + + if (ret != NO_ERROR) { + LOG(ERROR) << "Failed to release buffer."; + return; + } + } + + private: + sp<BufferItemConsumer> buffer_item_consumer_; + }; + + struct BufferQueueHolder { + explicit BufferQueueHolder(BufferTransportService* service) { + BufferQueue::createBufferQueue(&producer, &consumer); + + sp<BufferItemConsumer> buffer_item_consumer = + new BufferItemConsumer(consumer, kBufferUsage, kMaxAcquiredImages, + /*controlledByApp=*/true); + buffer_item_consumer->setName(String8("BinderBufferTransport")); + frame_listener_ = new FrameListener(service, buffer_item_consumer); + buffer_item_consumer->setFrameAvailableListener(frame_listener_); + } + + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + + private: + sp<FrameListener> frame_listener_; + }; + + std::vector<std::shared_ptr<BufferQueueHolder>> buffer_queues_; +}; + +// A virtual interfaces that abstracts the common BufferQueue operations, so +// that the test suite can use the same test case to drive different types of +// transport backends. +class BufferTransport { + public: + virtual ~BufferTransport() {} + + virtual int Start() = 0; + virtual sp<Surface> CreateSurface() = 0; +}; + +// Binder-based buffer transport backend. +// +// On Start() a new process will be swapned to run a Binder server that +// actually consumes the buffer. +// On CreateSurface() a new Binder BufferQueue will be created, which the +// service holds the concrete binder node of the IGraphicBufferProducer while +// sending the binder proxy to the client. In another word, the producer side +// operations are carried out process while the consumer side operations are +// carried out within the BufferTransportService's own process. +class BinderBufferTransport : public BufferTransport { + public: + BinderBufferTransport() {} + + int Start() override { + sp<IServiceManager> sm = defaultServiceManager(); + service_ = sm->getService(kBinderService); + if (service_ == nullptr) { + LOG(ERROR) << "Failed to get the benchmark service."; + return -EIO; + } + + LOG(INFO) << "Binder server is ready for client."; + return 0; + } + + sp<Surface> CreateSurface() override { + Parcel data; + Parcel reply; + int error = service_->transact(CREATE_BUFFER_QUEUE, data, &reply); + if (error != NO_ERROR) { + LOG(ERROR) << "Failed to get buffer queue over binder."; + return nullptr; + } + + sp<IBinder> binder; + error = reply.readNullableStrongBinder(&binder); + if (error != NO_ERROR) { + LOG(ERROR) << "Failed to get IGraphicBufferProducer over binder."; + return nullptr; + } + + auto producer = interface_cast<IGraphicBufferProducer>(binder); + if (producer == nullptr) { + LOG(ERROR) << "Failed to get IGraphicBufferProducer over binder."; + return nullptr; + } + + sp<Surface> surface = new Surface(producer, /*controlledByApp=*/true); + + // Set buffer dimension. + ANativeWindow* window = static_cast<ANativeWindow*>(surface.get()); + ANativeWindow_setBuffersGeometry(window, kBufferWidth, kBufferHeight, + kBufferFormat); + + return surface; + } + + private: + sp<IBinder> service_; +}; + +class DvrApi { + public: + DvrApi() { + handle_ = dlopen("libdvr.so", RTLD_NOW | RTLD_LOCAL); + CHECK(handle_); + + auto dvr_get_api = + reinterpret_cast<decltype(&dvrGetApi)>(dlsym(handle_, "dvrGetApi")); + int ret = dvr_get_api(&api_, sizeof(api_), /*version=*/1); + + CHECK(ret == 0); + } + + ~DvrApi() { dlclose(handle_); } + + const DvrApi_v1& Api() { return api_; } + + private: + void* handle_ = nullptr; + DvrApi_v1 api_; +}; + +// BufferHub/PDX-based buffer transport. +// +// On Start() a new thread will be swapned to run an epoll polling thread which +// minics the behavior of a compositor. Similar to Binder-based backend, the +// buffer available handler is also a no-op: Buffer gets acquired and released +// immediately. +// On CreateSurface() a pair of dvr::ProducerQueue and dvr::ConsumerQueue will +// be created. The epoll thread holds on the consumer queue and dequeues buffer +// from it; while the producer queue will be wrapped in a Surface and returned +// to test suite. +class BufferHubTransport : public BufferTransport { + public: + virtual ~BufferHubTransport() { + stopped_.store(true); + if (reader_thread_.joinable()) { + reader_thread_.join(); + } + } + + int Start() override { + int ret = epoll_fd_.Create(); + if (ret < 0) { + LOG(ERROR) << "Failed to create epoll fd: %s", strerror(-ret); + return -1; + } + + // Create the reader thread. + reader_thread_ = std::thread([this]() { + int ret = dvr_.Api().PerformanceSetSchedulerPolicy(0, "graphics"); + if (ret < 0) { + LOG(ERROR) << "Failed to set scheduler policy, ret=" << ret; + return; + } + + stopped_.store(false); + LOG(INFO) << "Reader Thread Running..."; + + while (!stopped_.load()) { + std::array<epoll_event, kMaxQueueCounts> events; + + // Don't sleep forever so that we will have a chance to wake up. + const int ret = epoll_fd_.Wait(events.data(), events.size(), + /*timeout=*/100); + if (ret < 0) { + LOG(ERROR) << "Error polling consumer queues."; + continue; + } + if (ret == 0) { + continue; + } + + const int num_events = ret; + for (int i = 0; i < num_events; i++) { + uint32_t index = events[i].data.u32; + dvr_.Api().ReadBufferQueueHandleEvents( + buffer_queues_[index]->GetReadQueue()); + } + } + + LOG(INFO) << "Reader Thread Exiting..."; + }); + + return 0; + } + + sp<Surface> CreateSurface() override { + auto new_queue = std::make_shared<BufferQueueHolder>(); + if (!new_queue->IsReady()) { + LOG(ERROR) << "Failed to create BufferHub-based BufferQueue."; + return nullptr; + } + + // Set buffer dimension. + ANativeWindow_setBuffersGeometry(new_queue->GetSurface(), kBufferWidth, + kBufferHeight, kBufferFormat); + + // Use the next position as buffer_queue index. + uint32_t index = buffer_queues_.size(); + epoll_event event = {.events = EPOLLIN | EPOLLET, .data = {.u32 = index}}; + int queue_fd = + dvr_.Api().ReadBufferQueueGetEventFd(new_queue->GetReadQueue()); + const int ret = epoll_fd_.Control(EPOLL_CTL_ADD, queue_fd, &event); + if (ret < 0) { + LOG(ERROR) << "Failed to track consumer queue: " << strerror(-ret) + << ", consumer queue fd: " << queue_fd; + return nullptr; + } + + buffer_queues_.push_back(new_queue); + ANativeWindow_acquire(new_queue->GetSurface()); + return static_cast<Surface*>(new_queue->GetSurface()); + } + + private: + struct BufferQueueHolder { + BufferQueueHolder() { + int ret = 0; + ret = dvr_.Api().WriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kBufferLayer, + kBufferUsage, 0, sizeof(DvrNativeBufferMetadata), &write_queue_); + if (ret < 0) { + LOG(ERROR) << "Failed to create write buffer queue, ret=" << ret; + return; + } + + ret = dvr_.Api().WriteBufferQueueCreateReadQueue(write_queue_, + &read_queue_); + if (ret < 0) { + LOG(ERROR) << "Failed to create read buffer queue, ret=" << ret; + return; + } + + ret = dvr_.Api().ReadBufferQueueSetBufferAvailableCallback( + read_queue_, BufferAvailableCallback, this); + if (ret < 0) { + LOG(ERROR) << "Failed to create buffer available callback, ret=" << ret; + return; + } + + ret = + dvr_.Api().WriteBufferQueueGetANativeWindow(write_queue_, &surface_); + if (ret < 0) { + LOG(ERROR) << "Failed to create surface, ret=" << ret; + return; + } + } + + static void BufferAvailableCallback(void* context) { + BufferQueueHolder* thiz = static_cast<BufferQueueHolder*>(context); + thiz->HandleBufferAvailable(); + } + + DvrReadBufferQueue* GetReadQueue() { return read_queue_; } + + ANativeWindow* GetSurface() { return surface_; } + + bool IsReady() { + return write_queue_ != nullptr && read_queue_ != nullptr && + surface_ != nullptr; + } + + void HandleBufferAvailable() { + int ret = 0; + DvrNativeBufferMetadata meta; + DvrReadBuffer* buffer = nullptr; + DvrNativeBufferMetadata metadata; + int acquire_fence = kInvalidFence; + + { + ATRACE_NAME("AcquireBuffer"); + ret = dvr_.Api().ReadBufferQueueAcquireBuffer( + read_queue_, 0, &buffer, &metadata, &acquire_fence); + } + if (ret < 0) { + LOG(ERROR) << "Failed to acquire consumer buffer, error: " << ret; + return; + } + + if (buffer != nullptr) { + ATRACE_NAME("ReleaseBuffer"); + ret = dvr_.Api().ReadBufferQueueReleaseBuffer(read_queue_, buffer, + &meta, kInvalidFence); + } + if (ret < 0) { + LOG(ERROR) << "Failed to release consumer buffer, error: " << ret; + } + } + + private: + DvrWriteBufferQueue* write_queue_ = nullptr; + DvrReadBufferQueue* read_queue_ = nullptr; + ANativeWindow* surface_ = nullptr; + }; + + static DvrApi dvr_; + std::atomic<bool> stopped_; + std::thread reader_thread_; + + dvr::EpollFileDescriptor epoll_fd_; + std::vector<std::shared_ptr<BufferQueueHolder>> buffer_queues_; +}; + +DvrApi BufferHubTransport::dvr_ = {}; + +enum TransportType { + kBinderBufferTransport, + kBufferHubTransport, +}; + +// Main test suite, which supports two transport backend: 1) BinderBufferQueue, +// 2) BufferHubQueue. The test case drives the producer end of both transport +// backend by queuing buffers into the buffer queue by using ANativeWindow API. +class BufferTransportBenchmark : public ::benchmark::Fixture { + public: + void SetUp(State& state) override { + if (state.thread_index == 0) { + const int transport = state.range(0); + switch (transport) { + case kBinderBufferTransport: + transport_.reset(new BinderBufferTransport); + break; + case kBufferHubTransport: + transport_.reset(new BufferHubTransport); + break; + default: + CHECK(false) << "Unknown test case."; + break; + } + + CHECK(transport_); + const int ret = transport_->Start(); + CHECK_EQ(ret, 0); + + LOG(INFO) << "Transport backend running, transport=" << transport << "."; + + // Create surfaces for each thread. + surfaces_.resize(state.threads); + for (int i = 0; i < state.threads; i++) { + // Common setup every thread needs. + surfaces_[i] = transport_->CreateSurface(); + CHECK(surfaces_[i]); + + LOG(INFO) << "Surface initialized on thread " << i << "."; + } + } + } + + void TearDown(State& state) override { + if (state.thread_index == 0) { + surfaces_.clear(); + transport_.reset(); + LOG(INFO) << "Tear down benchmark."; + } + } + + protected: + std::unique_ptr<BufferTransport> transport_; + std::vector<sp<Surface>> surfaces_; +}; + +BENCHMARK_DEFINE_F(BufferTransportBenchmark, Producers)(State& state) { + ANativeWindow* window = nullptr; + ANativeWindow_Buffer buffer; + int32_t error = 0; + double total_gain_buffer_us = 0; + double total_post_buffer_us = 0; + int iterations = 0; + + while (state.KeepRunning()) { + if (window == nullptr) { + CHECK(surfaces_[state.thread_index]); + window = static_cast<ANativeWindow*>(surfaces_[state.thread_index].get()); + + // Lock buffers a couple time from the queue, so that we have the buffer + // allocated. + for (int i = 0; i < kQueueDepth; i++) { + error = ANativeWindow_lock(window, &buffer, + /*inOutDirtyBounds=*/nullptr); + CHECK_EQ(error, 0); + error = ANativeWindow_unlockAndPost(window); + CHECK_EQ(error, 0); + } + } + + { + ATRACE_NAME("GainBuffer"); + auto t1 = std::chrono::high_resolution_clock::now(); + error = ANativeWindow_lock(window, &buffer, + /*inOutDirtyBounds=*/nullptr); + auto t2 = std::chrono::high_resolution_clock::now(); + std::chrono::duration<double, std::micro> delta_us = t2 - t1; + total_gain_buffer_us += delta_us.count(); + } + CHECK_EQ(error, 0); + + { + ATRACE_NAME("PostBuffer"); + auto t1 = std::chrono::high_resolution_clock::now(); + error = ANativeWindow_unlockAndPost(window); + auto t2 = std::chrono::high_resolution_clock::now(); + std::chrono::duration<double, std::micro> delta_us = t2 - t1; + total_post_buffer_us += delta_us.count(); + } + CHECK_EQ(error, 0); + + iterations++; + } + + state.counters["gain_buffer_us"] = ::benchmark::Counter( + total_gain_buffer_us / iterations, ::benchmark::Counter::kAvgThreads); + state.counters["post_buffer_us"] = ::benchmark::Counter( + total_post_buffer_us / iterations, ::benchmark::Counter::kAvgThreads); + state.counters["producer_us"] = ::benchmark::Counter( + (total_gain_buffer_us + total_post_buffer_us) / iterations, + ::benchmark::Counter::kAvgThreads); +} + +BENCHMARK_REGISTER_F(BufferTransportBenchmark, Producers) + ->Unit(::benchmark::kMicrosecond) + ->Ranges({{kBinderBufferTransport, kBufferHubTransport}}) + ->ThreadRange(1, 32); + +static void runBinderServer() { + ProcessState::self()->setThreadPoolMaxThreadCount(0); + ProcessState::self()->startThreadPool(); + + sp<IServiceManager> sm = defaultServiceManager(); + sp<BufferTransportService> service = new BufferTransportService; + sm->addService(kBinderService, service, false); + + LOG(INFO) << "Binder server running..."; + + while (true) { + int stat, retval; + retval = wait(&stat); + if (retval == -1 && errno == ECHILD) { + break; + } + } + + LOG(INFO) << "Service Exiting..."; +} + +// To run binder-based benchmark, use: +// adb shell buffer_transport_benchmark \ +// --benchmark_filter="BufferTransportBenchmark/ContinuousLoad/0/" +// +// To run bufferhub-based benchmark, use: +// adb shell buffer_transport_benchmark \ +// --benchmark_filter="BufferTransportBenchmark/ContinuousLoad/1/" +int main(int argc, char** argv) { + bool tracing_enabled = false; + + // Parse arguments in addition to "--benchmark_filter" paramters. + for (int i = 1; i < argc; i++) { + if (std::string(argv[i]) == "--help") { + std::cout << "Usage: binderThroughputTest [OPTIONS]" << std::endl; + std::cout << "\t--trace: Enable systrace logging." << std::endl; + return 0; + } + if (std::string(argv[i]) == "--trace") { + tracing_enabled = true; + continue; + } + } + + // Setup ATRACE/systrace based on command line. + atrace_setup(); + atrace_set_tracing_enabled(tracing_enabled); + + pid_t pid = fork(); + if (pid == 0) { + // Child, i.e. the client side. + ProcessState::self()->startThreadPool(); + + ::benchmark::Initialize(&argc, argv); + ::benchmark::RunSpecifiedBenchmarks(); + } else { + LOG(INFO) << "Benchmark process pid: " << pid; + runBinderServer(); + } +} diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp index 8bea0cde7a..8feb1cd803 100644 --- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp +++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp @@ -31,20 +31,6 @@ namespace dvr { namespace { -// Polls an fd for the given events. -Status<int> PollEvents(int fd, short events) { - const int kTimeoutMs = 0; - pollfd pfd{fd, events, 0}; - const int count = RETRY_EINTR(poll(&pfd, 1, kTimeoutMs)); - if (count < 0) { - return ErrorStatus(errno); - } else if (count == 0) { - return ErrorStatus(ETIMEDOUT); - } else { - return {pfd.revents}; - } -} - std::pair<int32_t, int32_t> Unstuff(uint64_t value) { return {static_cast<int32_t>(value >> 32), static_cast<int32_t>(value & ((1ull << 32) - 1))}; @@ -137,6 +123,28 @@ Status<LocalChannelHandle> BufferHubQueue::CreateConsumerQueueHandle( return status; } +pdx::Status<ConsumerQueueParcelable> +BufferHubQueue::CreateConsumerQueueParcelable(bool silent) { + auto status = CreateConsumerQueueHandle(silent); + if (!status) + return status.error_status(); + + // A temporary consumer queue client to pull its channel parcelable. + auto consumer_queue = + std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take())); + ConsumerQueueParcelable queue_parcelable( + consumer_queue->GetChannel()->TakeChannelParcelable()); + + if (!queue_parcelable.IsValid()) { + ALOGE( + "BufferHubQueue::CreateConsumerQueueParcelable: Failed to create " + "consumer queue parcelable."); + return ErrorStatus(EINVAL); + } + + return {std::move(queue_parcelable)}; +} + bool BufferHubQueue::WaitForBuffers(int timeout) { ATRACE_NAME("BufferHubQueue::WaitForBuffers"); std::array<epoll_event, kMaxEvents> events; @@ -555,6 +563,31 @@ pdx::Status<std::shared_ptr<BufferProducer>> ProducerQueue::Dequeue( return {std::move(buffer)}; } +pdx::Status<ProducerQueueParcelable> ProducerQueue::TakeAsParcelable() { + if (capacity() != 0) { + ALOGE( + "ProducerQueue::TakeAsParcelable: producer queue can only be taken out" + " as a parcelable when empty. Current queue capacity: %zu", + capacity()); + return ErrorStatus(EINVAL); + } + + std::unique_ptr<pdx::ClientChannel> channel = TakeChannel(); + ProducerQueueParcelable queue_parcelable(channel->TakeChannelParcelable()); + + // Here the queue parcelable is returned and holds the underlying system + // resources backing the queue; while the original client channel of this + // producer queue is destroyed in place so that this client can no longer + // provide producer operations. + return {std::move(queue_parcelable)}; +} + +/*static */ +std::unique_ptr<ConsumerQueue> ConsumerQueue::Import( + LocalChannelHandle handle) { + return std::unique_ptr<ConsumerQueue>(new ConsumerQueue(std::move(handle))); +} + ConsumerQueue::ConsumerQueue(LocalChannelHandle handle) : BufferHubQueue(std::move(handle)) { auto status = ImportQueue(); @@ -629,27 +662,7 @@ Status<void> ConsumerQueue::AddBuffer( const std::shared_ptr<BufferConsumer>& buffer, size_t slot) { ALOGD_IF(TRACE, "ConsumerQueue::AddBuffer: queue_id=%d buffer_id=%d slot=%zu", id(), buffer->id(), slot); - auto status = BufferHubQueue::AddBuffer(buffer, slot); - if (!status) - return status; - - // Check to see if the buffer is already signaled. This is necessary to catch - // cases where buffers are already available; epoll edge triggered mode does - // not fire until an edge transition when adding new buffers to the epoll - // set. Note that we only poll the fd events because HandleBufferEvent() takes - // care of checking the translated buffer events. - auto poll_status = PollEvents(buffer->event_fd(), POLLIN); - if (!poll_status && poll_status.error() != ETIMEDOUT) { - ALOGE("ConsumerQueue::AddBuffer: Failed to poll consumer buffer: %s", - poll_status.GetErrorMessage().c_str()); - return poll_status.error_status(); - } - - // Update accounting if the buffer is available. - if (poll_status) - return HandleBufferEvent(slot, buffer->event_fd(), poll_status.get()); - else - return {}; + return BufferHubQueue::AddBuffer(buffer, slot); } Status<std::shared_ptr<BufferConsumer>> ConsumerQueue::Dequeue( diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_parcelable.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_parcelable.cpp new file mode 100644 index 0000000000..2cd7c452be --- /dev/null +++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_parcelable.cpp @@ -0,0 +1,82 @@ +#include "include/private/dvr/buffer_hub_queue_parcelable.h" + +#include <binder/Parcel.h> +#include <pdx/default_transport/channel_parcelable.h> + +namespace android { +namespace dvr { + +template <BufferHubQueueParcelableMagic Magic> +bool BufferHubQueueParcelable<Magic>::IsValid() const { + return !!channel_parcelable_ && channel_parcelable_->IsValid(); +} + +template <BufferHubQueueParcelableMagic Magic> +pdx::LocalChannelHandle BufferHubQueueParcelable<Magic>::TakeChannelHandle() { + if (!IsValid()) { + ALOGE( + "BufferHubQueueParcelable::TakeChannelHandle: Invalid channel parcel."); + return {}; // Returns an empty channel handle. + } + + // Take channel handle out of the parcelable and reset the parcelable. + pdx::LocalChannelHandle handle = channel_parcelable_->TakeChannelHandle(); + // Now channel_parcelable_ should already be invalid, but reset it to release + // the invalid parcelable object from unique_ptr. + channel_parcelable_ = nullptr; + return handle; +} + +template <BufferHubQueueParcelableMagic Magic> +status_t BufferHubQueueParcelable<Magic>::writeToParcel(Parcel* parcel) const { + if (!IsValid()) { + ALOGE("BufferHubQueueParcelable::writeToParcel: Invalid channel."); + return -EINVAL; + } + + status_t res = parcel->writeUint32(Magic); + if (res != NO_ERROR) { + ALOGE("BufferHubQueueParcelable::writeToParcel: Cannot write magic."); + return res; + } + + return channel_parcelable_->writeToParcel(parcel); +} + +template <BufferHubQueueParcelableMagic Magic> +status_t BufferHubQueueParcelable<Magic>::readFromParcel(const Parcel* parcel) { + if (IsValid()) { + ALOGE( + "BufferHubQueueParcelable::readFromParcel: This parcelable object has " + "been initialized already."); + return -EINVAL; + } + + uint32_t out_magic = 0; + status_t res = NO_ERROR; + + res = parcel->readUint32(&out_magic); + if (res != NO_ERROR) + return res; + + if (out_magic != Magic) { + ALOGE( + "BufferHubQueueParcelable::readFromParcel: Unexpected magic: 0x%x, " + "epxected: 0x%x", + out_magic, Magic); + return -EINVAL; + } + + // (Re)Alocate channel parcelable object. + channel_parcelable_ = + std::make_unique<pdx::default_transport::ChannelParcelable>(); + return channel_parcelable_->readFromParcel(parcel); +} + +template class BufferHubQueueParcelable< + BufferHubQueueParcelableMagic::Producer>; +template class BufferHubQueueParcelable< + BufferHubQueueParcelableMagic::Consumer>; + +} // namespace dvr +} // namespace android diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp deleted file mode 100644 index 221bc4f9d2..0000000000 --- a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp +++ /dev/null @@ -1,686 +0,0 @@ -#include "include/private/dvr/buffer_hub_queue_producer.h" - -#include <dvr/dvr_api.h> -#include <inttypes.h> -#include <log/log.h> -#include <system/window.h> - -namespace android { -namespace dvr { - -/* static */ -sp<BufferHubQueueProducer> BufferHubQueueProducer::Create() { - sp<BufferHubQueueProducer> producer = new BufferHubQueueProducer; - auto config = ProducerQueueConfigBuilder() - .SetMetadata<DvrNativeBufferMetadata>() - .Build(); - producer->queue_ = ProducerQueue::Create(config, UsagePolicy{}); - return producer; -} - -/* static */ -sp<BufferHubQueueProducer> BufferHubQueueProducer::Create( - const std::shared_ptr<ProducerQueue>& queue) { - if (queue->metadata_size() != sizeof(DvrNativeBufferMetadata)) { - ALOGE( - "BufferHubQueueProducer::Create producer's metadata size is different " - "than the size of DvrNativeBufferMetadata"); - return nullptr; - } - - sp<BufferHubQueueProducer> producer = new BufferHubQueueProducer; - producer->queue_ = queue; - return producer; -} - -status_t BufferHubQueueProducer::requestBuffer(int slot, - sp<GraphicBuffer>* buf) { - ALOGD_IF(TRACE, "requestBuffer: slot=%d", slot); - - std::unique_lock<std::mutex> lock(mutex_); - - if (connected_api_ == kNoConnectedApi) { - ALOGE("requestBuffer: BufferHubQueueProducer has no connected producer"); - return NO_INIT; - } - - if (slot < 0 || slot >= max_buffer_count_) { - ALOGE("requestBuffer: slot index %d out of range [0, %d)", slot, - max_buffer_count_); - return BAD_VALUE; - } else if (!buffers_[slot].mBufferState.isDequeued()) { - ALOGE("requestBuffer: slot %d is not owned by the producer (state = %s)", - slot, buffers_[slot].mBufferState.string()); - return BAD_VALUE; - } else if (buffers_[slot].mGraphicBuffer != nullptr) { - ALOGE("requestBuffer: slot %d is not empty.", slot); - return BAD_VALUE; - } else if (buffers_[slot].mBufferProducer == nullptr) { - ALOGE("requestBuffer: slot %d is not dequeued.", slot); - return BAD_VALUE; - } - - const auto& buffer_producer = buffers_[slot].mBufferProducer; - sp<GraphicBuffer> graphic_buffer = buffer_producer->buffer()->buffer(); - - buffers_[slot].mGraphicBuffer = graphic_buffer; - buffers_[slot].mRequestBufferCalled = true; - - *buf = graphic_buffer; - return NO_ERROR; -} - -status_t BufferHubQueueProducer::setMaxDequeuedBufferCount( - int max_dequeued_buffers) { - ALOGD_IF(TRACE, "setMaxDequeuedBufferCount: max_dequeued_buffers=%d", - max_dequeued_buffers); - - std::unique_lock<std::mutex> lock(mutex_); - - if (max_dequeued_buffers <= 0 || - max_dequeued_buffers > - static_cast<int>(BufferHubQueue::kMaxQueueCapacity - - kDefaultUndequeuedBuffers)) { - ALOGE("setMaxDequeuedBufferCount: %d out of range (0, %zu]", - max_dequeued_buffers, BufferHubQueue::kMaxQueueCapacity); - return BAD_VALUE; - } - - // The new dequeued_buffers count should not be violated by the number - // of currently dequeued buffers. - int dequeued_count = 0; - for (const auto& buf : buffers_) { - if (buf.mBufferState.isDequeued()) { - dequeued_count++; - } - } - if (dequeued_count > max_dequeued_buffers) { - ALOGE( - "setMaxDequeuedBufferCount: the requested dequeued_buffers" - "count (%d) exceeds the current dequeued buffer count (%d)", - max_dequeued_buffers, dequeued_count); - return BAD_VALUE; - } - - max_dequeued_buffer_count_ = max_dequeued_buffers; - return NO_ERROR; -} - -status_t BufferHubQueueProducer::setAsyncMode(bool async) { - if (async) { - // TODO(b/36724099) BufferHubQueue's consumer end always acquires the buffer - // automatically and behaves differently from IGraphicBufferConsumer. Thus, - // android::BufferQueue's async mode (a.k.a. allocating an additional buffer - // to prevent dequeueBuffer from being blocking) technically does not apply - // here. - // - // In Daydream, non-blocking producer side dequeue is guaranteed by careful - // buffer consumer implementations. In another word, BufferHubQueue based - // dequeueBuffer should never block whether setAsyncMode(true) is set or - // not. - // - // See: IGraphicBufferProducer::setAsyncMode and - // BufferQueueProducer::setAsyncMode for more about original implementation. - ALOGW( - "BufferHubQueueProducer::setAsyncMode: BufferHubQueue should always be " - "asynchronous. This call makes no effact."); - return NO_ERROR; - } - return NO_ERROR; -} - -status_t BufferHubQueueProducer::dequeueBuffer( - int* out_slot, sp<Fence>* out_fence, uint32_t width, uint32_t height, - PixelFormat format, uint64_t usage, uint64_t* /*outBufferAge*/, - FrameEventHistoryDelta* /* out_timestamps */) { - ALOGD_IF(TRACE, "dequeueBuffer: w=%u, h=%u, format=%d, usage=%" PRIu64, width, - height, format, usage); - - status_t ret; - std::unique_lock<std::mutex> lock(mutex_); - - if (connected_api_ == kNoConnectedApi) { - ALOGE("dequeueBuffer: BufferQueue has no connected producer"); - return NO_INIT; - } - - const uint32_t kLayerCount = 1; - if (static_cast<int32_t>(queue_->capacity()) < - max_dequeued_buffer_count_ + kDefaultUndequeuedBuffers) { - // Lazy allocation. When the capacity of |queue_| has not reached - // |max_dequeued_buffer_count_|, allocate new buffer. - // TODO(jwcai) To save memory, the really reasonable thing to do is to go - // over existing slots and find first existing one to dequeue. - ret = AllocateBuffer(width, height, kLayerCount, format, usage); - if (ret < 0) - return ret; - } - - size_t slot; - std::shared_ptr<BufferProducer> buffer_producer; - - for (size_t retry = 0; retry < BufferHubQueue::kMaxQueueCapacity; retry++) { - LocalHandle fence; - auto buffer_status = queue_->Dequeue(dequeue_timeout_ms_, &slot, &fence); - if (!buffer_status) - return NO_MEMORY; - - buffer_producer = buffer_status.take(); - if (!buffer_producer) - return NO_MEMORY; - - if (width == buffer_producer->width() && - height == buffer_producer->height() && - static_cast<uint32_t>(format) == buffer_producer->format()) { - // The producer queue returns a buffer producer matches the request. - break; - } - - // Needs reallocation. - // TODO(jwcai) Consider use VLOG instead if we find this log is not useful. - ALOGI( - "dequeueBuffer: requested buffer (w=%u, h=%u, format=%u) is different " - "from the buffer returned at slot: %zu (w=%u, h=%u, format=%u). Need " - "re-allocattion.", - width, height, format, slot, buffer_producer->width(), - buffer_producer->height(), buffer_producer->format()); - // Mark the slot as reallocating, so that later we can set - // BUFFER_NEEDS_REALLOCATION when the buffer actually get dequeued. - buffers_[slot].mIsReallocating = true; - - // Remove the old buffer once the allocation before allocating its - // replacement. - RemoveBuffer(slot); - - // Allocate a new producer buffer with new buffer configs. Note that if - // there are already multiple buffers in the queue, the next one returned - // from |queue_->Dequeue| may not be the new buffer we just reallocated. - // Retry up to BufferHubQueue::kMaxQueueCapacity times. - ret = AllocateBuffer(width, height, kLayerCount, format, usage); - if (ret < 0) - return ret; - } - - // With the BufferHub backed solution. Buffer slot returned from - // |queue_->Dequeue| is guaranteed to avaiable for producer's use. - // It's either in free state (if the buffer has never been used before) or - // in queued state (if the buffer has been dequeued and queued back to - // BufferHubQueue). - LOG_ALWAYS_FATAL_IF( - (!buffers_[slot].mBufferState.isFree() && - !buffers_[slot].mBufferState.isQueued()), - "dequeueBuffer: slot %zu is not free or queued, actual state: %s.", slot, - buffers_[slot].mBufferState.string()); - - buffers_[slot].mBufferState.freeQueued(); - buffers_[slot].mBufferState.dequeue(); - ALOGD_IF(TRACE, "dequeueBuffer: slot=%zu", slot); - - // TODO(jwcai) Handle fence properly. |BufferHub| has full fence support, we - // just need to exopose that through |BufferHubQueue| once we need fence. - *out_fence = Fence::NO_FENCE; - *out_slot = slot; - ret = NO_ERROR; - - if (buffers_[slot].mIsReallocating) { - ret |= BUFFER_NEEDS_REALLOCATION; - buffers_[slot].mIsReallocating = false; - } - - return ret; -} - -status_t BufferHubQueueProducer::detachBuffer(int /* slot */) { - ALOGE("BufferHubQueueProducer::detachBuffer not implemented."); - return INVALID_OPERATION; -} - -status_t BufferHubQueueProducer::detachNextBuffer( - sp<GraphicBuffer>* /* out_buffer */, sp<Fence>* /* out_fence */) { - ALOGE("BufferHubQueueProducer::detachNextBuffer not implemented."); - return INVALID_OPERATION; -} - -status_t BufferHubQueueProducer::attachBuffer( - int* /* out_slot */, const sp<GraphicBuffer>& /* buffer */) { - // With this BufferHub backed implementation, we assume (for now) all buffers - // are allocated and owned by the BufferHub. Thus the attempt of transfering - // ownership of a buffer to the buffer queue is intentionally unsupported. - LOG_ALWAYS_FATAL("BufferHubQueueProducer::attachBuffer not supported."); - return INVALID_OPERATION; -} - -status_t BufferHubQueueProducer::queueBuffer(int slot, - const QueueBufferInput& input, - QueueBufferOutput* output) { - ALOGD_IF(TRACE, "queueBuffer: slot %d", slot); - - if (output == nullptr) { - return BAD_VALUE; - } - - int64_t timestamp; - bool is_auto_timestamp; - android_dataspace dataspace; - Rect crop(Rect::EMPTY_RECT); - int scaling_mode; - uint32_t transform; - sp<Fence> fence; - - input.deflate(×tamp, &is_auto_timestamp, &dataspace, &crop, - &scaling_mode, &transform, &fence); - - // Check input scaling mode is valid. - switch (scaling_mode) { - case NATIVE_WINDOW_SCALING_MODE_FREEZE: - case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: - case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: - case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP: - break; - default: - ALOGE("queueBuffer: unknown scaling mode %d", scaling_mode); - return BAD_VALUE; - } - - // Check input fence is valid. - if (fence == nullptr) { - ALOGE("queueBuffer: fence is NULL"); - return BAD_VALUE; - } - - status_t ret; - std::unique_lock<std::mutex> lock(mutex_); - - if (connected_api_ == kNoConnectedApi) { - ALOGE("queueBuffer: BufferQueue has no connected producer"); - return NO_INIT; - } - - if (slot < 0 || slot >= max_buffer_count_) { - ALOGE("queueBuffer: slot index %d out of range [0, %d)", slot, - max_buffer_count_); - return BAD_VALUE; - } else if (!buffers_[slot].mBufferState.isDequeued()) { - ALOGE("queueBuffer: slot %d is not owned by the producer (state = %s)", - slot, buffers_[slot].mBufferState.string()); - return BAD_VALUE; - } else if ((!buffers_[slot].mRequestBufferCalled || - buffers_[slot].mGraphicBuffer == nullptr)) { - ALOGE( - "queueBuffer: slot %d is not requested (mRequestBufferCalled=%d, " - "mGraphicBuffer=%p)", - slot, buffers_[slot].mRequestBufferCalled, - buffers_[slot].mGraphicBuffer.get()); - return BAD_VALUE; - } - - // Post the buffer producer with timestamp in the metadata. - const auto& buffer_producer = buffers_[slot].mBufferProducer; - - // Check input crop is not out of boundary of current buffer. - Rect buffer_rect(buffer_producer->width(), buffer_producer->height()); - Rect cropped_rect(Rect::EMPTY_RECT); - crop.intersect(buffer_rect, &cropped_rect); - if (cropped_rect != crop) { - ALOGE("queueBuffer: slot %d has out-of-boundary crop.", slot); - return BAD_VALUE; - } - - LocalHandle fence_fd(fence->isValid() ? fence->dup() : -1); - - DvrNativeBufferMetadata meta_data; - meta_data.timestamp = timestamp; - meta_data.is_auto_timestamp = static_cast<int32_t>(is_auto_timestamp); - meta_data.dataspace = static_cast<int32_t>(dataspace); - meta_data.crop_left = crop.left; - meta_data.crop_top = crop.top; - meta_data.crop_right = crop.right; - meta_data.crop_bottom = crop.bottom; - meta_data.scaling_mode = static_cast<int32_t>(scaling_mode); - meta_data.transform = static_cast<int32_t>(transform); - - buffer_producer->PostAsync(&meta_data, fence_fd); - buffers_[slot].mBufferState.queue(); - - output->width = buffer_producer->width(); - output->height = buffer_producer->height(); - output->transformHint = 0; // default value, we don't use it yet. - - // |numPendingBuffers| counts of the number of buffers that has been enqueued - // by the producer but not yet acquired by the consumer. Due to the nature - // of BufferHubQueue design, this is hard to trace from the producer's client - // side, but it's safe to assume it's zero. - output->numPendingBuffers = 0; - - // Note that we are not setting nextFrameNumber here as it seems to be only - // used by surface flinger. See more at b/22802885, ag/791760. - output->nextFrameNumber = 0; - - return NO_ERROR; -} - -status_t BufferHubQueueProducer::cancelBuffer(int slot, - const sp<Fence>& fence) { - ALOGD_IF(TRACE, __FUNCTION__); - - std::unique_lock<std::mutex> lock(mutex_); - - if (connected_api_ == kNoConnectedApi) { - ALOGE("cancelBuffer: BufferQueue has no connected producer"); - return NO_INIT; - } - - if (slot < 0 || slot >= max_buffer_count_) { - ALOGE("cancelBuffer: slot index %d out of range [0, %d)", slot, - max_buffer_count_); - return BAD_VALUE; - } else if (!buffers_[slot].mBufferState.isDequeued()) { - ALOGE("cancelBuffer: slot %d is not owned by the producer (state = %s)", - slot, buffers_[slot].mBufferState.string()); - return BAD_VALUE; - } else if (fence == nullptr) { - ALOGE("cancelBuffer: fence is NULL"); - return BAD_VALUE; - } - - auto buffer_producer = buffers_[slot].mBufferProducer; - queue_->Enqueue(buffer_producer, slot, 0ULL); - buffers_[slot].mBufferState.cancel(); - buffers_[slot].mFence = fence; - ALOGD_IF(TRACE, "cancelBuffer: slot %d", slot); - - return NO_ERROR; -} - -status_t BufferHubQueueProducer::query(int what, int* out_value) { - ALOGD_IF(TRACE, __FUNCTION__); - - std::unique_lock<std::mutex> lock(mutex_); - - if (out_value == nullptr) { - ALOGE("query: out_value was NULL"); - return BAD_VALUE; - } - - int value = 0; - switch (what) { - case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: - // TODO(b/36187402) This should be the maximum number of buffers that this - // producer queue's consumer can acquire. Set to be at least one. Need to - // find a way to set from the consumer side. - value = kDefaultUndequeuedBuffers; - break; - case NATIVE_WINDOW_BUFFER_AGE: - value = 0; - break; - case NATIVE_WINDOW_WIDTH: - value = queue_->default_width(); - break; - case NATIVE_WINDOW_HEIGHT: - value = queue_->default_height(); - break; - case NATIVE_WINDOW_FORMAT: - value = queue_->default_format(); - break; - case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: - // BufferHubQueue is always operating in async mode, thus semantically - // consumer can never be running behind. See BufferQueueCore.cpp core - // for more information about the original meaning of this flag. - value = 0; - break; - case NATIVE_WINDOW_CONSUMER_USAGE_BITS: - // TODO(jwcai) This is currently not implement as we don't need - // IGraphicBufferConsumer parity. - value = 0; - break; - case NATIVE_WINDOW_DEFAULT_DATASPACE: - // TODO(jwcai) Return the default value android::BufferQueue is using as - // there is no way dvr::ConsumerQueue can set it. - value = 0; // HAL_DATASPACE_UNKNOWN - break; - case NATIVE_WINDOW_STICKY_TRANSFORM: - // TODO(jwcai) Return the default value android::BufferQueue is using as - // there is no way dvr::ConsumerQueue can set it. - value = 0; - break; - case NATIVE_WINDOW_CONSUMER_IS_PROTECTED: - // In Daydream's implementation, the consumer end (i.e. VR Compostior) - // knows how to handle protected buffers. - value = 1; - break; - default: - return BAD_VALUE; - } - - ALOGD_IF(TRACE, "query: key=%d, v=%d", what, value); - *out_value = value; - return NO_ERROR; -} - -status_t BufferHubQueueProducer::connect( - const sp<IProducerListener>& /* listener */, int api, - bool /* producer_controlled_by_app */, QueueBufferOutput* output) { - // Consumer interaction are actually handled by buffer hub, and we need - // to maintain consumer operations here. We only need to perform basic input - // parameter checks here. - ALOGD_IF(TRACE, __FUNCTION__); - - if (output == nullptr) { - return BAD_VALUE; - } - - std::unique_lock<std::mutex> lock(mutex_); - - if (connected_api_ != kNoConnectedApi) { - return BAD_VALUE; - } - - switch (api) { - case NATIVE_WINDOW_API_EGL: - case NATIVE_WINDOW_API_CPU: - case NATIVE_WINDOW_API_MEDIA: - case NATIVE_WINDOW_API_CAMERA: - connected_api_ = api; - - output->width = queue_->default_width(); - output->height = queue_->default_height(); - - // default values, we don't use them yet. - output->transformHint = 0; - output->numPendingBuffers = 0; - output->nextFrameNumber = 0; - output->bufferReplaced = false; - - break; - default: - ALOGE("BufferHubQueueProducer::connect: unknow API %d", api); - return BAD_VALUE; - } - - return NO_ERROR; -} - -status_t BufferHubQueueProducer::disconnect(int api, DisconnectMode /*mode*/) { - // Consumer interaction are actually handled by buffer hub, and we need - // to maintain consumer operations here. We only need to perform basic input - // parameter checks here. - ALOGD_IF(TRACE, __FUNCTION__); - - std::unique_lock<std::mutex> lock(mutex_); - - if (kNoConnectedApi == connected_api_) { - return NO_INIT; - } else if (api != connected_api_) { - return BAD_VALUE; - } - - FreeAllBuffers(); - connected_api_ = kNoConnectedApi; - return NO_ERROR; -} - -status_t BufferHubQueueProducer::setSidebandStream( - const sp<NativeHandle>& stream) { - if (stream != nullptr) { - // TODO(jwcai) Investigate how is is used, maybe use BufferHubBuffer's - // metadata. - ALOGE("SidebandStream is not currently supported."); - return INVALID_OPERATION; - } - return NO_ERROR; -} - -void BufferHubQueueProducer::allocateBuffers(uint32_t /* width */, - uint32_t /* height */, - PixelFormat /* format */, - uint64_t /* usage */) { - // TODO(jwcai) |allocateBuffers| aims to preallocate up to the maximum number - // of buffers permitted by the current BufferQueue configuration (aka - // |max_buffer_count_|). - ALOGE("BufferHubQueueProducer::allocateBuffers not implemented."); -} - -status_t BufferHubQueueProducer::allowAllocation(bool /* allow */) { - ALOGE("BufferHubQueueProducer::allowAllocation not implemented."); - return INVALID_OPERATION; -} - -status_t BufferHubQueueProducer::setGenerationNumber( - uint32_t generation_number) { - ALOGD_IF(TRACE, __FUNCTION__); - - std::unique_lock<std::mutex> lock(mutex_); - generation_number_ = generation_number; - return NO_ERROR; -} - -String8 BufferHubQueueProducer::getConsumerName() const { - // BufferHub based implementation could have one to many producer/consumer - // relationship, thus |getConsumerName| from the producer side does not - // make any sense. - ALOGE("BufferHubQueueProducer::getConsumerName not supported."); - return String8("BufferHubQueue::DummyConsumer"); -} - -status_t BufferHubQueueProducer::setSharedBufferMode(bool shared_buffer_mode) { - if (shared_buffer_mode) { - ALOGE( - "BufferHubQueueProducer::setSharedBufferMode(true) is not supported."); - // TODO(b/36373181) Front buffer mode for buffer hub queue as ANativeWindow. - return INVALID_OPERATION; - } - // Setting to default should just work as a no-op. - return NO_ERROR; -} - -status_t BufferHubQueueProducer::setAutoRefresh(bool auto_refresh) { - if (auto_refresh) { - ALOGE("BufferHubQueueProducer::setAutoRefresh(true) is not supported."); - return INVALID_OPERATION; - } - // Setting to default should just work as a no-op. - return NO_ERROR; -} - -status_t BufferHubQueueProducer::setDequeueTimeout(nsecs_t timeout) { - ALOGD_IF(TRACE, __FUNCTION__); - - std::unique_lock<std::mutex> lock(mutex_); - dequeue_timeout_ms_ = static_cast<int>(timeout / (1000 * 1000)); - return NO_ERROR; -} - -status_t BufferHubQueueProducer::getLastQueuedBuffer( - sp<GraphicBuffer>* /* out_buffer */, sp<Fence>* /* out_fence */, - float /*out_transform_matrix*/[16]) { - ALOGE("BufferHubQueueProducer::getLastQueuedBuffer not implemented."); - return INVALID_OPERATION; -} - -void BufferHubQueueProducer::getFrameTimestamps( - FrameEventHistoryDelta* /*outDelta*/) { - ALOGE("BufferHubQueueProducer::getFrameTimestamps not implemented."); -} - -status_t BufferHubQueueProducer::getUniqueId(uint64_t* out_id) const { - ALOGD_IF(TRACE, __FUNCTION__); - - *out_id = unique_id_; - return NO_ERROR; -} - -status_t BufferHubQueueProducer::getConsumerUsage(uint64_t* out_usage) const { - ALOGD_IF(TRACE, __FUNCTION__); - - // same value as returned by querying NATIVE_WINDOW_CONSUMER_USAGE_BITS - *out_usage = 0; - return NO_ERROR; -} - -status_t BufferHubQueueProducer::AllocateBuffer(uint32_t width, uint32_t height, - uint32_t layer_count, - PixelFormat format, - uint64_t usage) { - auto status = - queue_->AllocateBuffer(width, height, layer_count, format, usage); - if (!status) { - ALOGE( - "BufferHubQueueProducer::AllocateBuffer: Failed to allocate buffer: %s", - status.GetErrorMessage().c_str()); - return NO_MEMORY; - } - - size_t slot = status.get(); - auto buffer_producer = queue_->GetBuffer(slot); - - LOG_ALWAYS_FATAL_IF(buffer_producer == nullptr, - "Failed to get buffer producer at slot: %zu", slot); - - buffers_[slot].mBufferProducer = buffer_producer; - - return NO_ERROR; -} - -status_t BufferHubQueueProducer::RemoveBuffer(size_t slot) { - auto status = queue_->RemoveBuffer(slot); - if (!status) { - ALOGE("BufferHubQueueProducer::RemoveBuffer: Failed to remove buffer: %s", - status.GetErrorMessage().c_str()); - return INVALID_OPERATION; - } - - // Reset in memory objects related the the buffer. - buffers_[slot].mBufferProducer = nullptr; - buffers_[slot].mGraphicBuffer = nullptr; - buffers_[slot].mBufferState.detachProducer(); - return NO_ERROR; -} - -status_t BufferHubQueueProducer::FreeAllBuffers() { - for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) { - // Reset in memory objects related the the buffer. - buffers_[slot].mGraphicBuffer = nullptr; - buffers_[slot].mBufferState.reset(); - buffers_[slot].mRequestBufferCalled = false; - buffers_[slot].mBufferProducer = nullptr; - buffers_[slot].mFence = Fence::NO_FENCE; - } - - auto status = queue_->FreeAllBuffers(); - if (!status) { - ALOGE( - "BufferHubQueueProducer::FreeAllBuffers: Failed to free all buffers on " - "the queue: %s", - status.GetErrorMessage().c_str()); - } - - if (queue_->capacity() != 0 || queue_->count() != 0) { - LOG_ALWAYS_FATAL( - "BufferHubQueueProducer::FreeAllBuffers: Not all buffers are freed."); - } - - return NO_ERROR; -} - -} // namespace dvr -} // namespace android diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h index 6962d6c9f8..60e1c4b8a9 100644 --- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h +++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h @@ -1,14 +1,26 @@ #ifndef ANDROID_DVR_BUFFER_HUB_QUEUE_CLIENT_H_ #define ANDROID_DVR_BUFFER_HUB_QUEUE_CLIENT_H_ -#include <gui/BufferQueueDefs.h> +#include <ui/BufferQueueDefs.h> +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Weverything" +#endif + +// The following headers are included without checking every warning. +// TODO(b/72172820): Remove the workaround once we have enforced -Weverything +// in these headers and their dependencies. #include <pdx/client.h> #include <pdx/status.h> #include <private/dvr/buffer_hub_client.h> +#include <private/dvr/buffer_hub_queue_parcelable.h> #include <private/dvr/bufferhub_rpc.h> #include <private/dvr/epoll_file_descriptor.h> -#include <private/dvr/ring_buffer.h> + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif #include <memory> #include <queue> @@ -45,15 +57,20 @@ class BufferHubQueue : public pdx::Client { uint32_t default_width() const { return default_width_; } // Returns the default buffer height of this buffer queue. - uint32_t default_height() const { return default_height_; } + uint32_t default_height() const { return static_cast<uint32_t>(default_height_); } // Returns the default buffer format of this buffer queue. - uint32_t default_format() const { return default_format_; } + uint32_t default_format() const { return static_cast<uint32_t>(default_format_); } // Creates a new consumer in handle form for immediate transport over RPC. pdx::Status<pdx::LocalChannelHandle> CreateConsumerQueueHandle( bool silent = false); + // Creates a new consumer in parcelable form for immediate transport over + // Binder. + pdx::Status<ConsumerQueueParcelable> CreateConsumerQueueParcelable( + bool silent = false); + // Returns the number of buffers avaiable for dequeue. size_t count() const { return available_buffers_.size(); } @@ -68,7 +85,8 @@ class BufferHubQueue : public pdx::Client { return available_buffers_.size() >= kMaxQueueCapacity; } - explicit operator bool() const { return epoll_fd_.IsValid(); } + // Returns whether the buffer queue is connected to bufferhubd. + bool is_connected() const { return !!GetChannel(); } int GetBufferId(size_t slot) const { return (slot < buffers_.size() && buffers_[slot]) ? buffers_[slot]->id() @@ -150,20 +168,20 @@ class BufferHubQueue : public pdx::Client { int poll_events); pdx::Status<void> HandleQueueEvent(int poll_events); - // Entry in the ring buffer of available buffers that stores related + // Entry in the priority queue of available buffers that stores related // per-buffer data. struct Entry { Entry() : slot(0) {} - Entry(const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot, - uint64_t index) - : buffer(buffer), slot(slot), index(index) {} - Entry(const std::shared_ptr<BufferHubBuffer>& buffer, - std::unique_ptr<uint8_t[]> metadata, pdx::LocalHandle fence, - size_t slot) - : buffer(buffer), - metadata(std::move(metadata)), - fence(std::move(fence)), - slot(slot) {} + Entry(const std::shared_ptr<BufferHubBuffer>& in_buffer, size_t in_slot, + uint64_t in_index) + : buffer(in_buffer), slot(in_slot), index(in_index) {} + Entry(const std::shared_ptr<BufferHubBuffer>& in_buffer, + std::unique_ptr<uint8_t[]> in_metadata, pdx::LocalHandle in_fence, + size_t in_slot) + : buffer(in_buffer), + metadata(std::move(in_metadata)), + fence(std::move(in_fence)), + slot(in_slot) {} Entry(Entry&&) = default; Entry& operator=(Entry&&) = default; @@ -221,13 +239,13 @@ class BufferHubQueue : public pdx::Client { bool is_async_{false}; // Default buffer width that is set during ProducerQueue's creation. - size_t default_width_{1}; + uint32_t default_width_{1}; // Default buffer height that is set during ProducerQueue's creation. - size_t default_height_{1}; + uint32_t default_height_{1}; // Default buffer format that is set during ProducerQueue's creation. - int32_t default_format_{1}; // PIXEL_FORMAT_RGBA_8888 + uint32_t default_format_{1}; // PIXEL_FORMAT_RGBA_8888 // Tracks the buffers belonging to this queue. Buffers are stored according to // "slot" in this vector. Each slot is a logical id of the buffer within this @@ -235,7 +253,6 @@ class BufferHubQueue : public pdx::Client { std::array<std::shared_ptr<BufferHubBuffer>, kMaxQueueCapacity> buffers_; // Buffers and related data that are available for dequeue. - // RingBuffer<Entry> available_buffers_{kMaxQueueCapacity}; std::priority_queue<Entry, std::vector<Entry>, EntryComparator> available_buffers_; @@ -337,6 +354,11 @@ class ProducerQueue : public pdx::ClientBase<ProducerQueue, BufferHubQueue> { return BufferHubQueue::Enqueue({buffer, slot, index}); } + // Takes out the current producer queue as a binder parcelable object. Note + // that the queue must be empty to be exportable. After successful export, the + // producer queue client should no longer be used. + pdx::Status<ProducerQueueParcelable> TakeAsParcelable(); + private: friend BASE; @@ -363,10 +385,7 @@ class ConsumerQueue : public BufferHubQueue { // used to avoid participation in the buffer lifecycle by a consumer queue // that is only used to spawn other consumer queues, such as in an // intermediate service. - static std::unique_ptr<ConsumerQueue> Import(pdx::LocalChannelHandle handle) { - return std::unique_ptr<ConsumerQueue>( - new ConsumerQueue(std::move(handle))); - } + static std::unique_ptr<ConsumerQueue> Import(pdx::LocalChannelHandle handle); // Import newly created buffers from the service side. // Returns number of buffers successfully imported or an error. diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h new file mode 100644 index 0000000000..4dea9b2f6c --- /dev/null +++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h @@ -0,0 +1,74 @@ +#ifndef ANDROID_DVR_BUFFER_HUB_QUEUE_PARCELABLE_H_ +#define ANDROID_DVR_BUFFER_HUB_QUEUE_PARCELABLE_H_ + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Weverything" +#endif + +// The following headers are included without checking every warning. +// TODO(b/72172820): Remove the workaround once we have enforced -Weverything +// in these headers and their dependencies. +#include <pdx/channel_parcelable.h> + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + +namespace android { +namespace dvr { + +enum BufferHubQueueParcelableMagic : uint32_t { + Producer = 0x62687170, // 'bhqp' + Consumer = 0x62687163, // 'bhqc' +}; + +template <BufferHubQueueParcelableMagic Magic> +class BufferHubQueueParcelable : public Parcelable { + public: + BufferHubQueueParcelable() = default; + + BufferHubQueueParcelable(BufferHubQueueParcelable&& other) = default; + BufferHubQueueParcelable& operator=(BufferHubQueueParcelable&& other) { + channel_parcelable_ = std::move(other.channel_parcelable_); + return *this; + } + + // Constructs an parcelable contains the channel parcelable. + BufferHubQueueParcelable( + std::unique_ptr<pdx::ChannelParcelable> channel_parcelable) + : channel_parcelable_(std::move(channel_parcelable)) {} + + BufferHubQueueParcelable(const BufferHubQueueParcelable&) = delete; + void operator=(const BufferHubQueueParcelable&) = delete; + + bool IsValid() const; + + // Returns a channel handle constructed from this parcelable object and takes + // the ownership of all resources from the parcelable object. + pdx::LocalChannelHandle TakeChannelHandle(); + + // Serializes the queue parcelable into the given parcel. Note that no system + // resources are getting duplicated, nor did the parcel takes ownership of the + // queue parcelable. Thus, the parcelable object must remain valid for the + // lifetime of the parcel. + status_t writeToParcel(Parcel* parcel) const override; + + // Deserialize the queue parcelable from the given parcel. Note that system + // resources are duplicated from the parcel into the queue parcelable. Returns + // error if the targeting parcelable object is already valid. + status_t readFromParcel(const Parcel* parcel) override; + + private: + std::unique_ptr<pdx::ChannelParcelable> channel_parcelable_; +}; + +using ProducerQueueParcelable = + BufferHubQueueParcelable<BufferHubQueueParcelableMagic::Producer>; +using ConsumerQueueParcelable = + BufferHubQueueParcelable<BufferHubQueueParcelableMagic::Consumer>; + +} // namespace dvr +} // namespace android + +#endif // ANDROID_DVR_BUFFER_HUB_QUEUE_PARCELABLE_H_ diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h deleted file mode 100644 index 7ed55fb533..0000000000 --- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h +++ /dev/null @@ -1,191 +0,0 @@ -#ifndef ANDROID_DVR_BUFFER_HUB_QUEUE_PRODUCER_H_ -#define ANDROID_DVR_BUFFER_HUB_QUEUE_PRODUCER_H_ - -#include <gui/IGraphicBufferProducer.h> -#include <private/dvr/buffer_hub_queue_client.h> - -namespace android { -namespace dvr { - -class BufferHubQueueProducer : public BnGraphicBufferProducer { - public: - static constexpr int kNoConnectedApi = -1; - - // TODO(b/36187402) The actual implementation of BufferHubQueue's consumer - // side logic doesn't limit the number of buffer it can acquire - // simultaneously. We need a way for consumer logic to configure and enforce - // that. - static constexpr int kDefaultUndequeuedBuffers = 1; - - // Create a BufferHubQueueProducer instance by creating a new producer queue. - static sp<BufferHubQueueProducer> Create(); - - // Create a BufferHubQueueProducer instance by importing an existing prodcuer - // queue. - static sp<BufferHubQueueProducer> Create( - const std::shared_ptr<ProducerQueue>& producer); - - // See |IGraphicBufferProducer::requestBuffer| - status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override; - - // For the BufferHub based implementation. All buffers in the queue are - // allowed to be dequeued from the consumer side. It call always returns - // 0 for |NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS| query. Thus setting - // |max_dequeued_buffers| here can be considered the same as setting queue - // capacity. - // - // See |IGraphicBufferProducer::setMaxDequeuedBufferCount| for more info - status_t setMaxDequeuedBufferCount(int max_dequeued_buffers) override; - - // See |IGraphicBufferProducer::setAsyncMode| - status_t setAsyncMode(bool async) override; - - // See |IGraphicBufferProducer::dequeueBuffer| - status_t dequeueBuffer(int* out_slot, sp<Fence>* out_fence, uint32_t width, - uint32_t height, PixelFormat format, uint64_t usage, - uint64_t* outBufferAge, - FrameEventHistoryDelta* outTimestamps) override; - - // See |IGraphicBufferProducer::detachBuffer| - status_t detachBuffer(int slot) override; - - // See |IGraphicBufferProducer::detachNextBuffer| - status_t detachNextBuffer(sp<GraphicBuffer>* out_buffer, - sp<Fence>* out_fence) override; - - // See |IGraphicBufferProducer::attachBuffer| - status_t attachBuffer(int* out_slot, - const sp<GraphicBuffer>& buffer) override; - - // See |IGraphicBufferProducer::queueBuffer| - status_t queueBuffer(int slot, const QueueBufferInput& input, - QueueBufferOutput* output) override; - - // See |IGraphicBufferProducer::cancelBuffer| - status_t cancelBuffer(int slot, const sp<Fence>& fence) override; - - // See |IGraphicBufferProducer::query| - status_t query(int what, int* out_value) override; - - // See |IGraphicBufferProducer::connect| - status_t connect(const sp<IProducerListener>& listener, int api, - bool producer_controlled_by_app, - QueueBufferOutput* output) override; - - // See |IGraphicBufferProducer::disconnect| - status_t disconnect(int api, - DisconnectMode mode = DisconnectMode::Api) override; - - // See |IGraphicBufferProducer::setSidebandStream| - status_t setSidebandStream(const sp<NativeHandle>& stream) override; - - // See |IGraphicBufferProducer::allocateBuffers| - void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format, - uint64_t usage) override; - - // See |IGraphicBufferProducer::allowAllocation| - status_t allowAllocation(bool allow) override; - - // See |IGraphicBufferProducer::setGenerationNumber| - status_t setGenerationNumber(uint32_t generation_number) override; - - // See |IGraphicBufferProducer::getConsumerName| - String8 getConsumerName() const override; - - // See |IGraphicBufferProducer::setSharedBufferMode| - status_t setSharedBufferMode(bool shared_buffer_mode) override; - - // See |IGraphicBufferProducer::setAutoRefresh| - status_t setAutoRefresh(bool auto_refresh) override; - - // See |IGraphicBufferProducer::setDequeueTimeout| - status_t setDequeueTimeout(nsecs_t timeout) override; - - // See |IGraphicBufferProducer::getLastQueuedBuffer| - status_t getLastQueuedBuffer(sp<GraphicBuffer>* out_buffer, - sp<Fence>* out_fence, - float out_transform_matrix[16]) override; - - // See |IGraphicBufferProducer::getFrameTimestamps| - void getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) override; - - // See |IGraphicBufferProducer::getUniqueId| - status_t getUniqueId(uint64_t* out_id) const override; - - // See |IGraphicBufferProducer::getConsumerUsage| - status_t getConsumerUsage(uint64_t* out_usage) const override; - - private: - using LocalHandle = pdx::LocalHandle; - - // Private constructor to force use of |Create|. - BufferHubQueueProducer() {} - - static uint64_t genUniqueId() { - static std::atomic<uint32_t> counter{0}; - static uint64_t id = static_cast<uint64_t>(getpid()) << 32; - return id | counter++; - } - - // Allocate new buffer through BufferHub and add it into |queue_| for - // bookkeeping. - status_t AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count, - PixelFormat format, uint64_t usage); - - // Remove a buffer via BufferHubRPC. - status_t RemoveBuffer(size_t slot); - - // Free all buffers which are owned by the prodcuer. Note that if graphic - // buffers are acquired by the consumer, we can't . - status_t FreeAllBuffers(); - - // Concreate implementation backed by BufferHubBuffer. - std::shared_ptr<ProducerQueue> queue_; - - // Mutex for thread safety. - std::mutex mutex_; - - // Connect client API, should be one of the NATIVE_WINDOW_API_* flags. - int connected_api_{kNoConnectedApi}; - - // |max_buffer_count_| sets the capacity of the underlying buffer queue. - int32_t max_buffer_count_{BufferHubQueue::kMaxQueueCapacity}; - - // |max_dequeued_buffer_count_| set the maximum number of buffers that can - // be dequeued at the same momment. - int32_t max_dequeued_buffer_count_{1}; - - // Sets how long dequeueBuffer or attachBuffer will block if a buffer or - // slot is not yet available. The timeout is stored in milliseconds. - int dequeue_timeout_ms_{BufferHubQueue::kNoTimeOut}; - - // |generation_number_| stores the current generation number of the attached - // producer. Any attempt to attach a buffer with a different generation - // number will fail. - // TOOD(b/38137191) Currently not used as we don't support - // IGraphicBufferProducer::detachBuffer. - uint32_t generation_number_{0}; - - // |buffers_| stores the buffers that have been dequeued from - // |dvr::BufferHubQueue|, It is initialized to invalid buffers, and gets - // filled in with the result of |Dequeue|. - // TODO(jwcai) The buffer allocated to a slot will also be replaced if the - // requested buffer usage or geometry differs from that of the buffer - // allocated to a slot. - struct BufferHubSlot : public BufferSlot { - BufferHubSlot() : mBufferProducer(nullptr), mIsReallocating(false) {} - // BufferSlot comes from android framework, using m prefix to comply with - // the name convention with the reset of data fields from BufferSlot. - std::shared_ptr<BufferProducer> mBufferProducer; - bool mIsReallocating; - }; - BufferHubSlot buffers_[BufferHubQueue::kMaxQueueCapacity]; - - // A uniqueId used by IGraphicBufferProducer interface. - const uint64_t unique_id_{genUniqueId()}; -}; - -} // namespace dvr -} // namespace android - -#endif // ANDROID_DVR_BUFFER_HUB_QUEUE_PRODUCER_H_ diff --git a/libs/vr/libdvrcommon/include/private/dvr/epoll_file_descriptor.h b/libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h index 099a409005..6e303a5e5a 100644 --- a/libs/vr/libdvrcommon/include/private/dvr/epoll_file_descriptor.h +++ b/libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h @@ -1,5 +1,5 @@ -#ifndef LIBS_VR_LIBDVRCOMMON_INCLUDE_PRIVATE_DVR_EPOLL_FILE_DESCRIPTOR_H_ -#define LIBS_VR_LIBDVRCOMMON_INCLUDE_PRIVATE_DVR_EPOLL_FILE_DESCRIPTOR_H_ +#ifndef ANDROID_DVR_EPOLL_FILE_DESCRIPTOR_H_ +#define ANDROID_DVR_EPOLL_FILE_DESCRIPTOR_H_ #include <android-base/unique_fd.h> #include <log/log.h> @@ -61,4 +61,4 @@ class EpollFileDescriptor { } // namespace dvr } // namespace android -#endif // LIBS_VR_LIBDVRCOMMON_INCLUDE_PRIVATE_DVR_EPOLL_FILE_DESCRIPTOR_H_ +#endif // ANDROID_DVR_EPOLL_FILE_DESCRIPTOR_H_ diff --git a/libs/vr/libbufferhubqueue/tests/Android.bp b/libs/vr/libbufferhubqueue/tests/Android.bp index 29e4ffec60..a33792177b 100644 --- a/libs/vr/libbufferhubqueue/tests/Android.bp +++ b/libs/vr/libbufferhubqueue/tests/Android.bp @@ -6,20 +6,21 @@ header_libraries = [ shared_libraries = [ "libbase", "libbinder", + "libbufferhubqueue", "libcutils", "libgui", "liblog", "libhardware", "libui", "libutils", + "libnativewindow", + "libpdx_default_transport", ] static_libraries = [ - "libbufferhubqueue", - "libbufferhub", "libchrome", "libdvrcommon", - "libpdx_default_transport", + "libperformance", ] cc_test { diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp index 8a72531ed5..47a27344bd 100644 --- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp +++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp @@ -1,4 +1,5 @@ #include <base/logging.h> +#include <binder/Parcel.h> #include <private/dvr/buffer_hub_client.h> #include <private/dvr/buffer_hub_queue_client.h> @@ -14,6 +15,7 @@ namespace android { namespace dvr { +using pdx::LocalChannelHandle; using pdx::LocalHandle; namespace { @@ -23,6 +25,8 @@ constexpr uint32_t kBufferHeight = 1; constexpr uint32_t kBufferLayerCount = 1; constexpr uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB; constexpr uint64_t kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY; +constexpr int kTimeoutMs = 100; +constexpr int kNoTimeout = 0; class BufferHubQueueTest : public ::testing::Test { public: @@ -82,41 +86,49 @@ class BufferHubQueueTest : public ::testing::Test { }; TEST_F(BufferHubQueueTest, TestDequeue) { - const size_t nb_dequeue_times = 16; + const int64_t nb_dequeue_times = 16; - ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<size_t>().Build(), - UsagePolicy{})); + ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{})); // Allocate only one buffer. AllocateBuffer(); // But dequeue multiple times. - for (size_t i = 0; i < nb_dequeue_times; i++) { + for (int64_t i = 0; i < nb_dequeue_times; i++) { size_t slot; LocalHandle fence; - auto p1_status = producer_queue_->Dequeue(100, &slot, &fence); - ASSERT_TRUE(p1_status.ok()); + DvrNativeBufferMetadata mi, mo; + + // Producer gains a buffer. + auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); + EXPECT_TRUE(p1_status.ok()); auto p1 = p1_status.take(); - ASSERT_NE(nullptr, p1); - size_t mi = i; - ASSERT_EQ(p1->Post(LocalHandle(), &mi, sizeof(mi)), 0); - size_t mo; - auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence); - ASSERT_TRUE(c1_status.ok()); + ASSERT_NE(p1, nullptr); + + // Producer posts the buffer. + mi.index = i; + EXPECT_EQ(p1->PostAsync(&mi, LocalHandle()), 0); + + // Consumer acquires a buffer. + auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); + EXPECT_TRUE(c1_status.ok()); auto c1 = c1_status.take(); - ASSERT_NE(nullptr, c1); - ASSERT_EQ(mi, mo); - c1->Release(LocalHandle()); + ASSERT_NE(c1, nullptr); + EXPECT_EQ(mi.index, i); + EXPECT_EQ(mo.index, i); + + // Consumer releases the buffer. + EXPECT_EQ(c1->ReleaseAsync(&mi, LocalHandle()), 0); } } TEST_F(BufferHubQueueTest, TestProducerConsumer) { const size_t kBufferCount = 16; size_t slot; - uint64_t seq; + DvrNativeBufferMetadata mi, mo; + LocalHandle fence; - ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<uint64_t>().Build(), - UsagePolicy{})); + ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{})); for (size_t i = 0; i < kBufferCount; i++) { AllocateBuffer(); @@ -131,8 +143,7 @@ TEST_F(BufferHubQueueTest, TestProducerConsumer) { ASSERT_EQ(consumer_queue_->capacity(), i); // Dequeue returns timeout since no buffer is ready to consumer, but // this implicitly triggers buffer import and bump up |capacity|. - LocalHandle fence; - auto status = consumer_queue_->Dequeue(100, &slot, &seq, &fence); + auto status = consumer_queue_->Dequeue(kNoTimeout, &slot, &mo, &fence); ASSERT_FALSE(status.ok()); ASSERT_EQ(ETIMEDOUT, status.error()); ASSERT_EQ(consumer_queue_->capacity(), i + 1); @@ -142,37 +153,37 @@ TEST_F(BufferHubQueueTest, TestProducerConsumer) { LocalHandle post_fence(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); for (size_t i = 0; i < kBufferCount; i++) { - LocalHandle fence; - // First time there is no buffer available to dequeue. - auto consumer_status = consumer_queue_->Dequeue(100, &slot, &seq, &fence); + auto consumer_status = + consumer_queue_->Dequeue(kNoTimeout, &slot, &mo, &fence); ASSERT_FALSE(consumer_status.ok()); - ASSERT_EQ(ETIMEDOUT, consumer_status.error()); + ASSERT_EQ(consumer_status.error(), ETIMEDOUT); // Make sure Producer buffer is POSTED so that it's ready to Accquire // in the consumer's Dequeue() function. - auto producer_status = producer_queue_->Dequeue(100, &slot, &fence); + auto producer_status = + producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); ASSERT_TRUE(producer_status.ok()); auto producer = producer_status.take(); ASSERT_NE(nullptr, producer); - uint64_t seq_in = static_cast<uint64_t>(i); - ASSERT_EQ(producer->Post(post_fence, &seq_in, sizeof(seq_in)), 0); + mi.index = static_cast<int64_t>(i); + ASSERT_EQ(producer->PostAsync(&mi, post_fence), 0); // Second time the just the POSTED buffer should be dequeued. - uint64_t seq_out = 0; - consumer_status = consumer_queue_->Dequeue(100, &slot, &seq_out, &fence); + consumer_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); ASSERT_TRUE(consumer_status.ok()); EXPECT_TRUE(fence.IsValid()); auto consumer = consumer_status.take(); ASSERT_NE(nullptr, consumer); - ASSERT_EQ(seq_in, seq_out); + ASSERT_EQ(mi.index, mo.index); } } TEST_F(BufferHubQueueTest, TestRemoveBuffer) { ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{})); + DvrNativeBufferMetadata mo; // Allocate buffers. const size_t kBufferCount = 4u; @@ -201,7 +212,7 @@ TEST_F(BufferHubQueueTest, TestRemoveBuffer) { for (size_t i = 0; i < kBufferCount; i++) { Entry* entry = &buffers[i]; auto producer_status = producer_queue_->Dequeue( - /*timeout_ms=*/100, &entry->slot, &entry->fence); + kTimeoutMs, &entry->slot, &mo, &entry->fence); ASSERT_TRUE(producer_status.ok()); entry->buffer = producer_status.take(); ASSERT_NE(nullptr, entry->buffer); @@ -221,7 +232,7 @@ TEST_F(BufferHubQueueTest, TestRemoveBuffer) { buffers[0].buffer = nullptr; // Now the consumer queue should know it's gone. - EXPECT_FALSE(WaitAndHandleOnce(consumer_queue_.get(), /*timeout_ms=*/100)); + EXPECT_FALSE(WaitAndHandleOnce(consumer_queue_.get(), kTimeoutMs)); ASSERT_EQ(kBufferCount - 1, consumer_queue_->capacity()); // Allocate a new buffer. This should take the first empty slot. @@ -290,126 +301,156 @@ TEST_F(BufferHubQueueTest, TestMultipleConsumers) { ASSERT_NE(nullptr, silent_queue); // Check that silent queue doesn't import buffers on creation. - EXPECT_EQ(0, silent_queue->capacity()); + EXPECT_EQ(silent_queue->capacity(), 0U); // Dequeue and post a buffer. size_t slot; LocalHandle fence; + DvrNativeBufferMetadata mi, mo; auto producer_status = - producer_queue_->Dequeue(/*timeout_ms=*/100, &slot, &fence); - ASSERT_TRUE(producer_status.ok()); + producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); + EXPECT_TRUE(producer_status.ok()); auto producer_buffer = producer_status.take(); - ASSERT_NE(nullptr, producer_buffer); - ASSERT_EQ(0, producer_buffer->Post<void>({})); + ASSERT_NE(producer_buffer, nullptr); + EXPECT_EQ(producer_buffer->PostAsync(&mi, {}), 0); // After post, check the number of remaining available buffers. - EXPECT_EQ(kBufferCount - 1, producer_queue_->count()); + EXPECT_EQ(producer_queue_->count(), kBufferCount - 1); // Currently we expect no buffer to be available prior to calling // WaitForBuffers/HandleQueueEvents. // TODO(eieio): Note this behavior may change in the future. - EXPECT_EQ(0u, silent_queue->count()); + EXPECT_EQ(silent_queue->count(), 0U); EXPECT_FALSE(silent_queue->HandleQueueEvents()); - EXPECT_EQ(0u, silent_queue->count()); + EXPECT_EQ(silent_queue->count(), 0U); // Build a new consumer queue to test multi-consumer queue features. consumer_queue_ = silent_queue->CreateConsumerQueue(); - ASSERT_NE(nullptr, consumer_queue_); + ASSERT_NE(consumer_queue_, nullptr); // Check that buffers are correctly imported on construction. - EXPECT_EQ(kBufferCount, consumer_queue_->capacity()); - EXPECT_EQ(1u, consumer_queue_->count()); + EXPECT_EQ(consumer_queue_->capacity(), kBufferCount); + // Buffers are only imported, but their availability is not checked until + // first call to Dequeue(). + EXPECT_EQ(consumer_queue_->count(), 0U); // Reclaim released/ignored buffers. - ASSERT_EQ(kBufferCount - 1, producer_queue_->count()); + EXPECT_EQ(producer_queue_->count(), kBufferCount - 1); usleep(10000); - WaitAndHandleOnce(producer_queue_.get(), /*timeout_ms=*/100); - ASSERT_EQ(kBufferCount - 1, producer_queue_->count()); + WaitAndHandleOnce(producer_queue_.get(), kTimeoutMs); + EXPECT_EQ(producer_queue_->count(), kBufferCount - 1); // Post another buffer. - producer_status = producer_queue_->Dequeue(/*timeout_ms=*/100, &slot, &fence); - ASSERT_TRUE(producer_status.ok()); + producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); + EXPECT_TRUE(producer_status.ok()); producer_buffer = producer_status.take(); - ASSERT_NE(nullptr, producer_buffer); - ASSERT_EQ(0, producer_buffer->Post<void>({})); + ASSERT_NE(producer_buffer, nullptr); + EXPECT_EQ(producer_buffer->PostAsync(&mi, {}), 0); // Verify that the consumer queue receives it. size_t consumer_queue_count = consumer_queue_->count(); - WaitAndHandleOnce(consumer_queue_.get(), /*timeout_ms=*/100); - EXPECT_LT(consumer_queue_count, consumer_queue_->count()); + WaitAndHandleOnce(consumer_queue_.get(), kTimeoutMs); + EXPECT_GT(consumer_queue_->count(), consumer_queue_count); // Save the current consumer queue buffer count to compare after the dequeue. consumer_queue_count = consumer_queue_->count(); // Dequeue and acquire/release (discard) buffers on the consumer end. auto consumer_status = - consumer_queue_->Dequeue(/*timeout_ms=*/100, &slot, &fence); - ASSERT_TRUE(consumer_status.ok()); + consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); + EXPECT_TRUE(consumer_status.ok()); auto consumer_buffer = consumer_status.take(); - ASSERT_NE(nullptr, consumer_buffer); + ASSERT_NE(consumer_buffer, nullptr); consumer_buffer->Discard(); // Buffer should be returned to the producer queue without being handled by // the silent consumer queue. - EXPECT_GT(consumer_queue_count, consumer_queue_->count()); - EXPECT_EQ(kBufferCount - 2, producer_queue_->count()); - EXPECT_TRUE(producer_queue_->HandleQueueEvents()); - EXPECT_EQ(kBufferCount - 1, producer_queue_->count()); + EXPECT_LT(consumer_queue_->count(), consumer_queue_count); + EXPECT_EQ(producer_queue_->count(), kBufferCount - 2); + + WaitAndHandleOnce(producer_queue_.get(), kTimeoutMs); + EXPECT_EQ(producer_queue_->count(), kBufferCount - 1); } -struct TestMetadata { +struct TestUserMetadata { char a; int32_t b; int64_t c; }; -TEST_F(BufferHubQueueTest, TestMetadata) { - ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<TestMetadata>().Build(), - UsagePolicy{})); +constexpr uint64_t kUserMetadataSize = + static_cast<uint64_t>(sizeof(TestUserMetadata)); + +TEST_F(BufferHubQueueTest, TestUserMetadata) { + ASSERT_TRUE(CreateQueues( + config_builder_.SetMetadata<TestUserMetadata>().Build(), UsagePolicy{})); AllocateBuffer(); - std::vector<TestMetadata> ms = { + std::vector<TestUserMetadata> user_metadata_list = { {'0', 0, 0}, {'1', 10, 3333}, {'@', 123, 1000000000}}; - for (auto mi : ms) { + for (auto user_metadata : user_metadata_list) { size_t slot; LocalHandle fence; - auto p1_status = producer_queue_->Dequeue(100, &slot, &fence); - ASSERT_TRUE(p1_status.ok()); + DvrNativeBufferMetadata mi, mo; + + auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); + EXPECT_TRUE(p1_status.ok()); auto p1 = p1_status.take(); - ASSERT_NE(nullptr, p1); - ASSERT_EQ(p1->Post(LocalHandle(-1), &mi, sizeof(mi)), 0); - TestMetadata mo; - auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence); - ASSERT_TRUE(c1_status.ok()); + ASSERT_NE(p1, nullptr); + + // TODO(b/69469185): Test against metadata from consumer once we implement + // release metadata properly. + // EXPECT_EQ(mo.user_metadata_ptr, 0U); + // EXPECT_EQ(mo.user_metadata_size, 0U); + + mi.user_metadata_size = kUserMetadataSize; + mi.user_metadata_ptr = reinterpret_cast<uint64_t>(&user_metadata); + EXPECT_EQ(p1->PostAsync(&mi, {}), 0); + auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); + EXPECT_TRUE(c1_status.ok()); auto c1 = c1_status.take(); - ASSERT_EQ(mi.a, mo.a); - ASSERT_EQ(mi.b, mo.b); - ASSERT_EQ(mi.c, mo.c); - c1->Release(LocalHandle(-1)); + ASSERT_NE(c1, nullptr); + + EXPECT_EQ(mo.user_metadata_size, kUserMetadataSize); + auto out_user_metadata = + reinterpret_cast<TestUserMetadata*>(mo.user_metadata_ptr); + EXPECT_EQ(user_metadata.a, out_user_metadata->a); + EXPECT_EQ(user_metadata.b, out_user_metadata->b); + EXPECT_EQ(user_metadata.c, out_user_metadata->c); + + // When release, empty metadata is also legit. + mi.user_metadata_size = 0U; + mi.user_metadata_ptr = 0U; + c1->ReleaseAsync(&mi, {}); } } -TEST_F(BufferHubQueueTest, TestMetadataMismatch) { - ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(), - UsagePolicy{})); +TEST_F(BufferHubQueueTest, TestUserMetadataMismatch) { + ASSERT_TRUE(CreateQueues( + config_builder_.SetMetadata<TestUserMetadata>().Build(), UsagePolicy{})); AllocateBuffer(); - int64_t mi = 3; + TestUserMetadata user_metadata; size_t slot; LocalHandle fence; - auto p1_status = producer_queue_->Dequeue(100, &slot, &fence); - ASSERT_TRUE(p1_status.ok()); + DvrNativeBufferMetadata mi, mo; + auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); + EXPECT_TRUE(p1_status.ok()); auto p1 = p1_status.take(); - ASSERT_NE(nullptr, p1); - ASSERT_EQ(p1->Post(LocalHandle(-1), &mi, sizeof(mi)), 0); - - int32_t mo; - // Acquire a buffer with mismatched metadata is not OK. - auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence); - ASSERT_FALSE(c1_status.ok()); + ASSERT_NE(p1, nullptr); + + // Post with mismatched user metadata size will fail. But the producer buffer + // itself should stay untouched. + mi.user_metadata_ptr = reinterpret_cast<uint64_t>(&user_metadata); + mi.user_metadata_size = kUserMetadataSize + 1; + EXPECT_EQ(p1->PostAsync(&mi, {}), -E2BIG); + // Post with the exact same user metdata size can success. + mi.user_metadata_ptr = reinterpret_cast<uint64_t>(&user_metadata); + mi.user_metadata_size = kUserMetadataSize; + EXPECT_EQ(p1->PostAsync(&mi, {}), 0); } TEST_F(BufferHubQueueTest, TestEnqueue) { @@ -419,32 +460,32 @@ TEST_F(BufferHubQueueTest, TestEnqueue) { size_t slot; LocalHandle fence; - auto p1_status = producer_queue_->Dequeue(100, &slot, &fence); + DvrNativeBufferMetadata mo; + auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); ASSERT_TRUE(p1_status.ok()); auto p1 = p1_status.take(); ASSERT_NE(nullptr, p1); - int64_t mo; producer_queue_->Enqueue(p1, slot, 0ULL); - auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence); + auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); ASSERT_FALSE(c1_status.ok()); } TEST_F(BufferHubQueueTest, TestAllocateBuffer) { - ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(), - UsagePolicy{})); + ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{})); - size_t s1; + size_t ps1; AllocateBuffer(); LocalHandle fence; - auto p1_status = producer_queue_->Dequeue(100, &s1, &fence); + DvrNativeBufferMetadata mi, mo; + auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &ps1, &mo, &fence); ASSERT_TRUE(p1_status.ok()); auto p1 = p1_status.take(); - ASSERT_NE(nullptr, p1); + ASSERT_NE(p1, nullptr); // producer queue is exhausted - size_t s2; - auto p2_status = producer_queue_->Dequeue(100, &s2, &fence); + size_t ps2; + auto p2_status = producer_queue_->Dequeue(kTimeoutMs, &ps2, &mo, &fence); ASSERT_FALSE(p2_status.ok()); ASSERT_EQ(ETIMEDOUT, p2_status.error()); @@ -454,41 +495,43 @@ TEST_F(BufferHubQueueTest, TestAllocateBuffer) { ASSERT_EQ(producer_queue_->capacity(), 2U); // now we can dequeue again - p2_status = producer_queue_->Dequeue(100, &s2, &fence); + p2_status = producer_queue_->Dequeue(kTimeoutMs, &ps2, &mo, &fence); ASSERT_TRUE(p2_status.ok()); auto p2 = p2_status.take(); - ASSERT_NE(nullptr, p2); + ASSERT_NE(p2, nullptr); ASSERT_EQ(producer_queue_->count(), 0U); // p1 and p2 should have different slot number - ASSERT_NE(s1, s2); + ASSERT_NE(ps1, ps2); // Consumer queue does not import buffers until |Dequeue| or |ImportBuffers| // are called. So far consumer_queue_ should be empty. ASSERT_EQ(consumer_queue_->count(), 0U); int64_t seq = 1; - ASSERT_EQ(p1->Post(LocalHandle(), seq), 0); + mi.index = seq; + ASSERT_EQ(p1->PostAsync(&mi, {}), 0); + size_t cs1, cs2; - auto c1_status = consumer_queue_->Dequeue(100, &cs1, &seq, &fence); + auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &cs1, &mo, &fence); ASSERT_TRUE(c1_status.ok()); auto c1 = c1_status.take(); - ASSERT_NE(nullptr, c1); + ASSERT_NE(c1, nullptr); ASSERT_EQ(consumer_queue_->count(), 0U); ASSERT_EQ(consumer_queue_->capacity(), 2U); - ASSERT_EQ(cs1, s1); + ASSERT_EQ(cs1, ps1); - ASSERT_EQ(p2->Post(LocalHandle(), seq), 0); - auto c2_status = consumer_queue_->Dequeue(100, &cs2, &seq, &fence); + ASSERT_EQ(p2->PostAsync(&mi, {}), 0); + auto c2_status = consumer_queue_->Dequeue(kTimeoutMs, &cs2, &mo, &fence); ASSERT_TRUE(c2_status.ok()); auto c2 = c2_status.take(); - ASSERT_NE(nullptr, c2); - ASSERT_EQ(cs2, s2); + ASSERT_NE(c2, nullptr); + ASSERT_EQ(cs2, ps2); } TEST_F(BufferHubQueueTest, TestUsageSetMask) { const uint32_t set_mask = GRALLOC_USAGE_SW_WRITE_OFTEN; - ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(), - UsagePolicy{set_mask, 0, 0, 0})); + ASSERT_TRUE( + CreateQueues(config_builder_.Build(), UsagePolicy{set_mask, 0, 0, 0})); // When allocation, leave out |set_mask| from usage bits on purpose. auto status = producer_queue_->AllocateBuffer( @@ -498,7 +541,8 @@ TEST_F(BufferHubQueueTest, TestUsageSetMask) { LocalHandle fence; size_t slot; - auto p1_status = producer_queue_->Dequeue(100, &slot, &fence); + DvrNativeBufferMetadata mo; + auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); ASSERT_TRUE(p1_status.ok()); auto p1 = p1_status.take(); ASSERT_EQ(p1->usage() & set_mask, set_mask); @@ -506,8 +550,8 @@ TEST_F(BufferHubQueueTest, TestUsageSetMask) { TEST_F(BufferHubQueueTest, TestUsageClearMask) { const uint32_t clear_mask = GRALLOC_USAGE_SW_WRITE_OFTEN; - ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(), - UsagePolicy{0, clear_mask, 0, 0})); + ASSERT_TRUE( + CreateQueues(config_builder_.Build(), UsagePolicy{0, clear_mask, 0, 0})); // When allocation, add |clear_mask| into usage bits on purpose. auto status = producer_queue_->AllocateBuffer( @@ -517,10 +561,11 @@ TEST_F(BufferHubQueueTest, TestUsageClearMask) { LocalHandle fence; size_t slot; - auto p1_status = producer_queue_->Dequeue(100, &slot, &fence); + DvrNativeBufferMetadata mo; + auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); ASSERT_TRUE(p1_status.ok()); auto p1 = p1_status.take(); - ASSERT_EQ(0u, p1->usage() & clear_mask); + ASSERT_EQ(p1->usage() & clear_mask, 0U); } TEST_F(BufferHubQueueTest, TestUsageDenySetMask) { @@ -598,16 +643,15 @@ TEST_F(BufferHubQueueTest, TestFreeAllBuffers) { EXPECT_EQ(producer_queue_->capacity(), num_buffers); size_t slot; - uint64_t seq; LocalHandle fence; pdx::Status<void> status; pdx::Status<std::shared_ptr<BufferConsumer>> consumer_status; pdx::Status<std::shared_ptr<BufferProducer>> producer_status; std::shared_ptr<BufferConsumer> consumer_buffer; std::shared_ptr<BufferProducer> producer_buffer; + DvrNativeBufferMetadata mi, mo; - ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<uint64_t>().Build(), - UsagePolicy{})); + ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{})); // Free all buffers when buffers are avaible for dequeue. CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); @@ -616,7 +660,7 @@ TEST_F(BufferHubQueueTest, TestFreeAllBuffers) { // Free all buffers when one buffer is dequeued. CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); - producer_status = producer_queue_->Dequeue(100, &slot, &fence); + producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); ASSERT_TRUE(producer_status.ok()); status = producer_queue_->FreeAllBuffers(); EXPECT_TRUE(status.ok()); @@ -624,7 +668,7 @@ TEST_F(BufferHubQueueTest, TestFreeAllBuffers) { // Free all buffers when all buffers are dequeued. CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); for (size_t i = 0; i < kBufferCount; i++) { - producer_status = producer_queue_->Dequeue(100, &slot, &fence); + producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); ASSERT_TRUE(producer_status.ok()); } status = producer_queue_->FreeAllBuffers(); @@ -632,22 +676,22 @@ TEST_F(BufferHubQueueTest, TestFreeAllBuffers) { // Free all buffers when one buffer is posted. CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); - producer_status = producer_queue_->Dequeue(100, &slot, &fence); + producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); ASSERT_TRUE(producer_status.ok()); producer_buffer = producer_status.take(); ASSERT_NE(nullptr, producer_buffer); - ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq))); + ASSERT_EQ(0, producer_buffer->PostAsync(&mi, fence)); status = producer_queue_->FreeAllBuffers(); EXPECT_TRUE(status.ok()); // Free all buffers when all buffers are posted. CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); for (size_t i = 0; i < kBufferCount; i++) { - producer_status = producer_queue_->Dequeue(100, &slot, &fence); + producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); ASSERT_TRUE(producer_status.ok()); producer_buffer = producer_status.take(); - ASSERT_NE(nullptr, producer_buffer); - ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq))); + ASSERT_NE(producer_buffer, nullptr); + ASSERT_EQ(producer_buffer->PostAsync(&mi, fence), 0); } status = producer_queue_->FreeAllBuffers(); EXPECT_TRUE(status.ok()); @@ -655,12 +699,12 @@ TEST_F(BufferHubQueueTest, TestFreeAllBuffers) { // Free all buffers when all buffers are acquired. CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); for (size_t i = 0; i < kBufferCount; i++) { - producer_status = producer_queue_->Dequeue(100, &slot, &fence); + producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); ASSERT_TRUE(producer_status.ok()); producer_buffer = producer_status.take(); - ASSERT_NE(nullptr, producer_buffer); - ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq))); - consumer_status = consumer_queue_->Dequeue(100, &slot, &seq, &fence); + ASSERT_NE(producer_buffer, nullptr); + ASSERT_EQ(producer_buffer->PostAsync(&mi, fence), 0); + consumer_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); ASSERT_TRUE(consumer_status.ok()); } @@ -680,6 +724,156 @@ TEST_F(BufferHubQueueTest, TestFreeAllBuffers) { #undef CHECK_NO_BUFFER_THEN_ALLOCATE } +TEST_F(BufferHubQueueTest, TestProducerToParcelableNotEmpty) { + ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<uint64_t>().Build(), + UsagePolicy{})); + + // Allocate only one buffer. + AllocateBuffer(); + + // Export should fail as the queue is not empty. + auto status = producer_queue_->TakeAsParcelable(); + EXPECT_FALSE(status.ok()); +} + +TEST_F(BufferHubQueueTest, TestProducerExportToParcelable) { + ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{})); + + auto s1 = producer_queue_->TakeAsParcelable(); + EXPECT_TRUE(s1.ok()); + + ProducerQueueParcelable output_parcelable = s1.take(); + EXPECT_TRUE(output_parcelable.IsValid()); + + Parcel parcel; + status_t res; + res = output_parcelable.writeToParcel(&parcel); + EXPECT_EQ(res, NO_ERROR); + + // After written into parcelable, the output_parcelable is still valid has + // keeps the producer channel alive. + EXPECT_TRUE(output_parcelable.IsValid()); + + // Creating producer buffer should fail. + auto s2 = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight, + kBufferLayerCount, kBufferFormat, + kBufferUsage); + ASSERT_FALSE(s2.ok()); + + // Reset the data position so that we can read back from the same parcel + // without doing actually Binder IPC. + parcel.setDataPosition(0); + producer_queue_ = nullptr; + + // Recreate the producer queue from the parcel. + ProducerQueueParcelable input_parcelable; + EXPECT_FALSE(input_parcelable.IsValid()); + + res = input_parcelable.readFromParcel(&parcel); + EXPECT_EQ(res, NO_ERROR); + EXPECT_TRUE(input_parcelable.IsValid()); + + EXPECT_EQ(producer_queue_, nullptr); + producer_queue_ = ProducerQueue::Import(input_parcelable.TakeChannelHandle()); + EXPECT_FALSE(input_parcelable.IsValid()); + ASSERT_NE(producer_queue_, nullptr); + + // Newly created queue from the parcel can allocate buffer, post buffer to + // consumer. + EXPECT_NO_FATAL_FAILURE(AllocateBuffer()); + EXPECT_EQ(producer_queue_->count(), 1U); + EXPECT_EQ(producer_queue_->capacity(), 1U); + + size_t slot; + DvrNativeBufferMetadata producer_meta; + DvrNativeBufferMetadata consumer_meta; + LocalHandle fence; + auto s3 = producer_queue_->Dequeue(0, &slot, &producer_meta, &fence); + EXPECT_TRUE(s3.ok()); + + std::shared_ptr<BufferProducer> p1 = s3.take(); + ASSERT_NE(p1, nullptr); + + producer_meta.timestamp = 42; + EXPECT_EQ(p1->PostAsync(&producer_meta, LocalHandle()), 0); + + // Make sure the buffer can be dequeued from consumer side. + auto s4 = consumer_queue_->Dequeue(kTimeoutMs, &slot, &consumer_meta, &fence); + EXPECT_TRUE(s4.ok()); + EXPECT_EQ(consumer_queue_->capacity(), 1U); + + auto consumer = s4.take(); + ASSERT_NE(consumer, nullptr); + EXPECT_EQ(producer_meta.timestamp, consumer_meta.timestamp); +} + +TEST_F(BufferHubQueueTest, TestCreateConsumerParcelable) { + ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{})); + + auto s1 = producer_queue_->CreateConsumerQueueParcelable(); + EXPECT_TRUE(s1.ok()); + ConsumerQueueParcelable output_parcelable = s1.take(); + EXPECT_TRUE(output_parcelable.IsValid()); + + // Write to a Parcel new object. + Parcel parcel; + status_t res; + res = output_parcelable.writeToParcel(&parcel); + + // Reset the data position so that we can read back from the same parcel + // without doing actually Binder IPC. + parcel.setDataPosition(0); + + // No consumer queue created yet. + EXPECT_EQ(consumer_queue_, nullptr); + + // If the parcel contains a consumer queue, read into a + // ProducerQueueParcelable should fail. + ProducerQueueParcelable wrongly_typed_parcelable; + EXPECT_FALSE(wrongly_typed_parcelable.IsValid()); + res = wrongly_typed_parcelable.readFromParcel(&parcel); + EXPECT_EQ(res, -EINVAL); + parcel.setDataPosition(0); + + // Create the consumer queue from the parcel. + ConsumerQueueParcelable input_parcelable; + EXPECT_FALSE(input_parcelable.IsValid()); + + res = input_parcelable.readFromParcel(&parcel); + EXPECT_EQ(res, NO_ERROR); + EXPECT_TRUE(input_parcelable.IsValid()); + + consumer_queue_ = ConsumerQueue::Import(input_parcelable.TakeChannelHandle()); + EXPECT_FALSE(input_parcelable.IsValid()); + ASSERT_NE(consumer_queue_, nullptr); + + EXPECT_NO_FATAL_FAILURE(AllocateBuffer()); + EXPECT_EQ(producer_queue_->count(), 1U); + EXPECT_EQ(producer_queue_->capacity(), 1U); + + size_t slot; + DvrNativeBufferMetadata producer_meta; + DvrNativeBufferMetadata consumer_meta; + LocalHandle fence; + auto s2 = producer_queue_->Dequeue(0, &slot, &producer_meta, &fence); + EXPECT_TRUE(s2.ok()); + + std::shared_ptr<BufferProducer> p1 = s2.take(); + ASSERT_NE(p1, nullptr); + + producer_meta.timestamp = 42; + EXPECT_EQ(p1->PostAsync(&producer_meta, LocalHandle()), 0); + + // Make sure the buffer can be dequeued from consumer side. + auto s3 = consumer_queue_->Dequeue(kTimeoutMs, &slot, &consumer_meta, &fence); + EXPECT_TRUE(s3.ok()); + EXPECT_EQ(consumer_queue_->capacity(), 1U); + + auto consumer = s3.take(); + ASSERT_NE(consumer, nullptr); + EXPECT_EQ(producer_meta.timestamp, consumer_meta.timestamp); +} + } // namespace } // namespace dvr diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp index 28cd63af2d..4f10f83211 100644 --- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp +++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp @@ -1,14 +1,16 @@ -#include <private/dvr/buffer_hub_queue_producer.h> - #include <base/logging.h> +#include <gui/BufferHubProducer.h> #include <gui/IProducerListener.h> #include <gui/Surface.h> +#include <pdx/default_transport/channel_parcelable.h> #include <gtest/gtest.h> namespace android { namespace dvr { +using pdx::LocalHandle; + namespace { // Default dimensions before setDefaultBufferSize is called by the consumer. @@ -92,7 +94,11 @@ class BufferHubQueueProducerTest : public ::testing::Test { ALOGD_IF(TRACE, "Begin test: %s.%s", testInfo->test_case_name(), testInfo->name()); - mProducer = BufferHubQueueProducer::Create(); + auto config = ProducerQueueConfigBuilder().Build(); + auto queue = ProducerQueue::Create(config, UsagePolicy{}); + ASSERT_TRUE(queue != nullptr); + + mProducer = BufferHubProducer::Create(std::move(queue)); ASSERT_TRUE(mProducer != nullptr); mSurface = new Surface(mProducer, true); ASSERT_TRUE(mSurface != nullptr); @@ -136,7 +142,7 @@ class BufferHubQueueProducerTest : public ::testing::Test { const sp<IProducerListener> kDummyListener{new DummyProducerListener}; - sp<BufferHubQueueProducer> mProducer; + sp<BufferHubProducer> mProducer; sp<Surface> mSurface; }; @@ -546,6 +552,55 @@ TEST_F(BufferHubQueueProducerTest, ConnectDisconnectReconnect) { EXPECT_EQ(NO_ERROR, mProducer->disconnect(kTestApi)); } +TEST_F(BufferHubQueueProducerTest, TakeAsParcelable) { + // Connected producer cannot be taken out as a parcelable. + EXPECT_NO_FATAL_FAILURE(ConnectProducer()); + ProducerQueueParcelable producer_parcelable; + EXPECT_EQ(mProducer->TakeAsParcelable(&producer_parcelable), BAD_VALUE); + + // Create a valid dummy producer parcelable. + auto dummy_channel_parcelable = + std::make_unique<pdx::default_transport::ChannelParcelable>( + LocalHandle(0), LocalHandle(0), LocalHandle(0)); + EXPECT_TRUE(dummy_channel_parcelable->IsValid()); + ProducerQueueParcelable dummy_producer_parcelable( + std::move(dummy_channel_parcelable)); + EXPECT_TRUE(dummy_producer_parcelable.IsValid()); + + // Disconnect producer can be taken out, but only to an invalid parcelable. + ASSERT_EQ(mProducer->disconnect(kTestApi), NO_ERROR); + EXPECT_EQ(mProducer->TakeAsParcelable(&dummy_producer_parcelable), BAD_VALUE); + EXPECT_FALSE(producer_parcelable.IsValid()); + EXPECT_EQ(mProducer->TakeAsParcelable(&producer_parcelable), NO_ERROR); + EXPECT_TRUE(producer_parcelable.IsValid()); + + // Should still be able to query buffer dimension after disconnect. + int32_t value = -1; + EXPECT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_WIDTH, &value)); + EXPECT_EQ(static_cast<uint32_t>(value), kDefaultWidth); + + EXPECT_EQ(mProducer->query(NATIVE_WINDOW_HEIGHT, &value), NO_ERROR); + EXPECT_EQ(static_cast<uint32_t>(value), kDefaultHeight); + + EXPECT_EQ(mProducer->query(NATIVE_WINDOW_FORMAT, &value), NO_ERROR); + EXPECT_EQ(value, kDefaultFormat); + + // But connect to API will fail. + IGraphicBufferProducer::QueueBufferOutput output; + EXPECT_EQ(mProducer->connect(kDummyListener, kTestApi, kTestControlledByApp, + &output), + BAD_VALUE); + + // Create a new producer from the parcelable and connect to kTestApi should + // succeed. + sp<BufferHubProducer> new_producer = + BufferHubProducer::Create(std::move(producer_parcelable)); + ASSERT_TRUE(new_producer != nullptr); + EXPECT_EQ(new_producer->connect(kDummyListener, kTestApi, + kTestControlledByApp, &output), + NO_ERROR); +} + } // namespace } // namespace dvr diff --git a/libs/vr/libdisplay/Android.bp b/libs/vr/libdisplay/Android.bp index aa9f28823b..9c678815cd 100644 --- a/libs/vr/libdisplay/Android.bp +++ b/libs/vr/libdisplay/Android.bp @@ -26,6 +26,8 @@ localIncludeFiles = [ sharedLibraries = [ "libbase", + "libbinder", + "libbufferhubqueue", "libcutils", "liblog", "libutils", @@ -34,14 +36,12 @@ sharedLibraries = [ "libhardware", "libsync", "libnativewindow", + "libpdx_default_transport", ] staticLibraries = [ "libdvrcommon", - "libbufferhubqueue", - "libbufferhub", "libbroadcastring", - "libpdx_default_transport", ] headerLibraries = [ diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp index 442c82d17f..f67e258cee 100644 --- a/libs/vr/libdisplay/display_client.cpp +++ b/libs/vr/libdisplay/display_client.cpp @@ -9,7 +9,6 @@ #include <mutex> #include <private/dvr/display_protocol.h> -#include <private/dvr/native_buffer.h> using android::pdx::ErrorStatus; using android::pdx::LocalHandle; diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp index 04418d2636..16906f57cd 100644 --- a/libs/vr/libdvr/Android.bp +++ b/libs/vr/libdvr/Android.bp @@ -15,8 +15,8 @@ cc_library_headers { name: "libdvr_headers", - owner: "google", export_include_dirs: ["include"], + vendor_available: true, } cflags = [ @@ -41,8 +41,6 @@ srcs = [ static_libs = [ "libbroadcastring", - "libbufferhub", - "libbufferhubqueue", "libvrsensor", "libdisplay", "libvirtualtouchpadclient", @@ -50,13 +48,13 @@ static_libs = [ "libvr_hwc-binder", "libgrallocusage", "libperformance", - "libpdx_default_transport", ] shared_libs = [ "android.hardware.graphics.bufferqueue@1.0", "android.hidl.token@1.0-utils", "libbase", + "libbufferhubqueue", "libbinder", "liblog", "libcutils", @@ -64,6 +62,7 @@ shared_libs = [ "libnativewindow", "libgui", "libui", + "libpdx_default_transport", ] cc_library_shared { diff --git a/libs/vr/libdvr/dvr_api.cpp b/libs/vr/libdvr/dvr_api.cpp index 7d4e2d130f..d14f040f12 100644 --- a/libs/vr/libdvr/dvr_api.cpp +++ b/libs/vr/libdvr/dvr_api.cpp @@ -41,10 +41,19 @@ int dvrGetApi(void* api, size_t struct_size, int version) { } \ } while (0) +#define DVR_V1_API_ENTRY_DEPRECATED(name) \ + do { \ + if ((offsetof(DvrApi_v1, name) + sizeof(dvr_api->name)) <= \ + clamped_struct_size) { \ + dvr_api->name = nullptr; \ + } \ + } while (0) + #include "include/dvr/dvr_api_entries.h" // Undefine macro definitions to play nice with Google3 style rules. #undef DVR_V1_API_ENTRY +#undef DVR_V1_API_ENTRY_DEPRECATED return 0; } diff --git a/libs/vr/libdvr/dvr_buffer.cpp b/libs/vr/libdvr/dvr_buffer.cpp index 1a9923444e..baf1f2f5da 100644 --- a/libs/vr/libdvr/dvr_buffer.cpp +++ b/libs/vr/libdvr/dvr_buffer.cpp @@ -38,17 +38,13 @@ int ConvertToAHardwareBuffer(GraphicBuffer* graphic_buffer, extern "C" { -void dvrWriteBufferCreateEmpty(DvrWriteBuffer** write_buffer) { - if (write_buffer) - *write_buffer = new DvrWriteBuffer; -} - void dvrWriteBufferDestroy(DvrWriteBuffer* write_buffer) { if (write_buffer != nullptr) { ALOGW_IF( write_buffer->slot != -1, "dvrWriteBufferDestroy: Destroying a buffer associated with a valid " - "buffer queue slot. This may indicate possible leaks."); + "buffer queue slot. This may indicate possible leaks, buffer_id=%d.", + dvrWriteBufferGetId(write_buffer)); delete write_buffer; } } @@ -57,14 +53,6 @@ int dvrWriteBufferIsValid(DvrWriteBuffer* write_buffer) { return write_buffer && write_buffer->write_buffer; } -int dvrWriteBufferClear(DvrWriteBuffer* write_buffer) { - if (!write_buffer) - return -EINVAL; - - write_buffer->write_buffer = nullptr; - return 0; -} - int dvrWriteBufferGetId(DvrWriteBuffer* write_buffer) { if (!write_buffer || !write_buffer->write_buffer) return -EINVAL; @@ -81,44 +69,13 @@ int dvrWriteBufferGetAHardwareBuffer(DvrWriteBuffer* write_buffer, write_buffer->write_buffer->buffer()->buffer().get(), hardware_buffer); } -int dvrWriteBufferPost(DvrWriteBuffer* write_buffer, int ready_fence_fd, - const void* meta, size_t meta_size_bytes) { - if (!write_buffer || !write_buffer->write_buffer) - return -EINVAL; - - pdx::LocalHandle fence(ready_fence_fd); - int result = write_buffer->write_buffer->Post(fence, meta, meta_size_bytes); - return result; -} - -int dvrWriteBufferGain(DvrWriteBuffer* write_buffer, int* release_fence_fd) { - if (!write_buffer || !write_buffer->write_buffer || !release_fence_fd) - return -EINVAL; - - pdx::LocalHandle release_fence; - int result = write_buffer->write_buffer->Gain(&release_fence); - *release_fence_fd = release_fence.Release(); - return result; -} - -int dvrWriteBufferGainAsync(DvrWriteBuffer* write_buffer) { - if (!write_buffer || !write_buffer->write_buffer) - return -EINVAL; - - return write_buffer->write_buffer->GainAsync(); -} - -void dvrReadBufferCreateEmpty(DvrReadBuffer** read_buffer) { - if (read_buffer) - *read_buffer = new DvrReadBuffer; -} - void dvrReadBufferDestroy(DvrReadBuffer* read_buffer) { if (read_buffer != nullptr) { ALOGW_IF( read_buffer->slot != -1, "dvrReadBufferDestroy: Destroying a buffer associated with a valid " - "buffer queue slot. This may indicate possible leaks."); + "buffer queue slot. This may indicate possible leaks, buffer_id=%d.", + dvrReadBufferGetId(read_buffer)); delete read_buffer; } } @@ -127,14 +84,6 @@ int dvrReadBufferIsValid(DvrReadBuffer* read_buffer) { return read_buffer && read_buffer->read_buffer; } -int dvrReadBufferClear(DvrReadBuffer* read_buffer) { - if (!read_buffer) - return -EINVAL; - - read_buffer->read_buffer = nullptr; - return 0; -} - int dvrReadBufferGetId(DvrReadBuffer* read_buffer) { if (!read_buffer || !read_buffer->read_buffer) return -EINVAL; @@ -151,34 +100,6 @@ int dvrReadBufferGetAHardwareBuffer(DvrReadBuffer* read_buffer, read_buffer->read_buffer->buffer()->buffer().get(), hardware_buffer); } -int dvrReadBufferAcquire(DvrReadBuffer* read_buffer, int* ready_fence_fd, - void* meta, size_t meta_size_bytes) { - if (!read_buffer || !read_buffer->read_buffer) - return -EINVAL; - - pdx::LocalHandle ready_fence; - int result = - read_buffer->read_buffer->Acquire(&ready_fence, meta, meta_size_bytes); - *ready_fence_fd = ready_fence.Release(); - return result; -} - -int dvrReadBufferRelease(DvrReadBuffer* read_buffer, int release_fence_fd) { - if (!read_buffer || !read_buffer->read_buffer) - return -EINVAL; - - pdx::LocalHandle fence(release_fence_fd); - int result = read_buffer->read_buffer->Release(fence); - return result; -} - -int dvrReadBufferReleaseAsync(DvrReadBuffer* read_buffer) { - if (!read_buffer || !read_buffer->read_buffer) - return -EINVAL; - - return read_buffer->read_buffer->ReleaseAsync(); -} - void dvrBufferDestroy(DvrBuffer* buffer) { delete buffer; } int dvrBufferGetAHardwareBuffer(DvrBuffer* buffer, @@ -196,27 +117,4 @@ int dvrBufferGlobalLayoutVersionGet() { return android::dvr::kSharedBufferLayoutVersion; } -const struct native_handle* dvrWriteBufferGetNativeHandle( - DvrWriteBuffer* write_buffer) { - if (!write_buffer || !write_buffer->write_buffer) - return nullptr; - - return write_buffer->write_buffer->native_handle(); -} - -const struct native_handle* dvrReadBufferGetNativeHandle( - DvrReadBuffer* read_buffer) { - if (!read_buffer || !read_buffer->read_buffer) - return nullptr; - - return read_buffer->read_buffer->native_handle(); -} - -const struct native_handle* dvrBufferGetNativeHandle(DvrBuffer* buffer) { - if (!buffer || !buffer->buffer) - return nullptr; - - return buffer->buffer->handle(); -} - } // extern "C" diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp index 09a49dd713..74cee3fa1f 100644 --- a/libs/vr/libdvr/dvr_buffer_queue.cpp +++ b/libs/vr/libdvr/dvr_buffer_queue.cpp @@ -2,7 +2,7 @@ #include "include/dvr/dvr_buffer_queue.h" #include <android/native_window.h> -#include <private/dvr/buffer_hub_queue_producer.h> +#include <gui/BufferHubProducer.h> #include "dvr_internal.h" #include "dvr_buffer_queue_internal.h" @@ -10,7 +10,6 @@ using namespace android; using android::dvr::BufferConsumer; using android::dvr::BufferHubBuffer; -using android::dvr::BufferHubQueueProducer; using android::dvr::BufferProducer; using android::dvr::ConsumerQueue; using android::dvr::ProducerQueue; @@ -30,8 +29,7 @@ int DvrWriteBufferQueue::GetNativeWindow(ANativeWindow** out_window) { if (native_window_ == nullptr) { // Lazy creation of |native_window|, as not everyone is using // DvrWriteBufferQueue as an external surface. - sp<IGraphicBufferProducer> gbp = - BufferHubQueueProducer::Create(producer_queue_); + sp<IGraphicBufferProducer> gbp = BufferHubProducer::Create(producer_queue_); native_window_ = new Surface(gbp, true); } @@ -275,14 +273,6 @@ int dvrWriteBufferQueueGetId(DvrWriteBufferQueue* write_queue) { return write_queue->id(); } -int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue, - ANativeWindow** out_window) { - ALOGW( - "dvrWriteBufferQueueGetExternalSurface: This API has been deprecated and " - "renamed to dvrWriteBufferQueueGetANativeWindow."); - return dvrWriteBufferQueueGetANativeWindow(write_queue, out_window); -} - int dvrWriteBufferQueueGetANativeWindow(DvrWriteBufferQueue* write_queue, ANativeWindow** out_window) { if (!write_queue || !out_window) @@ -299,15 +289,6 @@ int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue, return write_queue->CreateReadQueue(out_read_queue); } -int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout, - DvrWriteBuffer* write_buffer, - int* out_fence_fd) { - if (!write_queue || !write_buffer || !out_fence_fd) - return -EINVAL; - - return write_queue->Dequeue(timeout, write_buffer, out_fence_fd); -} - int dvrWriteBufferQueueGainBuffer(DvrWriteBufferQueue* write_queue, int timeout, DvrWriteBuffer** out_write_buffer, DvrNativeBufferMetadata* out_meta, @@ -357,34 +338,6 @@ int DvrReadBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) { return 0; } -int DvrReadBufferQueue::Dequeue(int timeout, DvrReadBuffer* read_buffer, - int* out_fence_fd, void* out_meta, - size_t meta_size_bytes) { - if (meta_size_bytes != consumer_queue_->metadata_size()) { - ALOGE( - "DvrReadBufferQueue::Dequeue: Invalid metadata size, expected (%zu), " - "but actual (%zu).", - consumer_queue_->metadata_size(), meta_size_bytes); - return -EINVAL; - } - - size_t slot; - pdx::LocalHandle acquire_fence; - auto buffer_status = consumer_queue_->Dequeue( - timeout, &slot, out_meta, meta_size_bytes, &acquire_fence); - if (!buffer_status) { - ALOGE_IF(buffer_status.error() != ETIMEDOUT, - "dvrReadBufferQueueDequeue: Failed to dequeue buffer: %s", - buffer_status.GetErrorMessage().c_str()); - return -buffer_status.error(); - } - - read_buffer->read_buffer = buffer_status.take(); - *out_fence_fd = acquire_fence.Release(); - - return 0; -} - int DvrReadBufferQueue::AcquireBuffer(int timeout, DvrReadBuffer** out_read_buffer, DvrNativeBufferMetadata* out_meta, @@ -436,12 +389,22 @@ int DvrReadBufferQueue::ReleaseBuffer(DvrReadBuffer* read_buffer, return -EINVAL; } if (read_buffer->read_buffer->id() != consumer_queue_->GetBufferId(slot)) { - ALOGE( - "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released does not " - "belong to this buffer queue. Releasing buffer: id=%d, buffer in " - "queue: id=%d", - read_buffer->read_buffer->id(), consumer_queue_->GetBufferId(slot)); - return -EINVAL; + if (consumer_queue_->GetBufferId(slot) > 0) { + ALOGE( + "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released may not " + "belong to this queue (queue_id=%d): attempting to release buffer " + "(buffer_id=%d) at slot %d which holds a different buffer " + "(buffer_id=%d).", + consumer_queue_->id(), read_buffer->read_buffer->id(), + static_cast<int>(slot), consumer_queue_->GetBufferId(slot)); + } else { + ALOGI( + "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released may not " + "belong to this queue (queue_id=%d): attempting to release buffer " + "(buffer_id=%d) at slot %d which is empty.", + consumer_queue_->id(), read_buffer->read_buffer->id(), + static_cast<int>(slot)); + } } pdx::LocalHandle fence(release_fence_fd); diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h index 499b7c190a..80ffc82920 100644 --- a/libs/vr/libdvr/include/dvr/dvr_api.h +++ b/libs/vr/libdvr/include/dvr/dvr_api.h @@ -443,11 +443,13 @@ static_assert(sizeof(DvrNativeBufferMetadata) == 104, struct DvrApi_v1 { // Defines an API entry for V1 (no version suffix). #define DVR_V1_API_ENTRY(name) Dvr##name##Ptr name +#define DVR_V1_API_ENTRY_DEPRECATED(name) Dvr##name##Ptr name #include "dvr_api_entries.h" // Undefine macro definitions to play nice with Google3 style rules. #undef DVR_V1_API_ENTRY +#undef DVR_V1_API_ENTRY_DEPRECATED }; int dvrGetApi(void* api, size_t struct_size, int version); diff --git a/libs/vr/libdvr/include/dvr/dvr_api_entries.h b/libs/vr/libdvr/include/dvr/dvr_api_entries.h index cce8c7ee40..f0d8ec6d24 100644 --- a/libs/vr/libdvr/include/dvr/dvr_api_entries.h +++ b/libs/vr/libdvr/include/dvr/dvr_api_entries.h @@ -8,6 +8,10 @@ #error Do not include this header directly. #endif +#ifndef DVR_V1_API_ENTRY_DEPRECATED +#error Do not include this header directly. +#endif + // Do not delete this line: BEGIN CODEGEN OUTPUT // Display manager client DVR_V1_API_ENTRY(DisplayManagerCreate); @@ -32,42 +36,42 @@ DVR_V1_API_ENTRY(SurfaceStateGetAttributeCount); DVR_V1_API_ENTRY(SurfaceStateGetAttributes); // Write buffer -DVR_V1_API_ENTRY(WriteBufferCreateEmpty); +DVR_V1_API_ENTRY_DEPRECATED(WriteBufferCreateEmpty); DVR_V1_API_ENTRY(WriteBufferDestroy); DVR_V1_API_ENTRY(WriteBufferIsValid); -DVR_V1_API_ENTRY(WriteBufferClear); +DVR_V1_API_ENTRY_DEPRECATED(WriteBufferClear); DVR_V1_API_ENTRY(WriteBufferGetId); DVR_V1_API_ENTRY(WriteBufferGetAHardwareBuffer); -DVR_V1_API_ENTRY(WriteBufferPost); -DVR_V1_API_ENTRY(WriteBufferGain); -DVR_V1_API_ENTRY(WriteBufferGainAsync); -DVR_V1_API_ENTRY(WriteBufferGetNativeHandle); +DVR_V1_API_ENTRY_DEPRECATED(WriteBufferPost); +DVR_V1_API_ENTRY_DEPRECATED(WriteBufferGain); +DVR_V1_API_ENTRY_DEPRECATED(WriteBufferGainAsync); +DVR_V1_API_ENTRY_DEPRECATED(WriteBufferGetNativeHandle); // Read buffer -DVR_V1_API_ENTRY(ReadBufferCreateEmpty); +DVR_V1_API_ENTRY_DEPRECATED(ReadBufferCreateEmpty); DVR_V1_API_ENTRY(ReadBufferDestroy); DVR_V1_API_ENTRY(ReadBufferIsValid); -DVR_V1_API_ENTRY(ReadBufferClear); +DVR_V1_API_ENTRY_DEPRECATED(ReadBufferClear); DVR_V1_API_ENTRY(ReadBufferGetId); DVR_V1_API_ENTRY(ReadBufferGetAHardwareBuffer); -DVR_V1_API_ENTRY(ReadBufferAcquire); -DVR_V1_API_ENTRY(ReadBufferRelease); -DVR_V1_API_ENTRY(ReadBufferReleaseAsync); -DVR_V1_API_ENTRY(ReadBufferGetNativeHandle); +DVR_V1_API_ENTRY_DEPRECATED(ReadBufferAcquire); +DVR_V1_API_ENTRY_DEPRECATED(ReadBufferRelease); +DVR_V1_API_ENTRY_DEPRECATED(ReadBufferReleaseAsync); +DVR_V1_API_ENTRY_DEPRECATED(ReadBufferGetNativeHandle); // Buffer DVR_V1_API_ENTRY(BufferDestroy); DVR_V1_API_ENTRY(BufferGetAHardwareBuffer); -DVR_V1_API_ENTRY(BufferGetNativeHandle); +DVR_V1_API_ENTRY_DEPRECATED(BufferGetNativeHandle); DVR_V1_API_ENTRY(BufferGlobalLayoutVersionGet); // Write buffer queue DVR_V1_API_ENTRY(WriteBufferQueueDestroy); DVR_V1_API_ENTRY(WriteBufferQueueGetCapacity); DVR_V1_API_ENTRY(WriteBufferQueueGetId); -DVR_V1_API_ENTRY(WriteBufferQueueGetExternalSurface); // deprecated +DVR_V1_API_ENTRY_DEPRECATED(WriteBufferQueueGetExternalSurface); DVR_V1_API_ENTRY(WriteBufferQueueCreateReadQueue); -DVR_V1_API_ENTRY(WriteBufferQueueDequeue); +DVR_V1_API_ENTRY_DEPRECATED(WriteBufferQueueDequeue); DVR_V1_API_ENTRY(WriteBufferQueueResizeBuffer); // Read buffer queue @@ -75,7 +79,7 @@ DVR_V1_API_ENTRY(ReadBufferQueueDestroy); DVR_V1_API_ENTRY(ReadBufferQueueGetCapacity); DVR_V1_API_ENTRY(ReadBufferQueueGetId); DVR_V1_API_ENTRY(ReadBufferQueueCreateReadQueue); -DVR_V1_API_ENTRY(ReadBufferQueueDequeue); +DVR_V1_API_ENTRY_DEPRECATED(ReadBufferQueueDequeue); DVR_V1_API_ENTRY(ReadBufferQueueSetBufferAvailableCallback); DVR_V1_API_ENTRY(ReadBufferQueueSetBufferRemovedCallback); DVR_V1_API_ENTRY(ReadBufferQueueHandleEvents); diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer.h b/libs/vr/libdvr/include/dvr/dvr_buffer.h index 935a7b2b8a..4234844c0f 100644 --- a/libs/vr/libdvr/include/dvr/dvr_buffer.h +++ b/libs/vr/libdvr/include/dvr/dvr_buffer.h @@ -14,20 +14,12 @@ typedef struct DvrBuffer DvrBuffer; typedef struct AHardwareBuffer AHardwareBuffer; struct native_handle; -// Creates an empty write buffer that may be filled with an acutal buffer by -// other functions. -void dvrWriteBufferCreateEmpty(DvrWriteBuffer** write_buffer); - // Destroys the write buffer. void dvrWriteBufferDestroy(DvrWriteBuffer* write_buffer); // Returns 1 if the given write buffer object contains a buffer, 0 otherwise. int dvrWriteBufferIsValid(DvrWriteBuffer* write_buffer); -// Clears the contents of the buffer object. After a call to this function -// dvrWriteBufferIsValid on the same buffer object returns 0. -int dvrWriteBufferClear(DvrWriteBuffer* write_buffer); - // Returns the global BufferHub id of this buffer. int dvrWriteBufferGetId(DvrWriteBuffer* write_buffer); @@ -36,34 +28,12 @@ int dvrWriteBufferGetId(DvrWriteBuffer* write_buffer); int dvrWriteBufferGetAHardwareBuffer(DvrWriteBuffer* write_buffer, AHardwareBuffer** hardware_buffer); -// Posts the buffer, notifying any connected read buffers. Takes ownership of -// |ready_fence_fd|. -int dvrWriteBufferPost(DvrWriteBuffer* write_buffer, int ready_fence_fd, - const void* meta, size_t meta_size_bytes); - -// Gains a buffer that has been released by all connected read buffers. -int dvrWriteBufferGain(DvrWriteBuffer* write_buffer, int* release_fence_fd); -int dvrWriteBufferGainAsync(DvrWriteBuffer* write_buffer); - -// TODO(eieio): Switch to return int and take an out parameter for the native -// handle. -const struct native_handle* dvrWriteBufferGetNativeHandle( - DvrWriteBuffer* write_buffer); - -// Creates an empty read buffer that may be filled with and actual buffer by -// other functions. -void dvrReadBufferCreateEmpty(DvrReadBuffer** read_buffer); - // Destroys the read buffer. void dvrReadBufferDestroy(DvrReadBuffer* read_buffer); // Returns 1 if the given write buffer object contains a buffer, 0 otherwise. int dvrReadBufferIsValid(DvrReadBuffer* read_buffer); -// Clears the contents of the buffer object. After a call to this function -// dvrReadBufferIsValid on the same buffer object returns 0. -int dvrReadBufferClear(DvrReadBuffer* read_buffer); - // Returns the global BufferHub id of this buffer. int dvrReadBufferGetId(DvrReadBuffer* read_buffer); @@ -72,21 +42,6 @@ int dvrReadBufferGetId(DvrReadBuffer* read_buffer); int dvrReadBufferGetAHardwareBuffer(DvrReadBuffer* read_buffer, AHardwareBuffer** hardware_buffer); -// Acquires the read buffer after it has been posted by the write buffer it is -// connected to. -int dvrReadBufferAcquire(DvrReadBuffer* read_buffer, int* ready_fence_fd, - void* meta, size_t meta_size_bytes); - -// Releases the read buffer, notifying the write buffer it is connected to. -// Takes ownership of |release_fence_fd|. -int dvrReadBufferRelease(DvrReadBuffer* read_buffer, int release_fence_fd); -int dvrReadBufferReleaseAsync(DvrReadBuffer* read_buffer); - -// TODO(eieio): Switch to return int and take an out parameter for the native -// handle. -const struct native_handle* dvrReadBufferGetNativeHandle( - DvrReadBuffer* read_buffer); - // Destroys the buffer. void dvrBufferDestroy(DvrBuffer* buffer); @@ -98,10 +53,6 @@ int dvrBufferGetAHardwareBuffer(DvrBuffer* buffer, // Retrieve the shared buffer layout version defined in dvr_shared_buffers.h. int dvrBufferGlobalLayoutVersionGet(); -// TODO(eieio): Switch to return int and take an out parameter for the native -// handle. -const struct native_handle* dvrBufferGetNativeHandle(DvrBuffer* buffer); - __END_DECLS #endif // ANDROID_DVR_BUFFER_H_ diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h index bf695c7dbc..ac789daf3d 100644 --- a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h +++ b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h @@ -76,10 +76,6 @@ int dvrWriteBufferQueueGetId(DvrWriteBufferQueue* write_queue); int dvrWriteBufferQueueGetANativeWindow(DvrWriteBufferQueue* write_queue, ANativeWindow** out_window); -// @deprecated Please use dvrWriteBufferQueueGetANativeWindow instead. -int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue, - ANativeWindow** out_window); - // Create a read buffer queue from an existing write buffer queue. // // @param write_queue The DvrWriteBufferQueue of interest. @@ -89,10 +85,6 @@ int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue, int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue, DvrReadBufferQueue** out_read_queue); -// @deprecated Please use dvrWriteBufferQueueGainBuffer instead. -int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout, - DvrWriteBuffer* out_buffer, int* out_fence_fd); - // Gains a buffer to write into. // // @param write_queue The DvrWriteBufferQueue to gain buffer from. @@ -176,11 +168,6 @@ int dvrReadBufferQueueGetEventFd(DvrReadBufferQueue* read_queue); int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue, DvrReadBufferQueue** out_read_queue); -// @deprecated Please use dvrReadBufferQueueAcquireBuffer instead. -int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout, - DvrReadBuffer* out_buffer, int* out_fence_fd, - void* out_meta, size_t meta_size_bytes); - // Dequeues a buffer to read from. // // @param read_queue The DvrReadBufferQueue to acquire buffer from. diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp index 887766a535..1ae75fbe04 100644 --- a/libs/vr/libdvr/tests/Android.bp +++ b/libs/vr/libdvr/tests/Android.bp @@ -15,6 +15,7 @@ shared_libraries = [ "libbase", "libbinder", + "libbufferhubqueue", "libcutils", "libgui", "liblog", @@ -22,22 +23,19 @@ shared_libraries = [ "libui", "libutils", "libnativewindow", + "libpdx_default_transport", ] static_libraries = [ "libdvr_static", - "libbufferhubqueue", - "libbufferhub", "libchrome", "libdvrcommon", "libdisplay", - "libpdx_default_transport", "libbroadcastring", ] cc_test { srcs: [ - "dvr_buffer_queue-test.cpp", "dvr_display_manager-test.cpp", "dvr_named_buffer-test.cpp", ], diff --git a/libs/vr/libdvr/tests/Android.mk b/libs/vr/libdvr/tests/Android.mk new file mode 100644 index 0000000000..0f3840d52c --- /dev/null +++ b/libs/vr/libdvr/tests/Android.mk @@ -0,0 +1,73 @@ +# Copyright (C) 2018 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. + +LOCAL_PATH:= $(call my-dir) + +# TODO(b/73133405): Currently, building cc_test against NDK using Android.bp +# doesn't work well. Migrate to use Android.bp once b/73133405 gets fixed. + +include $(CLEAR_VARS) +LOCAL_MODULE:= dvr_buffer_queue-test + +# Includes the dvr_api.h header. Tests should only include "dvr_api.h", +# and shall only get access to |dvrGetApi|, as other symbols are hidden from the +# library. +LOCAL_C_INCLUDES := \ + frameworks/native/libs/vr/libdvr/include \ + +LOCAL_SANITIZE := thread + +LOCAL_SRC_FILES := dvr_buffer_queue-test.cpp + +LOCAL_SHARED_LIBRARIES := \ + libandroid \ + liblog \ + +LOCAL_CFLAGS := \ + -DTRACE=0 \ + -O2 \ + -g \ + +# DTS Should only link to NDK libraries. +LOCAL_SDK_VERSION := 26 +LOCAL_NDK_STL_VARIANT := c++_static + +include $(BUILD_NATIVE_TEST) + + +include $(CLEAR_VARS) +LOCAL_MODULE:= dvr_display-test + +LOCAL_C_INCLUDES := \ + frameworks/native/libs/vr/libdvr/include \ + frameworks/native/libs/nativewindow/include + +LOCAL_SANITIZE := thread + +LOCAL_SRC_FILES := dvr_display-test.cpp + +LOCAL_SHARED_LIBRARIES := \ + libandroid \ + liblog + +LOCAL_CFLAGS := \ + -DTRACE=0 \ + -O2 \ + -g + +# DTS Should only link to NDK libraries. +LOCAL_SDK_VERSION := 26 +LOCAL_NDK_STL_VARIANT := c++_static + +include $(BUILD_NATIVE_TEST)
\ No newline at end of file diff --git a/libs/vr/libdvr/tests/dvr_api_test.h b/libs/vr/libdvr/tests/dvr_api_test.h new file mode 100644 index 0000000000..d8359e78a8 --- /dev/null +++ b/libs/vr/libdvr/tests/dvr_api_test.h @@ -0,0 +1,36 @@ +#include <dlfcn.h> +#include <dvr/dvr_api.h> + +#include <gtest/gtest.h> + +/** DvrTestBase loads the libdvr.so at runtime and get the Dvr API version 1. */ +class DvrApiTest : public ::testing::Test { + protected: + void SetUp() override { + int flags = RTLD_NOW | RTLD_LOCAL; + + // Here we need to ensure that libdvr is loaded with RTLD_NODELETE flag set + // (so that calls to `dlclose` don't actually unload the library). This is a + // workaround for an Android NDK bug. See more detail: + // https://github.com/android-ndk/ndk/issues/360 + flags |= RTLD_NODELETE; + platform_handle_ = dlopen("libdvr.so", flags); + ASSERT_NE(nullptr, platform_handle_) << "Dvr shared library missing."; + + auto dvr_get_api = reinterpret_cast<decltype(&dvrGetApi)>( + dlsym(platform_handle_, "dvrGetApi")); + ASSERT_NE(nullptr, dvr_get_api) << "Platform library missing dvrGetApi."; + + ASSERT_EQ(dvr_get_api(&api_, sizeof(api_), /*version=*/1), 0) + << "Unable to find compatible Dvr API."; + } + + void TearDown() override { + if (platform_handle_ != nullptr) { + dlclose(platform_handle_); + } + } + + void* platform_handle_ = nullptr; + DvrApi_v1 api_; +}; diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp index 62cd8d4e53..2d5f0043e3 100644 --- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp +++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp @@ -1,6 +1,5 @@ #include <android/log.h> #include <android/native_window.h> -#include <android-base/unique_fd.h> #include <dvr/dvr_api.h> #include <dvr/dvr_buffer_queue.h> @@ -9,6 +8,10 @@ #include <array> #include <unordered_map> +#include "dvr_api_test.h" + +#define LOG_TAG "dvr_buffer_queue-test" + #ifndef ALOGD #define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) #endif @@ -27,7 +30,7 @@ static constexpr uint32_t kBufferFormat = AHARDWAREBUFFER_FORMAT_BLOB; static constexpr uint64_t kBufferUsage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN; static constexpr size_t kQueueCapacity = 3; -class DvrBufferQueueTest : public ::testing::Test { +class DvrBufferQueueTest : public DvrApiTest { public: static void BufferAvailableCallback(void* context) { DvrBufferQueueTest* thiz = static_cast<DvrBufferQueueTest*>(context); @@ -42,9 +45,10 @@ class DvrBufferQueueTest : public ::testing::Test { protected: void TearDown() override { if (write_queue_ != nullptr) { - dvrWriteBufferQueueDestroy(write_queue_); + api_.WriteBufferQueueDestroy(write_queue_); write_queue_ = nullptr; } + DvrApiTest::TearDown(); } void HandleBufferAvailable() { @@ -64,85 +68,85 @@ class DvrBufferQueueTest : public ::testing::Test { }; TEST_F(DvrBufferQueueTest, WriteQueueCreateDestroy) { - int ret = dvrWriteBufferQueueCreate( + int ret = api_.WriteBufferQueueCreate( kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_); ASSERT_EQ(0, ret); - dvrWriteBufferQueueDestroy(write_queue_); + api_.WriteBufferQueueDestroy(write_queue_); write_queue_ = nullptr; } TEST_F(DvrBufferQueueTest, WriteQueueGetCapacity) { - int ret = dvrWriteBufferQueueCreate( + int ret = api_.WriteBufferQueueCreate( kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_); ASSERT_EQ(0, ret); - size_t capacity = dvrWriteBufferQueueGetCapacity(write_queue_); + size_t capacity = api_.WriteBufferQueueGetCapacity(write_queue_); ALOGD_IF(TRACE, "TestWrite_QueueGetCapacity, capacity=%zu", capacity); ASSERT_EQ(kQueueCapacity, capacity); } TEST_F(DvrBufferQueueTest, CreateReadQueueFromWriteQueue) { - int ret = dvrWriteBufferQueueCreate( + int ret = api_.WriteBufferQueueCreate( kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_); ASSERT_EQ(0, ret); DvrReadBufferQueue* read_queue = nullptr; - ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue); + ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue); ASSERT_EQ(0, ret); ASSERT_NE(nullptr, read_queue); - dvrReadBufferQueueDestroy(read_queue); + api_.ReadBufferQueueDestroy(read_queue); } TEST_F(DvrBufferQueueTest, CreateReadQueueFromReadQueue) { - int ret = dvrWriteBufferQueueCreate( + int ret = api_.WriteBufferQueueCreate( kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_); ASSERT_EQ(0, ret); DvrReadBufferQueue* read_queue1 = nullptr; DvrReadBufferQueue* read_queue2 = nullptr; - ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue1); + ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue1); ASSERT_EQ(0, ret); ASSERT_NE(nullptr, read_queue1); - ret = dvrReadBufferQueueCreateReadQueue(read_queue1, &read_queue2); + ret = api_.ReadBufferQueueCreateReadQueue(read_queue1, &read_queue2); ASSERT_EQ(0, ret); ASSERT_NE(nullptr, read_queue2); ASSERT_NE(read_queue1, read_queue2); - dvrReadBufferQueueDestroy(read_queue1); - dvrReadBufferQueueDestroy(read_queue2); + api_.ReadBufferQueueDestroy(read_queue1); + api_.ReadBufferQueueDestroy(read_queue2); } TEST_F(DvrBufferQueueTest, GainBuffer) { - int ret = dvrWriteBufferQueueCreate( + int ret = api_.WriteBufferQueueCreate( kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_); ASSERT_EQ(ret, 0); DvrWriteBuffer* wb = nullptr; - EXPECT_FALSE(dvrWriteBufferIsValid(wb)); + EXPECT_FALSE(api_.WriteBufferIsValid(wb)); DvrNativeBufferMetadata meta; int fence_fd = -1; - ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, &meta, - &fence_fd); + ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, &meta, + &fence_fd); ASSERT_EQ(ret, 0); EXPECT_EQ(fence_fd, -1); EXPECT_NE(wb, nullptr); - EXPECT_TRUE(dvrWriteBufferIsValid(wb)); + EXPECT_TRUE(api_.WriteBufferIsValid(wb)); } TEST_F(DvrBufferQueueTest, AcquirePostGainRelease) { - int ret = dvrWriteBufferQueueCreate( + int ret = api_.WriteBufferQueueCreate( kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_); ASSERT_EQ(ret, 0); @@ -154,40 +158,40 @@ TEST_F(DvrBufferQueueTest, AcquirePostGainRelease) { DvrNativeBufferMetadata meta2; int fence_fd = -1; - ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue); + ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue); ASSERT_EQ(ret, 0); ASSERT_NE(read_queue, nullptr); - dvrReadBufferQueueSetBufferAvailableCallback(read_queue, - &BufferAvailableCallback, this); + api_.ReadBufferQueueSetBufferAvailableCallback( + read_queue, &BufferAvailableCallback, this); // Gain buffer for writing. - ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, &meta1, - &fence_fd); + ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, + &meta1, &fence_fd); ASSERT_EQ(ret, 0); ASSERT_NE(wb, nullptr); - ASSERT_TRUE(dvrWriteBufferIsValid(wb)); + ASSERT_TRUE(api_.WriteBufferIsValid(wb)); ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, gain buffer %p, fence_fd=%d", wb, fence_fd); - android::base::unique_fd release_fence(fence_fd); + close(fence_fd); // Post buffer to the read_queue. meta1.timestamp = 42; - ret = dvrWriteBufferQueuePostBuffer(write_queue_, wb, &meta1, /*fence=*/-1); + ret = api_.WriteBufferQueuePostBuffer(write_queue_, wb, &meta1, /*fence=*/-1); ASSERT_EQ(ret, 0); - ASSERT_FALSE(dvrWriteBufferIsValid(wb)); + ASSERT_FALSE(api_.WriteBufferIsValid(wb)); wb = nullptr; // Acquire buffer for reading. - ret = dvrReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, &rb, &meta2, - &fence_fd); + ret = api_.ReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, &rb, + &meta2, &fence_fd); ASSERT_EQ(ret, 0); ASSERT_NE(rb, nullptr); // Dequeue is successfully, BufferAvailableCallback should be fired once. ASSERT_EQ(buffer_available_count_, 1); - ASSERT_TRUE(dvrReadBufferIsValid(rb)); + ASSERT_TRUE(api_.ReadBufferIsValid(rb)); // Metadata should be passed along from producer to consumer properly. ASSERT_EQ(meta1.timestamp, meta2.timestamp); @@ -195,34 +199,34 @@ TEST_F(DvrBufferQueueTest, AcquirePostGainRelease) { ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, acquire buffer %p, fence_fd=%d", rb, fence_fd); - android::base::unique_fd acquire_fence(fence_fd); + close(fence_fd); // Release buffer to the write_queue. - ret = dvrReadBufferQueueReleaseBuffer(read_queue, rb, &meta2, - /*release_fence_fd=*/-1); + ret = api_.ReadBufferQueueReleaseBuffer(read_queue, rb, &meta2, + /*release_fence_fd=*/-1); ASSERT_EQ(ret, 0); - ASSERT_FALSE(dvrReadBufferIsValid(rb)); + ASSERT_FALSE(api_.ReadBufferIsValid(rb)); rb = nullptr; // TODO(b/34387835) Currently buffer allocation has to happen after all queues // are initialized. - size_t capacity = dvrReadBufferQueueGetCapacity(read_queue); + size_t capacity = api_.ReadBufferQueueGetCapacity(read_queue); ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, capacity=%zu", capacity); ASSERT_EQ(kQueueCapacity, capacity); - dvrReadBufferQueueDestroy(read_queue); + api_.ReadBufferQueueDestroy(read_queue); } TEST_F(DvrBufferQueueTest, GetANativeWindow) { - int ret = dvrWriteBufferQueueCreate( + int ret = api_.WriteBufferQueueCreate( kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, - /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_); + /*capacity=*/0, /*user_metadata_size=*/0, &write_queue_); ASSERT_EQ(0, ret); ASSERT_NE(nullptr, write_queue_); ANativeWindow* window = nullptr; - ret = dvrWriteBufferQueueGetANativeWindow(write_queue_, &window); + ret = api_.WriteBufferQueueGetANativeWindow(write_queue_, &window); ASSERT_EQ(0, ret); ASSERT_NE(nullptr, window); @@ -238,7 +242,7 @@ TEST_F(DvrBufferQueueTest, GetANativeWindow) { // Before each dequeue operation, we resize the buffer queue and expect the // queue always return buffer with desired dimension. TEST_F(DvrBufferQueueTest, ResizeBuffer) { - int ret = dvrWriteBufferQueueCreate( + int ret = api_.WriteBufferQueueCreate( kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_); ASSERT_EQ(0, ret); @@ -255,37 +259,37 @@ TEST_F(DvrBufferQueueTest, ResizeBuffer) { AHardwareBuffer* ahb3 = nullptr; AHardwareBuffer_Desc buffer_desc; - ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue); + ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue); ASSERT_EQ(0, ret); ASSERT_NE(nullptr, read_queue); - dvrReadBufferQueueSetBufferRemovedCallback(read_queue, &BufferRemovedCallback, - this); + api_.ReadBufferQueueSetBufferRemovedCallback(read_queue, + &BufferRemovedCallback, this); // Handle all pending events on the read queue. - ret = dvrReadBufferQueueHandleEvents(read_queue); + ret = api_.ReadBufferQueueHandleEvents(read_queue); ASSERT_EQ(0, ret); - size_t capacity = dvrReadBufferQueueGetCapacity(read_queue); + size_t capacity = api_.ReadBufferQueueGetCapacity(read_queue); ALOGD_IF(TRACE, "TestResizeBuffer, capacity=%zu", capacity); ASSERT_EQ(kQueueCapacity, capacity); // Resize before dequeuing. constexpr uint32_t w1 = 10; - ret = dvrWriteBufferQueueResizeBuffer(write_queue_, w1, kBufferHeight); + ret = api_.WriteBufferQueueResizeBuffer(write_queue_, w1, kBufferHeight); ASSERT_EQ(0, ret); // Gain first buffer for writing. All buffers will be resized. - ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb1, &meta, - &fence_fd); + ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb1, + &meta, &fence_fd); ASSERT_EQ(0, ret); - ASSERT_TRUE(dvrWriteBufferIsValid(wb1)); + ASSERT_TRUE(api_.WriteBufferIsValid(wb1)); ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p", wb1); - android::base::unique_fd release_fence1(fence_fd); + close(fence_fd); // Check the buffer dimension. - ret = dvrWriteBufferGetAHardwareBuffer(wb1, &ahb1); + ret = api_.WriteBufferGetAHardwareBuffer(wb1, &ahb1); ASSERT_EQ(0, ret); AHardwareBuffer_describe(ahb1, &buffer_desc); ASSERT_EQ(w1, buffer_desc.width); @@ -294,26 +298,26 @@ TEST_F(DvrBufferQueueTest, ResizeBuffer) { // For the first resize, all buffers are reallocated. int expected_buffer_removed_count = kQueueCapacity; - ret = dvrReadBufferQueueHandleEvents(read_queue); + ret = api_.ReadBufferQueueHandleEvents(read_queue); ASSERT_EQ(0, ret); ASSERT_EQ(expected_buffer_removed_count, buffer_removed_count_); // Resize the queue. We are testing with blob format, keep height to be 1. constexpr uint32_t w2 = 20; - ret = dvrWriteBufferQueueResizeBuffer(write_queue_, w2, kBufferHeight); + ret = api_.WriteBufferQueueResizeBuffer(write_queue_, w2, kBufferHeight); ASSERT_EQ(0, ret); // The next buffer we dequeued should have new width. - ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb2, &meta, - &fence_fd); + ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb2, + &meta, &fence_fd); ASSERT_EQ(0, ret); - ASSERT_TRUE(dvrWriteBufferIsValid(wb2)); + ASSERT_TRUE(api_.WriteBufferIsValid(wb2)); ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb2, fence_fd); - android::base::unique_fd release_fence2(fence_fd); + close(fence_fd); // Check the buffer dimension, should be new width - ret = dvrWriteBufferGetAHardwareBuffer(wb2, &ahb2); + ret = api_.WriteBufferGetAHardwareBuffer(wb2, &ahb2); ASSERT_EQ(0, ret); AHardwareBuffer_describe(ahb2, &buffer_desc); ASSERT_EQ(w2, buffer_desc.width); @@ -321,26 +325,26 @@ TEST_F(DvrBufferQueueTest, ResizeBuffer) { // For the second resize, all but one buffers are reallocated. expected_buffer_removed_count += (kQueueCapacity - 1); - ret = dvrReadBufferQueueHandleEvents(read_queue); + ret = api_.ReadBufferQueueHandleEvents(read_queue); ASSERT_EQ(0, ret); ASSERT_EQ(expected_buffer_removed_count, buffer_removed_count_); // Resize the queue for the third time. constexpr uint32_t w3 = 30; - ret = dvrWriteBufferQueueResizeBuffer(write_queue_, w3, kBufferHeight); + ret = api_.WriteBufferQueueResizeBuffer(write_queue_, w3, kBufferHeight); ASSERT_EQ(0, ret); // The next buffer we dequeued should have new width. - ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb3, &meta, - &fence_fd); + ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb3, + &meta, &fence_fd); ASSERT_EQ(0, ret); - ASSERT_TRUE(dvrWriteBufferIsValid(wb3)); + ASSERT_TRUE(api_.WriteBufferIsValid(wb3)); ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb3, fence_fd); - android::base::unique_fd release_fence3(fence_fd); + close(fence_fd); // Check the buffer dimension, should be new width - ret = dvrWriteBufferGetAHardwareBuffer(wb3, &ahb3); + ret = api_.WriteBufferGetAHardwareBuffer(wb3, &ahb3); ASSERT_EQ(0, ret); AHardwareBuffer_describe(ahb3, &buffer_desc); ASSERT_EQ(w3, buffer_desc.width); @@ -348,26 +352,26 @@ TEST_F(DvrBufferQueueTest, ResizeBuffer) { // For the third resize, all but two buffers are reallocated. expected_buffer_removed_count += (kQueueCapacity - 2); - ret = dvrReadBufferQueueHandleEvents(read_queue); + ret = api_.ReadBufferQueueHandleEvents(read_queue); ASSERT_EQ(0, ret); ASSERT_EQ(expected_buffer_removed_count, buffer_removed_count_); - dvrReadBufferQueueDestroy(read_queue); + api_.ReadBufferQueueDestroy(read_queue); } TEST_F(DvrBufferQueueTest, ReadQueueEventFd) { - int ret = dvrWriteBufferQueueCreate( + int ret = api_.WriteBufferQueueCreate( kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_); ASSERT_EQ(0, ret); DvrReadBufferQueue* read_queue = nullptr; - ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue); + ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue); ASSERT_EQ(0, ret); ASSERT_NE(nullptr, read_queue); - int event_fd = dvrReadBufferQueueGetEventFd(read_queue); + int event_fd = api_.ReadBufferQueueGetEventFd(read_queue); ASSERT_GT(event_fd, 0); } @@ -375,14 +379,14 @@ TEST_F(DvrBufferQueueTest, ReadQueueEventFd) { // Dvr{Read,Write}Buffer(s) during their lifecycles. And for the same buffer_id, // the corresponding AHardwareBuffer handle stays the same. TEST_F(DvrBufferQueueTest, StableBufferIdAndHardwareBuffer) { - int ret = dvrWriteBufferQueueCreate( + int ret = api_.WriteBufferQueueCreate( kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_); ASSERT_EQ(0, ret); int fence_fd = -1; DvrReadBufferQueue* read_queue = nullptr; - EXPECT_EQ(0, dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue)); + EXPECT_EQ(0, api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue)); // Read buffers. std::array<DvrReadBuffer*, kQueueCapacity> rbs; @@ -400,16 +404,16 @@ TEST_F(DvrBufferQueueTest, StableBufferIdAndHardwareBuffer) { // This test runs the following operations many many times. Thus we prefer to // use ASSERT_XXX rather than EXPECT_XXX to avoid spamming the output. std::function<void(size_t i)> Gain = [&](size_t i) { - int ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/10, - &wbs[i], &metas[i], &fence_fd); + int ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/10, + &wbs[i], &metas[i], &fence_fd); ASSERT_EQ(ret, 0); ASSERT_LT(fence_fd, 0); // expect invalid fence. - ASSERT_TRUE(dvrWriteBufferIsValid(wbs[i])); - int buffer_id = dvrWriteBufferGetId(wbs[i]); + ASSERT_TRUE(api_.WriteBufferIsValid(wbs[i])); + int buffer_id = api_.WriteBufferGetId(wbs[i]); ASSERT_GT(buffer_id, 0); AHardwareBuffer* hb = nullptr; - ASSERT_EQ(0, dvrWriteBufferGetAHardwareBuffer(wbs[i], &hb)); + ASSERT_EQ(0, api_.WriteBufferGetAHardwareBuffer(wbs[i], &hb)); auto whb_it = whbs.find(buffer_id); if (whb_it == whbs.end()) { @@ -425,26 +429,26 @@ TEST_F(DvrBufferQueueTest, StableBufferIdAndHardwareBuffer) { }; std::function<void(size_t i)> Post = [&](size_t i) { - ASSERT_TRUE(dvrWriteBufferIsValid(wbs[i])); + ASSERT_TRUE(api_.WriteBufferIsValid(wbs[i])); metas[i].timestamp++; - int ret = dvrWriteBufferQueuePostBuffer(write_queue_, wbs[i], &metas[i], - /*fence=*/-1); + int ret = api_.WriteBufferQueuePostBuffer(write_queue_, wbs[i], &metas[i], + /*fence=*/-1); ASSERT_EQ(ret, 0); }; std::function<void(size_t i)> Acquire = [&](size_t i) { - int ret = dvrReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, - &rbs[i], &metas[i], &fence_fd); + int ret = api_.ReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, + &rbs[i], &metas[i], &fence_fd); ASSERT_EQ(ret, 0); ASSERT_LT(fence_fd, 0); // expect invalid fence. - ASSERT_TRUE(dvrReadBufferIsValid(rbs[i])); + ASSERT_TRUE(api_.ReadBufferIsValid(rbs[i])); - int buffer_id = dvrReadBufferGetId(rbs[i]); + int buffer_id = api_.ReadBufferGetId(rbs[i]); ASSERT_GT(buffer_id, 0); AHardwareBuffer* hb = nullptr; - ASSERT_EQ(0, dvrReadBufferGetAHardwareBuffer(rbs[i], &hb)); + ASSERT_EQ(0, api_.ReadBufferGetAHardwareBuffer(rbs[i], &hb)); auto rhb_it = rhbs.find(buffer_id); if (rhb_it == rhbs.end()) { @@ -460,10 +464,10 @@ TEST_F(DvrBufferQueueTest, StableBufferIdAndHardwareBuffer) { }; std::function<void(size_t i)> Release = [&](size_t i) { - ASSERT_TRUE(dvrReadBufferIsValid(rbs[i])); + ASSERT_TRUE(api_.ReadBufferIsValid(rbs[i])); - int ret = dvrReadBufferQueueReleaseBuffer(read_queue, rbs[i], &metas[i], - /*release_fence_fd=*/-1); + int ret = api_.ReadBufferQueueReleaseBuffer(read_queue, rbs[i], &metas[i], + /*release_fence_fd=*/-1); ASSERT_EQ(ret, 0); }; @@ -521,4 +525,55 @@ TEST_F(DvrBufferQueueTest, StableBufferIdAndHardwareBuffer) { } } +TEST_F(DvrBufferQueueTest, ConsumerReleaseAfterProducerDestroy) { + int ret = api_.WriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_); + ASSERT_EQ(ret, 0); + + DvrReadBufferQueue* read_queue = nullptr; + DvrReadBuffer* rb = nullptr; + DvrWriteBuffer* wb = nullptr; + DvrNativeBufferMetadata meta1; + DvrNativeBufferMetadata meta2; + int fence_fd = -1; + + ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue); + ASSERT_EQ(ret, 0); + + api_.ReadBufferQueueSetBufferAvailableCallback( + read_queue, &BufferAvailableCallback, this); + + // Gain buffer for writing. + ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, + &meta1, &fence_fd); + ASSERT_EQ(ret, 0); + close(fence_fd); + + // Post buffer to the read_queue. + ret = api_.WriteBufferQueuePostBuffer(write_queue_, wb, &meta1, /*fence=*/-1); + ASSERT_EQ(ret, 0); + wb = nullptr; + + // Acquire buffer for reading. + ret = api_.ReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, &rb, + &meta2, &fence_fd); + ASSERT_EQ(ret, 0); + close(fence_fd); + + // Destroy the write buffer queue and make sure the reader queue is picking + // these events up. + api_.WriteBufferQueueDestroy(write_queue_); + ret = api_.ReadBufferQueueHandleEvents(read_queue); + ASSERT_EQ(0, ret); + + // Release buffer to the write_queue. + ret = api_.ReadBufferQueueReleaseBuffer(read_queue, rb, &meta2, + /*release_fence_fd=*/-1); + ASSERT_EQ(ret, 0); + rb = nullptr; + + api_.ReadBufferQueueDestroy(read_queue); +} + } // namespace diff --git a/libs/vr/libdvr/tests/dvr_display-test.cpp b/libs/vr/libdvr/tests/dvr_display-test.cpp new file mode 100644 index 0000000000..c72f94035b --- /dev/null +++ b/libs/vr/libdvr/tests/dvr_display-test.cpp @@ -0,0 +1,351 @@ +#include <android/hardware_buffer.h> +#include <android/log.h> +#include <dvr/dvr_api.h> +#include <dvr/dvr_display_types.h> +#include <dvr/dvr_surface.h> + +#include <gtest/gtest.h> + +#include "dvr_api_test.h" + +#define LOG_TAG "dvr_display-test" + +#ifndef ALOGD +#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) +#endif + +class DvrDisplayTest : public DvrApiTest { + protected: + void SetUp() override { + DvrApiTest::SetUp(); + int ret = api_.GetNativeDisplayMetrics(sizeof(display_metrics_), + &display_metrics_); + ASSERT_EQ(ret, 0) << "Failed to get display metrics."; + ALOGD( + "display_width: %d, display_height: %d, display_x_dpi: %d, " + "display_y_dpi: %d, vsync_period_ns: %d.", + display_metrics_.display_width, display_metrics_.display_height, + display_metrics_.display_x_dpi, display_metrics_.display_y_dpi, + display_metrics_.vsync_period_ns); + } + + void TearDown() override { + if (write_queue_ != nullptr) { + api_.WriteBufferQueueDestroy(write_queue_); + write_queue_ = nullptr; + } + if (direct_surface_ != nullptr) { + api_.SurfaceDestroy(direct_surface_); + direct_surface_ = nullptr; + } + DvrApiTest::TearDown(); + } + + /* Convert a write buffer to an android hardware buffer and fill in + * color_textures evenly to the buffer. + * AssertionError if the width of the buffer is not equal to the input width, + * AssertionError if the height of the buffer is not equal to the input + * height. + */ + void FillWriteBuffer(DvrWriteBuffer* write_buffer, + const std::vector<uint32_t>& color_textures, + uint32_t width, uint32_t height); + + // Write buffer queue properties. + static constexpr uint64_t kUsage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | + AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT | + AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN; + uint32_t kFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM; + static constexpr size_t kMetadataSize = 0; + static constexpr int kTimeoutMs = 1000; // Time for getting buffer. + uint32_t kLayerCount = 1; + DvrWriteBufferQueue* write_queue_ = nullptr; + DvrSurface* direct_surface_ = nullptr; + + // Device display properties. + DvrNativeDisplayMetrics display_metrics_; +}; + +TEST_F(DvrDisplayTest, DisplayWithOneBuffer) { + // Create a direct surface. + std::vector<DvrSurfaceAttribute> direct_surface_attributes = { + {.key = DVR_SURFACE_ATTRIBUTE_DIRECT, + .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL, + .value.bool_value = true}, + {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER, + .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32, + .value.int32_value = 10}, + {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE, + .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL, + .value.bool_value = true}, + }; + int ret = + api_.SurfaceCreate(direct_surface_attributes.data(), + direct_surface_attributes.size(), &direct_surface_); + ASSERT_EQ(ret, 0) << "Failed to create direct surface."; + + // Create a buffer queue with the direct surface. + constexpr size_t kCapacity = 1; + uint32_t width = display_metrics_.display_width; + uint32_t height = display_metrics_.display_height; + ret = api_.SurfaceCreateWriteBufferQueue( + direct_surface_, width, height, kFormat, kLayerCount, kUsage, kCapacity, + kMetadataSize, &write_queue_); + EXPECT_EQ(0, ret) << "Failed to create buffer queue."; + ASSERT_NE(nullptr, write_queue_) << "Write buffer queue should not be null."; + + // Get buffer from WriteBufferQueue. + DvrWriteBuffer* write_buffer = nullptr; + DvrNativeBufferMetadata out_meta; + int out_fence_fd = -1; + ret = api_.WriteBufferQueueGainBuffer(write_queue_, kTimeoutMs, &write_buffer, + &out_meta, &out_fence_fd); + EXPECT_EQ(0, ret) << "Failed to get the buffer."; + ASSERT_NE(nullptr, write_buffer) << "Gained buffer should not be null."; + + // Color the write buffer. + FillWriteBuffer(write_buffer, + {0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000}, + width, height); + + // Post buffer. + int ready_fence_fd = -1; + ret = api_.WriteBufferQueuePostBuffer(write_queue_, write_buffer, &out_meta, + ready_fence_fd); + EXPECT_EQ(0, ret) << "Failed to post the buffer."; + + sleep(5); // For visual check on the device under test. + // Should observe three primary colors on the screen center. +} + +TEST_F(DvrDisplayTest, DisplayWithDoubleBuffering) { + // Create a direct surface. + std::vector<DvrSurfaceAttribute> direct_surface_attributes = { + {.key = DVR_SURFACE_ATTRIBUTE_DIRECT, + .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL, + .value.bool_value = true}, + {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER, + .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32, + .value.int32_value = 10}, + {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE, + .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL, + .value.bool_value = true}, + }; + int ret = + api_.SurfaceCreate(direct_surface_attributes.data(), + direct_surface_attributes.size(), &direct_surface_); + ASSERT_EQ(ret, 0) << "Failed to create direct surface."; + + // Create a buffer queue with the direct surface. + constexpr size_t kCapacity = 2; + uint32_t width = display_metrics_.display_width; + uint32_t height = display_metrics_.display_height; + ret = api_.SurfaceCreateWriteBufferQueue( + direct_surface_, width, height, kFormat, kLayerCount, kUsage, kCapacity, + kMetadataSize, &write_queue_); + EXPECT_EQ(0, ret) << "Failed to create buffer queue."; + ASSERT_NE(nullptr, write_queue_) << "Write buffer queue should not be null."; + + int num_display_cycles_in_5s = 5 / (display_metrics_.vsync_period_ns / 1e9); + ALOGD("The number of display cycles: %d", num_display_cycles_in_5s); + int bufferhub_id_prev_write_buffer = -1; + for (int i = 0; i < num_display_cycles_in_5s; ++i) { + // Get a buffer from the WriteBufferQueue. + DvrWriteBuffer* write_buffer = nullptr; + DvrNativeBufferMetadata out_meta; + int out_fence_fd = -1; + ret = api_.WriteBufferQueueGainBuffer( + write_queue_, kTimeoutMs, &write_buffer, &out_meta, &out_fence_fd); + EXPECT_EQ(0, ret) << "Failed to get the a write buffer."; + ASSERT_NE(nullptr, write_buffer) << "The gained buffer should not be null."; + + int bufferhub_id = api_.WriteBufferGetId(write_buffer); + ALOGD("Display cycle: %d, bufferhub id of the write buffer: %d", i, + bufferhub_id); + EXPECT_NE(bufferhub_id_prev_write_buffer, bufferhub_id) + << "Double buffering should be using the two buffers in turns, not " + "reusing the same write buffer."; + bufferhub_id_prev_write_buffer = bufferhub_id; + + // Color the write buffer. + if (i % 2) { + FillWriteBuffer(write_buffer, {0xffff0000, 0xff00ff00, 0xff0000ff}, width, + height); + } else { + FillWriteBuffer(write_buffer, {0xff00ff00, 0xff0000ff, 0xffff0000}, width, + height); + } + + // Post the write buffer. + int ready_fence_fd = -1; + ret = api_.WriteBufferQueuePostBuffer(write_queue_, write_buffer, &out_meta, + ready_fence_fd); + EXPECT_EQ(0, ret) << "Failed to post the buffer."; + } + // Should observe blinking screen in secondary colors + // although it is actually displaying primary colors. +} + +TEST_F(DvrDisplayTest, DisplayWithTwoHardwareLayers) { + // Create the direct_surface_0 of z order 10 and direct_surface_1 of z + // order 11. + DvrSurface* direct_surface_0 = nullptr; + std::vector<DvrSurfaceAttribute> direct_surface_0_attributes = { + {.key = DVR_SURFACE_ATTRIBUTE_DIRECT, + .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL, + .value.bool_value = true}, + {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER, + .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32, + .value.int32_value = 10}, + {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE, + .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL, + .value.bool_value = true}, + }; + int ret = + api_.SurfaceCreate(direct_surface_0_attributes.data(), + direct_surface_0_attributes.size(), &direct_surface_0); + EXPECT_EQ(ret, 0) << "Failed to create direct surface."; + + DvrSurface* direct_surface_1 = nullptr; + std::vector<DvrSurfaceAttribute> direct_surface_1_attributes = { + {.key = DVR_SURFACE_ATTRIBUTE_DIRECT, + .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL, + .value.bool_value = true}, + {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER, + .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32, + .value.int32_value = 11}, + {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE, + .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL, + .value.bool_value = true}, + }; + ret = + api_.SurfaceCreate(direct_surface_1_attributes.data(), + direct_surface_1_attributes.size(), &direct_surface_1); + EXPECT_EQ(ret, 0) << "Failed to create direct surface."; + + // Create a buffer queue for each of the direct surfaces. + constexpr size_t kCapacity = 1; + uint32_t width = display_metrics_.display_width; + uint32_t height = display_metrics_.display_height; + + DvrWriteBufferQueue* write_queue_0 = nullptr; + ret = api_.SurfaceCreateWriteBufferQueue( + direct_surface_0, width, height, kFormat, kLayerCount, kUsage, kCapacity, + kMetadataSize, &write_queue_0); + EXPECT_EQ(0, ret) << "Failed to create buffer queue."; + EXPECT_NE(nullptr, write_queue_0) << "Write buffer queue should not be null."; + + DvrWriteBufferQueue* write_queue_1 = nullptr; + ret = api_.SurfaceCreateWriteBufferQueue( + direct_surface_1, width, height, kFormat, kLayerCount, kUsage, kCapacity, + kMetadataSize, &write_queue_1); + EXPECT_EQ(0, ret) << "Failed to create buffer queue."; + EXPECT_NE(nullptr, write_queue_1) << "Write buffer queue should not be null."; + + // Get a buffer from each of the write buffer queues. + DvrWriteBuffer* write_buffer_0 = nullptr; + DvrNativeBufferMetadata out_meta_0; + int out_fence_fd = -1; + ret = api_.WriteBufferQueueGainBuffer( + write_queue_0, kTimeoutMs, &write_buffer_0, &out_meta_0, &out_fence_fd); + EXPECT_EQ(0, ret) << "Failed to get the buffer."; + EXPECT_NE(nullptr, write_buffer_0) << "Gained buffer should not be null."; + + DvrWriteBuffer* write_buffer_1 = nullptr; + DvrNativeBufferMetadata out_meta_1; + out_fence_fd = -1; + ret = api_.WriteBufferQueueGainBuffer( + write_queue_1, kTimeoutMs, &write_buffer_1, &out_meta_1, &out_fence_fd); + EXPECT_EQ(0, ret) << "Failed to get the buffer."; + EXPECT_NE(nullptr, write_buffer_1) << "Gained buffer should not be null."; + + // Color the write buffers. + FillWriteBuffer(write_buffer_0, {0xffff0000, 0xff00ff00, 0xff0000ff}, width, + height); + FillWriteBuffer(write_buffer_1, {0x7f00ff00, 0x7f0000ff, 0x7fff0000}, width, + height); + + // Post buffers. + int ready_fence_fd = -1; + ret = api_.WriteBufferQueuePostBuffer(write_queue_0, write_buffer_0, + &out_meta_0, ready_fence_fd); + EXPECT_EQ(0, ret) << "Failed to post the buffer."; + + ready_fence_fd = -1; + ret = api_.WriteBufferQueuePostBuffer(write_queue_1, write_buffer_1, + &out_meta_1, ready_fence_fd); + EXPECT_EQ(0, ret) << "Failed to post the buffer."; + + sleep(5); // For visual check on the device under test. + // Should observe three secondary colors. + + // Test finished. Clean up buffers and surfaces. + if (write_queue_0 != nullptr) { + api_.WriteBufferQueueDestroy(write_queue_0); + write_queue_0 = nullptr; + } + if (write_queue_1 != nullptr) { + api_.WriteBufferQueueDestroy(write_queue_1); + write_queue_1 = nullptr; + } + if (direct_surface_0 != nullptr) { + api_.SurfaceDestroy(direct_surface_0); + } + if (direct_surface_1 != nullptr) { + api_.SurfaceDestroy(direct_surface_1); + } +} + +void DvrDisplayTest::FillWriteBuffer( + DvrWriteBuffer* write_buffer, const std::vector<uint32_t>& color_textures, + uint32_t width, uint32_t height) { + uint32_t num_colors = color_textures.size(); + // Convert the first write buffer to an android hardware buffer. + AHardwareBuffer* ah_buffer = nullptr; + int ret = api_.WriteBufferGetAHardwareBuffer(write_buffer, &ah_buffer); + ASSERT_EQ(0, ret) << "Failed to get a hardware buffer from the write buffer."; + ASSERT_NE(nullptr, ah_buffer) << "AHardware buffer should not be null."; + AHardwareBuffer_Desc ah_buffer_describe; + AHardwareBuffer_describe(ah_buffer, &ah_buffer_describe); + ASSERT_EQ(ah_buffer_describe.format, kFormat) + << "The format of the android hardware buffer is wrong."; + ASSERT_EQ(ah_buffer_describe.layers, kLayerCount) + << "The obtained android hardware buffer should have 2 layers."; + ASSERT_EQ(ah_buffer_describe.width, width) + << "The obtained android hardware buffer width is wrong."; + ASSERT_EQ(ah_buffer_describe.height, height) + << "The obtained android hardware buffer height is wrong."; + // Change the content of the android hardware buffer. + void* buffer_data = nullptr; + int32_t fence = -1; + ret = AHardwareBuffer_lock(ah_buffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, + fence, nullptr, &buffer_data); + ASSERT_EQ(0, ret) << "Failed to lock the hardware buffer."; + ASSERT_NE(nullptr, buffer_data) << "Buffer data should not be null."; + + uint32_t num_pixels = width * height / num_colors; + for (uint32_t color_index = 0; color_index < num_colors - 1; ++color_index) { + uint32_t color_texture = color_textures[color_index]; + for (uint32_t i = 0; i < num_pixels; ++i) { + memcpy(reinterpret_cast<void*>(reinterpret_cast<int64_t>(buffer_data) + + (i + num_pixels * color_index) * + sizeof(color_texture)), + &color_texture, sizeof(color_texture)); + } + } + uint32_t color_texture = color_textures[num_colors - 1]; + uint32_t num_colored_pixels = num_pixels * (num_colors - 1); + num_pixels = width * height - num_colored_pixels; + for (uint32_t i = 0; i < num_pixels; ++i) { + memcpy(reinterpret_cast<void*>(reinterpret_cast<int64_t>(buffer_data) + + (i + num_colored_pixels) * + sizeof(color_texture)), + &color_texture, sizeof(color_texture)); + } + fence = -1; + ret = AHardwareBuffer_unlock(ah_buffer, &fence); + EXPECT_EQ(0, ret) << "Failed to unlock the hardware buffer."; + + // Release the android hardware buffer. + AHardwareBuffer_release(ah_buffer); +} diff --git a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp b/libs/vr/libdvr/tests/dvr_display_manager-test.cpp index f83b26e86c..c9a5c09caa 100644 --- a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp +++ b/libs/vr/libdvr/tests/dvr_display_manager-test.cpp @@ -845,10 +845,10 @@ TEST_F(DvrDisplayManagerTest, MultiLayerBufferQueue) { ASSERT_NE(nullptr, write_queue.get()); DvrWriteBuffer* buffer = nullptr; - dvrWriteBufferCreateEmpty(&buffer); + DvrNativeBufferMetadata metadata; int fence_fd = -1; - int error = - dvrWriteBufferQueueDequeue(write_queue.get(), 1000, buffer, &fence_fd); + int error = dvrWriteBufferQueueGainBuffer(write_queue.get(), /*timeout=*/1000, + &buffer, &metadata, &fence_fd); ASSERT_EQ(0, error); AHardwareBuffer* hardware_buffer = nullptr; diff --git a/libs/vr/libdvrcommon/Android.bp b/libs/vr/libdvrcommon/Android.bp index 8e63d246a8..e75176846e 100644 --- a/libs/vr/libdvrcommon/Android.bp +++ b/libs/vr/libdvrcommon/Android.bp @@ -26,9 +26,10 @@ sharedLibraries = [ "libui", "libgui", "libhardware", + "libpdx_default_transport", ] -staticLibraries = ["libpdx_default_transport", "libbroadcastring"] +staticLibraries = ["libbroadcastring"] headerLibraries = [ "libeigen", diff --git a/libs/vr/libpdx/Android.bp b/libs/vr/libpdx/Android.bp index 113074b1b9..1a9d7274a1 100644 --- a/libs/vr/libpdx/Android.bp +++ b/libs/vr/libpdx/Android.bp @@ -22,6 +22,12 @@ cc_library_static { "service_dispatcher.cpp", "status.cpp", ], + shared_libs: [ + "libbinder", + "libcutils", + "libutils", + "liblog", + ], } cc_test { diff --git a/libs/vr/libpdx/client.cpp b/libs/vr/libpdx/client.cpp index a01c4d67ec..3c66a40a1b 100644 --- a/libs/vr/libpdx/client.cpp +++ b/libs/vr/libpdx/client.cpp @@ -119,6 +119,10 @@ LocalChannelHandle& Client::GetChannelHandle() { return channel_->GetChannelHandle(); } +const LocalChannelHandle& Client::GetChannelHandle() const { + return channel_->GetChannelHandle(); +} + ///////////////////////////// Transaction implementation ////////////////////// Transaction::Transaction(Client& client) : client_{client} {} diff --git a/libs/vr/libpdx/private/pdx/channel_parcelable.h b/libs/vr/libpdx/private/pdx/channel_parcelable.h new file mode 100644 index 0000000000..59ef9d3119 --- /dev/null +++ b/libs/vr/libpdx/private/pdx/channel_parcelable.h @@ -0,0 +1,31 @@ +#ifndef ANDROID_PDX_CHANNEL_PARCELABLE_H_ +#define ANDROID_PDX_CHANNEL_PARCELABLE_H_ + +#include <binder/Parcelable.h> +#include <pdx/channel_handle.h> + +namespace android { +namespace pdx { + +/** + * A parcelable object holds all necessary objects to recreate a ClientChannel. + * In addition to the android::Parcelable interface, this interface exposees + * more PDX-related interface. + */ +class ChannelParcelable : public Parcelable { + public: + virtual ~ChannelParcelable() = default; + + // Returns whether the parcelable object holds a valid client channel. + virtual bool IsValid() const = 0; + + // Returns a channel handle constructed from this parcelable object and takes + // the ownership of all resources from the parcelable object. In another word, + // the parcelable object will become invalid after TakeChannelHandle returns. + virtual LocalChannelHandle TakeChannelHandle() = 0; +}; + +} // namespace pdx +} // namespace android + +#endif // ANDROID_PDX_CHANNEL_PARCELABLE_H_ diff --git a/libs/vr/libpdx/private/pdx/client.h b/libs/vr/libpdx/private/pdx/client.h index 656de7e2ca..c35dabddf7 100644 --- a/libs/vr/libpdx/private/pdx/client.h +++ b/libs/vr/libpdx/private/pdx/client.h @@ -49,6 +49,7 @@ class Client { // Returns a reference to IPC channel handle. LocalChannelHandle& GetChannelHandle(); + const LocalChannelHandle& GetChannelHandle() const; protected: friend Transaction; diff --git a/libs/vr/libpdx/private/pdx/client_channel.h b/libs/vr/libpdx/private/pdx/client_channel.h index 10a49bb8d7..f33a60e881 100644 --- a/libs/vr/libpdx/private/pdx/client_channel.h +++ b/libs/vr/libpdx/private/pdx/client_channel.h @@ -4,6 +4,7 @@ #include <vector> #include <pdx/channel_handle.h> +#include <pdx/channel_parcelable.h> #include <pdx/file_handle.h> #include <pdx/status.h> @@ -32,6 +33,7 @@ class ClientChannel { virtual std::vector<EventSource> GetEventSources() const = 0; virtual LocalChannelHandle& GetChannelHandle() = 0; + virtual const LocalChannelHandle& GetChannelHandle() const = 0; virtual void* AllocateTransactionState() = 0; virtual void FreeTransactionState(void* state) = 0; @@ -61,6 +63,11 @@ class ClientChannel { LocalHandle* handle) const = 0; virtual bool GetChannelHandle(void* transaction_state, ChannelReference ref, LocalChannelHandle* handle) const = 0; + + // Returns the internal state of the channel as a parcelable object. The + // ClientChannel is invalidated however, the channel is kept alive by the + // parcelable object and may be transferred to another process. + virtual std::unique_ptr<ChannelParcelable> TakeChannelParcelable() = 0; }; } // namespace pdx diff --git a/libs/vr/libpdx/private/pdx/mock_client_channel.h b/libs/vr/libpdx/private/pdx/mock_client_channel.h index 49e0682bc9..b1a12996c5 100644 --- a/libs/vr/libpdx/private/pdx/mock_client_channel.h +++ b/libs/vr/libpdx/private/pdx/mock_client_channel.h @@ -14,6 +14,7 @@ class MockClientChannel : public ClientChannel { MOCK_CONST_METHOD0(GetEventSources, std::vector<EventSource>()); MOCK_METHOD1(GetEventMask, Status<int>(int)); MOCK_METHOD0(GetChannelHandle, LocalChannelHandle&()); + MOCK_CONST_METHOD0(GetChannelHandle, const LocalChannelHandle&()); MOCK_METHOD0(AllocateTransactionState, void*()); MOCK_METHOD1(FreeTransactionState, void(void* state)); MOCK_METHOD3(SendImpulse, @@ -49,6 +50,7 @@ class MockClientChannel : public ClientChannel { MOCK_CONST_METHOD3(GetChannelHandle, bool(void* transaction_state, ChannelReference ref, LocalChannelHandle* handle)); + MOCK_METHOD0(TakeChannelParcelable, std::unique_ptr<ChannelParcelable>()); }; } // namespace pdx diff --git a/libs/vr/libpdx/private/pdx/service.h b/libs/vr/libpdx/private/pdx/service.h index 0d30614562..13aa3e90d7 100644 --- a/libs/vr/libpdx/private/pdx/service.h +++ b/libs/vr/libpdx/private/pdx/service.h @@ -589,6 +589,14 @@ class Service : public std::enable_shared_from_this<Service> { } /* + * Return true if a channel with the given ID exists in the Channel map. + */ + bool HasChannelId(int channel_id) const { + std::lock_guard<std::mutex> autolock(channels_mutex_); + return channels_.find(channel_id) != channels_.end(); + } + + /* * Subclasses of Service may override this method to provide a text string * describing the state of the service. This method is called by * HandleSystemMessage in response to the standard diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp index f891c59fde..74b8c8bd21 100644 --- a/libs/vr/libpdx_default_transport/Android.bp +++ b/libs/vr/libpdx_default_transport/Android.bp @@ -26,13 +26,21 @@ cc_defaults { whole_static_libs: ["libpdx_uds"], } -cc_library_static { +cc_library_shared { name: "libpdx_default_transport", defaults: [ "pdx_default_transport_compiler_defaults", "pdx_default_transport_lib_defaults", "pdx_use_transport_uds", ], + shared_libs: [ + "libbase", + "libbinder", + "libcutils", + "liblog", + "libutils", + "libcrypto", + ], } cc_binary { @@ -42,10 +50,9 @@ cc_binary { "pdx_tool.cpp", ], shared_libs: [ + "libbinder", "libcutils", "liblog", - ], - static_libs: [ "libpdx_default_transport", ], } @@ -59,12 +66,11 @@ cc_binary { ], shared_libs: [ "libbase", + "libbinder", "libchrome", "libcutils", "liblog", "libutils", - ], - static_libs: [ "libpdx_default_transport", ], } diff --git a/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/channel_parcelable.h b/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/channel_parcelable.h new file mode 100644 index 0000000000..a8623b25f7 --- /dev/null +++ b/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/channel_parcelable.h @@ -0,0 +1,17 @@ +#ifndef ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_CHANNEL_PARCELABLE_H_ +#define ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_CHANNEL_PARCELABLE_H_ + +#include <servicefs/channel_parcelable.h> + +namespace android { +namespace pdx { +namespace default_transport { + +using ChannelParcelable = ::android::pdx::servicefs::ChannelParcelable; + +} // namespace default_transport +} // namespace pdx +} // namespace android + + +#endif // ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_CHANNEL_PARCELABLE_H_ diff --git a/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/channel_parcelable.h b/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/channel_parcelable.h new file mode 100644 index 0000000000..bcd74e6f25 --- /dev/null +++ b/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/channel_parcelable.h @@ -0,0 +1,17 @@ +#ifndef ANDROID_PDX_DEFAULT_TRANSPORT_UDS_CHANNEL_PARCELABLE_H_ +#define ANDROID_PDX_DEFAULT_TRANSPORT_UDS_CHANNEL_PARCELABLE_H_ + +#include <uds/channel_parcelable.h> + +namespace android { +namespace pdx { +namespace default_transport { + +using ChannelParcelable = ::android::pdx::uds::ChannelParcelable; + +} // namespace default_transport +} // namespace pdx +} // namespace android + + +#endif // ANDROID_PDX_DEFAULT_TRANSPORT_UDS_CHANNEL_PARCELABLE_H_ diff --git a/libs/vr/libpdx_uds/Android.bp b/libs/vr/libpdx_uds/Android.bp index d0b7cab34f..d64095061e 100644 --- a/libs/vr/libpdx_uds/Android.bp +++ b/libs/vr/libpdx_uds/Android.bp @@ -13,6 +13,7 @@ cc_library_static { srcs: [ "channel_event_set.cpp", "channel_manager.cpp", + "channel_parcelable.cpp", "client_channel_factory.cpp", "client_channel.cpp", "ipc_helper.cpp", @@ -23,6 +24,9 @@ cc_library_static { "libbase", "libpdx", ], + shared_libs: [ + "libbinder", + ], whole_static_libs: [ "libselinux", ], @@ -52,5 +56,6 @@ cc_test { "libcutils", "liblog", "libutils", + "libbinder", ], } diff --git a/libs/vr/libpdx_uds/channel_parcelable.cpp b/libs/vr/libpdx_uds/channel_parcelable.cpp new file mode 100644 index 0000000000..e7bce27045 --- /dev/null +++ b/libs/vr/libpdx_uds/channel_parcelable.cpp @@ -0,0 +1,125 @@ +#include "uds/channel_parcelable.h" + +#include <binder/Parcel.h> +#include <uds/channel_manager.h> + +namespace android { +namespace pdx { +namespace uds { + +namespace { + +static constexpr uint32_t kUdsMagicParcelHeader = 0x7564736d; // 'udsm'. + +} // namespace + +ChannelParcelable::ChannelParcelable(LocalHandle data_fd, + LocalHandle pollin_event_fd, + LocalHandle pollhup_event_fd) + : data_fd_{std::move(data_fd)}, + pollin_event_fd_{std::move(pollin_event_fd)}, + pollhup_event_fd_{std::move(pollhup_event_fd)} {} + +bool ChannelParcelable::IsValid() const { + return !!data_fd_ && !!pollin_event_fd_ && !!pollhup_event_fd_; +} + +LocalChannelHandle ChannelParcelable::TakeChannelHandle() { + if (!IsValid()) { + ALOGE("ChannelParcelable::TakeChannelHandle: Invalid channel parcel."); + return {}; // Returns an empty channel handle. + } + + return ChannelManager::Get().CreateHandle(std::move(data_fd_), + std::move(pollin_event_fd_), + std::move(pollhup_event_fd_)); +} + +status_t ChannelParcelable::writeToParcel(Parcel* parcel) const { + status_t res = NO_ERROR; + + if (!IsValid()) { + ALOGE("ChannelParcelable::writeToParcel: Invalid channel parcel."); + return BAD_VALUE; + } + + res = parcel->writeUint32(kUdsMagicParcelHeader); + if (res != NO_ERROR) { + ALOGE("ChannelParcelable::writeToParcel: Cannot write magic: res=%d.", res); + return res; + } + + res = parcel->writeFileDescriptor(data_fd_.Get()); + if (res != NO_ERROR) { + ALOGE("ChannelParcelable::writeToParcel: Cannot write data fd: res=%d.", + res); + return res; + } + + res = parcel->writeFileDescriptor(pollin_event_fd_.Get()); + if (res != NO_ERROR) { + ALOGE( + "ChannelParcelable::writeToParcel: Cannot write pollin event fd: " + "res=%d.", + res); + return res; + } + + res = parcel->writeFileDescriptor(pollhup_event_fd_.Get()); + if (res != NO_ERROR) { + ALOGE( + "ChannelParcelable::writeToParcel: Cannot write pollhup event fd: " + "res=%d.", + res); + return res; + } + + return res; +} + +status_t ChannelParcelable::readFromParcel(const Parcel* parcel) { + uint32_t magic = 0; + status_t res = NO_ERROR; + + if (IsValid()) { + ALOGE( + "ChannelParcelable::readFromParcel: This channel parcel is already " + "initailzied."); + return ALREADY_EXISTS; + } + + res = parcel->readUint32(&magic); + if (res != NO_ERROR) { + ALOGE("ChannelParcelable::readFromParcel: Failed to read magic: res=%d.", + res); + return res; + } + + if (magic != kUdsMagicParcelHeader) { + ALOGE( + "ChannelParcelable::readFromParcel: Unknown magic: 0x%x, epxected: " + "0x%x", + magic, kUdsMagicParcelHeader); + return BAD_VALUE; + } + + // TODO(b/69010509): We have to dup() the FD from android::Parcel as it + // doesn't support taking out the FD's ownership. We can remove the dup() here + // once android::Parcel support such operation. + data_fd_.Reset(dup(parcel->readFileDescriptor())); + pollin_event_fd_.Reset(dup(parcel->readFileDescriptor())); + pollhup_event_fd_.Reset(dup(parcel->readFileDescriptor())); + if (!IsValid()) { + ALOGE( + "ChannelParcelable::readFromParcel: Cannot read fd from parcel: " + "data_fd=%d, pollin_event_fd=%d, pollhup_event_fd=%d.", + data_fd_.Get(), pollin_event_fd_.Get(), pollhup_event_fd_.Get()); + return DEAD_OBJECT; + } + + return res; +} + +} // namespace uds +} // namespace pdx +} // namespace android diff --git a/libs/vr/libpdx_uds/client_channel.cpp b/libs/vr/libpdx_uds/client_channel.cpp index 2e9c1def3b..6073c3cd05 100644 --- a/libs/vr/libpdx_uds/client_channel.cpp +++ b/libs/vr/libpdx_uds/client_channel.cpp @@ -1,3 +1,4 @@ +#include "uds/channel_parcelable.h" #include "uds/client_channel.h" #include <errno.h> @@ -292,6 +293,29 @@ bool ClientChannel::GetChannelHandle(void* transaction_state, return state->GetLocalChannelHandle(ref, handle); } +std::unique_ptr<pdx::ChannelParcelable> ClientChannel::TakeChannelParcelable() + { + if (!channel_handle_) + return nullptr; + + if (auto* channel_data = + ChannelManager::Get().GetChannelData(channel_handle_.value())) { + auto fds = channel_data->TakeFds(); + auto parcelable = std::make_unique<ChannelParcelable>( + std::move(std::get<0>(fds)), std::move(std::get<1>(fds)), + std::move(std::get<2>(fds))); + + // Here we need to explicitly close the channel handle so that the channel + // won't get shutdown in the destructor, while the FDs in ChannelParcelable + // can keep the channel alive so that new client can be created from it + // later. + channel_handle_.Close(); + return parcelable; + } else { + return nullptr; + } +} + } // namespace uds } // namespace pdx } // namespace android diff --git a/libs/vr/libpdx_uds/private/uds/channel_event_set.h b/libs/vr/libpdx_uds/private/uds/channel_event_set.h index 99e75028d1..e960740787 100644 --- a/libs/vr/libpdx_uds/private/uds/channel_event_set.h +++ b/libs/vr/libpdx_uds/private/uds/channel_event_set.h @@ -54,6 +54,14 @@ class ChannelEventReceiver { BorrowedHandle pollhup_event_fd() const { return pollhup_event_fd_.Borrow(); } BorrowedHandle data_fd() const { return data_fd_.Borrow(); } + // Moves file descriptors out of ChannelEventReceiver. Note these operations + // immediately invalidates the receiver. + std::tuple<LocalHandle, LocalHandle, LocalHandle> TakeFds() { + epoll_fd_.Close(); + return {std::move(data_fd_), std::move(pollin_event_fd_), + std::move(pollhup_event_fd_)}; + } + Status<int> GetPendingEvents() const; Status<int> PollPendingEvents(int timeout_ms) const; diff --git a/libs/vr/libpdx_uds/private/uds/channel_parcelable.h b/libs/vr/libpdx_uds/private/uds/channel_parcelable.h new file mode 100644 index 0000000000..1c3fae91d8 --- /dev/null +++ b/libs/vr/libpdx_uds/private/uds/channel_parcelable.h @@ -0,0 +1,35 @@ +#ifndef ANDROID_PDX_UDS_CHANNEL_PARCELABLE_H_ +#define ANDROID_PDX_UDS_CHANNEL_PARCELABLE_H_ + +#include <pdx/channel_parcelable.h> +#include <pdx/file_handle.h> + +namespace android { +namespace pdx { +namespace uds { + +class ChannelParcelable : public pdx::ChannelParcelable { + public: + ChannelParcelable() = default; + ChannelParcelable(LocalHandle data_fd, LocalHandle pollin_event_fd, + LocalHandle pollhup_event_fd); + + // Implements pdx::ChannelParcelable interface. + bool IsValid() const override; + LocalChannelHandle TakeChannelHandle() override; + + // Implements android::Parcelable interface. + status_t writeToParcel(Parcel* parcel) const override; + status_t readFromParcel(const Parcel* parcel) override; + + private: + LocalHandle data_fd_; + LocalHandle pollin_event_fd_; + LocalHandle pollhup_event_fd_; +}; + +} // namespace uds +} // namespace pdx +} // namespace android + +#endif // ANDROID_PDX_UDS_CHANNEL_PARCELABLE_H_ diff --git a/libs/vr/libpdx_uds/private/uds/client_channel.h b/libs/vr/libpdx_uds/private/uds/client_channel.h index 7a5ddf40eb..3561c6f191 100644 --- a/libs/vr/libpdx_uds/private/uds/client_channel.h +++ b/libs/vr/libpdx_uds/private/uds/client_channel.h @@ -41,6 +41,9 @@ class ClientChannel : public pdx::ClientChannel { } LocalChannelHandle& GetChannelHandle() override { return channel_handle_; } + const LocalChannelHandle& GetChannelHandle() const override { + return channel_handle_; + } void* AllocateTransactionState() override; void FreeTransactionState(void* state) override; @@ -74,6 +77,8 @@ class ClientChannel : public pdx::ClientChannel { bool GetChannelHandle(void* transaction_state, ChannelReference ref, LocalChannelHandle* handle) const override; + std::unique_ptr<pdx::ChannelParcelable> TakeChannelParcelable() override; + private: explicit ClientChannel(LocalChannelHandle channel_handle); diff --git a/libs/vr/libpdx_uds/service_endpoint.cpp b/libs/vr/libpdx_uds/service_endpoint.cpp index 0ee77f43a6..32d40e8371 100644 --- a/libs/vr/libpdx_uds/service_endpoint.cpp +++ b/libs/vr/libpdx_uds/service_endpoint.cpp @@ -594,9 +594,10 @@ Status<void> Endpoint::MessageReceive(Message* message) { if (socket_fd_ && event.data.fd == socket_fd_.Get()) { auto status = AcceptConnection(message); - if (!status) - return status; - return ReenableEpollEvent(socket_fd_.Borrow()); + auto reenable_status = ReenableEpollEvent(socket_fd_.Borrow()); + if (!reenable_status) + return reenable_status; + return status; } BorrowedHandle channel_fd{event.data.fd}; diff --git a/libs/vr/libperformance/Android.bp b/libs/vr/libperformance/Android.bp index 6a4687629e..35d3dea9de 100644 --- a/libs/vr/libperformance/Android.bp +++ b/libs/vr/libperformance/Android.bp @@ -19,13 +19,13 @@ sourceFiles = [ includeFiles = [ "include" ] -staticLibraries = ["libpdx_default_transport"] - sharedLibraries = [ "libbase", + "libbinder", "libcutils", "liblog", "libutils", + "libpdx_default_transport", ] cc_library { @@ -37,7 +37,6 @@ cc_library { "-Werror", ], export_include_dirs: includeFiles, - static_libs: staticLibraries, shared_libs: sharedLibraries, name: "libperformance", } diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp index 4d80e91283..4dc669b339 100644 --- a/libs/vr/libvrflinger/Android.bp +++ b/libs/vr/libvrflinger/Android.bp @@ -26,16 +26,11 @@ sourceFiles = [ includeFiles = [ "include" ] staticLibraries = [ - "libsurfaceflingerincludes", - "libhwcomposer-command-buffer", - "libbufferhub", - "libbufferhubqueue", "libdisplay", "libdvrcommon", "libperformance", "libvrsensor", "libbroadcastring", - "libpdx_default_transport", "libvr_manager", "libbroadcastring", ] @@ -44,8 +39,10 @@ sharedLibraries = [ "android.frameworks.vr.composer@1.0", "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.composer@2.2", "libbinder", "libbase", + "libbufferhubqueue", "libcutils", "liblog", "libhardware", @@ -61,16 +58,21 @@ sharedLibraries = [ "libhidlbase", "libhidltransport", "libfmq", + "libpdx_default_transport", ] headerLibraries = [ - "libdvr_headers" + "android.hardware.graphics.composer@2.1-command-buffer", + "android.hardware.graphics.composer@2.2-command-buffer", + "libdvr_headers", + "libsurfaceflinger_headers", ] cc_library_static { srcs: sourceFiles, export_include_dirs: includeFiles, + clang: true, cflags: [ "-DLOG_TAG=\"vr_flinger\"", "-DTRACE=0", @@ -82,6 +84,9 @@ cc_library_static { "-Wno-error=sign-compare", // to fix later "-Wno-unused-variable", ], + cppflags: [ + "-std=c++1z" + ], shared_libs: sharedLibraries, whole_static_libs: staticLibraries, header_libs: headerLibraries, diff --git a/libs/vr/libvrflinger/display_manager_service.cpp b/libs/vr/libvrflinger/display_manager_service.cpp index ef8cca38dd..34b3b0a6f4 100644 --- a/libs/vr/libvrflinger/display_manager_service.cpp +++ b/libs/vr/libvrflinger/display_manager_service.cpp @@ -45,6 +45,14 @@ std::shared_ptr<pdx::Channel> DisplayManagerService::OnChannelOpen( const int user_id = message.GetEffectiveUserId(); const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id); + // Check if the display_manager_ has a defunct channel. + if (display_manager_ && !HasChannelId(display_manager_->channel_id())) { + ALOGE("DisplayManagerService::OnChannelOpen: Found defunct channel %d with " + "no OnChannelClose, clearing prior display manager.", + display_manager_->channel_id()); + display_manager_ = nullptr; + } + // Prevent more than one display manager from registering at a time or // untrusted UIDs from connecting. if (display_manager_ || !trusted) { diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp index ac68a5e3a4..87162c0b5a 100644 --- a/libs/vr/libvrflinger/display_service.cpp +++ b/libs/vr/libvrflinger/display_service.cpp @@ -38,10 +38,12 @@ namespace android { namespace dvr { DisplayService::DisplayService(Hwc2::Composer* hidl, + hwc2_display_t primary_display_id, RequestDisplayCallback request_display_callback) : BASE("DisplayService", Endpoint::Create(display::DisplayProtocol::kClientPath)) { - hardware_composer_.Initialize(hidl, request_display_callback); + hardware_composer_.Initialize( + hidl, primary_display_id, request_display_callback); } bool DisplayService::IsInitialized() const { @@ -175,12 +177,12 @@ Status<void> DisplayService::HandleMessage(pdx::Message& message) { Status<display::Metrics> DisplayService::OnGetMetrics( pdx::Message& /*message*/) { - return {{static_cast<uint32_t>(GetDisplayMetrics().width), - static_cast<uint32_t>(GetDisplayMetrics().height), - static_cast<uint32_t>(GetDisplayMetrics().dpi.x), - static_cast<uint32_t>(GetDisplayMetrics().dpi.y), - static_cast<uint32_t>( - hardware_composer_.native_display_metrics().vsync_period_ns), + const auto& params = hardware_composer_.GetPrimaryDisplayParams(); + return {{static_cast<uint32_t>(params.width), + static_cast<uint32_t>(params.height), + static_cast<uint32_t>(params.dpi.x), + static_cast<uint32_t>(params.dpi.y), + static_cast<uint32_t>(params.vsync_period_ns), 0, 0, 0, diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h index 55e33ab852..3090bd1e7a 100644 --- a/libs/vr/libvrflinger/display_service.h +++ b/libs/vr/libvrflinger/display_service.h @@ -65,12 +65,9 @@ class DisplayService : public pdx::ServiceBase<DisplayService> { hardware_composer_.SetVSyncCallback(callback); } - HWCDisplayMetrics GetDisplayMetrics() { - return hardware_composer_.display_metrics(); - } - void GrantDisplayOwnership() { hardware_composer_.Enable(); } void SeizeDisplayOwnership() { hardware_composer_.Disable(); } + void OnBootFinished() { hardware_composer_.OnBootFinished(); } private: friend BASE; @@ -81,6 +78,7 @@ class DisplayService : public pdx::ServiceBase<DisplayService> { using RequestDisplayCallback = std::function<void(bool)>; DisplayService(android::Hwc2::Composer* hidl, + hwc2_display_t primary_display_id, RequestDisplayCallback request_display_callback); pdx::Status<BorrowedNativeBufferHandle> OnGetGlobalBuffer( diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp index fb69d5cf59..44ce78c854 100644 --- a/libs/vr/libvrflinger/hardware_composer.cpp +++ b/libs/vr/libvrflinger/hardware_composer.cpp @@ -45,14 +45,22 @@ namespace dvr { namespace { -const char kBacklightBrightnessSysFile[] = - "/sys/class/leds/lcd-backlight/brightness"; - const char kDvrPerformanceProperty[] = "sys.dvr.performance"; const char kDvrStandaloneProperty[] = "ro.boot.vr"; const char kRightEyeOffsetProperty[] = "dvr.right_eye_offset_ns"; +const char kUseExternalDisplayProperty[] = "persist.vr.use_external_display"; + +// How long to wait after boot finishes before we turn the display off. +constexpr int kBootFinishedDisplayOffTimeoutSec = 10; + +constexpr int kDefaultDisplayWidth = 1920; +constexpr int kDefaultDisplayHeight = 1080; +constexpr int64_t kDefaultVsyncPeriodNs = 16666667; +// Hardware composer reports dpi as dots per thousand inches (dpi * 1000). +constexpr int kDefaultDpi = 400000; + // Get time offset from a vsync to when the pose for that vsync should be // predicted out to. For example, if scanout gets halfway through the frame // at the halfway point between vsyncs, then this could be half the period. @@ -109,6 +117,11 @@ class TraceArgs { #define TRACE_FORMAT(format, ...) \ TraceArgs PASTE(__tracer, __LINE__) { format, ##__VA_ARGS__ } +// Returns "primary" or "external". Useful for writing more readable logs. +const char* GetDisplayName(bool is_primary) { + return is_primary ? "primary" : "external"; +} + } // anonymous namespace HardwareComposer::HardwareComposer() @@ -121,7 +134,8 @@ HardwareComposer::~HardwareComposer(void) { } bool HardwareComposer::Initialize( - Hwc2::Composer* composer, RequestDisplayCallback request_display_callback) { + Hwc2::Composer* composer, hwc2_display_t primary_display_id, + RequestDisplayCallback request_display_callback) { if (initialized_) { ALOGE("HardwareComposer::Initialize: already initialized."); return false; @@ -131,42 +145,7 @@ bool HardwareComposer::Initialize( request_display_callback_ = request_display_callback; - HWC::Error error = HWC::Error::None; - - Hwc2::Config config; - error = composer->getActiveConfig(HWC_DISPLAY_PRIMARY, &config); - - if (error != HWC::Error::None) { - ALOGE("HardwareComposer: Failed to get current display config : %d", - config); - return false; - } - - error = GetDisplayMetrics(composer, HWC_DISPLAY_PRIMARY, config, - &native_display_metrics_); - - if (error != HWC::Error::None) { - ALOGE( - "HardwareComposer: Failed to get display attributes for current " - "configuration : %d", - error.value); - return false; - } - - ALOGI( - "HardwareComposer: primary display attributes: width=%d height=%d " - "vsync_period_ns=%d DPI=%dx%d", - native_display_metrics_.width, native_display_metrics_.height, - native_display_metrics_.vsync_period_ns, native_display_metrics_.dpi.x, - native_display_metrics_.dpi.y); - - // Set the display metrics but never use rotation to avoid the long latency of - // rotation processing in hwc. - display_transform_ = HWC_TRANSFORM_NONE; - display_metrics_ = native_display_metrics_; - - // Setup the display metrics used by all Layer instances. - Layer::SetDisplayMetrics(native_display_metrics_); + primary_display_ = GetDisplayParams(composer, primary_display_id, true); post_thread_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); LOG_ALWAYS_FATAL_IF( @@ -187,6 +166,21 @@ void HardwareComposer::Enable() { void HardwareComposer::Disable() { UpdatePostThreadState(PostThreadState::Suspended, true); + + std::unique_lock<std::mutex> lock(post_thread_mutex_); + post_thread_ready_.wait(lock, [this] { + return !post_thread_resumed_; + }); +} + +void HardwareComposer::OnBootFinished() { + std::lock_guard<std::mutex> lock(post_thread_mutex_); + if (boot_finished_) + return; + boot_finished_ = true; + post_thread_wait_.notify_one(); + if (is_standalone_device_) + request_display_callback_(true); } // Update the post thread quiescent state based on idle and suspended inputs. @@ -218,59 +212,65 @@ void HardwareComposer::UpdatePostThreadState(PostThreadStateType state, eventfd_read(post_thread_event_fd_.Get(), &value); post_thread_wait_.notify_one(); } +} - // Wait until the post thread is in the requested state. - post_thread_ready_.wait(lock, [this, effective_suspend] { - return effective_suspend != post_thread_resumed_; - }); +void HardwareComposer::CreateComposer() { + if (composer_) + return; + composer_.reset(new Hwc2::impl::Composer("default")); + composer_callback_ = new ComposerCallback; + composer_->registerCallback(composer_callback_); + LOG_ALWAYS_FATAL_IF(!composer_callback_->GotFirstHotplug(), + "Registered composer callback but didn't get hotplug for primary" + " display"); } void HardwareComposer::OnPostThreadResumed() { - // Phones create a new composer client on resume and destroy it on pause. - // Standalones only create the composer client once and then use SetPowerMode - // to control the screen on pause/resume. - if (!is_standalone_device_ || !composer_) { - composer_.reset(new Hwc2::Composer("default")); - composer_callback_ = new ComposerCallback; - composer_->registerCallback(composer_callback_); - Layer::SetComposer(composer_.get()); - } else { - SetPowerMode(true); - } - - EnableVsync(true); - - // TODO(skiazyk): We need to do something about accessing this directly, - // supposedly there is a backlight service on the way. - // TODO(steventhomas): When we change the backlight setting, will surface - // flinger (or something else) set it back to its original value once we give - // control of the display back to surface flinger? - SetBacklightBrightness(255); + ALOGI("OnPostThreadResumed"); + EnableDisplay(*target_display_, true); // Trigger target-specific performance mode change. property_set(kDvrPerformanceProperty, "performance"); } void HardwareComposer::OnPostThreadPaused() { + ALOGI("OnPostThreadPaused"); retire_fence_fds_.clear(); layers_.clear(); - if (composer_) { - EnableVsync(false); - } - + // Phones create a new composer client on resume and destroy it on pause. + // Standalones only create the composer client once and then use SetPowerMode + // to control the screen on pause/resume. if (!is_standalone_device_) { composer_callback_ = nullptr; composer_.reset(nullptr); - Layer::SetComposer(nullptr); } else { - SetPowerMode(false); + EnableDisplay(*target_display_, false); } // Trigger target-specific performance mode change. property_set(kDvrPerformanceProperty, "idle"); } +bool HardwareComposer::PostThreadCondWait(std::unique_lock<std::mutex>& lock, + int timeout_sec, + const std::function<bool()>& pred) { + auto pred_with_quit = [&] { + return pred() || (post_thread_state_ & PostThreadState::Quit); + }; + if (timeout_sec >= 0) { + post_thread_wait_.wait_for(lock, std::chrono::seconds(timeout_sec), + pred_with_quit); + } else { + post_thread_wait_.wait(lock, pred_with_quit); + } + if (post_thread_state_ & PostThreadState::Quit) { + ALOGI("HardwareComposer::PostThread: Quitting."); + return true; + } + return false; +} + HWC::Error HardwareComposer::Validate(hwc2_display_t display) { uint32_t num_types; uint32_t num_requests; @@ -278,27 +278,55 @@ HWC::Error HardwareComposer::Validate(hwc2_display_t display) { composer_->validateDisplay(display, &num_types, &num_requests); if (error == HWC2_ERROR_HAS_CHANGES) { - // TODO(skiazyk): We might need to inspect the requested changes first, but - // so far it seems like we shouldn't ever hit a bad state. - // error = hwc2_funcs_.accept_display_changes_fn_(hardware_composer_device_, - // display); + ALOGE("Hardware composer has requested composition changes, " + "which we don't support."); + // Accept the changes anyway and see if we can get something on the screen. error = composer_->acceptDisplayChanges(display); } return error; } -HWC::Error HardwareComposer::EnableVsync(bool enabled) { - return composer_->setVsyncEnabled( - HWC_DISPLAY_PRIMARY, +bool HardwareComposer::EnableVsync(const DisplayParams& display, bool enabled) { + HWC::Error error = composer_->setVsyncEnabled(display.id, (Hwc2::IComposerClient::Vsync)(enabled ? HWC2_VSYNC_ENABLE : HWC2_VSYNC_DISABLE)); + if (error != HWC::Error::None) { + ALOGE("Error attempting to %s vsync on %s display: %s", + enabled ? "enable" : "disable", GetDisplayName(display.is_primary), + error.to_string().c_str()); + } + return error == HWC::Error::None; } -HWC::Error HardwareComposer::SetPowerMode(bool active) { +bool HardwareComposer::SetPowerMode(const DisplayParams& display, bool active) { + ALOGI("Turning %s display %s", GetDisplayName(display.is_primary), + active ? "on" : "off"); HWC::PowerMode power_mode = active ? HWC::PowerMode::On : HWC::PowerMode::Off; - return composer_->setPowerMode( - HWC_DISPLAY_PRIMARY, power_mode.cast<Hwc2::IComposerClient::PowerMode>()); + HWC::Error error = composer_->setPowerMode(display.id, + power_mode.cast<Hwc2::IComposerClient::PowerMode>()); + if (error != HWC::Error::None) { + ALOGE("Error attempting to turn %s display %s: %s", + GetDisplayName(display.is_primary), active ? "on" : "off", + error.to_string().c_str()); + } + return error == HWC::Error::None; +} + +bool HardwareComposer::EnableDisplay(const DisplayParams& display, + bool enabled) { + bool power_result; + bool vsync_result; + // When turning a display on, we set the power state then set vsync. When + // turning a display off we do it in the opposite order. + if (enabled) { + power_result = SetPowerMode(display, enabled); + vsync_result = EnableVsync(display, enabled); + } else { + vsync_result = EnableVsync(display, enabled); + power_result = SetPowerMode(display, enabled); + } + return power_result && vsync_result; } HWC::Error HardwareComposer::Present(hwc2_display_t display) { @@ -317,78 +345,105 @@ HWC::Error HardwareComposer::Present(hwc2_display_t display) { return error; } -HWC::Error HardwareComposer::GetDisplayAttribute(Hwc2::Composer* composer, - hwc2_display_t display, - hwc2_config_t config, - hwc2_attribute_t attribute, - int32_t* out_value) const { - return composer->getDisplayAttribute( - display, config, (Hwc2::IComposerClient::Attribute)attribute, out_value); -} +DisplayParams HardwareComposer::GetDisplayParams( + Hwc2::Composer* composer, hwc2_display_t display, bool is_primary) { + DisplayParams params; + params.id = display; + params.is_primary = is_primary; -HWC::Error HardwareComposer::GetDisplayMetrics( - Hwc2::Composer* composer, hwc2_display_t display, hwc2_config_t config, - HWCDisplayMetrics* out_metrics) const { - HWC::Error error; + Hwc2::Config config; + HWC::Error error = composer->getActiveConfig(display, &config); - error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_WIDTH, - &out_metrics->width); - if (error != HWC::Error::None) { - ALOGE( - "HardwareComposer::GetDisplayMetrics: Failed to get display width: %s", - error.to_string().c_str()); - return error; - } + if (error == HWC::Error::None) { + auto get_attr = [&](hwc2_attribute_t attr, const char* attr_name) + -> std::optional<int32_t> { + int32_t val; + HWC::Error error = composer->getDisplayAttribute( + display, config, (Hwc2::IComposerClient::Attribute)attr, &val); + if (error != HWC::Error::None) { + ALOGE("Failed to get %s display attr %s: %s", + GetDisplayName(is_primary), attr_name, + error.to_string().c_str()); + return std::nullopt; + } + return val; + }; - error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_HEIGHT, - &out_metrics->height); - if (error != HWC::Error::None) { - ALOGE( - "HardwareComposer::GetDisplayMetrics: Failed to get display height: %s", - error.to_string().c_str()); - return error; - } + auto width = get_attr(HWC2_ATTRIBUTE_WIDTH, "width"); + auto height = get_attr(HWC2_ATTRIBUTE_HEIGHT, "height"); - error = GetDisplayAttribute(composer, display, config, - HWC2_ATTRIBUTE_VSYNC_PERIOD, - &out_metrics->vsync_period_ns); - if (error != HWC::Error::None) { - ALOGE( - "HardwareComposer::GetDisplayMetrics: Failed to get display height: %s", - error.to_string().c_str()); - return error; - } + if (width && height) { + params.width = *width; + params.height = *height; + } else { + ALOGI("Failed to get width and/or height for %s display. Using default" + " size %dx%d.", GetDisplayName(is_primary), kDefaultDisplayWidth, + kDefaultDisplayHeight); + params.width = kDefaultDisplayWidth; + params.height = kDefaultDisplayHeight; + } - error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_DPI_X, - &out_metrics->dpi.x); - if (error != HWC::Error::None) { - ALOGE( - "HardwareComposer::GetDisplayMetrics: Failed to get display DPI X: %s", - error.to_string().c_str()); - return error; - } + auto vsync_period = get_attr(HWC2_ATTRIBUTE_VSYNC_PERIOD, "vsync period"); + if (vsync_period) { + params.vsync_period_ns = *vsync_period; + } else { + ALOGI("Failed to get vsync period for %s display. Using default vsync" + " period %.2fms", GetDisplayName(is_primary), + static_cast<float>(kDefaultVsyncPeriodNs) / 1000000); + params.vsync_period_ns = kDefaultVsyncPeriodNs; + } - error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_DPI_Y, - &out_metrics->dpi.y); - if (error != HWC::Error::None) { - ALOGE( - "HardwareComposer::GetDisplayMetrics: Failed to get display DPI Y: %s", - error.to_string().c_str()); - return error; + auto dpi_x = get_attr(HWC2_ATTRIBUTE_DPI_X, "DPI X"); + auto dpi_y = get_attr(HWC2_ATTRIBUTE_DPI_Y, "DPI Y"); + if (dpi_x && dpi_y) { + params.dpi.x = *dpi_x; + params.dpi.y = *dpi_y; + } else { + ALOGI("Failed to get dpi_x and/or dpi_y for %s display. Using default" + " dpi %d.", GetDisplayName(is_primary), kDefaultDpi); + params.dpi.x = kDefaultDpi; + params.dpi.y = kDefaultDpi; + } + } else { + ALOGE("HardwareComposer: Failed to get current %s display config: %d." + " Using default display values.", + GetDisplayName(is_primary), error.value); + params.width = kDefaultDisplayWidth; + params.height = kDefaultDisplayHeight; + params.dpi.x = kDefaultDpi; + params.dpi.y = kDefaultDpi; + params.vsync_period_ns = kDefaultVsyncPeriodNs; } - return HWC::Error::None; + ALOGI( + "HardwareComposer: %s display attributes: width=%d height=%d " + "vsync_period_ns=%d DPI=%dx%d", + GetDisplayName(is_primary), + params.width, + params.height, + params.vsync_period_ns, + params.dpi.x, + params.dpi.y); + + return params; } std::string HardwareComposer::Dump() { std::unique_lock<std::mutex> lock(post_thread_mutex_); std::ostringstream stream; - stream << "Display metrics: " << display_metrics_.width << "x" - << display_metrics_.height << " " << (display_metrics_.dpi.x / 1000.0) - << "x" << (display_metrics_.dpi.y / 1000.0) << " dpi @ " - << (1000000000.0 / display_metrics_.vsync_period_ns) << " Hz" - << std::endl; + auto print_display_metrics = [&](const DisplayParams& params) { + stream << GetDisplayName(params.is_primary) + << " display metrics: " << params.width << "x" + << params.height << " " << (params.dpi.x / 1000.0) + << "x" << (params.dpi.y / 1000.0) << " dpi @ " + << (1000000000.0 / params.vsync_period_ns) << " Hz" + << std::endl; + }; + + print_display_metrics(primary_display_); + if (external_display_) + print_display_metrics(*external_display_); stream << "Post thread resumed: " << post_thread_resumed_ << std::endl; stream << "Active layers: " << layers_.size() << std::endl; @@ -411,7 +466,7 @@ std::string HardwareComposer::Dump() { return stream.str(); } -void HardwareComposer::PostLayers() { +void HardwareComposer::PostLayers(hwc2_display_t display) { ATRACE_NAME("HardwareComposer::PostLayers"); // Setup the hardware composer layers with current buffers. @@ -419,13 +474,6 @@ void HardwareComposer::PostLayers() { layer.Prepare(); } - HWC::Error error = Validate(HWC_DISPLAY_PRIMARY); - if (error != HWC::Error::None) { - ALOGE("HardwareComposer::PostLayers: Validate failed: %s", - error.to_string().c_str()); - return; - } - // Now that we have taken in a frame from the application, we have a chance // to drop the frame before passing the frame along to HWC. // If the display driver has become backed up, we detect it here and then @@ -466,7 +514,14 @@ void HardwareComposer::PostLayers() { } #endif - error = Present(HWC_DISPLAY_PRIMARY); + HWC::Error error = Validate(display); + if (error != HWC::Error::None) { + ALOGE("HardwareComposer::PostLayers: Validate failed: %s display=%" PRIu64, + error.to_string().c_str(), display); + return; + } + + error = Present(display); if (error != HWC::Error::None) { ALOGE("HardwareComposer::PostLayers: Present failed: %s", error.to_string().c_str()); @@ -475,8 +530,8 @@ void HardwareComposer::PostLayers() { std::vector<Hwc2::Layer> out_layers; std::vector<int> out_fences; - error = composer_->getReleaseFences(HWC_DISPLAY_PRIMARY, &out_layers, - &out_fences); + error = composer_->getReleaseFences(display, + &out_layers, &out_fences); ALOGE_IF(error != HWC::Error::None, "HardwareComposer::PostLayers: Failed to get release fences: %s", error.to_string().c_str()); @@ -499,10 +554,11 @@ void HardwareComposer::SetDisplaySurfaces( const bool display_idle = surfaces.size() == 0; { std::unique_lock<std::mutex> lock(post_thread_mutex_); - pending_surfaces_ = std::move(surfaces); + surfaces_ = std::move(surfaces); + surfaces_changed_ = true; } - if (request_display_callback_ && (!is_standalone_device_ || !composer_)) + if (request_display_callback_ && !is_standalone_device_) request_display_callback_(!display_idle); // Set idle state based on whether there are any surfaces to handle. @@ -570,6 +626,9 @@ void HardwareComposer::UpdateConfigBuffer() { // Copy from latest record in shared_config_ring_ to local copy. DvrConfig record; if (shared_config_ring_.GetNewest(&shared_config_ring_sequence_, &record)) { + ALOGI("DvrConfig updated: sequence %u, post offset %d", + shared_config_ring_sequence_, record.frame_post_offset_ns); + ++shared_config_ring_sequence_; post_thread_config_ = record; } } @@ -612,21 +671,11 @@ int HardwareComposer::PostThreadPollInterruptible( } } -Status<int64_t> HardwareComposer::GetVSyncTime() { - auto status = composer_callback_->GetVsyncTime(HWC_DISPLAY_PRIMARY); - ALOGE_IF(!status, - "HardwareComposer::GetVSyncTime: Failed to get vsync timestamp: %s", - status.GetErrorMessage().c_str()); - return status; -} - -// Waits for the next vsync and returns the timestamp of the vsync event. If -// vsync already passed since the last call, returns the latest vsync timestamp -// instead of blocking. -Status<int64_t> HardwareComposer::WaitForVSync() { - const int64_t predicted_vsync_time = - last_vsync_timestamp_ + - display_metrics_.vsync_period_ns * vsync_prediction_interval_; +// Sleep until the next predicted vsync, returning the predicted vsync +// timestamp. +Status<int64_t> HardwareComposer::WaitForPredictedVSync() { + const int64_t predicted_vsync_time = last_vsync_timestamp_ + + (target_display_->vsync_period_ns * vsync_prediction_interval_); const int error = SleepUntil(predicted_vsync_time); if (error < 0) { ALOGE("HardwareComposer::WaifForVSync:: Failed to sleep: %s", @@ -665,16 +714,6 @@ void HardwareComposer::PostThread() { bool thread_policy_setup = SetThreadPolicy("graphics:high", "/system/performance"); -#if ENABLE_BACKLIGHT_BRIGHTNESS - // TODO(hendrikw): This isn't required at the moment. It's possible that there - // is another method to access this when needed. - // Open the backlight brightness control sysfs node. - backlight_brightness_fd_ = LocalHandle(kBacklightBrightnessSysFile, O_RDWR); - ALOGW_IF(!backlight_brightness_fd_, - "HardwareComposer: Failed to open backlight brightness control: %s", - strerror(errno)); -#endif // ENABLE_BACKLIGHT_BRIGHTNESS - // Create a timerfd based on CLOCK_MONOTINIC. vsync_sleep_timer_fd_.Reset(timerfd_create(CLOCK_MONOTONIC, 0)); LOG_ALWAYS_FATAL_IF( @@ -682,19 +721,49 @@ void HardwareComposer::PostThread() { "HardwareComposer: Failed to create vsync sleep timerfd: %s", strerror(errno)); - const int64_t ns_per_frame = display_metrics_.vsync_period_ns; - const int64_t photon_offset_ns = GetPosePredictionTimeOffset(ns_per_frame); + struct VsyncEyeOffsets { int64_t left_ns, right_ns; }; + bool was_running = false; - // TODO(jbates) Query vblank time from device, when such an API is available. - // This value (6.3%) was measured on A00 in low persistence mode. - int64_t vblank_ns = ns_per_frame * 63 / 1000; - int64_t right_eye_photon_offset_ns = (ns_per_frame - vblank_ns) / 2; + auto get_vsync_eye_offsets = [this]() -> VsyncEyeOffsets { + VsyncEyeOffsets offsets; + offsets.left_ns = + GetPosePredictionTimeOffset(target_display_->vsync_period_ns); - // Check property for overriding right eye offset value. - right_eye_photon_offset_ns = - property_get_int64(kRightEyeOffsetProperty, right_eye_photon_offset_ns); + // TODO(jbates) Query vblank time from device, when such an API is + // available. This value (6.3%) was measured on A00 in low persistence mode. + int64_t vblank_ns = target_display_->vsync_period_ns * 63 / 1000; + offsets.right_ns = (target_display_->vsync_period_ns - vblank_ns) / 2; - bool was_running = false; + // Check property for overriding right eye offset value. + offsets.right_ns = + property_get_int64(kRightEyeOffsetProperty, offsets.right_ns); + + return offsets; + }; + + VsyncEyeOffsets vsync_eye_offsets = get_vsync_eye_offsets(); + + if (is_standalone_device_) { + // First, wait until boot finishes. + std::unique_lock<std::mutex> lock(post_thread_mutex_); + if (PostThreadCondWait(lock, -1, [this] { return boot_finished_; })) { + return; + } + + // Then, wait until we're either leaving the quiescent state, or the boot + // finished display off timeout expires. + if (PostThreadCondWait(lock, kBootFinishedDisplayOffTimeoutSec, + [this] { return !post_thread_quiescent_; })) { + return; + } + + LOG_ALWAYS_FATAL_IF(post_thread_state_ & PostThreadState::Suspended, + "Vr flinger should own the display by now."); + post_thread_resumed_ = true; + post_thread_ready_.notify_all(); + if (!composer_) + CreateComposer(); + } while (1) { ATRACE_NAME("HardwareComposer::PostThread"); @@ -706,31 +775,36 @@ void HardwareComposer::PostThread() { std::unique_lock<std::mutex> lock(post_thread_mutex_); ALOGI("HardwareComposer::PostThread: Entering quiescent state."); - // Tear down resources if necessary. - if (was_running) - OnPostThreadPaused(); - + // Tear down resources. + OnPostThreadPaused(); was_running = false; post_thread_resumed_ = false; post_thread_ready_.notify_all(); - if (post_thread_state_ & PostThreadState::Quit) { - ALOGI("HardwareComposer::PostThread: Quitting."); + if (PostThreadCondWait(lock, -1, + [this] { return !post_thread_quiescent_; })) { + // A true return value means we've been asked to quit. return; } - post_thread_wait_.wait(lock, [this] { return !post_thread_quiescent_; }); - post_thread_resumed_ = true; post_thread_ready_.notify_all(); ALOGI("HardwareComposer::PostThread: Exiting quiescent state."); } - if (!was_running) { - // Setup resources. + if (!composer_) + CreateComposer(); + + bool target_display_changed = UpdateTargetDisplay(); + bool just_resumed_running = !was_running; + was_running = true; + + if (target_display_changed) + vsync_eye_offsets = get_vsync_eye_offsets(); + + if (just_resumed_running) { OnPostThreadResumed(); - was_running = true; // Try to setup the scheduler policy if it failed during startup. Only // attempt to do this on transitions from inactive to active to avoid @@ -739,12 +813,16 @@ void HardwareComposer::PostThread() { thread_policy_setup = SetThreadPolicy("graphics:high", "/system/performance"); } + } + if (target_display_changed || just_resumed_running) { // Initialize the last vsync timestamp with the current time. The // predictor below uses this time + the vsync interval in absolute time // units for the initial delay. Once the driver starts reporting vsync the // predictor will sync up with the real vsync. last_vsync_timestamp_ = GetSystemClockNs(); + vsync_prediction_interval_ = 1; + retire_fence_fds_.clear(); } int64_t vsync_timestamp = 0; @@ -754,7 +832,7 @@ void HardwareComposer::PostThread() { vsync_count_ + 1, last_vsync_timestamp_, vsync_prediction_interval_); - auto status = WaitForVSync(); + auto status = WaitForPredictedVSync(); ALOGE_IF( !status, "HardwareComposer::PostThread: Failed to wait for vsync event: %s", @@ -775,16 +853,16 @@ void HardwareComposer::PostThread() { if (vsync_prediction_interval_ == 1) ++vsync_count_; - const bool layer_config_changed = UpdateLayerConfig(); + UpdateLayerConfig(); // Publish the vsync event. if (vsync_ring_) { DvrVsync vsync; vsync.vsync_count = vsync_count_; vsync.vsync_timestamp_ns = vsync_timestamp; - vsync.vsync_left_eye_offset_ns = photon_offset_ns; - vsync.vsync_right_eye_offset_ns = right_eye_photon_offset_ns; - vsync.vsync_period_ns = ns_per_frame; + vsync.vsync_left_eye_offset_ns = vsync_eye_offsets.left_ns; + vsync.vsync_right_eye_offset_ns = vsync_eye_offsets.right_ns; + vsync.vsync_period_ns = target_display_->vsync_period_ns; vsync_ring_->Publish(vsync); } @@ -792,14 +870,14 @@ void HardwareComposer::PostThread() { // Signal all of the vsync clients. Because absolute time is used for the // wakeup time below, this can take a little time if necessary. if (vsync_callback_) - vsync_callback_(HWC_DISPLAY_PRIMARY, vsync_timestamp, - /*frame_time_estimate*/ 0, vsync_count_); + vsync_callback_(vsync_timestamp, /*frame_time_estimate*/ 0, vsync_count_); { // Sleep until shortly before vsync. ATRACE_NAME("sleep"); - const int64_t display_time_est_ns = vsync_timestamp + ns_per_frame; + const int64_t display_time_est_ns = + vsync_timestamp + target_display_->vsync_period_ns; const int64_t now_ns = GetSystemClockNs(); const int64_t sleep_time_ns = display_time_est_ns - now_ns - post_thread_config_.frame_post_offset_ns; @@ -809,26 +887,18 @@ void HardwareComposer::PostThread() { ATRACE_INT64("sleep_time_ns", sleep_time_ns); if (sleep_time_ns > 0) { int error = SleepUntil(wakeup_time_ns); - ALOGE_IF(error < 0, "HardwareComposer::PostThread: Failed to sleep: %s", + ALOGE_IF(error < 0 && error != kPostThreadInterrupted, + "HardwareComposer::PostThread: Failed to sleep: %s", strerror(-error)); - if (error == kPostThreadInterrupted) { - if (layer_config_changed) { - // If the layer config changed we need to validateDisplay() even if - // we're going to drop the frame, to flush the Composer object's - // internal command buffer and apply our layer changes. - Validate(HWC_DISPLAY_PRIMARY); - } - continue; - } + // If the sleep was interrupted (error == kPostThreadInterrupted), + // we still go through and present this frame because we may have set + // layers earlier and we want to flush the Composer's internal command + // buffer by continuing through to validate and present. } } { - auto status = GetVSyncTime(); - if (!status) { - ALOGE("HardwareComposer::PostThread: Failed to get VSYNC time: %s", - status.GetErrorMessage().c_str()); - } + auto status = composer_callback_->GetVsyncTime(target_display_->id); // If we failed to read vsync there might be a problem with the driver. // Since there's nothing we can do just behave as though we didn't get an @@ -855,20 +925,84 @@ void HardwareComposer::PostThread() { } } - PostLayers(); + PostLayers(target_display_->id); + } +} + +bool HardwareComposer::UpdateTargetDisplay() { + bool target_display_changed = false; + auto displays = composer_callback_->GetDisplays(); + if (displays.external_display_was_hotplugged) { + bool was_using_external_display = !target_display_->is_primary; + if (was_using_external_display) { + // The external display was hotplugged, so make sure to ignore any bad + // display errors as we destroy the layers. + for (auto& layer: layers_) + layer.IgnoreBadDisplayErrorsOnDestroy(true); + } + + if (displays.external_display) { + // External display was connected + external_display_ = GetDisplayParams(composer_.get(), + *displays.external_display, /*is_primary*/ false); + + if (property_get_bool(kUseExternalDisplayProperty, false)) { + ALOGI("External display connected. Switching to external display."); + target_display_ = &(*external_display_); + target_display_changed = true; + } else { + ALOGI("External display connected, but sysprop %s is unset, so" + " using primary display.", kUseExternalDisplayProperty); + if (was_using_external_display) { + target_display_ = &primary_display_; + target_display_changed = true; + } + } + } else { + // External display was disconnected + external_display_ = std::nullopt; + if (was_using_external_display) { + ALOGI("External display disconnected. Switching to primary display."); + target_display_ = &primary_display_; + target_display_changed = true; + } + } + } + + if (target_display_changed) { + // If we're switching to the external display, turn the primary display off. + if (!target_display_->is_primary) { + EnableDisplay(primary_display_, false); + } + // If we're switching to the primary display, and the external display is + // still connected, turn the external display off. + else if (target_display_->is_primary && external_display_) { + EnableDisplay(*external_display_, false); + } + + // Turn the new target display on. + EnableDisplay(*target_display_, true); + + // When we switch displays we need to recreate all the layers, so clear the + // current list, which will trigger layer recreation. + layers_.clear(); } + + return target_display_changed; } // Checks for changes in the surface stack and updates the layer config to // accomodate the new stack. -bool HardwareComposer::UpdateLayerConfig() { +void HardwareComposer::UpdateLayerConfig() { std::vector<std::shared_ptr<DirectDisplaySurface>> surfaces; { std::unique_lock<std::mutex> lock(post_thread_mutex_); - if (pending_surfaces_.empty()) - return false; - surfaces = std::move(pending_surfaces_); + if (!surfaces_changed_ && (!layers_.empty() || surfaces_.empty())) + return; + + surfaces = surfaces_; + surfaces_changed_ = false; } ATRACE_NAME("UpdateLayerConfig_HwLayers"); @@ -905,8 +1039,8 @@ bool HardwareComposer::UpdateLayerConfig() { layers_.erase(search); } else { // Insert a layer for the new surface. - layers.emplace_back(surface, blending, display_transform_, - HWC::Composition::Device, layer_index); + layers.emplace_back(composer_.get(), *target_display_, surface, blending, + HWC::Composition::Device, layer_index); } ALOGI_IF( @@ -927,26 +1061,36 @@ bool HardwareComposer::UpdateLayerConfig() { ALOGD_IF(TRACE, "HardwareComposer::UpdateLayerConfig: %zd active layers", layers_.size()); - return true; } void HardwareComposer::SetVSyncCallback(VSyncCallback callback) { vsync_callback_ = callback; } -void HardwareComposer::SetBacklightBrightness(int brightness) { - if (backlight_brightness_fd_) { - std::array<char, 32> text; - const int length = snprintf(text.data(), text.size(), "%d", brightness); - write(backlight_brightness_fd_.Get(), text.data(), length); +Return<void> HardwareComposer::ComposerCallback::onHotplug( + Hwc2::Display display, IComposerCallback::Connection conn) { + std::lock_guard<std::mutex> lock(mutex_); + ALOGI("onHotplug display=%" PRIu64 " conn=%d", display, conn); + + bool is_primary = !got_first_hotplug_ || display == primary_display_.id; + + // Our first onHotplug callback is always for the primary display. + if (!got_first_hotplug_) { + LOG_ALWAYS_FATAL_IF(conn != IComposerCallback::Connection::CONNECTED, + "Initial onHotplug callback should be primary display connected"); + got_first_hotplug_ = true; + } else if (is_primary) { + ALOGE("Ignoring unexpected onHotplug() call for primary display"); + return Void(); } -} -Return<void> HardwareComposer::ComposerCallback::onHotplug( - Hwc2::Display display, IComposerCallback::Connection /*conn*/) { - // See if the driver supports the vsync_event node in sysfs. - if (display < HWC_NUM_PHYSICAL_DISPLAY_TYPES && - !displays_[display].driver_vsync_event_fd) { + if (conn == IComposerCallback::Connection::CONNECTED) { + if (!is_primary) + external_display_ = DisplayInfo(); + DisplayInfo& display_info = is_primary ? + primary_display_ : *external_display_; + display_info.id = display; + std::array<char, 1024> buffer; snprintf(buffer.data(), buffer.size(), "/sys/class/graphics/fb%" PRIu64 "/vsync_event", display); @@ -955,15 +1099,20 @@ Return<void> HardwareComposer::ComposerCallback::onHotplug( "HardwareComposer::ComposerCallback::onHotplug: Driver supports " "vsync_event node for display %" PRIu64, display); - displays_[display].driver_vsync_event_fd = std::move(handle); + display_info.driver_vsync_event_fd = std::move(handle); } else { ALOGI( "HardwareComposer::ComposerCallback::onHotplug: Driver does not " "support vsync_event node for display %" PRIu64, display); } + } else if (conn == IComposerCallback::Connection::DISCONNECTED) { + external_display_ = std::nullopt; } + if (!is_primary) + external_display_was_hotplugged_ = true; + return Void(); } @@ -974,36 +1123,45 @@ Return<void> HardwareComposer::ComposerCallback::onRefresh( Return<void> HardwareComposer::ComposerCallback::onVsync(Hwc2::Display display, int64_t timestamp) { - TRACE_FORMAT("vsync_callback|display=%" PRIu64 ";timestamp=%" PRId64 "|", - display, timestamp); - if (display < HWC_NUM_PHYSICAL_DISPLAY_TYPES) { - displays_[display].callback_vsync_timestamp = timestamp; - } else { - ALOGW( - "HardwareComposer::ComposerCallback::onVsync: Received vsync on " - "non-physical display: display=%" PRId64, - display); + DisplayInfo* display_info = GetDisplayInfo(display); + if (display_info) { + TRACE_FORMAT("vsync_callback|display=%" PRIu64 ";timestamp=%" PRId64 "|", + display, timestamp); + display_info->callback_vsync_timestamp = timestamp; } + return Void(); } +HardwareComposer::ComposerCallback::Displays +HardwareComposer::ComposerCallback::GetDisplays() { + std::lock_guard<std::mutex> lock(mutex_); + Displays displays; + displays.primary_display = primary_display_.id; + if (external_display_) + displays.external_display = external_display_->id; + if (external_display_was_hotplugged_) { + external_display_was_hotplugged_ = false; + displays.external_display_was_hotplugged = true; + } + return displays; +} + Status<int64_t> HardwareComposer::ComposerCallback::GetVsyncTime( - Hwc2::Display display) { - if (display >= HWC_NUM_PHYSICAL_DISPLAY_TYPES) { - ALOGE( - "HardwareComposer::ComposerCallback::GetVsyncTime: Invalid physical " - "display requested: display=%" PRIu64, - display); + hwc2_display_t display) { + DisplayInfo* display_info = GetDisplayInfo(display); + if (!display_info) { + ALOGW("Attempt to get vsync time for unknown display %" PRIu64, display); return ErrorStatus(EINVAL); } // See if the driver supports direct vsync events. - LocalHandle& event_fd = displays_[display].driver_vsync_event_fd; + LocalHandle& event_fd = display_info->driver_vsync_event_fd; if (!event_fd) { // Fall back to returning the last timestamp returned by the vsync // callback. - std::lock_guard<std::mutex> autolock(vsync_mutex_); - return displays_[display].callback_vsync_timestamp; + std::lock_guard<std::mutex> autolock(mutex_); + return display_info->callback_vsync_timestamp; } // When the driver supports the vsync_event sysfs node we can use it to @@ -1051,18 +1209,32 @@ Status<int64_t> HardwareComposer::ComposerCallback::GetVsyncTime( return {timestamp}; } -Hwc2::Composer* Layer::composer_{nullptr}; -HWCDisplayMetrics Layer::display_metrics_{0, 0, {0, 0}, 0}; +HardwareComposer::ComposerCallback::DisplayInfo* +HardwareComposer::ComposerCallback::GetDisplayInfo(hwc2_display_t display) { + if (display == primary_display_.id) { + return &primary_display_; + } else if (external_display_ && display == external_display_->id) { + return &(*external_display_); + } + return nullptr; +} void Layer::Reset() { if (hardware_composer_layer_) { - composer_->destroyLayer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_); + HWC::Error error = + composer_->destroyLayer(display_params_.id, hardware_composer_layer_); + if (error != HWC::Error::None && + (!ignore_bad_display_errors_on_destroy_ || + error != HWC::Error::BadDisplay)) { + ALOGE("destroyLayer() failed for display %" PRIu64 ", layer %" PRIu64 + ". error: %s", display_params_.id, hardware_composer_layer_, + error.to_string().c_str()); + } hardware_composer_layer_ = 0; } z_order_ = 0; blending_ = HWC::BlendMode::None; - transform_ = HWC::Transform::None; composition_type_ = HWC::Composition::Invalid; target_composition_type_ = composition_type_; source_ = EmptyVariant{}; @@ -1070,25 +1242,29 @@ void Layer::Reset() { surface_rect_functions_applied_ = false; pending_visibility_settings_ = true; cached_buffer_map_.clear(); + ignore_bad_display_errors_on_destroy_ = false; } -Layer::Layer(const std::shared_ptr<DirectDisplaySurface>& surface, - HWC::BlendMode blending, HWC::Transform transform, - HWC::Composition composition_type, size_t z_order) - : z_order_{z_order}, +Layer::Layer(Hwc2::Composer* composer, const DisplayParams& display_params, + const std::shared_ptr<DirectDisplaySurface>& surface, + HWC::BlendMode blending, HWC::Composition composition_type, + size_t z_order) + : composer_(composer), + display_params_(display_params), + z_order_{z_order}, blending_{blending}, - transform_{transform}, target_composition_type_{composition_type}, source_{SourceSurface{surface}} { CommonLayerSetup(); } -Layer::Layer(const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending, - HWC::Transform transform, HWC::Composition composition_type, - size_t z_order) - : z_order_{z_order}, +Layer::Layer(Hwc2::Composer* composer, const DisplayParams& display_params, + const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending, + HWC::Composition composition_type, size_t z_order) + : composer_(composer), + display_params_(display_params), + z_order_{z_order}, blending_{blending}, - transform_{transform}, target_composition_type_{composition_type}, source_{SourceBuffer{buffer}} { CommonLayerSetup(); @@ -1102,10 +1278,11 @@ Layer& Layer::operator=(Layer&& other) { if (this != &other) { Reset(); using std::swap; + swap(composer_, other.composer_); + swap(display_params_, other.display_params_); swap(hardware_composer_layer_, other.hardware_composer_layer_); swap(z_order_, other.z_order_); swap(blending_, other.blending_); - swap(transform_, other.transform_); swap(composition_type_, other.composition_type_); swap(target_composition_type_, other.target_composition_type_); swap(source_, other.source_); @@ -1114,6 +1291,8 @@ Layer& Layer::operator=(Layer&& other) { other.surface_rect_functions_applied_); swap(pending_visibility_settings_, other.pending_visibility_settings_); swap(cached_buffer_map_, other.cached_buffer_map_); + swap(ignore_bad_display_errors_on_destroy_, + other.ignore_bad_display_errors_on_destroy_); } return *this; } @@ -1151,17 +1330,16 @@ void Layer::UpdateVisibilitySettings() { pending_visibility_settings_ = false; HWC::Error error; - hwc2_display_t display = HWC_DISPLAY_PRIMARY; error = composer_->setLayerBlendMode( - display, hardware_composer_layer_, + display_params_.id, hardware_composer_layer_, blending_.cast<Hwc2::IComposerClient::BlendMode>()); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting layer blend mode: %s", error.to_string().c_str()); - error = - composer_->setLayerZOrder(display, hardware_composer_layer_, z_order_); + error = composer_->setLayerZOrder(display_params_.id, + hardware_composer_layer_, z_order_); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting z_ order: %s", error.to_string().c_str()); @@ -1170,36 +1348,35 @@ void Layer::UpdateVisibilitySettings() { void Layer::UpdateLayerSettings() { HWC::Error error; - hwc2_display_t display = HWC_DISPLAY_PRIMARY; UpdateVisibilitySettings(); // TODO(eieio): Use surface attributes or some other mechanism to control // the layer display frame. error = composer_->setLayerDisplayFrame( - display, hardware_composer_layer_, - {0, 0, display_metrics_.width, display_metrics_.height}); + display_params_.id, hardware_composer_layer_, + {0, 0, display_params_.width, display_params_.height}); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting layer display frame: %s", error.to_string().c_str()); error = composer_->setLayerVisibleRegion( - display, hardware_composer_layer_, - {{0, 0, display_metrics_.width, display_metrics_.height}}); + display_params_.id, hardware_composer_layer_, + {{0, 0, display_params_.width, display_params_.height}}); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting layer visible region: %s", error.to_string().c_str()); - error = - composer_->setLayerPlaneAlpha(display, hardware_composer_layer_, 1.0f); + error = composer_->setLayerPlaneAlpha(display_params_.id, + hardware_composer_layer_, 1.0f); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting layer plane alpha: %s", error.to_string().c_str()); } void Layer::CommonLayerSetup() { - HWC::Error error = - composer_->createLayer(HWC_DISPLAY_PRIMARY, &hardware_composer_layer_); + HWC::Error error = composer_->createLayer(display_params_.id, + &hardware_composer_layer_); ALOGE_IF(error != HWC::Error::None, "Layer::CommonLayerSetup: Failed to create layer on primary " "display: %s", @@ -1243,10 +1420,10 @@ void Layer::Prepare() { if (composition_type_ == HWC::Composition::Invalid) { composition_type_ = HWC::Composition::SolidColor; composer_->setLayerCompositionType( - HWC_DISPLAY_PRIMARY, hardware_composer_layer_, + display_params_.id, hardware_composer_layer_, composition_type_.cast<Hwc2::IComposerClient::Composition>()); Hwc2::IComposerClient::Color layer_color = {0, 0, 0, 0}; - composer_->setLayerColor(HWC_DISPLAY_PRIMARY, hardware_composer_layer_, + composer_->setLayerColor(display_params_.id, hardware_composer_layer_, layer_color); } else { // The composition type is already set. Nothing else to do until a @@ -1256,7 +1433,7 @@ void Layer::Prepare() { if (composition_type_ != target_composition_type_) { composition_type_ = target_composition_type_; composer_->setLayerCompositionType( - HWC_DISPLAY_PRIMARY, hardware_composer_layer_, + display_params_.id, hardware_composer_layer_, composition_type_.cast<Hwc2::IComposerClient::Composition>()); } @@ -1267,7 +1444,7 @@ void Layer::Prepare() { HWC::Error error{HWC::Error::None}; error = - composer_->setLayerBuffer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_, + composer_->setLayerBuffer(display_params_.id, hardware_composer_layer_, slot, handle, acquire_fence_.Get()); ALOGE_IF(error != HWC::Error::None, @@ -1277,7 +1454,7 @@ void Layer::Prepare() { if (!surface_rect_functions_applied_) { const float float_right = right; const float float_bottom = bottom; - error = composer_->setLayerSourceCrop(HWC_DISPLAY_PRIMARY, + error = composer_->setLayerSourceCrop(display_params_.id, hardware_composer_layer_, {0, 0, float_right, float_bottom}); diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h index 7010db9630..1d8d46354d 100644 --- a/libs/vr/libvrflinger/hardware_composer.h +++ b/libs/vr/libvrflinger/hardware_composer.h @@ -13,6 +13,7 @@ #include <condition_variable> #include <memory> #include <mutex> +#include <optional> #include <thread> #include <tuple> #include <vector> @@ -35,16 +36,19 @@ namespace android { namespace dvr { -// Basic display metrics for physical displays. Dimensions and densities are -// relative to the physical display orientation, which may be different from the -// logical display orientation exposed to applications. -struct HWCDisplayMetrics { +// Basic display metrics for physical displays. +struct DisplayParams { + hwc2_display_t id; + bool is_primary; + int width; int height; + struct { int x; int y; } dpi; + int vsync_period_ns; }; @@ -58,26 +62,29 @@ class Layer { // automatically handles ACQUIRE/RELEASE phases for the surface's buffer train // every frame. // + // |composer| The composer instance. + // |display_params| Info about the display to use. // |blending| receives HWC_BLENDING_* values. - // |transform| receives HWC_TRANSFORM_* values. // |composition_type| receives either HWC_FRAMEBUFFER for most layers or // HWC_FRAMEBUFFER_TARGET (unless you know what you are doing). // |index| is the index of this surface in the DirectDisplaySurface array. - Layer(const std::shared_ptr<DirectDisplaySurface>& surface, - HWC::BlendMode blending, HWC::Transform transform, - HWC::Composition composition_type, size_t z_roder); + Layer(Hwc2::Composer* composer, const DisplayParams& display_params, + const std::shared_ptr<DirectDisplaySurface>& surface, + HWC::BlendMode blending, HWC::Composition composition_type, + size_t z_order); // Sets up the layer to use a direct buffer as its content source. No special // handling of the buffer is performed; responsibility for updating or // changing the buffer each frame is on the caller. // + // |composer| The composer instance. + // |display_params| Info about the display to use. // |blending| receives HWC_BLENDING_* values. - // |transform| receives HWC_TRANSFORM_* values. // |composition_type| receives either HWC_FRAMEBUFFER for most layers or // HWC_FRAMEBUFFER_TARGET (unless you know what you are doing). - Layer(const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending, - HWC::Transform transform, HWC::Composition composition_type, - size_t z_order); + Layer(Hwc2::Composer* composer, const DisplayParams& display_params, + const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending, + HWC::Composition composition_type, size_t z_order); Layer(Layer&&); Layer& operator=(Layer&&); @@ -144,12 +151,8 @@ class Layer { } bool operator<(int surface_id) const { return GetSurfaceId() < surface_id; } - // Sets the composer instance used by all Layer instances. - static void SetComposer(Hwc2::Composer* composer) { composer_ = composer; } - - // Sets the display metrics used by all Layer instances. - static void SetDisplayMetrics(HWCDisplayMetrics display_metrics) { - display_metrics_ = display_metrics; + void IgnoreBadDisplayErrorsOnDestroy(bool ignore) { + ignore_bad_display_errors_on_destroy_ = ignore; } private: @@ -169,16 +172,11 @@ class Layer { // associated and always returns false. bool CheckAndUpdateCachedBuffer(std::size_t slot, int buffer_id); - // Composer instance shared by all instances of Layer. This must be set - // whenever a new instance of the Composer is created. This may be set to - // nullptr as long as there are no instances of Layer that might need to use - // it. - static Hwc2::Composer* composer_; + // Composer instance. + Hwc2::Composer* composer_ = nullptr; - // Display metrics shared by all instances of Layer. This must be set at least - // once during VrFlinger initialization and is expected to remain constant - // thereafter. - static HWCDisplayMetrics display_metrics_; + // Parameters of the display to use for this layer. + DisplayParams display_params_; // The hardware composer layer and metrics to use during the prepare cycle. hwc2_layer_t hardware_composer_layer_ = 0; @@ -187,7 +185,6 @@ class Layer { // Prepare phase. size_t z_order_ = 0; HWC::BlendMode blending_ = HWC::BlendMode::None; - HWC::Transform transform_ = HWC::Transform::None; HWC::Composition composition_type_ = HWC::Composition::Invalid; HWC::Composition target_composition_type_ = HWC::Composition::Device; @@ -283,6 +280,12 @@ class Layer { // importing a buffer HWC already knows about. std::map<std::size_t, int> cached_buffer_map_; + // When calling destroyLayer() on an external display that's been removed we + // typically get HWC2_ERROR_BAD_DISPLAY errors. If + // ignore_bad_display_errors_on_destroy_ is true, don't log the bad display + // errors, since they're expected. + bool ignore_bad_display_errors_on_destroy_ = false; + Layer(const Layer&) = delete; void operator=(const Layer&) = delete; }; @@ -298,13 +301,14 @@ class Layer { class HardwareComposer { public: // Type for vsync callback. - using VSyncCallback = std::function<void(int, int64_t, int64_t, uint32_t)>; + using VSyncCallback = std::function<void(int64_t, int64_t, uint32_t)>; using RequestDisplayCallback = std::function<void(bool)>; HardwareComposer(); ~HardwareComposer(); bool Initialize(Hwc2::Composer* composer, + hwc2_display_t primary_display_id, RequestDisplayCallback request_display_callback); bool IsInitialized() const { return initialized_; } @@ -316,22 +320,15 @@ class HardwareComposer { // it's paused. This should only be called from surface flinger's main thread. void Disable(); - // Get the HMD display metrics for the current display. - display::Metrics GetHmdDisplayMetrics() const; + // Called on a binder thread. + void OnBootFinished(); std::string Dump(); void SetVSyncCallback(VSyncCallback callback); - // Metrics of the logical display, which is always landscape. - int DisplayWidth() const { return display_metrics_.width; } - int DisplayHeight() const { return display_metrics_.height; } - HWCDisplayMetrics display_metrics() const { return display_metrics_; } - - // Metrics of the native display, which depends on the specific hardware - // implementation of the display. - HWCDisplayMetrics native_display_metrics() const { - return native_display_metrics_; + const DisplayParams& GetPrimaryDisplayParams() const { + return primary_display_; } // Sets the display surfaces to compose the hardware layer stack. @@ -342,16 +339,16 @@ class HardwareComposer { void OnDeletedGlobalBuffer(DvrGlobalBufferKey key); private: - HWC::Error GetDisplayAttribute(Hwc2::Composer* composer, - hwc2_display_t display, hwc2_config_t config, - hwc2_attribute_t attributes, - int32_t* out_value) const; - HWC::Error GetDisplayMetrics(Hwc2::Composer* composer, hwc2_display_t display, - hwc2_config_t config, - HWCDisplayMetrics* out_metrics) const; + DisplayParams GetDisplayParams(Hwc2::Composer* composer, + hwc2_display_t display, bool is_primary); - HWC::Error EnableVsync(bool enabled); - HWC::Error SetPowerMode(bool active); + // Turn display vsync on/off. Returns true on success, false on failure. + bool EnableVsync(const DisplayParams& display, bool enabled); + // Turn display power on/off. Returns true on success, false on failure. + bool SetPowerMode(const DisplayParams& display, bool active); + // Convenience function to turn a display on/off. Turns both power and vsync + // on/off. Returns true on success, false on failure. + bool EnableDisplay(const DisplayParams& display, bool enabled); class ComposerCallback : public Hwc2::IComposerCallback { public: @@ -362,24 +359,38 @@ class HardwareComposer { hardware::Return<void> onVsync(Hwc2::Display display, int64_t timestamp) override; - pdx::Status<int64_t> GetVsyncTime(Hwc2::Display display); + bool GotFirstHotplug() { return got_first_hotplug_; } - private: - std::mutex vsync_mutex_; + struct Displays { + hwc2_display_t primary_display = 0; + std::optional<hwc2_display_t> external_display; + bool external_display_was_hotplugged = false; + }; - struct Display { + Displays GetDisplays(); + pdx::Status<int64_t> GetVsyncTime(hwc2_display_t display); + + private: + struct DisplayInfo { + hwc2_display_t id = 0; pdx::LocalHandle driver_vsync_event_fd; int64_t callback_vsync_timestamp{0}; }; - std::array<Display, HWC_NUM_PHYSICAL_DISPLAY_TYPES> displays_; + + DisplayInfo* GetDisplayInfo(hwc2_display_t display); + + std::mutex mutex_; + + bool got_first_hotplug_ = false; + DisplayInfo primary_display_; + std::optional<DisplayInfo> external_display_; + bool external_display_was_hotplugged_ = false; }; HWC::Error Validate(hwc2_display_t display); HWC::Error Present(hwc2_display_t display); - void SetBacklightBrightness(int brightness); - - void PostLayers(); + void PostLayers(hwc2_display_t display); void PostThread(); // The post thread has two controlling states: @@ -407,23 +418,40 @@ class HardwareComposer { int PostThreadPollInterruptible(const pdx::LocalHandle& event_fd, int requested_events, int timeout_ms); - // WaitForVSync and SleepUntil are blocking calls made on the post thread that - // can be interrupted by a control thread. If interrupted, these calls return - // kPostThreadInterrupted. + // WaitForPredictedVSync and SleepUntil are blocking calls made on the post + // thread that can be interrupted by a control thread. If interrupted, these + // calls return kPostThreadInterrupted. int ReadWaitPPState(); - pdx::Status<int64_t> WaitForVSync(); - pdx::Status<int64_t> GetVSyncTime(); + pdx::Status<int64_t> WaitForPredictedVSync(); int SleepUntil(int64_t wakeup_timestamp); + // Initialize any newly connected displays, and set target_display_ to the + // display we should render to. Returns true if target_display_ + // changed. Called only from the post thread. + bool UpdateTargetDisplay(); + // Reconfigures the layer stack if the display surfaces changed since the last // frame. Called only from the post thread. - bool UpdateLayerConfig(); + void UpdateLayerConfig(); + + // Called on the post thread to create the Composer instance. + void CreateComposer(); // Called on the post thread when the post thread is resumed. void OnPostThreadResumed(); // Called on the post thread when the post thread is paused or quits. void OnPostThreadPaused(); + // Use post_thread_wait_ to wait for a specific condition, specified by pred. + // timeout_sec < 0 means wait indefinitely, otherwise it specifies the timeout + // in seconds. + // The lock must be held when this function is called. + // Returns true if the wait was interrupted because the post thread was asked + // to quit. + bool PostThreadCondWait(std::unique_lock<std::mutex>& lock, + int timeout_sec, + const std::function<bool()>& pred); + // Map the given shared memory buffer to our broadcast ring to track updates // to the config parameters. int MapConfigBuffer(IonBuffer& ion_buffer); @@ -438,18 +466,19 @@ class HardwareComposer { sp<ComposerCallback> composer_callback_; RequestDisplayCallback request_display_callback_; - // Display metrics of the physical display. - HWCDisplayMetrics native_display_metrics_; - // Display metrics of the logical display, adjusted so that orientation is - // landscape. - HWCDisplayMetrics display_metrics_; - // Transform required to get from native to logical display orientation. - HWC::Transform display_transform_ = HWC::Transform::None; + DisplayParams primary_display_; + std::optional<DisplayParams> external_display_; + DisplayParams* target_display_ = &primary_display_; + + // The list of surfaces we should draw. Set by the display service when + // DirectSurfaces are added, removed, or change visibility. Written by the + // message dispatch thread and read by the post thread. + std::vector<std::shared_ptr<DirectDisplaySurface>> surfaces_; + // Set to true by the dispatch thread whenever surfaces_ changes. Set to false + // by the post thread when the new list of surfaces is processed. + bool surfaces_changed_ = false; - // Pending surface list. Set by the display service when DirectSurfaces are - // added, removed, or change visibility. Written by the message dispatch - // thread and read by the post thread. - std::vector<std::shared_ptr<DirectDisplaySurface>> pending_surfaces_; + std::vector<std::shared_ptr<DirectDisplaySurface>> current_surfaces_; // Layer set for handling buffer flow into hardware composer layers. This // vector must be sorted by surface_id in ascending order. @@ -472,8 +501,9 @@ class HardwareComposer { std::condition_variable post_thread_wait_; std::condition_variable post_thread_ready_; - // Backlight LED brightness sysfs node. - pdx::LocalHandle backlight_brightness_fd_; + // When boot is finished this will be set to true and the post thread will be + // notified via post_thread_wait_. + bool boot_finished_ = false; // VSync sleep timerfd. pdx::LocalHandle vsync_sleep_timer_fd_; diff --git a/libs/vr/libvrflinger/include/dvr/vr_flinger.h b/libs/vr/libvrflinger/include/dvr/vr_flinger.h index 33cbc84d7d..c740dde3d6 100644 --- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h +++ b/libs/vr/libvrflinger/include/dvr/vr_flinger.h @@ -4,6 +4,12 @@ #include <thread> #include <memory> +#define HWC2_INCLUDE_STRINGIFICATION +#define HWC2_USE_CPP11 +#include <hardware/hwcomposer2.h> +#undef HWC2_INCLUDE_STRINGIFICATION +#undef HWC2_USE_CPP11 + #include <pdx/service_dispatcher.h> #include <vr/vr_manager/vr_manager.h> @@ -21,7 +27,9 @@ class VrFlinger { public: using RequestDisplayCallback = std::function<void(bool)>; static std::unique_ptr<VrFlinger> Create( - Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback); + Hwc2::Composer* hidl, + hwc2_display_t primary_display_id, + RequestDisplayCallback request_display_callback); ~VrFlinger(); // These functions are all called on surface flinger's main thread. @@ -35,6 +43,7 @@ class VrFlinger { private: VrFlinger(); bool Init(Hwc2::Composer* hidl, + hwc2_display_t primary_display_id, RequestDisplayCallback request_display_callback); // Needs to be a separate class for binder's ref counting diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp index 85dc586eae..26aed4f25f 100644 --- a/libs/vr/libvrflinger/vr_flinger.cpp +++ b/libs/vr/libvrflinger/vr_flinger.cpp @@ -29,9 +29,10 @@ namespace android { namespace dvr { std::unique_ptr<VrFlinger> VrFlinger::Create( - Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback) { + Hwc2::Composer* hidl, hwc2_display_t primary_display_id, + RequestDisplayCallback request_display_callback) { std::unique_ptr<VrFlinger> vr_flinger(new VrFlinger); - if (vr_flinger->Init(hidl, request_display_callback)) + if (vr_flinger->Init(hidl, primary_display_id, request_display_callback)) return vr_flinger; else return nullptr; @@ -56,6 +57,7 @@ VrFlinger::~VrFlinger() { } bool VrFlinger::Init(Hwc2::Composer* hidl, + hwc2_display_t primary_display_id, RequestDisplayCallback request_display_callback) { if (!hidl || !request_display_callback) return false; @@ -74,8 +76,8 @@ bool VrFlinger::Init(Hwc2::Composer* hidl, dispatcher_ = android::pdx::ServiceDispatcher::Create(); CHECK_ERROR(!dispatcher_, error, "Failed to create service dispatcher."); - display_service_ = - android::dvr::DisplayService::Create(hidl, request_display_callback); + display_service_ = android::dvr::DisplayService::Create( + hidl, primary_display_id, request_display_callback); CHECK_ERROR(!display_service_, error, "Failed to create display service."); dispatcher_->AddService(display_service_); @@ -91,7 +93,7 @@ bool VrFlinger::Init(Hwc2::Composer* hidl, std::bind(&android::dvr::VSyncService::VSyncEvent, std::static_pointer_cast<android::dvr::VSyncService>(service), std::placeholders::_1, std::placeholders::_2, - std::placeholders::_3, std::placeholders::_4)); + std::placeholders::_3)); dispatcher_thread_ = std::thread([this]() { prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("VrDispatch"), 0, 0, 0); @@ -113,6 +115,7 @@ error: } void VrFlinger::OnBootFinished() { + display_service_->OnBootFinished(); sp<IVrManager> vr_manager = interface_cast<IVrManager>( defaultServiceManager()->checkService(String16("vrmanager"))); if (vr_manager.get()) { diff --git a/libs/vr/libvrflinger/vsync_service.cpp b/libs/vr/libvrflinger/vsync_service.cpp index fdeb899f66..b8d8b08b5f 100644 --- a/libs/vr/libvrflinger/vsync_service.cpp +++ b/libs/vr/libvrflinger/vsync_service.cpp @@ -32,21 +32,19 @@ VSyncService::VSyncService() VSyncService::~VSyncService() {} -void VSyncService::VSyncEvent(int display, int64_t timestamp_ns, +void VSyncService::VSyncEvent(int64_t timestamp_ns, int64_t compositor_time_ns, uint32_t vsync_count) { ATRACE_NAME("VSyncService::VSyncEvent"); std::lock_guard<std::mutex> autolock(mutex_); - if (display == HWC_DISPLAY_PRIMARY) { - last_vsync_ = current_vsync_; - current_vsync_ = timestamp_ns; - compositor_time_ns_ = compositor_time_ns; - current_vsync_count_ = vsync_count; + last_vsync_ = current_vsync_; + current_vsync_ = timestamp_ns; + compositor_time_ns_ = compositor_time_ns; + current_vsync_count_ = vsync_count; - NotifyWaiters(); - UpdateClients(); - } + NotifyWaiters(); + UpdateClients(); } std::shared_ptr<Channel> VSyncService::OnChannelOpen(pdx::Message& message) { diff --git a/libs/vr/libvrflinger/vsync_service.h b/libs/vr/libvrflinger/vsync_service.h index 215948eb05..822f02b266 100644 --- a/libs/vr/libvrflinger/vsync_service.h +++ b/libs/vr/libvrflinger/vsync_service.h @@ -63,9 +63,10 @@ class VSyncService : public pdx::ServiceBase<VSyncService> { const std::shared_ptr<pdx::Channel>& channel) override; // Called by the hardware composer HAL, or similar, whenever a vsync event - // occurs. |compositor_time_ns| is the number of ns before the next vsync when - // the compositor will preempt the GPU to do EDS and lens warp. - void VSyncEvent(int display, int64_t timestamp_ns, int64_t compositor_time_ns, + // occurs on the primary display. |compositor_time_ns| is the number of ns + // before the next vsync when the compositor will preempt the GPU to do EDS + // and lens warp. + void VSyncEvent(int64_t timestamp_ns, int64_t compositor_time_ns, uint32_t vsync_count); private: diff --git a/libs/vr/libvrsensor/Android.bp b/libs/vr/libvrsensor/Android.bp index e92178a43e..85427906f1 100644 --- a/libs/vr/libvrsensor/Android.bp +++ b/libs/vr/libvrsensor/Android.bp @@ -14,7 +14,6 @@ sourceFiles = [ "pose_client.cpp", - "sensor_client.cpp", "latency_model.cpp", ] @@ -24,20 +23,20 @@ includeFiles = [ staticLibraries = [ "libdisplay", - "libbufferhub", - "libbufferhubqueue", "libdvrcommon", "libbroadcastring", - "libpdx_default_transport", ] sharedLibraries = [ "libbase", + "libbinder", + "libbufferhubqueue", "libcutils", "libhardware", "liblog", "libutils", "libui", + "libpdx_default_transport", ] cc_library { diff --git a/libs/vr/libvrsensor/include/private/dvr/sensor-ipc.h b/libs/vr/libvrsensor/include/private/dvr/sensor-ipc.h deleted file mode 100644 index b2ebd95060..0000000000 --- a/libs/vr/libvrsensor/include/private/dvr/sensor-ipc.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef ANDROID_DVR_SENSOR_IPC_H_ -#define ANDROID_DVR_SENSOR_IPC_H_ - -#define DVR_SENSOR_SERVICE_BASE "system/vr/sensors" - -#define DVR_SENSOR_SERVICE_CLIENT (DVR_SENSOR_SERVICE_BASE "/client") - -/* - * Endpoint ops - */ -enum { - DVR_SENSOR_START = 0, - DVR_SENSOR_STOP, - DVR_SENSOR_POLL, -}; - -#endif // ANDROID_DVR_SENSOR_IPC_H_ diff --git a/libs/vr/libvrsensor/include/private/dvr/sensor_client.h b/libs/vr/libvrsensor/include/private/dvr/sensor_client.h deleted file mode 100644 index 15a9b8f5d1..0000000000 --- a/libs/vr/libvrsensor/include/private/dvr/sensor_client.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef ANDROID_DVR_SENSOR_CLIENT_H_ -#define ANDROID_DVR_SENSOR_CLIENT_H_ - -#include <hardware/sensors.h> -#include <pdx/client.h> -#include <poll.h> - -namespace android { -namespace dvr { - -// SensorClient is a remote interface to the sensor service in sensord. -class SensorClient : public pdx::ClientBase<SensorClient> { - public: - ~SensorClient(); - - int StartSensor(); - int StopSensor(); - int Poll(sensors_event_t* events, int max_count); - - private: - friend BASE; - - // Set up a channel associated with the sensor of the indicated type. - // NOTE(segal): If our hardware ends up with multiple sensors of the same - // type, we'll have to change this. - explicit SensorClient(int sensor_type); - - int sensor_type_; - - SensorClient(const SensorClient&); - SensorClient& operator=(const SensorClient&); -}; - -} // namespace dvr -} // namespace android - -#endif // ANDROID_DVR_SENSOR_CLIENT_H_ diff --git a/libs/vr/libvrsensor/sensor_client.cpp b/libs/vr/libvrsensor/sensor_client.cpp deleted file mode 100644 index 04e88cc9a1..0000000000 --- a/libs/vr/libvrsensor/sensor_client.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#define LOG_TAG "SensorClient" -#include <private/dvr/sensor_client.h> - -#include <log/log.h> -#include <poll.h> - -#include <pdx/default_transport/client_channel_factory.h> -#include <private/dvr/sensor-ipc.h> - -using android::pdx::Transaction; - -namespace android { -namespace dvr { - -SensorClient::SensorClient(int sensor_type) - : BASE(pdx::default_transport::ClientChannelFactory::Create( - DVR_SENSOR_SERVICE_CLIENT)), - sensor_type_(sensor_type) {} - -SensorClient::~SensorClient() {} - -int SensorClient::StartSensor() { - Transaction trans{*this}; - auto status = trans.Send<int>(DVR_SENSOR_START, &sensor_type_, - sizeof(sensor_type_), nullptr, 0); - ALOGE_IF(!status, "startSensor() failed because: %s\n", - status.GetErrorMessage().c_str()); - return ReturnStatusOrError(status); -} - -int SensorClient::StopSensor() { - Transaction trans{*this}; - auto status = trans.Send<int>(DVR_SENSOR_STOP); - ALOGE_IF(!status, "stopSensor() failed because: %s\n", - status.GetErrorMessage().c_str()); - return ReturnStatusOrError(status); -} - -int SensorClient::Poll(sensors_event_t* events, int max_events) { - int num_events = 0; - struct iovec rvec[] = { - {.iov_base = &num_events, .iov_len = sizeof(int)}, - {.iov_base = events, .iov_len = max_events * sizeof(sensors_event_t)}, - }; - Transaction trans{*this}; - auto status = trans.SendVector<int>(DVR_SENSOR_POLL, nullptr, rvec); - ALOGE_IF(!status, "Sensor poll() failed because: %s\n", - status.GetErrorMessage().c_str()); - return !status ? -status.error() : num_events; -} - -} // namespace dvr -} // namespace android - -// Entrypoints to simplify using the library when programmatically dynamicly -// loading it. -// Allows us to call this library without linking it, as, for instance, -// when compiling GVR in Google3. -// NOTE(segal): It's kind of a hack. - -extern "C" uint64_t dvrStartSensor(int type) { - android::dvr::SensorClient* service = - android::dvr::SensorClient::Create(type).release(); - service->StartSensor(); - return (uint64_t)service; -} - -extern "C" void dvrStopSensor(uint64_t service) { - android::dvr::SensorClient* iss = - reinterpret_cast<android::dvr::SensorClient*>(service); - iss->StopSensor(); - delete iss; -} - -extern "C" int dvrPollSensor(uint64_t service, int max_count, - sensors_event_t* events) { - return reinterpret_cast<android::dvr::SensorClient*>(service)->Poll( - events, max_count); -} |