diff options
Diffstat (limited to 'libs')
86 files changed, 4505 insertions, 1587 deletions
diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk index 79decfe21f..d5860ef6ca 100644 --- a/libs/binder/Android.mk +++ b/libs/binder/Android.mk @@ -26,6 +26,8 @@ sources := \ IMemory.cpp \ IPCThreadState.cpp \ IPermissionController.cpp \ + IProcessInfoService.cpp \ + ProcessInfoService.cpp \ IServiceManager.cpp \ MemoryDealer.cpp \ MemoryBase.cpp \ diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp index 61b4f7d661..e4d82019f1 100644 --- a/libs/binder/AppOpsManager.cpp +++ b/libs/binder/AppOpsManager.cpp @@ -44,7 +44,7 @@ sp<IAppOpsService> AppOpsManager::getService() int64_t startTime = 0; mLock.lock(); sp<IAppOpsService> service = mService; - while (service == NULL || !service->asBinder()->isBinderAlive()) { + while (service == NULL || !IInterface::asBinder(service)->isBinderAlive()) { sp<IBinder> binder = defaultServiceManager()->checkService(_appops); if (binder == NULL) { // Wait for the app ops service to come back... @@ -104,4 +104,13 @@ void AppOpsManager::stopWatchingMode(const sp<IAppOpsCallback>& callback) { } } +int32_t AppOpsManager::permissionToOpCode(const String16& permission) { + sp<IAppOpsService> service = getService(); + if (service != NULL) { + return service->permissionToOpCode(permission); + } + return -1; +} + + }; // namespace android diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp index 2554351cc6..9d200fb219 100644 --- a/libs/binder/Binder.cpp +++ b/libs/binder/Binder.cpp @@ -72,7 +72,7 @@ public: BBinder::BBinder() { - atomic_init(&mExtras, 0); + atomic_init(&mExtras, static_cast<uintptr_t>(0)); } bool BBinder::isBinderAlive() const @@ -160,10 +160,18 @@ void BBinder::attachObject( e->mObjects.attach(objectID, object, cleanupCookie, func); } +// The C11 standard doesn't allow atomic loads from const fields, +// though C++11 does. Fudge it until standards get straightened out. +static inline uintptr_t load_const_atomic(const atomic_uintptr_t* p, + memory_order mo) { + atomic_uintptr_t* non_const_p = const_cast<atomic_uintptr_t*>(p); + return atomic_load_explicit(non_const_p, mo); +} + void* BBinder::findObject(const void* objectID) const { Extras* e = reinterpret_cast<Extras*>( - atomic_load_explicit(&mExtras, memory_order_acquire)); + load_const_atomic(&mExtras, memory_order_acquire)); if (!e) return NULL; AutoMutex _l(e->mLock); diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index 101de7efd6..345ba20f1b 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -220,7 +220,6 @@ status_t BpBinder::unlinkToDeath( if ((obit.recipient == recipient || (recipient == NULL && obit.cookie == cookie)) && obit.flags == flags) { - const uint32_t allFlags = obit.flags|flags; if (outRecipient != NULL) { *outRecipient = mObituaries->itemAt(i).recipient; } diff --git a/libs/binder/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp index 2d493c1511..1339a67e62 100644 --- a/libs/binder/BufferedTextOutput.cpp +++ b/libs/binder/BufferedTextOutput.cpp @@ -49,9 +49,12 @@ struct BufferedTextOutput::BufferState : public RefBase status_t append(const char* txt, size_t len) { if ((len+bufferPos) > bufferSize) { - void* b = realloc(buffer, ((len+bufferPos)*3)/2); + size_t newSize = ((len+bufferPos)*3)/2; + if (newSize < (len+bufferPos)) return NO_MEMORY; // overflow + void* b = realloc(buffer, newSize); if (!b) return NO_MEMORY; buffer = (char*)b; + bufferSize = newSize; } memcpy(buffer+bufferPos, txt, len); bufferPos += len; diff --git a/libs/binder/Debug.cpp b/libs/binder/Debug.cpp index 0ffafbbeb4..bdb7182cc0 100644 --- a/libs/binder/Debug.cpp +++ b/libs/binder/Debug.cpp @@ -220,13 +220,8 @@ void printHexData(int32_t indent, const void *buf, size_t length, for (word = 0; word < bytesPerLine; ) { -#ifdef HAVE_LITTLE_ENDIAN const size_t startIndex = word+(alignment-(alignment?1:0)); const ssize_t dir = -1; -#else - const size_t startIndex = word; - const ssize_t dir = 1; -#endif for (index = 0; index < alignment || (alignment == 0 && index < bytesPerLine); index++) { diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp index f58a352d07..9558376dbf 100644 --- a/libs/binder/IAppOpsService.cpp +++ b/libs/binder/IAppOpsService.cpp @@ -91,14 +91,14 @@ public: data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); data.writeInt32(op); data.writeString16(packageName); - data.writeStrongBinder(callback->asBinder()); + data.writeStrongBinder(IInterface::asBinder(callback)); remote()->transact(START_WATCHING_MODE_TRANSACTION, data, &reply); } virtual void stopWatchingMode(const sp<IAppOpsCallback>& callback) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); - data.writeStrongBinder(callback->asBinder()); + data.writeStrongBinder(IInterface::asBinder(callback)); remote()->transact(STOP_WATCHING_MODE_TRANSACTION, data, &reply); } @@ -111,6 +111,17 @@ public: if (reply.readExceptionCode() != 0) return NULL; return reply.readStrongBinder(); } + + + virtual int32_t permissionToOpCode(const String16& permission) { + Parcel data, reply; + data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); + data.writeString16(permission); + remote()->transact(PERMISSION_TO_OP_CODE_TRANSACTION, data, &reply); + // fail on exception + if (reply.readExceptionCode() != 0) return -1; + return reply.readInt32(); + } }; IMPLEMENT_META_INTERFACE(AppOpsService, "com.android.internal.app.IAppOpsService"); @@ -187,6 +198,14 @@ status_t BnAppOpsService::onTransact( reply->writeStrongBinder(token); return NO_ERROR; } break; + case PERMISSION_TO_OP_CODE_TRANSACTION: { + CHECK_INTERFACE(IAppOpsService, data, reply); + String16 permission = data.readString16(); + const int32_t opCode = permissionToOpCode(permission); + reply->writeNoException(); + reply->writeInt32(opCode); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/binder/IBatteryStats.cpp b/libs/binder/IBatteryStats.cpp index 8f3b7b49ad..e32c628679 100644 --- a/libs/binder/IBatteryStats.cpp +++ b/libs/binder/IBatteryStats.cpp @@ -89,6 +89,47 @@ public: data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); remote()->transact(NOTE_RESET_AUDIO_TRANSACTION, data, &reply); } + + virtual void noteFlashlightOn(int uid) { + Parcel data, reply; + data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); + data.writeInt32(uid); + remote()->transact(NOTE_FLASHLIGHT_ON_TRANSACTION, data, &reply); + } + + virtual void noteFlashlightOff(int uid) { + Parcel data, reply; + data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); + data.writeInt32(uid); + remote()->transact(NOTE_FLASHLIGHT_OFF_TRANSACTION, data, &reply); + } + + virtual void noteStartCamera(int uid) { + Parcel data, reply; + data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); + data.writeInt32(uid); + remote()->transact(NOTE_START_CAMERA_TRANSACTION, data, &reply); + } + + virtual void noteStopCamera(int uid) { + Parcel data, reply; + data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); + data.writeInt32(uid); + remote()->transact(NOTE_STOP_CAMERA_TRANSACTION, data, &reply); + } + + virtual void noteResetCamera() { + Parcel data, reply; + data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); + remote()->transact(NOTE_RESET_CAMERA_TRANSACTION, data, &reply); + } + + virtual void noteResetFlashlight() { + Parcel data, reply; + data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); + remote()->transact(NOTE_RESET_FLASHLIGHT_TRANSACTION, data, &reply); + } + }; IMPLEMENT_META_INTERFACE(BatteryStats, "com.android.internal.app.IBatteryStats"); @@ -155,6 +196,46 @@ status_t BnBatteryStats::onTransact( reply->writeNoException(); return NO_ERROR; } break; + case NOTE_FLASHLIGHT_ON_TRANSACTION: { + CHECK_INTERFACE(IBatteryStats, data, reply); + int uid = data.readInt32(); + noteFlashlightOn(uid); + reply->writeNoException(); + return NO_ERROR; + } break; + case NOTE_FLASHLIGHT_OFF_TRANSACTION: { + CHECK_INTERFACE(IBatteryStats, data, reply); + int uid = data.readInt32(); + noteFlashlightOff(uid); + reply->writeNoException(); + return NO_ERROR; + } break; + case NOTE_START_CAMERA_TRANSACTION: { + CHECK_INTERFACE(IBatteryStats, data, reply); + int uid = data.readInt32(); + noteStartCamera(uid); + reply->writeNoException(); + return NO_ERROR; + } break; + case NOTE_STOP_CAMERA_TRANSACTION: { + CHECK_INTERFACE(IBatteryStats, data, reply); + int uid = data.readInt32(); + noteStopCamera(uid); + reply->writeNoException(); + return NO_ERROR; + } break; + case NOTE_RESET_CAMERA_TRANSACTION: { + CHECK_INTERFACE(IBatteryStats, data, reply); + noteResetCamera(); + reply->writeNoException(); + return NO_ERROR; + } break; + case NOTE_RESET_FLASHLIGHT_TRANSACTION: { + CHECK_INTERFACE(IBatteryStats, data, reply); + noteResetFlashlight(); + reply->writeNoException(); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/binder/IInterface.cpp b/libs/binder/IInterface.cpp index 29acf5ddd1..2fcd3d92fb 100644 --- a/libs/binder/IInterface.cpp +++ b/libs/binder/IInterface.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#define LOG_TAG "IInterface" +#include <utils/Log.h> #include <binder/IInterface.h> namespace android { @@ -27,16 +29,39 @@ IInterface::IInterface() IInterface::~IInterface() { } -sp<IBinder> IInterface::asBinder() +// static +sp<IBinder> IInterface::asBinder(const IInterface* iface) { - return this ? onAsBinder() : NULL; + if (iface == NULL) return NULL; + return const_cast<IInterface*>(iface)->onAsBinder(); } -sp<const IBinder> IInterface::asBinder() const +// static +sp<IBinder> IInterface::asBinder(const sp<IInterface>& iface) { - return this ? const_cast<IInterface*>(this)->onAsBinder() : NULL; + if (iface == NULL) return NULL; + return iface->onAsBinder(); } + // --------------------------------------------------------------------------- }; // namespace android + +extern "C" { + +void _ZN7android10IInterface8asBinderEv(void *retval, void* self) { + ALOGW("deprecated asBinder call, please update your code"); + //ALOGI("self: %p, retval: %p", self, retval); + android::sp<android::IBinder> *ret = new(retval) android::sp<android::IBinder>; + *ret = android::IInterface::asBinder((android::IInterface*)self); +} + +void _ZNK7android10IInterface8asBinderEv(void *retval, void *self) { + ALOGW("deprecated asBinder call, please update your code"); + //ALOGI("self: %p, retval: %p", self, retval); + android::sp<android::IBinder> *ret = new(retval) android::sp<android::IBinder>; + *ret = android::IInterface::asBinder((android::IInterface*)self); +} + +} // extern "C" diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp index b9a8bced37..fb8d620b4c 100644 --- a/libs/binder/IMemory.cpp +++ b/libs/binder/IMemory.cpp @@ -228,7 +228,7 @@ status_t BnMemory::onTransact( CHECK_INTERFACE(IMemory, data, reply); ssize_t offset; size_t size; - reply->writeStrongBinder( getMemory(&offset, &size)->asBinder() ); + reply->writeStrongBinder( IInterface::asBinder(getMemory(&offset, &size)) ); reply->writeInt32(offset); reply->writeInt32(size); return NO_ERROR; @@ -253,7 +253,7 @@ BpMemoryHeap::~BpMemoryHeap() { if (mRealHeap) { // by construction we're the last one if (mBase != MAP_FAILED) { - sp<IBinder> binder = const_cast<BpMemoryHeap*>(this)->asBinder(); + sp<IBinder> binder = IInterface::asBinder(this); if (VERBOSE) { ALOGD("UNMAPPING binder=%p, heap=%p, size=%zu, fd=%d", @@ -265,7 +265,7 @@ BpMemoryHeap::~BpMemoryHeap() { } } else { // remove from list only if it was mapped before - sp<IBinder> binder = const_cast<BpMemoryHeap*>(this)->asBinder(); + sp<IBinder> binder = IInterface::asBinder(this); free_heap(binder); } } @@ -274,7 +274,7 @@ BpMemoryHeap::~BpMemoryHeap() { void BpMemoryHeap::assertMapped() const { if (mHeapId == -1) { - sp<IBinder> binder(const_cast<BpMemoryHeap*>(this)->asBinder()); + sp<IBinder> binder(IInterface::asBinder(const_cast<BpMemoryHeap*>(this))); sp<BpMemoryHeap> heap(static_cast<BpMemoryHeap*>(find_heap(binder).get())); heap->assertReallyMapped(); if (heap->mBase != MAP_FAILED) { @@ -309,7 +309,8 @@ void BpMemoryHeap::assertReallyMapped() const uint32_t offset = reply.readInt32(); ALOGE_IF(err, "binder=%p transaction failed fd=%d, size=%zd, err=%d (%s)", - asBinder().get(), parcel_fd, size, err, strerror(-err)); + IInterface::asBinder(this).get(), + parcel_fd, size, err, strerror(-err)); int fd = dup( parcel_fd ); ALOGE_IF(fd==-1, "cannot dup fd=%d, size=%zd, err=%d (%s)", @@ -326,7 +327,7 @@ void BpMemoryHeap::assertReallyMapped() const mBase = mmap(0, size, access, MAP_SHARED, fd, offset); if (mBase == MAP_FAILED) { ALOGE("cannot map BpMemoryHeap (binder=%p), size=%zd, fd=%d (%s)", - asBinder().get(), size, fd, strerror(errno)); + IInterface::asBinder(this).get(), size, fd, strerror(errno)); close(fd); } else { mSize = size; diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 2296cd2b83..af18e119ab 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -29,21 +29,14 @@ #include <private/binder/binder_module.h> #include <private/binder/Static.h> -#include <sys/ioctl.h> -#include <signal.h> #include <errno.h> -#include <stdio.h> -#include <unistd.h> - -#ifdef HAVE_PTHREADS #include <pthread.h> #include <sched.h> +#include <signal.h> +#include <stdio.h> +#include <sys/ioctl.h> #include <sys/resource.h> -#endif -#ifdef HAVE_WIN32_THREADS -#include <windows.h> -#endif - +#include <unistd.h> #if LOG_NDEBUG @@ -70,13 +63,11 @@ namespace android { static const char* getReturnString(size_t idx); -static const char* getCommandString(size_t idx); static const void* printReturnCommand(TextOutput& out, const void* _cmd); static const void* printCommand(TextOutput& out, const void* _cmd); -// This will result in a missing symbol failure if the IF_LOG_COMMANDS() -// conditionals don't get stripped... but that is probably what we want. -#if !LOG_NDEBUG +// Static const and functions will be optimized out if not used, +// when LOG_NDEBUG and references in IF_LOG_COMMANDS() are optimized out. static const char *kReturnStrings[] = { "BR_ERROR", "BR_OK", @@ -126,14 +117,6 @@ static const char* getReturnString(size_t idx) return "unknown"; } -static const char* getCommandString(size_t idx) -{ - if (idx < sizeof(kCommandStrings) / sizeof(kCommandStrings[0])) - return kCommandStrings[idx]; - else - return "unknown"; -} - static const void* printBinderTransactionData(TextOutput& out, const void* data) { const binder_transaction_data* btd = @@ -145,7 +128,7 @@ static const void* printBinderTransactionData(TextOutput& out, const void* data) out << "target.ptr=" << btd->target.ptr; } out << " (cookie " << btd->cookie << ")" << endl - << "code=" << TypeCode(btd->code) << ", flags=" << (void*)btd->flags << endl + << "code=" << TypeCode(btd->code) << ", flags=" << (void*)(long)btd->flags << endl << "data=" << btd->data.ptr.buffer << " (" << (void*)btd->data_size << " bytes)" << endl << "offsets=" << btd->data.ptr.offsets << " (" << (void*)btd->offsets_size @@ -157,10 +140,10 @@ static const void* printReturnCommand(TextOutput& out, const void* _cmd) { static const size_t N = sizeof(kReturnStrings)/sizeof(kReturnStrings[0]); const int32_t* cmd = (const int32_t*)_cmd; - int32_t code = *cmd++; + uint32_t code = (uint32_t)*cmd++; size_t cmdIndex = code & 0xff; - if (code == (int32_t) BR_ERROR) { - out << "BR_ERROR: " << (void*)(*cmd++) << endl; + if (code == BR_ERROR) { + out << "BR_ERROR: " << (void*)(long)(*cmd++) << endl; return cmd; } else if (cmdIndex >= N) { out << "Unknown reply: " << code << endl; @@ -187,21 +170,21 @@ static const void* printReturnCommand(TextOutput& out, const void* _cmd) case BR_DECREFS: { const int32_t b = *cmd++; const int32_t c = *cmd++; - out << ": target=" << (void*)b << " (cookie " << (void*)c << ")"; + out << ": target=" << (void*)(long)b << " (cookie " << (void*)(long)c << ")"; } break; case BR_ATTEMPT_ACQUIRE: { const int32_t p = *cmd++; const int32_t b = *cmd++; const int32_t c = *cmd++; - out << ": target=" << (void*)b << " (cookie " << (void*)c + out << ": target=" << (void*)(long)b << " (cookie " << (void*)(long)c << "), pri=" << p; } break; case BR_DEAD_BINDER: case BR_CLEAR_DEATH_NOTIFICATION_DONE: { const int32_t c = *cmd++; - out << ": death cookie " << (void*)c; + out << ": death cookie " << (void*)(long)c; } break; default: @@ -218,7 +201,7 @@ static const void* printCommand(TextOutput& out, const void* _cmd) { static const size_t N = sizeof(kCommandStrings)/sizeof(kCommandStrings[0]); const int32_t* cmd = (const int32_t*)_cmd; - int32_t code = *cmd++; + uint32_t code = (uint32_t)*cmd++; size_t cmdIndex = code & 0xff; if (cmdIndex >= N) { @@ -242,7 +225,7 @@ static const void* printCommand(TextOutput& out, const void* _cmd) case BC_FREE_BUFFER: { const int32_t buf = *cmd++; - out << ": buffer=" << (void*)buf; + out << ": buffer=" << (void*)(long)buf; } break; case BC_INCREFS: @@ -257,7 +240,7 @@ static const void* printCommand(TextOutput& out, const void* _cmd) case BC_ACQUIRE_DONE: { const int32_t b = *cmd++; const int32_t c = *cmd++; - out << ": target=" << (void*)b << " (cookie " << (void*)c << ")"; + out << ": target=" << (void*)(long)b << " (cookie " << (void*)(long)c << ")"; } break; case BC_ATTEMPT_ACQUIRE: { @@ -270,12 +253,12 @@ static const void* printCommand(TextOutput& out, const void* _cmd) case BC_CLEAR_DEATH_NOTIFICATION: { const int32_t h = *cmd++; const int32_t c = *cmd++; - out << ": handle=" << h << " (death cookie " << (void*)c << ")"; + out << ": handle=" << h << " (death cookie " << (void*)(long)c << ")"; } break; case BC_DEAD_BINDER_DONE: { const int32_t c = *cmd++; - out << ": death cookie " << (void*)c; + out << ": death cookie " << (void*)(long)c; } break; default: @@ -287,7 +270,6 @@ static const void* printCommand(TextOutput& out, const void* _cmd) out << endl; return cmd; } -#endif static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER; static bool gHaveTLS = false; @@ -361,12 +343,12 @@ status_t IPCThreadState::clearLastError() return err; } -int IPCThreadState::getCallingPid() const +pid_t IPCThreadState::getCallingPid() const { return mCallingPid; } -int IPCThreadState::getCallingUid() const +uid_t IPCThreadState::getCallingUid() const { return mCallingUid; } @@ -417,6 +399,18 @@ void IPCThreadState::flushCommands() talkWithDriver(false); } +void IPCThreadState::blockUntilThreadAvailable() +{ + pthread_mutex_lock(&mProcess->mThreadCountLock); + while (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads) { + ALOGW("Waiting for thread to be free. mExecutingThreadsCount=%lu mMaxThreads=%lu\n", + static_cast<unsigned long>(mProcess->mExecutingThreadsCount), + static_cast<unsigned long>(mProcess->mMaxThreads)); + pthread_cond_wait(&mProcess->mThreadCountDecrement, &mProcess->mThreadCountLock); + } + pthread_mutex_unlock(&mProcess->mThreadCountLock); +} + status_t IPCThreadState::getAndExecuteCommand() { status_t result; @@ -432,8 +426,17 @@ status_t IPCThreadState::getAndExecuteCommand() << getReturnString(cmd) << endl; } + pthread_mutex_lock(&mProcess->mThreadCountLock); + mProcess->mExecutingThreadsCount++; + pthread_mutex_unlock(&mProcess->mThreadCountLock); + result = executeCommand(cmd); + pthread_mutex_lock(&mProcess->mThreadCountLock); + mProcess->mExecutingThreadsCount--; + pthread_cond_broadcast(&mProcess->mThreadCountDecrement); + pthread_mutex_unlock(&mProcess->mThreadCountLock); + // After executing the command, ensure that the thread is returned to the // foreground cgroup before rejoining the pool. The driver takes care of // restoring the priority, but doesn't do anything with cgroups so we @@ -682,7 +685,7 @@ status_t IPCThreadState::clearDeathNotification(int32_t handle, BpBinder* proxy) IPCThreadState::IPCThreadState() : mProcess(ProcessState::self()), - mMyThreadId(androidGetTid()), + mMyThreadId(gettid()), mStrictModePolicy(0), mLastTransactionBinderFlags(0) { @@ -708,7 +711,7 @@ status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags) status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult) { - int32_t cmd; + uint32_t cmd; int32_t err; while (1) { @@ -717,7 +720,7 @@ status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult) if (err < NO_ERROR) break; if (mIn.dataAvail() == 0) continue; - cmd = mIn.readInt32(); + cmd = (uint32_t)mIn.readInt32(); IF_LOG_COMMANDS() { alog << "Processing waitForResponse Command: " @@ -947,7 +950,7 @@ status_t IPCThreadState::executeCommand(int32_t cmd) RefBase::weakref_type* refs; status_t result = NO_ERROR; - switch (cmd) { + switch ((uint32_t)cmd) { case BR_ERROR: result = mIn.readInt32(); break; diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp index 437113d446..6bba9968bc 100644 --- a/libs/binder/IPermissionController.cpp +++ b/libs/binder/IPermissionController.cpp @@ -48,6 +48,36 @@ public: if (reply.readExceptionCode() != 0) return 0; return reply.readInt32() != 0; } + + virtual void getPackagesForUid(const uid_t uid, Vector<String16>& packages) + { + Parcel data, reply; + data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor()); + data.writeInt32(uid); + remote()->transact(GET_PACKAGES_FOR_UID_TRANSACTION, data, &reply); + // fail on exception + if (reply.readExceptionCode() != 0) { + return; + } + const int32_t size = reply.readInt32(); + if (size <= 0) { + return; + } + for (int i = 0; i < size; i++) { + packages.push(reply.readString16()); + } + } + + virtual bool isRuntimePermission(const String16& permission) + { + Parcel data, reply; + data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor()); + data.writeString16(permission); + remote()->transact(IS_RUNTIME_PERMISSION_TRANSACTION, data, &reply); + // fail on exception + if (reply.readExceptionCode() != 0) return false; + return reply.readInt32() != 0; + } }; IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController"); @@ -57,7 +87,6 @@ IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController status_t BnPermissionController::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { - //printf("PermissionController received: "); data.print(); switch(code) { case CHECK_PERMISSION_TRANSACTION: { CHECK_INTERFACE(IPermissionController, data, reply); @@ -69,6 +98,30 @@ status_t BnPermissionController::onTransact( reply->writeInt32(res ? 1 : 0); return NO_ERROR; } break; + + case GET_PACKAGES_FOR_UID_TRANSACTION: { + CHECK_INTERFACE(IPermissionController, data, reply); + int32_t uid = data.readInt32(); + Vector<String16> packages; + getPackagesForUid(uid, packages); + reply->writeNoException(); + size_t size = packages.size(); + reply->writeInt32(size); + for (size_t i = 0; i < size; i++) { + reply->writeString16(packages[i]); + } + return NO_ERROR; + } break; + + case IS_RUNTIME_PERMISSION_TRANSACTION: { + CHECK_INTERFACE(IPermissionController, data, reply); + String16 permission = data.readString16(); + const bool res = isRuntimePermission(permission); + reply->writeNoException(); + reply->writeInt32(res ? 1 : 0); + return NO_ERROR; + } break; + default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/binder/IProcessInfoService.cpp b/libs/binder/IProcessInfoService.cpp new file mode 100644 index 0000000000..d86eb27b4d --- /dev/null +++ b/libs/binder/IProcessInfoService.cpp @@ -0,0 +1,94 @@ +/* + * Copyright 2015 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/IProcessInfoService.h> +#include <binder/Parcel.h> +#include <utils/Errors.h> +#include <sys/types.h> + +namespace android { + +// ---------------------------------------------------------------------- + +class BpProcessInfoService : public BpInterface<IProcessInfoService> { +public: + BpProcessInfoService(const sp<IBinder>& impl) + : BpInterface<IProcessInfoService>(impl) {} + + virtual status_t getProcessStatesFromPids(size_t length, /*in*/ int32_t* pids, + /*out*/ int32_t* states) + { + Parcel data, reply; + data.writeInterfaceToken(IProcessInfoService::getInterfaceDescriptor()); + data.writeInt32Array(length, pids); + data.writeInt32(length); // write length of output array, used by java AIDL stubs + status_t err = remote()->transact(GET_PROCESS_STATES_FROM_PIDS, data, &reply); + if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) { + return err; + } + int32_t replyLen = reply.readInt32(); + if (static_cast<size_t>(replyLen) != length) { + return NOT_ENOUGH_DATA; + } + if (replyLen > 0 && (err = reply.read(states, length * sizeof(*states))) != NO_ERROR) { + return err; + } + return reply.readInt32(); + } + +}; + +IMPLEMENT_META_INTERFACE(ProcessInfoService, "android.os.IProcessInfoService"); + +// ---------------------------------------------------------------------- + +status_t BnProcessInfoService::onTransact( uint32_t code, const Parcel& data, Parcel* reply, + uint32_t flags) { + switch(code) { + case GET_PROCESS_STATES_FROM_PIDS: { + CHECK_INTERFACE(IProcessInfoService, data, reply); + int32_t arrayLen = data.readInt32(); + if (arrayLen <= 0) { + reply->writeNoException(); + reply->writeInt32(0); + reply->writeInt32(NOT_ENOUGH_DATA); + return NO_ERROR; + } + + size_t len = static_cast<size_t>(arrayLen); + int32_t pids[len]; + status_t res = data.read(pids, len * sizeof(*pids)); + + // Ignore output array length returned in the parcel here, as the states array must + // always be the same length as the input PIDs array. + int32_t states[len]; + for (size_t i = 0; i < len; i++) states[i] = -1; + if (res == NO_ERROR) { + res = getProcessStatesFromPids(len, /*in*/ pids, /*out*/ states); + } + reply->writeNoException(); + reply->writeInt32Array(len, states); + reply->writeInt32(res); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +// ---------------------------------------------------------------------- + +}; // namespace android diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 7b1b0e7270..3c716df177 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -87,7 +87,7 @@ bool checkPermission(const String16& permission, pid_t pid, uid_t uid) } // Is this a permission failure, or did the controller go away? - if (pc->asBinder()->isBinderAlive()) { + if (IInterface::asBinder(pc)->isBinderAlive()) { ALOGW("Permission failure: %s from uid=%d pid=%d", String8(permission).string(), uid, pid); return false; diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 3100a58111..cfcf73b8d6 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -54,17 +54,24 @@ // --------------------------------------------------------------------------- -#define PAD_SIZE(s) (((s)+3)&~3) +// This macro should never be used at runtime, as a too large value +// of s could cause an integer overflow. Instead, you should always +// use the wrapper function pad_size() +#define PAD_SIZE_UNSAFE(s) (((s)+3)&~3) + +static size_t pad_size(size_t s) { + if (s > (SIZE_T_MAX - 3)) { + abort(); + } + return PAD_SIZE_UNSAFE(s); +} // Note: must be kept in sync with android/os/StrictMode.java's PENALTY_GATHER -#define STRICT_MODE_PENALTY_GATHER 0x100 +#define STRICT_MODE_PENALTY_GATHER (0x40 << 16) // Note: must be kept in sync with android/os/Parcel.java's EX_HAS_REPLY_HEADER #define EX_HAS_REPLY_HEADER -128 -// Maximum size of a blob to transfer in-place. -static const size_t IN_PLACE_BLOB_LIMIT = 40 * 1024; - // XXX This can be made public if we want to provide // support for typed data. struct small_flat_data @@ -79,6 +86,15 @@ static pthread_mutex_t gParcelGlobalAllocSizeLock = PTHREAD_MUTEX_INITIALIZER; static size_t gParcelGlobalAllocSize = 0; static size_t gParcelGlobalAllocCount = 0; +// Maximum size of a blob to transfer in-place. +static const size_t BLOB_INPLACE_LIMIT = 16 * 1024; + +enum { + BLOB_INPLACE = 0, + BLOB_ASHMEM_IMMUTABLE = 1, + BLOB_ASHMEM_MUTABLE = 2, +}; + void acquire_object(const sp<ProcessState>& proc, const flat_binder_object& obj, const void* who) { @@ -355,6 +371,12 @@ size_t Parcel::dataCapacity() const status_t Parcel::setDataSize(size_t size) { + if (size > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + status_t err; err = continueWrite(size); if (err == NO_ERROR) { @@ -366,18 +388,36 @@ status_t Parcel::setDataSize(size_t size) void Parcel::setDataPosition(size_t pos) const { + if (pos > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + abort(); + } + mDataPos = pos; mNextObjectHint = 0; } status_t Parcel::setDataCapacity(size_t size) { + if (size > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + if (size > mDataCapacity) return continueWrite(size); return NO_ERROR; } status_t Parcel::setData(const uint8_t* buffer, size_t len) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + status_t err = restartWrite(len); if (err == NO_ERROR) { memcpy(const_cast<uint8_t*>(data()), buffer, len); @@ -401,6 +441,12 @@ status_t Parcel::appendFrom(const Parcel *parcel, size_t offset, size_t len) return NO_ERROR; } + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + // range checks against the source parcel size if ((offset > parcel->mDataSize) || (len > parcel->mDataSize) @@ -477,6 +523,11 @@ status_t Parcel::appendFrom(const Parcel *parcel, size_t offset, size_t len) return err; } +bool Parcel::allowFds() const +{ + return mAllowFds; +} + bool Parcel::pushAllowFds(bool allowFds) { const bool origValue = mAllowFds; @@ -562,6 +613,12 @@ void Parcel::setError(status_t err) status_t Parcel::finishWrite(size_t len) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + //printf("Finish write of %d\n", len); mDataPos += len; ALOGV("finishWrite Setting data pos of %p to %zu", this, mDataPos); @@ -575,6 +632,12 @@ status_t Parcel::finishWrite(size_t len) status_t Parcel::writeUnpadded(const void* data, size_t len) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + size_t end = mDataPos + len; if (end < mDataPos) { // integer overflow @@ -594,6 +657,12 @@ restart_write: status_t Parcel::write(const void* data, size_t len) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + void* const d = writeInplace(len); if (d) { memcpy(d, data, len); @@ -604,7 +673,13 @@ status_t Parcel::write(const void* data, size_t len) void* Parcel::writeInplace(size_t len) { - const size_t padded = PAD_SIZE(len); + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return NULL; + } + + const size_t padded = pad_size(len); // sanity check for integer overflow if (mDataPos+padded < mDataPos) { @@ -646,21 +721,39 @@ status_t Parcel::writeInt32(int32_t val) { return writeAligned(val); } + +status_t Parcel::writeUint32(uint32_t val) +{ + return writeAligned(val); +} + status_t Parcel::writeInt32Array(size_t len, const int32_t *val) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + if (!val) { - return writeAligned(-1); + return writeInt32(-1); } - status_t ret = writeAligned(len); + status_t ret = writeInt32(static_cast<uint32_t>(len)); if (ret == NO_ERROR) { ret = write(val, len * sizeof(*val)); } return ret; } status_t Parcel::writeByteArray(size_t len, const uint8_t *val) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + if (!val) { - return writeAligned(-1); + return writeInt32(-1); } - status_t ret = writeAligned(len); + status_t ret = writeInt32(static_cast<uint32_t>(len)); if (ret == NO_ERROR) { ret = write(val, len * sizeof(*val)); } @@ -672,6 +765,11 @@ status_t Parcel::writeInt64(int64_t val) return writeAligned(val); } +status_t Parcel::writeUint64(uint64_t val) +{ + return writeAligned(val); +} + status_t Parcel::writePointer(uintptr_t val) { return writeAligned<binder_uintptr_t>(val); @@ -800,45 +898,24 @@ status_t Parcel::writeDupFileDescriptor(int fd) return err; } -// WARNING: This method must stay in sync with -// Parcelable.Creator<ParcelFileDescriptor> CREATOR -// in frameworks/base/core/java/android/os/ParcelFileDescriptor.java -status_t Parcel::writeParcelFileDescriptor(int fd, int commChannel) { - status_t status; - - if (fd < 0) { - status = writeInt32(0); // ParcelFileDescriptor is null - if (status) return status; - } else { - status = writeInt32(1); // ParcelFileDescriptor is not null - if (status) return status; - status = writeDupFileDescriptor(fd); - if (status) return status; - if (commChannel < 0) { - status = writeInt32(0); // commChannel is null - if (status) return status; - } else { - status = writeInt32(1); // commChannel is not null - if (status) return status; - status = writeDupFileDescriptor(commChannel); - } +status_t Parcel::writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob) +{ + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; } - return status; -} -status_t Parcel::writeBlob(size_t len, WritableBlob* outBlob) -{ status_t status; - - if (!mAllowFds || len <= IN_PLACE_BLOB_LIMIT) { + if (!mAllowFds || len <= BLOB_INPLACE_LIMIT) { ALOGV("writeBlob: write in place"); - status = writeInt32(0); + status = writeInt32(BLOB_INPLACE); if (status) return status; void* ptr = writeInplace(len); if (!ptr) return NO_MEMORY; - outBlob->init(false /*mapped*/, ptr, len); + outBlob->init(-1, ptr, len, false); return NO_ERROR; } @@ -846,6 +923,8 @@ status_t Parcel::writeBlob(size_t len, WritableBlob* outBlob) int fd = ashmem_create_region("Parcel Blob", len); if (fd < 0) return NO_MEMORY; + mBlobAshmemSize += len; + int result = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE); if (result < 0) { status = result; @@ -854,15 +933,17 @@ status_t Parcel::writeBlob(size_t len, WritableBlob* outBlob) if (ptr == MAP_FAILED) { status = -errno; } else { - result = ashmem_set_prot_region(fd, PROT_READ); + if (!mutableCopy) { + result = ashmem_set_prot_region(fd, PROT_READ); + } if (result < 0) { status = result; } else { - status = writeInt32(1); + status = writeInt32(mutableCopy ? BLOB_ASHMEM_MUTABLE : BLOB_ASHMEM_IMMUTABLE); if (!status) { status = writeFileDescriptor(fd, true /*takeOwnership*/); if (!status) { - outBlob->init(true /*mapped*/, ptr, len); + outBlob->init(fd, ptr, len, mutableCopy); return NO_ERROR; } } @@ -874,6 +955,15 @@ status_t Parcel::writeBlob(size_t len, WritableBlob* outBlob) return status; } +status_t Parcel::writeDupImmutableBlobFileDescriptor(int fd) +{ + // Must match up with what's done in writeBlob. + if (!mAllowFds) return FDS_NOT_ALLOWED; + status_t status = writeInt32(BLOB_ASHMEM_IMMUTABLE); + if (status) return status; + return writeDupFileDescriptor(fd); +} + status_t Parcel::write(const FlattenableHelperInterface& val) { status_t err; @@ -882,6 +972,12 @@ status_t Parcel::write(const FlattenableHelperInterface& val) const size_t len = val.getFlattenedSize(); const size_t fd_count = val.getFdCount(); + if ((len > INT32_MAX) || (fd_count > INT32_MAX)) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + err = this->writeInt32(len); if (err) return err; @@ -889,7 +985,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(pad_size(len)); if (buf == NULL) return BAD_VALUE; @@ -918,21 +1014,22 @@ status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData) restart_write: *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val; - // Need to write meta-data? - if (nullMetaData || val.binder != 0) { - mObjects[mObjectsSize] = mDataPos; - acquire_object(ProcessState::self(), val, this); - mObjectsSize++; - } - // remember if it's a file descriptor if (val.type == BINDER_TYPE_FD) { if (!mAllowFds) { + // fail before modifying our object index return FDS_NOT_ALLOWED; } mHasFds = mFdsKnown = true; } + // Need to write meta-data? + if (nullMetaData || val.binder != 0) { + mObjects[mObjectsSize] = mDataPos; + acquire_object(ProcessState::self(), val, this); + mObjectsSize++; + } + return finishWrite(sizeof(flat_binder_object)); } @@ -964,10 +1061,16 @@ void Parcel::remove(size_t /*start*/, size_t /*amt*/) 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 (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + + if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize + && len <= pad_size(len)) { memcpy(outData, mData+mDataPos, len); - mDataPos += PAD_SIZE(len); + mDataPos += pad_size(len); ALOGV("read Setting data pos of %p to %zu", this, mDataPos); return NO_ERROR; } @@ -976,10 +1079,16 @@ status_t Parcel::read(void* outData, size_t len) const const void* Parcel::readInplace(size_t len) const { - if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize - && len <= PAD_SIZE(len)) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return NULL; + } + + if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize + && len <= pad_size(len)) { const void* data = mData+mDataPos; - mDataPos += PAD_SIZE(len); + mDataPos += pad_size(len); ALOGV("readInplace Setting data pos of %p to %zu", this, mDataPos); return data; } @@ -988,7 +1097,7 @@ const void* Parcel::readInplace(size_t len) const template<class T> status_t Parcel::readAligned(T *pArg) const { - COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T)); + COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T)); if ((mDataPos+sizeof(T)) <= mDataSize) { const void* data = mData+mDataPos; @@ -1012,7 +1121,7 @@ T Parcel::readAligned() const { template<class T> status_t Parcel::writeAligned(T val) { - COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T)); + COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T)); if ((mDataPos+sizeof(val)) <= mDataCapacity) { restart_write: @@ -1035,6 +1144,15 @@ int32_t Parcel::readInt32() const return readAligned<int32_t>(); } +status_t Parcel::readUint32(uint32_t *pArg) const +{ + return readAligned(pArg); +} + +uint32_t Parcel::readUint32() const +{ + return readAligned<uint32_t>(); +} status_t Parcel::readInt64(int64_t *pArg) const { @@ -1047,6 +1165,16 @@ int64_t Parcel::readInt64() const return readAligned<int64_t>(); } +status_t Parcel::readUint64(uint64_t *pArg) const +{ + return readAligned(pArg); +} + +uint64_t Parcel::readUint64() const +{ + return readAligned<uint64_t>(); +} + status_t Parcel::readPointer(uintptr_t *pArg) const { status_t ret; @@ -1134,7 +1262,7 @@ const char* Parcel::readCString() const const char* eos = reinterpret_cast<const char*>(memchr(str, 0, avail)); if (eos) { const size_t len = eos - str; - mDataPos += PAD_SIZE(len+1); + mDataPos += pad_size(len+1); ALOGV("readCString Setting data pos of %p to %zu", this, mDataPos); return str; } @@ -1254,46 +1382,31 @@ int Parcel::readFileDescriptor() const return BAD_TYPE; } -// WARNING: This method must stay in sync with writeToParcel() -// in frameworks/base/core/java/android/os/ParcelFileDescriptor.java -int Parcel::readParcelFileDescriptor(int& outCommChannel) const { - int fd; - outCommChannel = -1; - - if (readInt32() == 0) { - fd = -1; - } else { - fd = readFileDescriptor(); - if (fd >= 0 && readInt32() != 0) { - outCommChannel = readFileDescriptor(); - } - } - return fd; -} - status_t Parcel::readBlob(size_t len, ReadableBlob* outBlob) const { - int32_t useAshmem; - status_t status = readInt32(&useAshmem); + int32_t blobType; + status_t status = readInt32(&blobType); if (status) return status; - if (!useAshmem) { + if (blobType == BLOB_INPLACE) { ALOGV("readBlob: read in place"); const void* ptr = readInplace(len); if (!ptr) return BAD_VALUE; - outBlob->init(false /*mapped*/, const_cast<void*>(ptr), len); + outBlob->init(-1, const_cast<void*>(ptr), len, false); return NO_ERROR; } ALOGV("readBlob: read from ashmem"); + bool isMutable = (blobType == BLOB_ASHMEM_MUTABLE); int fd = readFileDescriptor(); if (fd == int(BAD_TYPE)) return BAD_VALUE; - void* ptr = ::mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0); + void* ptr = ::mmap(NULL, len, isMutable ? PROT_READ | PROT_WRITE : PROT_READ, + MAP_SHARED, fd, 0); if (ptr == MAP_FAILED) return NO_MEMORY; - outBlob->init(true /*mapped*/, ptr, len); + outBlob->init(fd, ptr, len, isMutable); return NO_ERROR; } @@ -1303,8 +1416,14 @@ status_t Parcel::read(FlattenableHelperInterface& val) const const size_t len = this->readInt32(); const size_t fd_count = this->readInt32(); + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + // payload - void const* const buf = this->readInplace(PAD_SIZE(len)); + void const* const buf = this->readInplace(pad_size(len)); if (buf == NULL) return BAD_VALUE; @@ -1450,7 +1569,7 @@ void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize, for (size_t i = 0; i < mObjectsSize; i++) { binder_size_t offset = mObjects[i]; if (offset < minOffset) { - ALOGE("%s: bad object offset %"PRIu64" < %"PRIu64"\n", + ALOGE("%s: bad object offset %" PRIu64 " < %" PRIu64 "\n", __func__, (uint64_t)offset, (uint64_t)minOffset); mObjectsSize = 0; break; @@ -1543,6 +1662,12 @@ void Parcel::freeDataNoInit() status_t Parcel::growData(size_t len) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + size_t newSize = ((mDataSize+len)*3)/2; return (newSize <= mDataSize) ? (status_t) NO_MEMORY @@ -1551,6 +1676,12 @@ status_t Parcel::growData(size_t len) status_t Parcel::restartWrite(size_t desired) { + if (desired > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + if (mOwner) { freeData(); return continueWrite(desired); @@ -1591,6 +1722,12 @@ status_t Parcel::restartWrite(size_t desired) status_t Parcel::continueWrite(size_t desired) { + if (desired > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + // If shrinking, first adjust for any objects that appear // after the new data size. size_t objectsSize = mObjectsSize; @@ -1623,7 +1760,7 @@ status_t Parcel::continueWrite(size_t desired) binder_size_t* objects = NULL; if (objectsSize) { - objects = (binder_size_t*)malloc(objectsSize*sizeof(binder_size_t)); + objects = (binder_size_t*)calloc(objectsSize, sizeof(binder_size_t)); if (!objects) { free(data); @@ -1759,6 +1896,7 @@ void Parcel::initState() mFdsKnown = true; mAllowFds = true; mOwner = NULL; + mBlobAshmemSize = 0; } void Parcel::scanForFds() const @@ -1776,10 +1914,15 @@ void Parcel::scanForFds() const mFdsKnown = true; } +size_t Parcel::getBlobAshmemSize() const +{ + return mBlobAshmemSize; +} + // --- Parcel::Blob --- Parcel::Blob::Blob() : - mMapped(false), mData(NULL), mSize(0) { + mFd(-1), mData(NULL), mSize(0), mMutable(false) { } Parcel::Blob::~Blob() { @@ -1787,22 +1930,24 @@ Parcel::Blob::~Blob() { } void Parcel::Blob::release() { - if (mMapped && mData) { + if (mFd != -1 && mData) { ::munmap(mData, mSize); } clear(); } -void Parcel::Blob::init(bool mapped, void* data, size_t size) { - mMapped = mapped; +void Parcel::Blob::init(int fd, void* data, size_t size, bool isMutable) { + mFd = fd; mData = data; mSize = size; + mMutable = isMutable; } void Parcel::Blob::clear() { - mMapped = false; + mFd = -1; mData = NULL; mSize = 0; + mMutable = false; } }; // namespace android diff --git a/libs/binder/ProcessInfoService.cpp b/libs/binder/ProcessInfoService.cpp new file mode 100644 index 0000000000..fb2864355d --- /dev/null +++ b/libs/binder/ProcessInfoService.cpp @@ -0,0 +1,70 @@ +/* + * Copyright 2015 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/ProcessInfoService.h> +#include <binder/IServiceManager.h> + +#include <utils/Log.h> +#include <utils/String16.h> + +namespace android { + +ProcessInfoService::ProcessInfoService() { + updateBinderLocked(); +} + +status_t ProcessInfoService::getProcessStatesImpl(size_t length, /*in*/ int32_t* pids, + /*out*/ int32_t* states) { + status_t err = NO_ERROR; + sp<IProcessInfoService> pis; + mProcessInfoLock.lock(); + pis = mProcessInfoService; + mProcessInfoLock.unlock(); + + for (int i = 0; i < BINDER_ATTEMPT_LIMIT; i++) { + + if (pis != NULL) { + err = pis->getProcessStatesFromPids(length, /*in*/ pids, /*out*/ states); + if (err == NO_ERROR) return NO_ERROR; // success + if (IInterface::asBinder(pis)->isBinderAlive()) return err; + } + sleep(1); + + mProcessInfoLock.lock(); + if (pis == mProcessInfoService) { + updateBinderLocked(); + } + pis = mProcessInfoService; + mProcessInfoLock.unlock(); + } + + ALOGW("%s: Could not retrieve process states from ProcessInfoService after %d retries.", + __FUNCTION__, BINDER_ATTEMPT_LIMIT); + + return TIMED_OUT; +} + +void ProcessInfoService::updateBinderLocked() { + const sp<IServiceManager> sm(defaultServiceManager()); + if (sm != NULL) { + const String16 name("processinfo"); + mProcessInfoService = interface_cast<IProcessInfoService>(sm->checkService(name)); + } +} + +ANDROID_SINGLETON_STATIC_INSTANCE(ProcessInfoService); + +}; // namespace android diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index 303d6cf3a2..016d3c54b0 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -42,12 +42,13 @@ #include <sys/stat.h> #define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2)) +#define DEFAULT_MAX_BINDER_THREADS 15 // --------------------------------------------------------------------------- namespace android { - + class PoolThread : public Thread { public: @@ -294,7 +295,9 @@ void ProcessState::spawnPooledThread(bool isMain) status_t ProcessState::setThreadPoolMaxThreadCount(size_t maxThreads) { status_t result = NO_ERROR; - if (ioctl(mDriverFD, BINDER_SET_MAX_THREADS, &maxThreads) == -1) { + if (ioctl(mDriverFD, BINDER_SET_MAX_THREADS, &maxThreads) != -1) { + mMaxThreads = maxThreads; + } else { result = -errno; ALOGE("Binder ioctl to set max threads failed: %s", strerror(-result)); } @@ -322,7 +325,7 @@ static int open_driver() close(fd); fd = -1; } - size_t maxThreads = 15; + size_t maxThreads = DEFAULT_MAX_BINDER_THREADS; result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads); if (result == -1) { ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno)); @@ -336,6 +339,10 @@ static int open_driver() ProcessState::ProcessState() : mDriverFD(open_driver()) , mVMStart(MAP_FAILED) + , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER) + , mThreadCountDecrement(PTHREAD_COND_INITIALIZER) + , mExecutingThreadsCount(0) + , mMaxThreads(DEFAULT_MAX_BINDER_THREADS) , mManagesContexts(false) , mBinderContextCheckFunc(NULL) , mBinderContextUserData(NULL) diff --git a/libs/binder/tests/Android.mk b/libs/binder/tests/Android.mk new file mode 100644 index 0000000000..36687296fb --- /dev/null +++ b/libs/binder/tests/Android.mk @@ -0,0 +1,34 @@ +# +# Copyright (C) 2014 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) + +include $(CLEAR_VARS) +ifneq ($(TARGET_USES_64_BIT_BINDER),true) +ifneq ($(TARGET_IS_64_BIT),true) +LOCAL_CFLAGS += -DBINDER_IPC_32BIT=1 +endif +endif + +LOCAL_MODULE := binderDriverInterfaceTest +LOCAL_SRC_FILES := binderDriverInterfaceTest.cpp +include $(BUILD_NATIVE_TEST) + +include $(CLEAR_VARS) +LOCAL_MODULE := binderLibTest +LOCAL_SRC_FILES := binderLibTest.cpp +LOCAL_SHARED_LIBRARIES := libbinder libutils +include $(BUILD_NATIVE_TEST) diff --git a/libs/binder/tests/binderDriverInterfaceTest.cpp b/libs/binder/tests/binderDriverInterfaceTest.cpp new file mode 100644 index 0000000000..315f34956c --- /dev/null +++ b/libs/binder/tests/binderDriverInterfaceTest.cpp @@ -0,0 +1,353 @@ +/* + * Copyright (C) 2014 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 <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> + +#include <gtest/gtest.h> +#include <linux/binder.h> +#include <binder/IBinder.h> +#include <sys/mman.h> +#include <poll.h> + +#define BINDER_DEV_NAME "/dev/binder" + +testing::Environment* binder_env; + +class BinderDriverInterfaceTestEnv : public ::testing::Environment { + virtual void SetUp() { + int ret; + uint32_t max_threads = 0; + + m_binderFd = open(BINDER_DEV_NAME, O_RDWR | O_NONBLOCK); + ASSERT_GE(m_binderFd, 0); + m_buffer = mmap(NULL, 64*1024, PROT_READ, MAP_SHARED, m_binderFd, 0); + ASSERT_NE(m_buffer, (void *)NULL); + ret = ioctl(m_binderFd, BINDER_SET_MAX_THREADS, &max_threads); + EXPECT_EQ(0, ret); + EnterLooper(); + } + virtual void TearDown() { + close(m_binderFd); + } + private: + int m_binderFd; + void *m_buffer; + public: + int getBinderFd(void) { + return m_binderFd; + } + void EnterLooper(void) { + int ret; + const uint32_t bc[] = { + BC_ENTER_LOOPER, + }; + struct binder_write_read bwr = binder_write_read(); + bwr.write_buffer = (uintptr_t)bc; + bwr.write_size = sizeof(bc); + ret = ioctl(m_binderFd, BINDER_WRITE_READ, &bwr); + EXPECT_EQ(0, ret); + if (ret < 0) { + EXPECT_EQ(0, errno); + } + EXPECT_EQ(sizeof(bc), bwr.write_consumed); + } +}; + +class BinderDriverInterfaceTest : public ::testing::Test { + public: + virtual void SetUp() { + m_binderFd = static_cast<BinderDriverInterfaceTestEnv *>(binder_env)->getBinderFd(); + } + virtual void TearDown() { + } + protected: + void binderTestIoctlRetErr2(int cmd, void *arg, int expect_ret, int expect_errno, int accept_errno) { + int ret; + + ret = ioctl(m_binderFd, cmd, arg); + EXPECT_EQ(expect_ret, ret); + if (ret < 0) { + if (errno != accept_errno) + EXPECT_EQ(expect_errno, errno); + } + } + void binderTestIoctlErr2(int cmd, void *arg, int expect_errno, int accept_errno) { + binderTestIoctlRetErr2(cmd, arg, -1, expect_errno, accept_errno); + } + void binderTestIoctlErr1(int cmd, void *arg, int expect_errno) { + binderTestIoctlErr2(cmd, arg, expect_errno, expect_errno); + } + void binderTestIoctl(int cmd, void *arg) { + binderTestIoctlRetErr2(cmd, arg, 0, 0, 0); + } + void binderTestIoctlUnimplemented(int cmd, void *arg) { + int ret; + + ret = ioctl(m_binderFd, cmd, arg); + if (ret < 0) { + /* Not currently implmented. Allow ret == -1, errno == EINVAL */ + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); + } + } + void binderTestReadEmpty(void) { + size_t i; + uint32_t br[32]; + struct binder_write_read bwr = binder_write_read(); + SCOPED_TRACE("TestReadEmpty"); + bwr.read_buffer = (uintptr_t)br; + bwr.read_size = sizeof(br); + binderTestIoctlErr1(BINDER_WRITE_READ, &bwr, EAGAIN); + EXPECT_EQ(0u, bwr.read_consumed); + for (i = 0; i * sizeof(uint32_t) < bwr.read_consumed; i++) { + SCOPED_TRACE(testing::Message() << "i = " << i); + EXPECT_EQ(BR_NOOP, br[i]); + } + } + void binderWaitForReadData(int timeout_ms) { + int ret; + pollfd pfd = pollfd(); + + pfd.fd = m_binderFd; + pfd.events = POLLIN; + ret = poll(&pfd, 1, timeout_ms); + EXPECT_EQ(1, ret); + } + private: + int m_binderFd; +}; + +TEST_F(BinderDriverInterfaceTest, Version) { + struct binder_version version; + binderTestIoctl(BINDER_VERSION, &version); + ASSERT_EQ(BINDER_CURRENT_PROTOCOL_VERSION, version.protocol_version); +} + +TEST_F(BinderDriverInterfaceTest, WriteReadNull) { + binderTestIoctlErr1(BINDER_WRITE_READ, NULL, EFAULT); +} + +TEST_F(BinderDriverInterfaceTest, SetIdleTimeoutNull) { + binderTestIoctlErr2(BINDER_SET_IDLE_TIMEOUT, NULL, EFAULT, EINVAL); +} + +TEST_F(BinderDriverInterfaceTest, SetMaxThreadsNull) { + binderTestIoctlErr2(BINDER_SET_MAX_THREADS, NULL, EFAULT, EINVAL); /* TODO: don't accept EINVAL */ +} + +TEST_F(BinderDriverInterfaceTest, SetIdlePriorityNull) { + binderTestIoctlErr2(BINDER_SET_IDLE_PRIORITY, NULL, EFAULT, EINVAL); +} + +TEST_F(BinderDriverInterfaceTest, VersionNull) { + binderTestIoctlErr2(BINDER_VERSION, NULL, EFAULT, EINVAL); /* TODO: don't accept EINVAL */ +} + +TEST_F(BinderDriverInterfaceTest, SetIdleTimeoutNoTest) { + int64_t idle_timeout = 100000; + binderTestIoctlUnimplemented(BINDER_SET_IDLE_TIMEOUT, &idle_timeout); +} + +TEST_F(BinderDriverInterfaceTest, SetMaxThreads) { + uint32_t max_threads = 0; + binderTestIoctl(BINDER_SET_MAX_THREADS, &max_threads); +} + +TEST_F(BinderDriverInterfaceTest, SetIdlePriorityNoTest) { + int idle_priority = 0; + binderTestIoctlUnimplemented(BINDER_SET_IDLE_PRIORITY, &idle_priority); +} + +TEST_F(BinderDriverInterfaceTest, SetContextMgrBusy) { + int32_t dummy = 0; + binderTestIoctlErr1(BINDER_SET_CONTEXT_MGR, &dummy, EBUSY); +} + +TEST_F(BinderDriverInterfaceTest, ThreadExit) { + int32_t dummy = 0; + binderTestIoctl(BINDER_THREAD_EXIT, &dummy); + static_cast<BinderDriverInterfaceTestEnv *>(binder_env)->EnterLooper(); +} + +TEST_F(BinderDriverInterfaceTest, WriteReadEmpty) { + struct binder_write_read bwr = binder_write_read(); + binderTestIoctl(BINDER_WRITE_READ, &bwr); +} + +TEST_F(BinderDriverInterfaceTest, Read) { + binderTestReadEmpty(); +} + +TEST_F(BinderDriverInterfaceTest, IncRefsAcquireReleaseDecRefs) { + const uint32_t bc[] = { + BC_INCREFS, + 0, + BC_ACQUIRE, + 0, + BC_RELEASE, + 0, + BC_DECREFS, + 0, + }; + struct binder_write_read bwr = binder_write_read(); + bwr.write_buffer = (uintptr_t)bc; + bwr.write_size = sizeof(bc); + binderTestIoctl(BINDER_WRITE_READ, &bwr); + EXPECT_EQ(sizeof(bc), bwr.write_consumed); + binderTestReadEmpty(); +} + +TEST_F(BinderDriverInterfaceTest, Transaction) { + binder_uintptr_t cookie = 1234; + struct { + uint32_t cmd1; + struct binder_transaction_data arg1; + } __attribute__((packed)) bc1 = { + .cmd1 = BC_TRANSACTION, + .arg1 = { + .target = { 0 }, + .cookie = 0, + .code = android::IBinder::PING_TRANSACTION, + .flags = 0, + .sender_pid = 0, + .sender_euid = 0, + .data_size = 0, + .offsets_size = 0, + .data = {0, 0}, + }, + }; + struct { + uint32_t cmd0; + uint32_t cmd1; + uint32_t cmd2; + binder_transaction_data arg2; + uint32_t pad[16]; + } __attribute__((packed)) br; + struct binder_write_read bwr = binder_write_read(); + + bwr.write_buffer = (uintptr_t)&bc1; + bwr.write_size = sizeof(bc1); + bwr.read_buffer = (uintptr_t)&br; + bwr.read_size = sizeof(br); + + { + SCOPED_TRACE("1st WriteRead"); + binderTestIoctl(BINDER_WRITE_READ, &bwr); + } + EXPECT_EQ(sizeof(bc1), bwr.write_consumed); + if (bwr.read_consumed < offsetof(typeof(br), pad)) { + SCOPED_TRACE("2nd WriteRead"); + binderWaitForReadData(10000); + binderTestIoctl(BINDER_WRITE_READ, &bwr); + } + EXPECT_EQ(offsetof(typeof(br), pad), bwr.read_consumed); + if (bwr.read_consumed > offsetof(typeof(br), cmd0)) + EXPECT_EQ(BR_NOOP, br.cmd0); + if (bwr.read_consumed > offsetof(typeof(br), cmd1)) + EXPECT_EQ(BR_TRANSACTION_COMPLETE, br.cmd1); + if (bwr.read_consumed > offsetof(typeof(br), cmd2)) + EXPECT_EQ(BR_REPLY, br.cmd2); + if (bwr.read_consumed >= offsetof(typeof(br), pad)) { + EXPECT_EQ(0u, br.arg2.target.ptr); + EXPECT_EQ(0u, br.arg2.cookie); + EXPECT_EQ(0u, br.arg2.code); + EXPECT_EQ(0u, br.arg2.flags); + EXPECT_EQ(0u, br.arg2.data_size); + EXPECT_EQ(0u, br.arg2.offsets_size); + + SCOPED_TRACE("3rd WriteRead"); + + binderTestReadEmpty(); + + struct { + uint32_t cmd1; + binder_uintptr_t arg1; + } __attribute__((packed)) bc2 = { + .cmd1 = BC_FREE_BUFFER, + .arg1 = br.arg2.data.ptr.buffer, + }; + + bwr.write_buffer = (uintptr_t)&bc2; + bwr.write_size = sizeof(bc2); + bwr.write_consumed = 0; + bwr.read_size = 0; + + binderTestIoctl(BINDER_WRITE_READ, &bwr); + EXPECT_EQ(sizeof(bc2), bwr.write_consumed); + } + binderTestReadEmpty(); +} + +TEST_F(BinderDriverInterfaceTest, RequestDeathNotification) { + binder_uintptr_t cookie = 1234; + struct { + uint32_t cmd0; + uint32_t arg0; + uint32_t cmd1; + struct binder_handle_cookie arg1; + uint32_t cmd2; + struct binder_handle_cookie arg2; + uint32_t cmd3; + uint32_t arg3; + } __attribute__((packed)) bc = { + .cmd0 = BC_INCREFS, + .arg0 = 0, + .cmd1 = BC_REQUEST_DEATH_NOTIFICATION, + .arg1 = { + .handle = 0, + .cookie = cookie, + }, + .cmd2 = BC_CLEAR_DEATH_NOTIFICATION, + .arg2 = { + .handle = 0, + .cookie = cookie, + }, + .cmd3 = BC_DECREFS, + .arg3 = 0, + }; + struct { + uint32_t cmd0; + uint32_t cmd1; + binder_uintptr_t arg1; + uint32_t pad[16]; + } __attribute__((packed)) br; + struct binder_write_read bwr = binder_write_read(); + + bwr.write_buffer = (uintptr_t)&bc; + bwr.write_size = sizeof(bc); + bwr.read_buffer = (uintptr_t)&br; + bwr.read_size = sizeof(br); + + binderTestIoctl(BINDER_WRITE_READ, &bwr); + EXPECT_EQ(sizeof(bc), bwr.write_consumed); + EXPECT_EQ(sizeof(br) - sizeof(br.pad), bwr.read_consumed); + EXPECT_EQ(BR_NOOP, br.cmd0); + EXPECT_EQ(BR_CLEAR_DEATH_NOTIFICATION_DONE, br.cmd1); + EXPECT_EQ(cookie, br.arg1); + binderTestReadEmpty(); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + + binder_env = AddGlobalTestEnvironment(new BinderDriverInterfaceTestEnv()); + + return RUN_ALL_TESTS(); +} + diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp new file mode 100644 index 0000000000..3df3acf9db --- /dev/null +++ b/libs/binder/tests/binderLibTest.cpp @@ -0,0 +1,954 @@ +/* + * Copyright (C) 2014 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 <errno.h> +#include <fcntl.h> +#include <poll.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + +#include <gtest/gtest.h> + +#include <binder/Binder.h> +#include <binder/IBinder.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> + +#define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) + +using namespace android; + +static testing::Environment* binder_env; +static char *binderservername; +static char binderserverarg[] = "--binderserver"; + +static String16 binderLibTestServiceName = String16("test.binderLib"); + +enum BinderLibTestTranscationCode { + BINDER_LIB_TEST_NOP_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, + BINDER_LIB_TEST_REGISTER_SERVER, + BINDER_LIB_TEST_ADD_SERVER, + BINDER_LIB_TEST_CALL_BACK, + BINDER_LIB_TEST_NOP_CALL_BACK, + BINDER_LIB_TEST_GET_ID_TRANSACTION, + BINDER_LIB_TEST_INDIRECT_TRANSACTION, + BINDER_LIB_TEST_SET_ERROR_TRANSACTION, + BINDER_LIB_TEST_GET_STATUS_TRANSACTION, + BINDER_LIB_TEST_ADD_STRONG_REF_TRANSACTION, + BINDER_LIB_TEST_LINK_DEATH_TRANSACTION, + BINDER_LIB_TEST_WRITE_FILE_TRANSACTION, + BINDER_LIB_TEST_PROMOTE_WEAK_REF_TRANSACTION, + BINDER_LIB_TEST_EXIT_TRANSACTION, + BINDER_LIB_TEST_DELAYED_EXIT_TRANSACTION, + BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION, +}; + +pid_t start_server_process(int arg2) +{ + int ret; + pid_t pid; + status_t status; + int pipefd[2]; + char stri[16]; + char strpipefd1[16]; + char *childargv[] = { + binderservername, + binderserverarg, + stri, + strpipefd1, + NULL + }; + + ret = pipe(pipefd); + if (ret < 0) + return ret; + + snprintf(stri, sizeof(stri), "%d", arg2); + snprintf(strpipefd1, sizeof(strpipefd1), "%d", pipefd[1]); + + pid = fork(); + if (pid == -1) + return pid; + if (pid == 0) { + close(pipefd[0]); + execv(binderservername, childargv); + status = -errno; + write(pipefd[1], &status, sizeof(status)); + fprintf(stderr, "execv failed, %s\n", strerror(errno)); + _exit(EXIT_FAILURE); + } + close(pipefd[1]); + ret = read(pipefd[0], &status, sizeof(status)); + //printf("pipe read returned %d, status %d\n", ret, status); + close(pipefd[0]); + if (ret == sizeof(status)) { + ret = status; + } else { + kill(pid, SIGKILL); + if (ret >= 0) { + ret = NO_INIT; + } + } + if (ret < 0) { + wait(NULL); + return ret; + } + return pid; +} + +class BinderLibTestEnv : public ::testing::Environment { + public: + BinderLibTestEnv() {} + sp<IBinder> getServer(void) { + return m_server; + } + + private: + virtual void SetUp() { + m_serverpid = start_server_process(0); + //printf("m_serverpid %d\n", m_serverpid); + ASSERT_GT(m_serverpid, 0); + + sp<IServiceManager> sm = defaultServiceManager(); + //printf("%s: pid %d, get service\n", __func__, m_pid); + m_server = sm->getService(binderLibTestServiceName); + ASSERT_TRUE(m_server != NULL); + //printf("%s: pid %d, get service done\n", __func__, m_pid); + } + virtual void TearDown() { + status_t ret; + Parcel data, reply; + int exitStatus; + pid_t pid; + + //printf("%s: pid %d\n", __func__, m_pid); + if (m_server != NULL) { + ret = m_server->transact(BINDER_LIB_TEST_GET_STATUS_TRANSACTION, data, &reply); + EXPECT_EQ(0, ret); + ret = m_server->transact(BINDER_LIB_TEST_EXIT_TRANSACTION, data, &reply, TF_ONE_WAY); + EXPECT_EQ(0, ret); + } + if (m_serverpid > 0) { + //printf("wait for %d\n", m_pids[i]); + pid = wait(&exitStatus); + EXPECT_EQ(m_serverpid, pid); + EXPECT_TRUE(WIFEXITED(exitStatus)); + EXPECT_EQ(0, WEXITSTATUS(exitStatus)); + } + } + + pid_t m_serverpid; + sp<IBinder> m_server; +}; + +class BinderLibTest : public ::testing::Test { + public: + virtual void SetUp() { + m_server = static_cast<BinderLibTestEnv *>(binder_env)->getServer(); + } + virtual void TearDown() { + } + protected: + sp<IBinder> addServer(int32_t *idPtr = NULL) + { + int ret; + int32_t id; + Parcel data, reply; + sp<IBinder> binder; + + ret = m_server->transact(BINDER_LIB_TEST_ADD_SERVER, data, &reply); + EXPECT_EQ(NO_ERROR, ret); + + EXPECT_FALSE(binder != NULL); + binder = reply.readStrongBinder(); + EXPECT_TRUE(binder != NULL); + ret = reply.readInt32(&id); + EXPECT_EQ(NO_ERROR, ret); + if (idPtr) + *idPtr = id; + return binder; + } + void waitForReadData(int fd, int timeout_ms) { + int ret; + pollfd pfd = pollfd(); + + pfd.fd = fd; + pfd.events = POLLIN; + ret = poll(&pfd, 1, timeout_ms); + EXPECT_EQ(1, ret); + } + + sp<IBinder> m_server; +}; + +class BinderLibTestBundle : public Parcel +{ + public: + BinderLibTestBundle(void) {} + BinderLibTestBundle(const Parcel *source) : m_isValid(false) { + int32_t mark; + int32_t bundleLen; + size_t pos; + + if (source->readInt32(&mark)) + return; + if (mark != MARK_START) + return; + if (source->readInt32(&bundleLen)) + return; + pos = source->dataPosition(); + if (Parcel::appendFrom(source, pos, bundleLen)) + return; + source->setDataPosition(pos + bundleLen); + if (source->readInt32(&mark)) + return; + if (mark != MARK_END) + return; + m_isValid = true; + setDataPosition(0); + } + void appendTo(Parcel *dest) { + dest->writeInt32(MARK_START); + dest->writeInt32(dataSize()); + dest->appendFrom(this, 0, dataSize()); + dest->writeInt32(MARK_END); + }; + bool isValid(void) { + return m_isValid; + } + private: + enum { + MARK_START = B_PACK_CHARS('B','T','B','S'), + MARK_END = B_PACK_CHARS('B','T','B','E'), + }; + bool m_isValid; +}; + +class BinderLibTestEvent +{ + public: + BinderLibTestEvent(void) + : m_eventTriggered(false) + { + pthread_mutex_init(&m_waitMutex, NULL); + pthread_cond_init(&m_waitCond, NULL); + } + int waitEvent(int timeout_s) + { + int ret; + pthread_mutex_lock(&m_waitMutex); + if (!m_eventTriggered) { +#if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE) + pthread_cond_timeout_np(&m_waitCond, &m_waitMutex, timeout_s * 1000); +#else + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += timeout_s; + pthread_cond_timedwait(&m_waitCond, &m_waitMutex, &ts); +#endif + } + ret = m_eventTriggered ? NO_ERROR : TIMED_OUT; + pthread_mutex_unlock(&m_waitMutex); + return ret; + } + protected: + void triggerEvent(void) { + pthread_mutex_lock(&m_waitMutex); + pthread_cond_signal(&m_waitCond); + m_eventTriggered = true; + pthread_mutex_unlock(&m_waitMutex); + }; + private: + pthread_mutex_t m_waitMutex; + pthread_cond_t m_waitCond; + bool m_eventTriggered; +}; + +class BinderLibTestCallBack : public BBinder, public BinderLibTestEvent +{ + public: + BinderLibTestCallBack() + : m_result(NOT_ENOUGH_DATA) + { + } + status_t getResult(void) + { + return m_result; + } + + private: + virtual status_t onTransact(uint32_t code, + const Parcel& data, Parcel* reply, + uint32_t flags = 0) + { + (void)reply; + (void)flags; + switch(code) { + case BINDER_LIB_TEST_CALL_BACK: + m_result = data.readInt32(); + triggerEvent(); + return NO_ERROR; + default: + return UNKNOWN_TRANSACTION; + } + } + + status_t m_result; +}; + +class TestDeathRecipient : public IBinder::DeathRecipient, public BinderLibTestEvent +{ + private: + virtual void binderDied(const wp<IBinder>& who) { + (void)who; + triggerEvent(); + }; +}; + +TEST_F(BinderLibTest, NopTransaction) { + status_t ret; + Parcel data, reply; + ret = m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply); + EXPECT_EQ(NO_ERROR, ret); +} + +TEST_F(BinderLibTest, SetError) { + int32_t testValue[] = { 0, -123, 123 }; + for (size_t i = 0; i < ARRAY_SIZE(testValue); i++) { + status_t ret; + Parcel data, reply; + data.writeInt32(testValue[i]); + ret = m_server->transact(BINDER_LIB_TEST_SET_ERROR_TRANSACTION, data, &reply); + EXPECT_EQ(testValue[i], ret); + } +} + +TEST_F(BinderLibTest, GetId) { + status_t ret; + int32_t id; + Parcel data, reply; + ret = m_server->transact(BINDER_LIB_TEST_GET_ID_TRANSACTION, data, &reply); + EXPECT_EQ(NO_ERROR, ret); + ret = reply.readInt32(&id); + EXPECT_EQ(NO_ERROR, ret); + EXPECT_EQ(0, id); +} + +TEST_F(BinderLibTest, PtrSize) { + status_t ret; + int32_t ptrsize; + Parcel data, reply; + sp<IBinder> server = addServer(); + ASSERT_TRUE(server != NULL); + ret = server->transact(BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION, data, &reply); + EXPECT_EQ(NO_ERROR, ret); + ret = reply.readInt32(&ptrsize); + EXPECT_EQ(NO_ERROR, ret); + RecordProperty("TestPtrSize", sizeof(void *)); + RecordProperty("ServerPtrSize", sizeof(void *)); +} + +TEST_F(BinderLibTest, IndirectGetId2) +{ + status_t ret; + int32_t id; + int32_t count; + Parcel data, reply; + int32_t serverId[3]; + + data.writeInt32(ARRAY_SIZE(serverId)); + for (size_t i = 0; i < ARRAY_SIZE(serverId); i++) { + sp<IBinder> server; + BinderLibTestBundle datai; + + server = addServer(&serverId[i]); + ASSERT_TRUE(server != NULL); + data.writeStrongBinder(server); + data.writeInt32(BINDER_LIB_TEST_GET_ID_TRANSACTION); + datai.appendTo(&data); + } + + ret = m_server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION, data, &reply); + ASSERT_EQ(NO_ERROR, ret); + + ret = reply.readInt32(&id); + ASSERT_EQ(NO_ERROR, ret); + EXPECT_EQ(0, id); + + ret = reply.readInt32(&count); + ASSERT_EQ(NO_ERROR, ret); + EXPECT_EQ(ARRAY_SIZE(serverId), count); + + for (size_t i = 0; i < (size_t)count; i++) { + BinderLibTestBundle replyi(&reply); + EXPECT_TRUE(replyi.isValid()); + ret = replyi.readInt32(&id); + EXPECT_EQ(NO_ERROR, ret); + EXPECT_EQ(serverId[i], id); + EXPECT_EQ(replyi.dataSize(), replyi.dataPosition()); + } + + EXPECT_EQ(reply.dataSize(), reply.dataPosition()); +} + +TEST_F(BinderLibTest, IndirectGetId3) +{ + status_t ret; + int32_t id; + int32_t count; + Parcel data, reply; + int32_t serverId[3]; + + data.writeInt32(ARRAY_SIZE(serverId)); + for (size_t i = 0; i < ARRAY_SIZE(serverId); i++) { + sp<IBinder> server; + BinderLibTestBundle datai; + BinderLibTestBundle datai2; + + server = addServer(&serverId[i]); + ASSERT_TRUE(server != NULL); + data.writeStrongBinder(server); + data.writeInt32(BINDER_LIB_TEST_INDIRECT_TRANSACTION); + + datai.writeInt32(1); + datai.writeStrongBinder(m_server); + datai.writeInt32(BINDER_LIB_TEST_GET_ID_TRANSACTION); + datai2.appendTo(&datai); + + datai.appendTo(&data); + } + + ret = m_server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION, data, &reply); + ASSERT_EQ(NO_ERROR, ret); + + ret = reply.readInt32(&id); + ASSERT_EQ(NO_ERROR, ret); + EXPECT_EQ(0, id); + + ret = reply.readInt32(&count); + ASSERT_EQ(NO_ERROR, ret); + EXPECT_EQ(ARRAY_SIZE(serverId), count); + + for (size_t i = 0; i < (size_t)count; i++) { + int32_t counti; + + BinderLibTestBundle replyi(&reply); + EXPECT_TRUE(replyi.isValid()); + ret = replyi.readInt32(&id); + EXPECT_EQ(NO_ERROR, ret); + EXPECT_EQ(serverId[i], id); + + ret = replyi.readInt32(&counti); + ASSERT_EQ(NO_ERROR, ret); + EXPECT_EQ(1, counti); + + BinderLibTestBundle replyi2(&replyi); + EXPECT_TRUE(replyi2.isValid()); + ret = replyi2.readInt32(&id); + EXPECT_EQ(NO_ERROR, ret); + EXPECT_EQ(0, id); + EXPECT_EQ(replyi2.dataSize(), replyi2.dataPosition()); + + EXPECT_EQ(replyi.dataSize(), replyi.dataPosition()); + } + + EXPECT_EQ(reply.dataSize(), reply.dataPosition()); +} + +TEST_F(BinderLibTest, CallBack) +{ + status_t ret; + Parcel data, reply; + sp<BinderLibTestCallBack> callBack = new BinderLibTestCallBack(); + data.writeStrongBinder(callBack); + ret = m_server->transact(BINDER_LIB_TEST_NOP_CALL_BACK, data, &reply, TF_ONE_WAY); + EXPECT_EQ(NO_ERROR, ret); + ret = callBack->waitEvent(5); + EXPECT_EQ(NO_ERROR, ret); + ret = callBack->getResult(); + EXPECT_EQ(NO_ERROR, ret); +} + +TEST_F(BinderLibTest, AddServer) +{ + sp<IBinder> server = addServer(); + ASSERT_TRUE(server != NULL); +} + +TEST_F(BinderLibTest, DeathNotificationNoRefs) +{ + status_t ret; + + sp<TestDeathRecipient> testDeathRecipient = new TestDeathRecipient(); + + { + sp<IBinder> binder = addServer(); + ASSERT_TRUE(binder != NULL); + ret = binder->linkToDeath(testDeathRecipient); + EXPECT_EQ(NO_ERROR, ret); + } + IPCThreadState::self()->flushCommands(); + ret = testDeathRecipient->waitEvent(5); + EXPECT_EQ(NO_ERROR, ret); +#if 0 /* Is there an unlink api that does not require a strong reference? */ + ret = binder->unlinkToDeath(testDeathRecipient); + EXPECT_EQ(NO_ERROR, ret); +#endif +} + +TEST_F(BinderLibTest, DeathNotificationWeakRef) +{ + status_t ret; + wp<IBinder> wbinder; + + sp<TestDeathRecipient> testDeathRecipient = new TestDeathRecipient(); + + { + sp<IBinder> binder = addServer(); + ASSERT_TRUE(binder != NULL); + ret = binder->linkToDeath(testDeathRecipient); + EXPECT_EQ(NO_ERROR, ret); + wbinder = binder; + } + IPCThreadState::self()->flushCommands(); + ret = testDeathRecipient->waitEvent(5); + EXPECT_EQ(NO_ERROR, ret); +#if 0 /* Is there an unlink api that does not require a strong reference? */ + ret = binder->unlinkToDeath(testDeathRecipient); + EXPECT_EQ(NO_ERROR, ret); +#endif +} + +TEST_F(BinderLibTest, DeathNotificationStrongRef) +{ + status_t ret; + sp<IBinder> sbinder; + + sp<TestDeathRecipient> testDeathRecipient = new TestDeathRecipient(); + + { + sp<IBinder> binder = addServer(); + ASSERT_TRUE(binder != NULL); + ret = binder->linkToDeath(testDeathRecipient); + EXPECT_EQ(NO_ERROR, ret); + sbinder = binder; + } + { + Parcel data, reply; + ret = sbinder->transact(BINDER_LIB_TEST_EXIT_TRANSACTION, data, &reply, TF_ONE_WAY); + EXPECT_EQ(0, ret); + } + IPCThreadState::self()->flushCommands(); + ret = testDeathRecipient->waitEvent(5); + EXPECT_EQ(NO_ERROR, ret); + ret = sbinder->unlinkToDeath(testDeathRecipient); + EXPECT_EQ(DEAD_OBJECT, ret); +} + +TEST_F(BinderLibTest, DeathNotificationMultiple) +{ + status_t ret; + const int clientcount = 2; + sp<IBinder> target; + sp<IBinder> linkedclient[clientcount]; + sp<BinderLibTestCallBack> callBack[clientcount]; + sp<IBinder> passiveclient[clientcount]; + + target = addServer(); + ASSERT_TRUE(target != NULL); + for (int i = 0; i < clientcount; i++) { + { + Parcel data, reply; + + linkedclient[i] = addServer(); + ASSERT_TRUE(linkedclient[i] != NULL); + callBack[i] = new BinderLibTestCallBack(); + data.writeStrongBinder(target); + data.writeStrongBinder(callBack[i]); + ret = linkedclient[i]->transact(BINDER_LIB_TEST_LINK_DEATH_TRANSACTION, data, &reply, TF_ONE_WAY); + EXPECT_EQ(NO_ERROR, ret); + } + { + Parcel data, reply; + + passiveclient[i] = addServer(); + ASSERT_TRUE(passiveclient[i] != NULL); + data.writeStrongBinder(target); + ret = passiveclient[i]->transact(BINDER_LIB_TEST_ADD_STRONG_REF_TRANSACTION, data, &reply, TF_ONE_WAY); + EXPECT_EQ(NO_ERROR, ret); + } + } + { + Parcel data, reply; + ret = target->transact(BINDER_LIB_TEST_EXIT_TRANSACTION, data, &reply, TF_ONE_WAY); + EXPECT_EQ(0, ret); + } + + for (int i = 0; i < clientcount; i++) { + ret = callBack[i]->waitEvent(5); + EXPECT_EQ(NO_ERROR, ret); + ret = callBack[i]->getResult(); + EXPECT_EQ(NO_ERROR, ret); + } +} + +TEST_F(BinderLibTest, PassFile) { + int ret; + int pipefd[2]; + uint8_t buf[1] = { 0 }; + uint8_t write_value = 123; + + ret = pipe2(pipefd, O_NONBLOCK); + ASSERT_EQ(0, ret); + + { + Parcel data, reply; + uint8_t writebuf[1] = { write_value }; + + ret = data.writeFileDescriptor(pipefd[1], true); + EXPECT_EQ(NO_ERROR, ret); + + ret = data.writeInt32(sizeof(writebuf)); + EXPECT_EQ(NO_ERROR, ret); + + ret = data.write(writebuf, sizeof(writebuf)); + EXPECT_EQ(NO_ERROR, ret); + + ret = m_server->transact(BINDER_LIB_TEST_WRITE_FILE_TRANSACTION, data, &reply); + EXPECT_EQ(NO_ERROR, ret); + } + + ret = read(pipefd[0], buf, sizeof(buf)); + EXPECT_EQ(sizeof(buf), ret); + EXPECT_EQ(write_value, buf[0]); + + waitForReadData(pipefd[0], 5000); /* wait for other proccess to close pipe */ + + ret = read(pipefd[0], buf, sizeof(buf)); + EXPECT_EQ(0, ret); + + close(pipefd[0]); +} + +TEST_F(BinderLibTest, PromoteLocal) { + sp<IBinder> strong = new BBinder(); + wp<IBinder> weak = strong; + sp<IBinder> strong_from_weak = weak.promote(); + EXPECT_TRUE(strong != NULL); + EXPECT_EQ(strong, strong_from_weak); + strong = NULL; + strong_from_weak = NULL; + strong_from_weak = weak.promote(); + EXPECT_TRUE(strong_from_weak == NULL); +} + +TEST_F(BinderLibTest, PromoteRemote) { + int ret; + Parcel data, reply; + sp<IBinder> strong = new BBinder(); + sp<IBinder> server = addServer(); + + ASSERT_TRUE(server != NULL); + ASSERT_TRUE(strong != NULL); + + ret = data.writeWeakBinder(strong); + EXPECT_EQ(NO_ERROR, ret); + + ret = server->transact(BINDER_LIB_TEST_PROMOTE_WEAK_REF_TRANSACTION, data, &reply); + EXPECT_GE(ret, 0); +} + +class BinderLibTestService : public BBinder +{ + public: + BinderLibTestService(int32_t id) + : m_id(id) + , m_nextServerId(id + 1) + , m_serverStartRequested(false) + { + pthread_mutex_init(&m_serverWaitMutex, NULL); + pthread_cond_init(&m_serverWaitCond, NULL); + } + ~BinderLibTestService() + { + exit(EXIT_SUCCESS); + } + virtual status_t onTransact(uint32_t code, + const Parcel& data, Parcel* reply, + uint32_t flags = 0) { + //printf("%s: code %d\n", __func__, code); + (void)flags; + + if (getuid() != (uid_t)IPCThreadState::self()->getCallingUid()) { + return PERMISSION_DENIED; + } + switch (code) { + case BINDER_LIB_TEST_REGISTER_SERVER: { + int32_t id; + sp<IBinder> binder; + id = data.readInt32(); + binder = data.readStrongBinder(); + if (binder == NULL) { + return BAD_VALUE; + } + + if (m_id != 0) + return INVALID_OPERATION; + + pthread_mutex_lock(&m_serverWaitMutex); + if (m_serverStartRequested) { + m_serverStartRequested = false; + m_serverStarted = binder; + pthread_cond_signal(&m_serverWaitCond); + } + pthread_mutex_unlock(&m_serverWaitMutex); + return NO_ERROR; + } + case BINDER_LIB_TEST_ADD_SERVER: { + int ret; + uint8_t buf[1] = { 0 }; + int serverid; + + if (m_id != 0) { + return INVALID_OPERATION; + } + pthread_mutex_lock(&m_serverWaitMutex); + if (m_serverStartRequested) { + ret = -EBUSY; + } else { + serverid = m_nextServerId++; + m_serverStartRequested = true; + + pthread_mutex_unlock(&m_serverWaitMutex); + ret = start_server_process(serverid); + pthread_mutex_lock(&m_serverWaitMutex); + } + if (ret > 0) { + if (m_serverStartRequested) { +#if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE) + ret = pthread_cond_timeout_np(&m_serverWaitCond, &m_serverWaitMutex, 5000); +#else + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += 5; + ret = pthread_cond_timedwait(&m_serverWaitCond, &m_serverWaitMutex, &ts); +#endif + } + if (m_serverStartRequested) { + m_serverStartRequested = false; + ret = -ETIMEDOUT; + } else { + reply->writeStrongBinder(m_serverStarted); + reply->writeInt32(serverid); + m_serverStarted = NULL; + ret = NO_ERROR; + } + } else if (ret >= 0) { + m_serverStartRequested = false; + ret = UNKNOWN_ERROR; + } + pthread_mutex_unlock(&m_serverWaitMutex); + return ret; + } + case BINDER_LIB_TEST_NOP_TRANSACTION: + return NO_ERROR; + case BINDER_LIB_TEST_NOP_CALL_BACK: { + Parcel data2, reply2; + sp<IBinder> binder; + binder = data.readStrongBinder(); + if (binder == NULL) { + return BAD_VALUE; + } + reply2.writeInt32(NO_ERROR); + binder->transact(BINDER_LIB_TEST_CALL_BACK, data2, &reply2); + return NO_ERROR; + } + case BINDER_LIB_TEST_GET_ID_TRANSACTION: + reply->writeInt32(m_id); + return NO_ERROR; + case BINDER_LIB_TEST_INDIRECT_TRANSACTION: { + int32_t count; + uint32_t indirect_code; + sp<IBinder> binder; + + count = data.readInt32(); + reply->writeInt32(m_id); + reply->writeInt32(count); + for (int i = 0; i < count; i++) { + binder = data.readStrongBinder(); + if (binder == NULL) { + return BAD_VALUE; + } + indirect_code = data.readInt32(); + BinderLibTestBundle data2(&data); + if (!data2.isValid()) { + return BAD_VALUE; + } + BinderLibTestBundle reply2; + binder->transact(indirect_code, data2, &reply2); + reply2.appendTo(reply); + } + return NO_ERROR; + } + case BINDER_LIB_TEST_SET_ERROR_TRANSACTION: + reply->setError(data.readInt32()); + return NO_ERROR; + case BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION: + reply->writeInt32(sizeof(void *)); + return NO_ERROR; + case BINDER_LIB_TEST_GET_STATUS_TRANSACTION: + return NO_ERROR; + case BINDER_LIB_TEST_ADD_STRONG_REF_TRANSACTION: + m_strongRef = data.readStrongBinder(); + return NO_ERROR; + case BINDER_LIB_TEST_LINK_DEATH_TRANSACTION: { + int ret; + Parcel data2, reply2; + sp<TestDeathRecipient> testDeathRecipient = new TestDeathRecipient(); + sp<IBinder> target; + sp<IBinder> callback; + + target = data.readStrongBinder(); + if (target == NULL) { + return BAD_VALUE; + } + callback = data.readStrongBinder(); + if (callback == NULL) { + return BAD_VALUE; + } + ret = target->linkToDeath(testDeathRecipient); + if (ret == NO_ERROR) + ret = testDeathRecipient->waitEvent(5); + data2.writeInt32(ret); + callback->transact(BINDER_LIB_TEST_CALL_BACK, data2, &reply2); + return NO_ERROR; + } + case BINDER_LIB_TEST_WRITE_FILE_TRANSACTION: { + int ret; + int32_t size; + const void *buf; + int fd; + + fd = data.readFileDescriptor(); + if (fd < 0) { + return BAD_VALUE; + } + ret = data.readInt32(&size); + if (ret != NO_ERROR) { + return ret; + } + buf = data.readInplace(size); + if (buf == NULL) { + return BAD_VALUE; + } + ret = write(fd, buf, size); + if (ret != size) + return UNKNOWN_ERROR; + return NO_ERROR; + } + case BINDER_LIB_TEST_PROMOTE_WEAK_REF_TRANSACTION: { + int ret; + wp<IBinder> weak; + sp<IBinder> strong; + Parcel data2, reply2; + sp<IServiceManager> sm = defaultServiceManager(); + sp<IBinder> server = sm->getService(binderLibTestServiceName); + + weak = data.readWeakBinder(); + if (weak == NULL) { + return BAD_VALUE; + } + strong = weak.promote(); + + ret = server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data2, &reply2); + if (ret != NO_ERROR) + exit(EXIT_FAILURE); + + if (strong == NULL) { + reply->setError(1); + } + return NO_ERROR; + } + case BINDER_LIB_TEST_DELAYED_EXIT_TRANSACTION: + alarm(10); + return NO_ERROR; + case BINDER_LIB_TEST_EXIT_TRANSACTION: + while (wait(NULL) != -1 || errno != ECHILD) + ; + exit(EXIT_SUCCESS); + default: + return UNKNOWN_TRANSACTION; + }; + } + private: + int32_t m_id; + int32_t m_nextServerId; + pthread_mutex_t m_serverWaitMutex; + pthread_cond_t m_serverWaitCond; + bool m_serverStartRequested; + sp<IBinder> m_serverStarted; + sp<IBinder> m_strongRef; +}; + +int run_server(int index, int readypipefd) +{ + status_t ret; + sp<IServiceManager> sm = defaultServiceManager(); + { + sp<BinderLibTestService> testService = new BinderLibTestService(index); + if (index == 0) { + ret = sm->addService(binderLibTestServiceName, testService); + } else { + sp<IBinder> server = sm->getService(binderLibTestServiceName); + Parcel data, reply; + data.writeInt32(index); + data.writeStrongBinder(testService); + + ret = server->transact(BINDER_LIB_TEST_REGISTER_SERVER, data, &reply); + } + } + write(readypipefd, &ret, sizeof(ret)); + close(readypipefd); + //printf("%s: ret %d\n", __func__, ret); + if (ret) + return 1; + //printf("%s: joinThreadPool\n", __func__); + ProcessState::self()->startThreadPool(); + IPCThreadState::self()->joinThreadPool(); + //printf("%s: joinThreadPool returned\n", __func__); + return 1; /* joinThreadPool should not return */ +} + +int main(int argc, char **argv) { + int ret; + + if (argc == 3 && !strcmp(argv[1], "--servername")) { + binderservername = argv[2]; + } else { + binderservername = argv[0]; + } + + if (argc == 4 && !strcmp(argv[1], binderserverarg)) { + return run_server(atoi(argv[2]), atoi(argv[3])); + } + + ::testing::InitGoogleTest(&argc, argv); + binder_env = AddGlobalTestEnvironment(new BinderLibTestEnv()); + ProcessState::self()->startThreadPool(); + return RUN_ALL_TESTS(); +} + diff --git a/libs/diskusage/dirsize.c b/libs/diskusage/dirsize.c index 24e5af02ab..7576994c0f 100644 --- a/libs/diskusage/dirsize.c +++ b/libs/diskusage/dirsize.c @@ -18,6 +18,7 @@ #include <dirent.h> #include <fcntl.h> #include <sys/stat.h> +#include <unistd.h> #include <diskusage/dirsize.h> diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk index ca94aa3990..8a965dddfc 100644 --- a/libs/gui/Android.mk +++ b/libs/gui/Android.mk @@ -1,7 +1,42 @@ -LOCAL_PATH:= $(call my-dir) +# Copyright 2010 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) include $(CLEAR_VARS) -LOCAL_SRC_FILES:= \ +LOCAL_CLANG := true +LOCAL_CPPFLAGS := -std=c++1y -Weverything -Werror + +# The static constructors and destructors in this library have not been noted to +# introduce significant overheads +LOCAL_CPPFLAGS += -Wno-exit-time-destructors +LOCAL_CPPFLAGS += -Wno-global-constructors + +# We only care about compiling as C++14 +LOCAL_CPPFLAGS += -Wno-c++98-compat-pedantic + +# We don't need to enumerate every case in a switch as long as a default case +# is present +LOCAL_CPPFLAGS += -Wno-switch-enum + +# Allow calling variadic macros without a __VA_ARGS__ list +LOCAL_CPPFLAGS += -Wno-gnu-zero-variadic-macro-arguments + +# Don't warn about struct padding +LOCAL_CPPFLAGS += -Wno-padded + +LOCAL_SRC_FILES := \ IGraphicBufferConsumer.cpp \ IConsumerListener.cpp \ BitTube.cpp \ @@ -47,7 +82,7 @@ LOCAL_SHARED_LIBRARIES := \ liblog -LOCAL_MODULE:= libgui +LOCAL_MODULE := libgui ifeq ($(TARGET_BOARD_PLATFORM), tegra) LOCAL_CFLAGS += -DDONT_USE_FENCE_SYNC diff --git a/libs/gui/BitTube.cpp b/libs/gui/BitTube.cpp index 3ed1f370a5..b653c5b69c 100644 --- a/libs/gui/BitTube.cpp +++ b/libs/gui/BitTube.cpp @@ -149,12 +149,12 @@ ssize_t BitTube::sendObjects(const sp<BitTube>& tube, ssize_t size = tube->write(vaddr, count*objSize); // should never happen because of SOCK_SEQPACKET - LOG_ALWAYS_FATAL_IF((size >= 0) && (size % objSize), + LOG_ALWAYS_FATAL_IF((size >= 0) && (size % static_cast<ssize_t>(objSize)), "BitTube::sendObjects(count=%zu, size=%zu), res=%zd (partial events were sent!)", count, objSize, size); //ALOGE_IF(size<0, "error %d sending %d events", size, count); - return size < 0 ? size : size / objSize; + return size < 0 ? size : size / static_cast<ssize_t>(objSize); } ssize_t BitTube::recvObjects(const sp<BitTube>& tube, @@ -164,12 +164,12 @@ ssize_t BitTube::recvObjects(const sp<BitTube>& tube, ssize_t size = tube->read(vaddr, count*objSize); // should never happen because of SOCK_SEQPACKET - LOG_ALWAYS_FATAL_IF((size >= 0) && (size % objSize), + LOG_ALWAYS_FATAL_IF((size >= 0) && (size % static_cast<ssize_t>(objSize)), "BitTube::recvObjects(count=%zu, size=%zu), res=%zd (partial events were received!)", count, objSize, size); //ALOGE_IF(size<0, "error %d receiving %d events", size, count); - return size < 0 ? size : size / objSize; + return size < 0 ? size : size / static_cast<ssize_t>(objSize); } // ---------------------------------------------------------------------------- diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp index e6fc791198..8f64ae0e04 100644 --- a/libs/gui/BufferItem.cpp +++ b/libs/gui/BufferItem.cpp @@ -28,6 +28,7 @@ BufferItem::BufferItem() : mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mTimestamp(0), mIsAutoTimestamp(false), + mDataSpace(HAL_DATASPACE_UNKNOWN), mFrameNumber(0), mSlot(INVALID_BUFFER_SLOT), mIsDroppable(false), @@ -38,66 +39,67 @@ BufferItem::BufferItem() : BufferItem::~BufferItem() {} -BufferItem::operator IGraphicBufferConsumer::BufferItem() const { - IGraphicBufferConsumer::BufferItem bufferItem; - bufferItem.mGraphicBuffer = mGraphicBuffer; - bufferItem.mFence = mFence; - bufferItem.mCrop = mCrop; - bufferItem.mTransform = mTransform; - bufferItem.mScalingMode = mScalingMode; - bufferItem.mTimestamp = mTimestamp; - bufferItem.mIsAutoTimestamp = mIsAutoTimestamp; - bufferItem.mFrameNumber = mFrameNumber; - bufferItem.mBuf = mSlot; - bufferItem.mIsDroppable = mIsDroppable; - bufferItem.mAcquireCalled = mAcquireCalled; - bufferItem.mTransformToDisplayInverse = mTransformToDisplayInverse; - return bufferItem; +template <typename T> +static void addAligned(size_t& size, T /* value */) { + size = FlattenableUtils::align<sizeof(T)>(size); + size += sizeof(T); } size_t BufferItem::getPodSize() const { - size_t c = sizeof(mCrop) + - sizeof(mTransform) + - sizeof(mScalingMode) + - sizeof(mTimestamp) + - sizeof(mIsAutoTimestamp) + - sizeof(mFrameNumber) + - sizeof(mSlot) + - sizeof(mIsDroppable) + - sizeof(mAcquireCalled) + - sizeof(mTransformToDisplayInverse); - return c; + size_t size = 0; + addAligned(size, mCrop); + addAligned(size, mTransform); + addAligned(size, mScalingMode); + addAligned(size, mTimestampLo); + addAligned(size, mTimestampHi); + addAligned(size, mIsAutoTimestamp); + addAligned(size, mDataSpace); + addAligned(size, mFrameNumberLo); + addAligned(size, mFrameNumberHi); + addAligned(size, mSlot); + addAligned(size, mIsDroppable); + addAligned(size, mAcquireCalled); + addAligned(size, mTransformToDisplayInverse); + return size; } size_t BufferItem::getFlattenedSize() const { - size_t c = 0; + size_t size = sizeof(uint32_t); // Flags if (mGraphicBuffer != 0) { - c += mGraphicBuffer->getFlattenedSize(); - FlattenableUtils::align<4>(c); + size += mGraphicBuffer->getFlattenedSize(); + FlattenableUtils::align<4>(size); } if (mFence != 0) { - c += mFence->getFlattenedSize(); - FlattenableUtils::align<4>(c); + size += mFence->getFlattenedSize(); + FlattenableUtils::align<4>(size); } - return sizeof(int32_t) + c + getPodSize(); + size += mSurfaceDamage.getFlattenedSize(); + size = FlattenableUtils::align<8>(size); + return size + getPodSize(); } size_t BufferItem::getFdCount() const { - size_t c = 0; + size_t count = 0; if (mGraphicBuffer != 0) { - c += mGraphicBuffer->getFdCount(); + count += mGraphicBuffer->getFdCount(); } if (mFence != 0) { - c += mFence->getFdCount(); + count += mFence->getFdCount(); } - return c; + return count; +} + +template <typename T> +static void writeAligned(void*& buffer, size_t& size, T value) { + size -= FlattenableUtils::align<alignof(T)>(buffer); + FlattenableUtils::write(buffer, size, value); } status_t BufferItem::flatten( void*& buffer, size_t& size, int*& fds, size_t& count) const { // make sure we have enough space - if (count < BufferItem::getFlattenedSize()) { + if (size < BufferItem::getFlattenedSize()) { return NO_MEMORY; } @@ -121,30 +123,44 @@ status_t BufferItem::flatten( flags |= 2; } - // check we have enough space (in case flattening the fence/graphicbuffer lied to us) + status_t err = mSurfaceDamage.flatten(buffer, size); + if (err) return err; + FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize()); + + // Check we still have enough space if (size < getPodSize()) { return NO_MEMORY; } - FlattenableUtils::write(buffer, size, mCrop); - FlattenableUtils::write(buffer, size, mTransform); - FlattenableUtils::write(buffer, size, mScalingMode); - FlattenableUtils::write(buffer, size, mTimestamp); - FlattenableUtils::write(buffer, size, mIsAutoTimestamp); - FlattenableUtils::write(buffer, size, mFrameNumber); - FlattenableUtils::write(buffer, size, mSlot); - FlattenableUtils::write(buffer, size, mIsDroppable); - FlattenableUtils::write(buffer, size, mAcquireCalled); - FlattenableUtils::write(buffer, size, mTransformToDisplayInverse); + writeAligned(buffer, size, mCrop); + writeAligned(buffer, size, mTransform); + writeAligned(buffer, size, mScalingMode); + writeAligned(buffer, size, mTimestampLo); + writeAligned(buffer, size, mTimestampHi); + writeAligned(buffer, size, mIsAutoTimestamp); + writeAligned(buffer, size, mDataSpace); + writeAligned(buffer, size, mFrameNumberLo); + writeAligned(buffer, size, mFrameNumberHi); + writeAligned(buffer, size, mSlot); + writeAligned(buffer, size, mIsDroppable); + writeAligned(buffer, size, mAcquireCalled); + writeAligned(buffer, size, mTransformToDisplayInverse); return NO_ERROR; } +template <typename T> +static void readAligned(const void*& buffer, size_t& size, T& value) { + size -= FlattenableUtils::align<alignof(T)>(buffer); + FlattenableUtils::read(buffer, size, value); +} + status_t BufferItem::unflatten( void const*& buffer, size_t& size, int const*& fds, size_t& count) { - if (size < sizeof(uint32_t)) + if (size < sizeof(uint32_t)) { return NO_MEMORY; + } uint32_t flags = 0; FlattenableUtils::read(buffer, size, flags); @@ -163,21 +179,28 @@ status_t BufferItem::unflatten( size -= FlattenableUtils::align<4>(buffer); } - // check we have enough space + status_t err = mSurfaceDamage.unflatten(buffer, size); + if (err) return err; + FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize()); + + // Check we still have enough space if (size < getPodSize()) { return NO_MEMORY; } - FlattenableUtils::read(buffer, size, mCrop); - FlattenableUtils::read(buffer, size, mTransform); - FlattenableUtils::read(buffer, size, mScalingMode); - FlattenableUtils::read(buffer, size, mTimestamp); - FlattenableUtils::read(buffer, size, mIsAutoTimestamp); - FlattenableUtils::read(buffer, size, mFrameNumber); - FlattenableUtils::read(buffer, size, mSlot); - FlattenableUtils::read(buffer, size, mIsDroppable); - FlattenableUtils::read(buffer, size, mAcquireCalled); - FlattenableUtils::read(buffer, size, mTransformToDisplayInverse); + readAligned(buffer, size, mCrop); + readAligned(buffer, size, mTransform); + readAligned(buffer, size, mScalingMode); + readAligned(buffer, size, mTimestampLo); + readAligned(buffer, size, mTimestampHi); + readAligned(buffer, size, mIsAutoTimestamp); + readAligned(buffer, size, mDataSpace); + readAligned(buffer, size, mFrameNumberLo); + readAligned(buffer, size, mFrameNumberHi); + readAligned(buffer, size, mSlot); + readAligned(buffer, size, mIsDroppable); + readAligned(buffer, size, mAcquireCalled); + readAligned(buffer, size, mTransformToDisplayInverse); return NO_ERROR; } diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp index fe50c55f51..578b8d96b1 100644 --- a/libs/gui/BufferItemConsumer.cpp +++ b/libs/gui/BufferItemConsumer.cpp @@ -16,16 +16,17 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "BufferItemConsumer" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS +//#define ATRACE_TAG ATRACE_TAG_GRAPHICS #include <utils/Log.h> +#include <gui/BufferItem.h> #include <gui/BufferItemConsumer.h> -#define BI_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__) -#define BI_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__) -#define BI_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__) -#define BI_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) -#define BI_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) +//#define BI_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) +//#define BI_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) +//#define BI_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) +//#define BI_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) +#define BI_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) namespace android { @@ -44,8 +45,7 @@ BufferItemConsumer::BufferItemConsumer( } } -BufferItemConsumer::~BufferItemConsumer() { -} +BufferItemConsumer::~BufferItemConsumer() {} void BufferItemConsumer::setName(const String8& name) { Mutex::Autolock _l(mMutex); @@ -100,14 +100,4 @@ status_t BufferItemConsumer::releaseBuffer(const BufferItem &item, return err; } -status_t BufferItemConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) { - Mutex::Autolock _l(mMutex); - return mConsumer->setDefaultBufferSize(w, h); -} - -status_t BufferItemConsumer::setDefaultBufferFormat(uint32_t defaultFormat) { - Mutex::Autolock _l(mMutex); - return mConsumer->setDefaultBufferFormat(defaultFormat); -} - } // namespace android diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 61fd8c42de..ccbb5a25f3 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -32,13 +32,21 @@ BufferQueue::ProxyConsumerListener::ProxyConsumerListener( BufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {} void BufferQueue::ProxyConsumerListener::onFrameAvailable( - const android::BufferItem& item) { + const BufferItem& item) { sp<ConsumerListener> listener(mConsumerListener.promote()); if (listener != NULL) { listener->onFrameAvailable(item); } } +void BufferQueue::ProxyConsumerListener::onFrameReplaced( + const BufferItem& item) { + sp<ConsumerListener> listener(mConsumerListener.promote()); + if (listener != NULL) { + listener->onFrameReplaced(item); + } +} + void BufferQueue::ProxyConsumerListener::onBuffersReleased() { sp<ConsumerListener> listener(mConsumerListener.promote()); if (listener != NULL) { diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index bc6f3f012a..7aea4bb742 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -40,142 +40,170 @@ BufferQueueConsumer::BufferQueueConsumer(const sp<BufferQueueCore>& core) : BufferQueueConsumer::~BufferQueueConsumer() {} status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, - nsecs_t expectedPresent) { + nsecs_t expectedPresent, uint64_t maxFrameNumber) { ATRACE_CALL(); - Mutex::Autolock lock(mCore->mMutex); - // Check that the consumer doesn't currently have the maximum number of - // buffers acquired. We allow the max buffer count to be exceeded by one - // buffer so that the consumer can successfully set up the newly acquired - // buffer before releasing the old one. - int numAcquiredBuffers = 0; - for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) { - ++numAcquiredBuffers; + int numDroppedBuffers = 0; + sp<IProducerListener> listener; + { + Mutex::Autolock lock(mCore->mMutex); + + // Check that the consumer doesn't currently have the maximum number of + // buffers acquired. We allow the max buffer count to be exceeded by one + // buffer so that the consumer can successfully set up the newly acquired + // buffer before releasing the old one. + int numAcquiredBuffers = 0; + for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { + if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) { + ++numAcquiredBuffers; + } + } + if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) { + BQ_LOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)", + numAcquiredBuffers, mCore->mMaxAcquiredBufferCount); + return INVALID_OPERATION; } - } - if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) { - BQ_LOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)", - numAcquiredBuffers, mCore->mMaxAcquiredBufferCount); - return INVALID_OPERATION; - } - // Check if the queue is empty. - // In asynchronous mode the list is guaranteed to be one buffer deep, - // while in synchronous mode we use the oldest buffer. - if (mCore->mQueue.empty()) { - return NO_BUFFER_AVAILABLE; - } + // Check if the queue is empty. + // In asynchronous mode the list is guaranteed to be one buffer deep, + // while in synchronous mode we use the oldest buffer. + if (mCore->mQueue.empty()) { + return NO_BUFFER_AVAILABLE; + } + + BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin()); - BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin()); - - // If expectedPresent is specified, we may not want to return a buffer yet. - // If it's specified and there's more than one buffer queued, we may want - // to drop a buffer. - if (expectedPresent != 0) { - const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second - - // The 'expectedPresent' argument indicates when the buffer is expected - // to be presented on-screen. If the buffer's desired present time is - // earlier (less) than expectedPresent -- meaning it will be displayed - // on time or possibly late if we show it as soon as possible -- we - // acquire and return it. If we don't want to display it until after the - // expectedPresent time, we return PRESENT_LATER without acquiring it. - // - // To be safe, we don't defer acquisition if expectedPresent is more - // than one second in the future beyond the desired present time - // (i.e., we'd be holding the buffer for a long time). - // - // NOTE: Code assumes monotonic time values from the system clock - // are positive. - - // Start by checking to see if we can drop frames. We skip this check if - // the timestamps are being auto-generated by Surface. If the app isn't - // generating timestamps explicitly, it probably doesn't want frames to - // be discarded based on them. - while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) { - // If entry[1] is timely, drop entry[0] (and repeat). We apply an - // additional criterion here: we only drop the earlier buffer if our - // desiredPresent falls within +/- 1 second of the expected present. - // Otherwise, bogus desiredPresent times (e.g., 0 or a small - // relative timestamp), which normally mean "ignore the timestamp - // and acquire immediately", would cause us to drop frames. + // If expectedPresent is specified, we may not want to return a buffer yet. + // If it's specified and there's more than one buffer queued, we may want + // to drop a buffer. + if (expectedPresent != 0) { + const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second + + // The 'expectedPresent' argument indicates when the buffer is expected + // to be presented on-screen. If the buffer's desired present time is + // earlier (less) than expectedPresent -- meaning it will be displayed + // on time or possibly late if we show it as soon as possible -- we + // acquire and return it. If we don't want to display it until after the + // expectedPresent time, we return PRESENT_LATER without acquiring it. // - // We may want to add an additional criterion: don't drop the - // earlier buffer if entry[1]'s fence hasn't signaled yet. - const BufferItem& bufferItem(mCore->mQueue[1]); - nsecs_t desiredPresent = bufferItem.mTimestamp; - if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC || - desiredPresent > expectedPresent) { - // This buffer is set to display in the near future, or - // desiredPresent is garbage. Either way we don't want to drop - // the previous buffer just to get this on the screen sooner. - BQ_LOGV("acquireBuffer: nodrop desire=%" PRId64 " expect=%" - PRId64 " (%" PRId64 ") now=%" PRId64, - desiredPresent, expectedPresent, - desiredPresent - expectedPresent, - systemTime(CLOCK_MONOTONIC)); - break; + // To be safe, we don't defer acquisition if expectedPresent is more + // than one second in the future beyond the desired present time + // (i.e., we'd be holding the buffer for a long time). + // + // NOTE: Code assumes monotonic time values from the system clock + // are positive. + + // Start by checking to see if we can drop frames. We skip this check if + // the timestamps are being auto-generated by Surface. If the app isn't + // generating timestamps explicitly, it probably doesn't want frames to + // be discarded based on them. + while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) { + const BufferItem& bufferItem(mCore->mQueue[1]); + + // If dropping entry[0] would leave us with a buffer that the + // consumer is not yet ready for, don't drop it. + if (maxFrameNumber && bufferItem.mFrameNumber > maxFrameNumber) { + break; + } + + // If entry[1] is timely, drop entry[0] (and repeat). We apply an + // additional criterion here: we only drop the earlier buffer if our + // desiredPresent falls within +/- 1 second of the expected present. + // Otherwise, bogus desiredPresent times (e.g., 0 or a small + // relative timestamp), which normally mean "ignore the timestamp + // and acquire immediately", would cause us to drop frames. + // + // We may want to add an additional criterion: don't drop the + // earlier buffer if entry[1]'s fence hasn't signaled yet. + nsecs_t desiredPresent = bufferItem.mTimestamp; + if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC || + desiredPresent > expectedPresent) { + // This buffer is set to display in the near future, or + // desiredPresent is garbage. Either way we don't want to drop + // the previous buffer just to get this on the screen sooner. + BQ_LOGV("acquireBuffer: nodrop desire=%" PRId64 " expect=%" + PRId64 " (%" PRId64 ") now=%" PRId64, + desiredPresent, expectedPresent, + desiredPresent - expectedPresent, + systemTime(CLOCK_MONOTONIC)); + break; + } + + BQ_LOGV("acquireBuffer: drop desire=%" PRId64 " expect=%" PRId64 + " size=%zu", + desiredPresent, expectedPresent, mCore->mQueue.size()); + if (mCore->stillTracking(front)) { + // Front buffer is still in mSlots, so mark the slot as free + mSlots[front->mSlot].mBufferState = BufferSlot::FREE; + mCore->mFreeBuffers.push_back(front->mSlot); + listener = mCore->mConnectedProducerListener; + ++numDroppedBuffers; + } + mCore->mQueue.erase(front); + front = mCore->mQueue.begin(); } - BQ_LOGV("acquireBuffer: drop desire=%" PRId64 " expect=%" PRId64 - " size=%zu", - desiredPresent, expectedPresent, mCore->mQueue.size()); - if (mCore->stillTracking(front)) { - // Front buffer is still in mSlots, so mark the slot as free - mSlots[front->mSlot].mBufferState = BufferSlot::FREE; + // See if the front buffer is ready to be acquired + nsecs_t desiredPresent = front->mTimestamp; + bool bufferIsDue = desiredPresent <= expectedPresent || + desiredPresent > expectedPresent + MAX_REASONABLE_NSEC; + bool consumerIsReady = maxFrameNumber > 0 ? + front->mFrameNumber <= maxFrameNumber : true; + if (!bufferIsDue || !consumerIsReady) { + BQ_LOGV("acquireBuffer: defer desire=%" PRId64 " expect=%" PRId64 + " (%" PRId64 ") now=%" PRId64 " frame=%" PRIu64 + " consumer=%" PRIu64, + desiredPresent, expectedPresent, + desiredPresent - expectedPresent, + systemTime(CLOCK_MONOTONIC), + front->mFrameNumber, maxFrameNumber); + return PRESENT_LATER; } - mCore->mQueue.erase(front); - front = mCore->mQueue.begin(); - } - // See if the front buffer is due - nsecs_t desiredPresent = front->mTimestamp; - if (desiredPresent > expectedPresent && - desiredPresent < expectedPresent + MAX_REASONABLE_NSEC) { - BQ_LOGV("acquireBuffer: defer desire=%" PRId64 " expect=%" PRId64 - " (%" PRId64 ") now=%" PRId64, - desiredPresent, expectedPresent, + BQ_LOGV("acquireBuffer: accept desire=%" PRId64 " expect=%" PRId64 " " + "(%" PRId64 ") now=%" PRId64, desiredPresent, expectedPresent, desiredPresent - expectedPresent, systemTime(CLOCK_MONOTONIC)); - return PRESENT_LATER; } - BQ_LOGV("acquireBuffer: accept desire=%" PRId64 " expect=%" PRId64 " " - "(%" PRId64 ") now=%" PRId64, desiredPresent, expectedPresent, - desiredPresent - expectedPresent, - systemTime(CLOCK_MONOTONIC)); - } + int slot = front->mSlot; + *outBuffer = *front; + ATRACE_BUFFER_INDEX(slot); - int slot = front->mSlot; - *outBuffer = *front; - ATRACE_BUFFER_INDEX(slot); + BQ_LOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }", + slot, front->mFrameNumber, front->mGraphicBuffer->handle); + // If the front buffer is still being tracked, update its slot state + if (mCore->stillTracking(front)) { + mSlots[slot].mAcquireCalled = true; + mSlots[slot].mNeedsCleanupOnRelease = false; + mSlots[slot].mBufferState = BufferSlot::ACQUIRED; + mSlots[slot].mFence = Fence::NO_FENCE; + } - BQ_LOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }", - slot, front->mFrameNumber, front->mGraphicBuffer->handle); - // If the front buffer is still being tracked, update its slot state - if (mCore->stillTracking(front)) { - mSlots[slot].mAcquireCalled = true; - mSlots[slot].mNeedsCleanupOnRelease = false; - mSlots[slot].mBufferState = BufferSlot::ACQUIRED; - mSlots[slot].mFence = Fence::NO_FENCE; - } + // If the buffer has previously been acquired by the consumer, set + // mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer + // on the consumer side + if (outBuffer->mAcquireCalled) { + outBuffer->mGraphicBuffer = NULL; + } - // If the buffer has previously been acquired by the consumer, set - // mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer - // on the consumer side - if (outBuffer->mAcquireCalled) { - outBuffer->mGraphicBuffer = NULL; - } + mCore->mQueue.erase(front); - mCore->mQueue.erase(front); + // We might have freed a slot while dropping old buffers, or the producer + // may be blocked waiting for the number of buffers in the queue to + // decrease. + mCore->mDequeueCondition.broadcast(); - // We might have freed a slot while dropping old buffers, or the producer - // may be blocked waiting for the number of buffers in the queue to - // decrease. - mCore->mDequeueCondition.broadcast(); + ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size()); - ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size()); + mCore->validateConsistencyLocked(); + } + + if (listener != NULL) { + for (int i = 0; i < numDroppedBuffers; ++i) { + listener->onBufferReleased(); + } + } return NO_ERROR; } @@ -203,6 +231,7 @@ status_t BufferQueueConsumer::detachBuffer(int slot) { mCore->freeBufferLocked(slot); mCore->mDequeueCondition.broadcast(); + mCore->validateConsistencyLocked(); return NO_ERROR; } @@ -221,18 +250,11 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot, Mutex::Autolock lock(mCore->mMutex); - // Make sure we don't have too many acquired buffers and find a free slot - // to put the buffer into (the oldest if there are multiple). + // Make sure we don't have too many acquired buffers int numAcquiredBuffers = 0; - int found = BufferQueueCore::INVALID_BUFFER_SLOT; for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) { ++numAcquiredBuffers; - } else if (mSlots[s].mBufferState == BufferSlot::FREE) { - if (found == BufferQueueCore::INVALID_BUFFER_SLOT || - mSlots[s].mFrameNumber < mSlots[found].mFrameNumber) { - found = s; - } } } @@ -242,6 +264,24 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot, mCore->mMaxAcquiredBufferCount); return INVALID_OPERATION; } + + if (buffer->getGenerationNumber() != mCore->mGenerationNumber) { + BQ_LOGE("attachBuffer: generation number mismatch [buffer %u] " + "[queue %u]", buffer->getGenerationNumber(), + mCore->mGenerationNumber); + return BAD_VALUE; + } + + // Find a free slot to put the buffer into + int found = BufferQueueCore::INVALID_BUFFER_SLOT; + if (!mCore->mFreeSlots.empty()) { + auto slot = mCore->mFreeSlots.begin(); + found = *slot; + mCore->mFreeSlots.erase(slot); + } else if (!mCore->mFreeBuffers.empty()) { + found = mCore->mFreeBuffers.front(); + mCore->mFreeBuffers.remove(found); + } if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { BQ_LOGE("attachBuffer(P): could not find free buffer slot"); return NO_MEMORY; @@ -275,6 +315,8 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot, // for attached buffers. mSlots[*outSlot].mAcquireCalled = false; + mCore->validateConsistencyLocked(); + return NO_ERROR; } @@ -286,6 +328,8 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS || releaseFence == NULL) { + BQ_LOGE("releaseBuffer: slot %d out of range or fence %p NULL", slot, + releaseFence.get()); return BAD_VALUE; } @@ -315,6 +359,7 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, mSlots[slot].mEglFence = eglFence; mSlots[slot].mFence = releaseFence; mSlots[slot].mBufferState = BufferSlot::FREE; + mCore->mFreeBuffers.push_back(slot); listener = mCore->mConnectedProducerListener; BQ_LOGV("releaseBuffer: releasing slot %d", slot); } else if (mSlots[slot].mNeedsCleanupOnRelease) { @@ -323,12 +368,13 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, mSlots[slot].mNeedsCleanupOnRelease = false; return STALE_BUFFER_SLOT; } else { - BQ_LOGV("releaseBuffer: attempted to release buffer slot %d " + BQ_LOGE("releaseBuffer: attempted to release buffer slot %d " "but its state was %d", slot, mSlots[slot].mBufferState); return BAD_VALUE; } mCore->mDequeueCondition.broadcast(); + mCore->validateConsistencyLocked(); } // Autolock scope // Call back without lock held @@ -492,7 +538,7 @@ void BufferQueueConsumer::setConsumerName(const String8& name) { mConsumerName = name; } -status_t BufferQueueConsumer::setDefaultBufferFormat(uint32_t defaultFormat) { +status_t BufferQueueConsumer::setDefaultBufferFormat(PixelFormat defaultFormat) { ATRACE_CALL(); BQ_LOGV("setDefaultBufferFormat: %u", defaultFormat); Mutex::Autolock lock(mCore->mMutex); @@ -500,6 +546,15 @@ status_t BufferQueueConsumer::setDefaultBufferFormat(uint32_t defaultFormat) { return NO_ERROR; } +status_t BufferQueueConsumer::setDefaultBufferDataSpace( + android_dataspace defaultDataSpace) { + ATRACE_CALL(); + BQ_LOGV("setDefaultBufferDataSpace: %u", defaultDataSpace); + Mutex::Autolock lock(mCore->mMutex); + mCore->mDefaultBufferDataSpace = defaultDataSpace; + return NO_ERROR; +} + status_t BufferQueueConsumer::setConsumerUsageBits(uint32_t usage) { ATRACE_CALL(); BQ_LOGV("setConsumerUsageBits: %#x", usage); diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index ec1e63112d..851a396155 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -53,6 +53,8 @@ BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) : mConnectedProducerListener(), mSlots(), mQueue(), + mFreeSlots(), + mFreeBuffers(), mOverrideMaxBufferCount(0), mDequeueCondition(), mUseAsyncBuffer(true), @@ -60,13 +62,17 @@ BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) : mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888), mDefaultWidth(1), mDefaultHeight(1), + mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN), mDefaultMaxBufferCount(2), mMaxAcquiredBufferCount(1), mBufferHasBeenQueued(false), mFrameCounter(0), mTransformHint(0), mIsAllocating(false), - mIsAllocatingCondition() + mIsAllocatingCondition(), + mAllowAllocation(true), + mBufferAge(0), + mGenerationNumber(0) { if (allocator == NULL) { sp<ISurfaceComposer> composer(ComposerService::getComposerService()); @@ -75,6 +81,9 @@ BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) : BQ_LOGE("createGraphicBufferAlloc failed"); } } + for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) { + mFreeSlots.insert(slot); + } } BufferQueueCore::~BufferQueueCore() {} @@ -189,13 +198,22 @@ status_t BufferQueueCore::setDefaultMaxBufferCountLocked(int count) { void BufferQueueCore::freeBufferLocked(int slot) { BQ_LOGV("freeBufferLocked: slot %d", slot); + bool hadBuffer = mSlots[slot].mGraphicBuffer != NULL; mSlots[slot].mGraphicBuffer.clear(); if (mSlots[slot].mBufferState == BufferSlot::ACQUIRED) { mSlots[slot].mNeedsCleanupOnRelease = true; } + if (mSlots[slot].mBufferState != BufferSlot::FREE) { + mFreeSlots.insert(slot); + } else if (hadBuffer) { + // If the slot was FREE, but we had a buffer, we need to move this slot + // from the free buffers list to the the free slots list + mFreeBuffers.remove(slot); + mFreeSlots.insert(slot); + } mSlots[slot].mBufferState = BufferSlot::FREE; - mSlots[slot].mFrameNumber = UINT32_MAX; mSlots[slot].mAcquireCalled = false; + mSlots[slot].mFrameNumber = 0; // Destroy fence as BufferQueue now takes ownership if (mSlots[slot].mEglFence != EGL_NO_SYNC_KHR) { @@ -203,6 +221,7 @@ void BufferQueueCore::freeBufferLocked(int slot) { mSlots[slot].mEglFence = EGL_NO_SYNC_KHR; } mSlots[slot].mFence = Fence::NO_FENCE; + validateConsistencyLocked(); } void BufferQueueCore::freeAllBuffersLocked() { @@ -235,4 +254,48 @@ void BufferQueueCore::waitWhileAllocatingLocked() const { } } +void BufferQueueCore::validateConsistencyLocked() const { + static const useconds_t PAUSE_TIME = 0; + for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) { + bool isInFreeSlots = mFreeSlots.count(slot) != 0; + bool isInFreeBuffers = + std::find(mFreeBuffers.cbegin(), mFreeBuffers.cend(), slot) != + mFreeBuffers.cend(); + if (mSlots[slot].mBufferState == BufferSlot::FREE) { + if (mSlots[slot].mGraphicBuffer == NULL) { + if (!isInFreeSlots) { + BQ_LOGE("Slot %d is FREE but is not in mFreeSlots", slot); + usleep(PAUSE_TIME); + } + if (isInFreeBuffers) { + BQ_LOGE("Slot %d is in mFreeSlots " + "but is also in mFreeBuffers", slot); + usleep(PAUSE_TIME); + } + } else { + if (!isInFreeBuffers) { + BQ_LOGE("Slot %d is FREE but is not in mFreeBuffers", slot); + usleep(PAUSE_TIME); + } + if (isInFreeSlots) { + BQ_LOGE("Slot %d is in mFreeBuffers " + "but is also in mFreeSlots", slot); + usleep(PAUSE_TIME); + } + } + } else { + if (isInFreeSlots) { + BQ_LOGE("Slot %d is in mFreeSlots but is not FREE (%d)", + slot, mSlots[slot].mBufferState); + usleep(PAUSE_TIME); + } + if (isInFreeBuffers) { + BQ_LOGE("Slot %d is in mFreeBuffers but is not FREE (%d)", + slot, mSlots[slot].mBufferState); + usleep(PAUSE_TIME); + } + } + } +} + } // namespace android diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 16b9747416..c6851c872d 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -161,8 +161,6 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, } } - // Look for a free buffer to give to the client - *found = BufferQueueCore::INVALID_BUFFER_SLOT; int dequeuedCount = 0; int acquiredCount = 0; for (int s = 0; s < maxBufferCount; ++s) { @@ -173,15 +171,6 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, case BufferSlot::ACQUIRED: ++acquiredCount; break; - case BufferSlot::FREE: - // We return the oldest of the free buffers to avoid - // stalling the producer if possible, since the consumer - // may still have pending reads of in-flight buffers - if (*found == BufferQueueCore::INVALID_BUFFER_SLOT || - mSlots[s].mFrameNumber < mSlots[*found].mFrameNumber) { - *found = s; - } - break; default: break; } @@ -214,6 +203,8 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, } } + *found = BufferQueueCore::INVALID_BUFFER_SLOT; + // If we disconnect and reconnect quickly, we can be in a state where // our slots are empty but we have many buffers in the queue. This can // cause us to run out of memory if we outrun the consumer. Wait here if @@ -223,6 +214,19 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, if (tooManyBuffers) { BQ_LOGV("%s: queue size is %zu, waiting", caller, mCore->mQueue.size()); + } else { + if (!mCore->mFreeBuffers.empty()) { + auto slot = mCore->mFreeBuffers.begin(); + *found = *slot; + mCore->mFreeBuffers.erase(slot); + } else if (mCore->mAllowAllocation && !mCore->mFreeSlots.empty()) { + auto slot = mCore->mFreeSlots.begin(); + // Only return free slots up to the max buffer count + if (*slot < maxBufferCount) { + *found = *slot; + mCore->mFreeSlots.erase(slot); + } + } } // If no buffer is found, or if the queue has too many buffers @@ -250,7 +254,7 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, status_t BufferQueueProducer::dequeueBuffer(int *outSlot, sp<android::Fence> *outFence, bool async, - uint32_t width, uint32_t height, uint32_t format, uint32_t usage) { + uint32_t width, uint32_t height, PixelFormat format, uint32_t usage) { ATRACE_CALL(); { // Autolock scope Mutex::Autolock lock(mCore->mMutex); @@ -281,17 +285,39 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, // Enable the usage bits the consumer requested usage |= mCore->mConsumerUsageBits; - int found; - status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async, - &found, &returnFlags); - if (status != NO_ERROR) { - return status; + const bool useDefaultSize = !width && !height; + if (useDefaultSize) { + width = mCore->mDefaultWidth; + height = mCore->mDefaultHeight; } - // This should not happen - if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { - BQ_LOGE("dequeueBuffer: no available buffer slots"); - return -EBUSY; + int found = BufferItem::INVALID_BUFFER_SLOT; + while (found == BufferItem::INVALID_BUFFER_SLOT) { + status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async, + &found, &returnFlags); + if (status != NO_ERROR) { + return status; + } + + // This should not happen + if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { + BQ_LOGE("dequeueBuffer: no available buffer slots"); + return -EBUSY; + } + + const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer); + + // If we are not allowed to allocate new buffers, + // waitForFreeSlotThenRelock must have returned a slot containing a + // buffer. If this buffer would require reallocation to meet the + // requested attributes, we free it and attempt to get another one. + if (!mCore->mAllowAllocation) { + if (buffer->needsReallocation(width, height, format, usage)) { + mCore->freeBufferLocked(found); + found = BufferItem::INVALID_BUFFER_SLOT; + continue; + } + } } *outSlot = found; @@ -299,20 +325,11 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, attachedByConsumer = mSlots[found].mAttachedByConsumer; - const bool useDefaultSize = !width && !height; - if (useDefaultSize) { - width = mCore->mDefaultWidth; - height = mCore->mDefaultHeight; - } - mSlots[found].mBufferState = BufferSlot::DEQUEUED; const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer); if ((buffer == NULL) || - (static_cast<uint32_t>(buffer->width) != width) || - (static_cast<uint32_t>(buffer->height) != height) || - (static_cast<uint32_t>(buffer->format) != format) || - ((static_cast<uint32_t>(buffer->usage) & usage) != usage)) + buffer->needsReallocation(width, height, format, usage)) { mSlots[found].mAcquireCalled = false; mSlots[found].mGraphicBuffer = NULL; @@ -320,10 +337,19 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, mSlots[found].mEglDisplay = EGL_NO_DISPLAY; mSlots[found].mEglFence = EGL_NO_SYNC_KHR; mSlots[found].mFence = Fence::NO_FENCE; + mCore->mBufferAge = 0; returnFlags |= BUFFER_NEEDS_REALLOCATION; + } else { + // We add 1 because that will be the frame number when this buffer + // is queued + mCore->mBufferAge = + mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber; } + BQ_LOGV("dequeueBuffer: setting buffer age to %" PRIu64, + mCore->mBufferAge); + if (CC_UNLIKELY(mSlots[found].mFence == NULL)) { BQ_LOGE("dequeueBuffer: about to return a NULL fence - " "slot=%d w=%d h=%d format=%u", @@ -335,13 +361,15 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, *outFence = mSlots[found].mFence; mSlots[found].mEglFence = EGL_NO_SYNC_KHR; mSlots[found].mFence = Fence::NO_FENCE; + + mCore->validateConsistencyLocked(); } // Autolock scope if (returnFlags & BUFFER_NEEDS_REALLOCATION) { status_t error; BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot); sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer( - width, height, format, usage, &error)); + width, height, format, usage, &error)); if (graphicBuffer == NULL) { BQ_LOGE("dequeueBuffer: createGraphicBuffer failed"); return error; @@ -355,7 +383,7 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, return NO_INIT; } - mSlots[*outSlot].mFrameNumber = UINT32_MAX; + graphicBuffer->setGenerationNumber(mCore->mGenerationNumber); mSlots[*outSlot].mGraphicBuffer = graphicBuffer; } // Autolock scope } @@ -414,6 +442,7 @@ status_t BufferQueueProducer::detachBuffer(int slot) { mCore->freeBufferLocked(slot); mCore->mDequeueCondition.broadcast(); + mCore->validateConsistencyLocked(); return NO_ERROR; } @@ -438,27 +467,19 @@ status_t BufferQueueProducer::detachNextBuffer(sp<GraphicBuffer>* outBuffer, return NO_INIT; } - // Find the oldest valid slot - int found = BufferQueueCore::INVALID_BUFFER_SLOT; - for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - if (mSlots[s].mBufferState == BufferSlot::FREE && - mSlots[s].mGraphicBuffer != NULL) { - if (found == BufferQueueCore::INVALID_BUFFER_SLOT || - mSlots[s].mFrameNumber < mSlots[found].mFrameNumber) { - found = s; - } - } - } - - if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { + if (mCore->mFreeBuffers.empty()) { return NO_MEMORY; } + int found = mCore->mFreeBuffers.front(); + mCore->mFreeBuffers.remove(found); + BQ_LOGV("detachNextBuffer detached slot %d", found); *outBuffer = mSlots[found].mGraphicBuffer; *outFence = mSlots[found].mFence; mCore->freeBufferLocked(found); + mCore->validateConsistencyLocked(); return NO_ERROR; } @@ -478,6 +499,13 @@ status_t BufferQueueProducer::attachBuffer(int* outSlot, Mutex::Autolock lock(mCore->mMutex); mCore->waitWhileAllocatingLocked(); + if (buffer->getGenerationNumber() != mCore->mGenerationNumber) { + BQ_LOGE("attachBuffer: generation number mismatch [buffer %u] " + "[queue %u]", buffer->getGenerationNumber(), + mCore->mGenerationNumber); + return BAD_VALUE; + } + status_t returnFlags = NO_ERROR; int found; // TODO: Should we provide an async flag to attachBuffer? It seems @@ -506,6 +534,8 @@ status_t BufferQueueProducer::attachBuffer(int* outSlot, mSlots[*outSlot].mFence = Fence::NO_FENCE; mSlots[*outSlot].mRequestBufferCalled = true; + mCore->validateConsistencyLocked(); + return returnFlags; } @@ -516,14 +546,16 @@ status_t BufferQueueProducer::queueBuffer(int slot, int64_t timestamp; bool isAutoTimestamp; + android_dataspace dataSpace; Rect crop; int scalingMode; uint32_t transform; uint32_t stickyTransform; bool async; sp<Fence> fence; - input.deflate(×tamp, &isAutoTimestamp, &crop, &scalingMode, &transform, - &async, &fence, &stickyTransform); + input.deflate(×tamp, &isAutoTimestamp, &dataSpace, &crop, &scalingMode, + &transform, &async, &fence, &stickyTransform); + Region surfaceDamage = input.getSurfaceDamage(); if (fence == NULL) { BQ_LOGE("queueBuffer: fence is NULL"); @@ -579,11 +611,11 @@ status_t BufferQueueProducer::queueBuffer(int slot, return BAD_VALUE; } - BQ_LOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64 + BQ_LOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64 " dataSpace=%d" " crop=[%d,%d,%d,%d] transform=%#x scale=%s", - slot, mCore->mFrameCounter + 1, timestamp, - crop.left, crop.top, crop.right, crop.bottom, - transform, BufferItem::scalingModeName(scalingMode)); + slot, mCore->mFrameCounter + 1, timestamp, dataSpace, + crop.left, crop.top, crop.right, crop.bottom, transform, + BufferItem::scalingModeName(static_cast<uint32_t>(scalingMode))); const sp<GraphicBuffer>& graphicBuffer(mSlots[slot].mGraphicBuffer); Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight()); @@ -595,6 +627,11 @@ status_t BufferQueueProducer::queueBuffer(int slot, return BAD_VALUE; } + // Override UNKNOWN dataspace with consumer default + if (dataSpace == HAL_DATASPACE_UNKNOWN) { + dataSpace = mCore->mDefaultBufferDataSpace; + } + mSlots[slot].mFence = fence; mSlots[slot].mBufferState = BufferSlot::QUEUED; ++mCore->mFrameCounter; @@ -603,16 +640,19 @@ status_t BufferQueueProducer::queueBuffer(int slot, item.mAcquireCalled = mSlots[slot].mAcquireCalled; item.mGraphicBuffer = mSlots[slot].mGraphicBuffer; item.mCrop = crop; - item.mTransform = transform & ~NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; + item.mTransform = transform & + ~static_cast<uint32_t>(NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY); item.mTransformToDisplayInverse = - bool(transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY); - item.mScalingMode = scalingMode; + (transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0; + item.mScalingMode = static_cast<uint32_t>(scalingMode); item.mTimestamp = timestamp; item.mIsAutoTimestamp = isAutoTimestamp; + item.mDataSpace = dataSpace; item.mFrameNumber = mCore->mFrameCounter; item.mSlot = slot; item.mFence = fence; item.mIsDroppable = mCore->mDequeueBufferCannotBlock || async; + item.mSurfaceDamage = surfaceDamage; mStickyTransform = stickyTransform; @@ -630,9 +670,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, // mark it as freed if (mCore->stillTracking(front)) { mSlots[front->mSlot].mBufferState = BufferSlot::FREE; - // Reset the frame number of the freed buffer so that it is - // the first in line to be dequeued again - mSlots[front->mSlot].mFrameNumber = 0; + mCore->mFreeBuffers.push_front(front->mSlot); } // Overwrite the droppable buffer with the incoming one *front = item; @@ -647,12 +685,15 @@ status_t BufferQueueProducer::queueBuffer(int slot, mCore->mDequeueCondition.broadcast(); output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight, - mCore->mTransformHint, mCore->mQueue.size()); + mCore->mTransformHint, + static_cast<uint32_t>(mCore->mQueue.size())); ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size()); // Take a ticket for the callback functions callbackTicket = mNextCallbackTicket++; + + mCore->validateConsistencyLocked(); } // Autolock scope // Wait without lock held @@ -713,10 +754,11 @@ void BufferQueueProducer::cancelBuffer(int slot, const sp<Fence>& fence) { return; } + mCore->mFreeBuffers.push_front(slot); mSlots[slot].mBufferState = BufferSlot::FREE; - mSlots[slot].mFrameNumber = 0; mSlots[slot].mFence = fence; mCore->mDequeueCondition.broadcast(); + mCore->validateConsistencyLocked(); } int BufferQueueProducer::query(int what, int *outValue) { @@ -736,25 +778,35 @@ int BufferQueueProducer::query(int what, int *outValue) { int value; switch (what) { case NATIVE_WINDOW_WIDTH: - value = mCore->mDefaultWidth; + value = static_cast<int32_t>(mCore->mDefaultWidth); break; case NATIVE_WINDOW_HEIGHT: - value = mCore->mDefaultHeight; + value = static_cast<int32_t>(mCore->mDefaultHeight); break; case NATIVE_WINDOW_FORMAT: - value = mCore->mDefaultBufferFormat; + value = static_cast<int32_t>(mCore->mDefaultBufferFormat); break; case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: value = mCore->getMinUndequeuedBufferCountLocked(false); break; case NATIVE_WINDOW_STICKY_TRANSFORM: - value = static_cast<int>(mStickyTransform); + value = static_cast<int32_t>(mStickyTransform); break; case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: value = (mCore->mQueue.size() > 1); break; case NATIVE_WINDOW_CONSUMER_USAGE_BITS: - value = mCore->mConsumerUsageBits; + value = static_cast<int32_t>(mCore->mConsumerUsageBits); + break; + case NATIVE_WINDOW_DEFAULT_DATASPACE: + value = static_cast<int32_t>(mCore->mDefaultBufferDataSpace); + break; + case NATIVE_WINDOW_BUFFER_AGE: + if (mCore->mBufferAge > INT32_MAX) { + value = 0; + } else { + value = static_cast<int32_t>(mCore->mBufferAge); + } break; default: return BAD_VALUE; @@ -802,13 +854,14 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener, case NATIVE_WINDOW_API_CAMERA: mCore->mConnectedApi = api; output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight, - mCore->mTransformHint, mCore->mQueue.size()); + mCore->mTransformHint, + static_cast<uint32_t>(mCore->mQueue.size())); // Set up a death notification so that we can disconnect // automatically if the remote producer dies if (listener != NULL && - listener->asBinder()->remoteBinder() != NULL) { - status = listener->asBinder()->linkToDeath( + IInterface::asBinder(listener)->remoteBinder() != NULL) { + status = IInterface::asBinder(listener)->linkToDeath( static_cast<IBinder::DeathRecipient*>(this)); if (status != NO_ERROR) { BQ_LOGE("connect(P): linkToDeath failed: %s (%d)", @@ -826,6 +879,7 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener, mCore->mBufferHasBeenQueued = false; mCore->mDequeueBufferCannotBlock = mCore->mConsumerControlledByApp && producerControlledByApp; + mCore->mAllowAllocation = true; return status; } @@ -857,7 +911,7 @@ status_t BufferQueueProducer::disconnect(int api) { // Remove our death notification callback if we have one if (mCore->mConnectedProducerListener != NULL) { sp<IBinder> token = - mCore->mConnectedProducerListener->asBinder(); + IInterface::asBinder(mCore->mConnectedProducerListener); // This can fail if we're here because of the death // notification, but we just ignore it token->unlinkToDeath( @@ -868,8 +922,8 @@ status_t BufferQueueProducer::disconnect(int api) { mCore->mSidebandStream.clear(); mCore->mDequeueCondition.broadcast(); listener = mCore->mConsumerListener; - } else { - BQ_LOGE("disconnect(P): connected to another API " + } else if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) { + BQ_LOGE("disconnect(P): still connected to another API " "(cur=%d req=%d)", mCore->mConnectedApi, api); status = BAD_VALUE; } @@ -904,19 +958,25 @@ status_t BufferQueueProducer::setSidebandStream(const sp<NativeHandle>& stream) } void BufferQueueProducer::allocateBuffers(bool async, uint32_t width, - uint32_t height, uint32_t format, uint32_t usage) { + uint32_t height, PixelFormat format, uint32_t usage) { ATRACE_CALL(); while (true) { Vector<int> freeSlots; size_t newBufferCount = 0; uint32_t allocWidth = 0; uint32_t allocHeight = 0; - uint32_t allocFormat = 0; + PixelFormat allocFormat = PIXEL_FORMAT_UNKNOWN; uint32_t allocUsage = 0; { // Autolock scope Mutex::Autolock lock(mCore->mMutex); mCore->waitWhileAllocatingLocked(); + if (!mCore->mAllowAllocation) { + BQ_LOGE("allocateBuffers: allocation is not allowed for this " + "BufferQueue"); + return; + } + int currentBufferCount = 0; for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) { if (mSlots[slot].mGraphicBuffer != NULL) { @@ -937,7 +997,8 @@ void BufferQueueProducer::allocateBuffers(bool async, uint32_t width, currentBufferCount, maxBufferCount); if (maxBufferCount <= currentBufferCount) return; - newBufferCount = maxBufferCount - currentBufferCount; + newBufferCount = + static_cast<size_t>(maxBufferCount - currentBufferCount); if (freeSlots.size() < newBufferCount) { BQ_LOGE("allocateBuffers: ran out of free slots"); return; @@ -950,7 +1011,7 @@ void BufferQueueProducer::allocateBuffers(bool async, uint32_t width, mCore->mIsAllocating = true; } // Autolock scope - Vector<sp<GraphicBuffer> > buffers; + Vector<sp<GraphicBuffer>> buffers; for (size_t i = 0; i < newBufferCount; ++i) { status_t result = NO_ERROR; sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer( @@ -970,7 +1031,8 @@ void BufferQueueProducer::allocateBuffers(bool async, uint32_t width, Mutex::Autolock lock(mCore->mMutex); uint32_t checkWidth = width > 0 ? width : mCore->mDefaultWidth; uint32_t checkHeight = height > 0 ? height : mCore->mDefaultHeight; - uint32_t checkFormat = format != 0 ? format : mCore->mDefaultBufferFormat; + PixelFormat checkFormat = format != 0 ? + format : mCore->mDefaultBufferFormat; uint32_t checkUsage = usage | mCore->mConsumerUsageBits; if (checkWidth != allocWidth || checkHeight != allocHeight || checkFormat != allocFormat || checkUsage != allocUsage) { @@ -992,17 +1054,48 @@ void BufferQueueProducer::allocateBuffers(bool async, uint32_t width, } mCore->freeBufferLocked(slot); // Clean up the slot first mSlots[slot].mGraphicBuffer = buffers[i]; - mSlots[slot].mFrameNumber = 0; mSlots[slot].mFence = Fence::NO_FENCE; + + // freeBufferLocked puts this slot on the free slots list. Since + // we then attached a buffer, move the slot to free buffer list. + mCore->mFreeSlots.erase(slot); + mCore->mFreeBuffers.push_front(slot); + BQ_LOGV("allocateBuffers: allocated a new buffer in slot %d", slot); } mCore->mIsAllocating = false; mCore->mIsAllocatingCondition.broadcast(); + mCore->validateConsistencyLocked(); } // Autolock scope } } +status_t BufferQueueProducer::allowAllocation(bool allow) { + ATRACE_CALL(); + BQ_LOGV("allowAllocation: %s", allow ? "true" : "false"); + + Mutex::Autolock lock(mCore->mMutex); + mCore->mAllowAllocation = allow; + return NO_ERROR; +} + +status_t BufferQueueProducer::setGenerationNumber(uint32_t generationNumber) { + ATRACE_CALL(); + BQ_LOGV("setGenerationNumber: %u", generationNumber); + + Mutex::Autolock lock(mCore->mMutex); + mCore->mGenerationNumber = generationNumber; + return NO_ERROR; +} + +String8 BufferQueueProducer::getConsumerName() const { + ATRACE_CALL(); + Mutex::Autolock lock(mCore->mMutex); + BQ_LOGV("getConsumerName: %s", mConsumerName.string()); + return mConsumerName; +} + void BufferQueueProducer::binderDied(const wp<android::IBinder>& /* who */) { // If we're here, it means that a producer we were connected to died. // We're guaranteed that we are still connected to it because we remove diff --git a/libs/gui/BufferSlot.cpp b/libs/gui/BufferSlot.cpp index b8877fef61..01595de448 100644 --- a/libs/gui/BufferSlot.cpp +++ b/libs/gui/BufferSlot.cpp @@ -24,8 +24,8 @@ const char* BufferSlot::bufferStateName(BufferState state) { case BufferSlot::QUEUED: return "QUEUED"; case BufferSlot::FREE: return "FREE"; case BufferSlot::ACQUIRED: return "ACQUIRED"; - default: return "Unknown"; } + return "Unknown"; } } // namespace android diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index 210e98e446..04ab06b557 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -27,6 +27,7 @@ #include <hardware/hardware.h> +#include <gui/BufferItem.h> #include <gui/IGraphicBufferAlloc.h> #include <gui/ISurfaceComposer.h> #include <gui/SurfaceComposerClient.h> @@ -39,11 +40,11 @@ #include <utils/Trace.h> // Macros for including the ConsumerBase name in log messages -#define CB_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__) -#define CB_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__) -#define CB_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__) -#define CB_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) -#define CB_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) +#define CB_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) +//#define CB_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) +//#define CB_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) +//#define CB_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) +#define CB_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) namespace android { @@ -113,6 +114,21 @@ void ConsumerBase::onFrameAvailable(const BufferItem& item) { } } +void ConsumerBase::onFrameReplaced(const BufferItem &item) { + CB_LOGV("onFrameReplaced"); + + sp<FrameAvailableListener> listener; + { + Mutex::Autolock lock(mMutex); + listener = mFrameAvailableListener.promote(); + } + + if (listener != NULL) { + CB_LOGV("actually calling onFrameReplaced"); + listener->onFrameReplaced(item); + } +} + void ConsumerBase::onBuffersReleased() { Mutex::Autolock lock(mMutex); @@ -155,6 +171,11 @@ void ConsumerBase::abandonLocked() { mConsumer.clear(); } +bool ConsumerBase::isAbandoned() { + Mutex::Autolock _l(mMutex); + return mAbandoned; +} + void ConsumerBase::setFrameAvailableListener( const wp<FrameAvailableListener>& listener) { CB_LOGV("setFrameAvailableListener"); @@ -162,6 +183,37 @@ void ConsumerBase::setFrameAvailableListener( mFrameAvailableListener = listener; } +status_t ConsumerBase::detachBuffer(int slot) { + CB_LOGV("detachBuffer"); + Mutex::Autolock lock(mMutex); + + status_t result = mConsumer->detachBuffer(slot); + if (result != NO_ERROR) { + CB_LOGE("Failed to detach buffer: %d", result); + return result; + } + + freeBufferLocked(slot); + + return result; +} + +status_t ConsumerBase::setDefaultBufferSize(uint32_t width, uint32_t height) { + Mutex::Autolock _l(mMutex); + return mConsumer->setDefaultBufferSize(width, height); +} + +status_t ConsumerBase::setDefaultBufferFormat(PixelFormat defaultFormat) { + Mutex::Autolock _l(mMutex); + return mConsumer->setDefaultBufferFormat(defaultFormat); +} + +status_t ConsumerBase::setDefaultBufferDataSpace( + android_dataspace defaultDataSpace) { + Mutex::Autolock _l(mMutex); + return mConsumer->setDefaultBufferDataSpace(defaultDataSpace); +} + void ConsumerBase::dump(String8& result) const { dump(result, ""); } @@ -179,9 +231,9 @@ void ConsumerBase::dumpLocked(String8& result, const char* prefix) const { } } -status_t ConsumerBase::acquireBufferLocked(BufferQueue::BufferItem *item, - nsecs_t presentWhen) { - status_t err = mConsumer->acquireBuffer(item, presentWhen); +status_t ConsumerBase::acquireBufferLocked(BufferItem *item, + nsecs_t presentWhen, uint64_t maxFrameNumber) { + status_t err = mConsumer->acquireBuffer(item, presentWhen, maxFrameNumber); if (err != NO_ERROR) { return err; } diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp index c541ff4a7a..e29b740188 100644 --- a/libs/gui/CpuConsumer.cpp +++ b/libs/gui/CpuConsumer.cpp @@ -16,22 +16,23 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "CpuConsumer" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS +//#define ATRACE_TAG ATRACE_TAG_GRAPHICS #include <cutils/compiler.h> #include <utils/Log.h> +#include <gui/BufferItem.h> #include <gui/CpuConsumer.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__) -#define CC_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) -#define CC_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) +#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__) +#define CC_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) +#define CC_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) namespace android { CpuConsumer::CpuConsumer(const sp<IGraphicBufferConsumer>& bq, - uint32_t maxLockedBuffers, bool controlledByApp) : + size_t maxLockedBuffers, bool controlledByApp) : ConsumerBase(bq, controlledByApp), mMaxLockedBuffers(maxLockedBuffers), mCurrentLockedBuffers(0) @@ -40,7 +41,7 @@ CpuConsumer::CpuConsumer(const sp<IGraphicBufferConsumer>& bq, mAcquiredBuffers.insertAt(0, maxLockedBuffers); mConsumer->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN); - mConsumer->setMaxAcquiredBufferCount(maxLockedBuffers); + mConsumer->setMaxAcquiredBufferCount(static_cast<int32_t>(maxLockedBuffers)); } CpuConsumer::~CpuConsumer() { @@ -55,30 +56,16 @@ void CpuConsumer::setName(const String8& name) { mConsumer->setConsumerName(name); } -status_t CpuConsumer::setDefaultBufferSize(uint32_t width, uint32_t height) -{ - Mutex::Autolock _l(mMutex); - return mConsumer->setDefaultBufferSize(width, height); -} - -status_t CpuConsumer::setDefaultBufferFormat(uint32_t defaultFormat) -{ - Mutex::Autolock _l(mMutex); - return mConsumer->setDefaultBufferFormat(defaultFormat); -} - static bool isPossiblyYUV(PixelFormat format) { - switch ((int)format) { + switch (static_cast<int>(format)) { case HAL_PIXEL_FORMAT_RGBA_8888: case HAL_PIXEL_FORMAT_RGBX_8888: case HAL_PIXEL_FORMAT_RGB_888: case HAL_PIXEL_FORMAT_RGB_565: case HAL_PIXEL_FORMAT_BGRA_8888: - case HAL_PIXEL_FORMAT_sRGB_A_8888: - case HAL_PIXEL_FORMAT_sRGB_X_8888: case HAL_PIXEL_FORMAT_Y8: case HAL_PIXEL_FORMAT_Y16: - case HAL_PIXEL_FORMAT_RAW16: // same as HAL_PIXEL_FORMAT_RAW_SENSOR + case HAL_PIXEL_FORMAT_RAW16: case HAL_PIXEL_FORMAT_RAW10: case HAL_PIXEL_FORMAT_RAW_OPAQUE: case HAL_PIXEL_FORMAT_BLOB: @@ -100,12 +87,12 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { if (!nativeBuffer) return BAD_VALUE; if (mCurrentLockedBuffers == mMaxLockedBuffers) { - CC_LOGW("Max buffers have been locked (%d), cannot lock anymore.", + CC_LOGW("Max buffers have been locked (%zd), cannot lock anymore.", mMaxLockedBuffers); return NOT_ENOUGH_DATA; } - BufferQueue::BufferItem b; + BufferItem b; Mutex::Autolock _l(mMutex); @@ -173,7 +160,7 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { } size_t lockedIdx = 0; - for (; lockedIdx < mMaxLockedBuffers; lockedIdx++) { + for (; lockedIdx < static_cast<size_t>(mMaxLockedBuffers); lockedIdx++) { if (mAcquiredBuffers[lockedIdx].mSlot == BufferQueue::INVALID_BUFFER_SLOT) { break; @@ -193,19 +180,20 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { nativeBuffer->format = format; nativeBuffer->flexFormat = flexFormat; nativeBuffer->stride = (ycbcr.y != NULL) ? - ycbcr.ystride : + static_cast<uint32_t>(ycbcr.ystride) : mSlots[buf].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 = ycbcr.cstride; - nativeBuffer->chromaStep = ycbcr.chroma_step; + nativeBuffer->chromaStride = static_cast<uint32_t>(ycbcr.cstride); + nativeBuffer->chromaStep = static_cast<uint32_t>(ycbcr.chroma_step); mCurrentLockedBuffers++; @@ -215,10 +203,9 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) { Mutex::Autolock _l(mMutex); size_t lockedIdx = 0; - status_t err; void *bufPtr = reinterpret_cast<void *>(nativeBuffer.data); - for (; lockedIdx < mMaxLockedBuffers; lockedIdx++) { + for (; lockedIdx < static_cast<size_t>(mMaxLockedBuffers); lockedIdx++) { if (bufPtr == mAcquiredBuffers[lockedIdx].mBufferPointer) break; } if (lockedIdx == mMaxLockedBuffers) { @@ -229,13 +216,13 @@ status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) { return releaseAcquiredBufferLocked(lockedIdx); } -status_t CpuConsumer::releaseAcquiredBufferLocked(int lockedIdx) { +status_t CpuConsumer::releaseAcquiredBufferLocked(size_t lockedIdx) { status_t err; int fd = -1; err = mAcquiredBuffers[lockedIdx].mGraphicBuffer->unlockAsync(&fd); if (err != OK) { - CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, + CC_LOGE("%s: Unable to unlock graphic buffer %zd", __FUNCTION__, lockedIdx); return err; } diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index 318c087887..757e08a907 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -29,6 +29,7 @@ #include <hardware/hardware.h> +#include <gui/BufferItem.h> #include <gui/GLConsumer.h> #include <gui/IGraphicBufferAlloc.h> #include <gui/ISurfaceComposer.h> @@ -47,18 +48,28 @@ EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint na namespace android { // Macros for including the GLConsumer name in log messages -#define ST_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__) -#define ST_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__) -#define ST_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__) -#define ST_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) -#define ST_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) +#define GLC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) +#define GLC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) +//#define GLC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) +#define GLC_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) +#define GLC_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) static const struct { - size_t width, height; + uint32_t width, height; char const* bits; } kDebugData = { 15, 12, - "___________________________________XX_XX_______X_X_____X_X____X_XXXXXXX_X____XXXXXXXXXXX__" - "___XX_XXX_XX_______XXXXXXX_________X___X_________X_____X__________________________________" + "_______________" + "_______________" + "_____XX_XX_____" + "__X_X_____X_X__" + "__X_XXXXXXX_X__" + "__XXXXXXXXXXX__" + "___XX_XXX_XX___" + "____XXXXXXX____" + "_____X___X_____" + "____X_____X____" + "_______________" + "_______________" }; // Transform matrices @@ -135,7 +146,7 @@ GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex, mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT), mAttached(true) { - ST_LOGV("GLConsumer"); + GLC_LOGV("GLConsumer"); memcpy(mCurrentTransformMatrix, mtxIdentity, sizeof(mCurrentTransformMatrix)); @@ -154,7 +165,7 @@ GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t texTarget, mDefaultWidth(1), mDefaultHeight(1), mFilteringEnabled(true), - mTexName(-1), + mTexName(0), mUseFenceSync(useFenceSync), mTexTarget(texTarget), mEglDisplay(EGL_NO_DISPLAY), @@ -162,7 +173,7 @@ GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t texTarget, mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT), mAttached(false) { - ST_LOGV("GLConsumer"); + GLC_LOGV("GLConsumer"); memcpy(mCurrentTransformMatrix, mtxIdentity, sizeof(mCurrentTransformMatrix)); @@ -186,11 +197,11 @@ status_t GLConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) status_t GLConsumer::updateTexImage() { ATRACE_CALL(); - ST_LOGV("updateTexImage"); + GLC_LOGV("updateTexImage"); Mutex::Autolock lock(mMutex); if (mAbandoned) { - ST_LOGE("updateTexImage: GLConsumer is abandoned!"); + GLC_LOGE("updateTexImage: GLConsumer is abandoned!"); return NO_INIT; } @@ -200,7 +211,7 @@ status_t GLConsumer::updateTexImage() { return err; } - BufferQueue::BufferItem item; + BufferItem item; // Acquire the next buffer. // In asynchronous mode the list is guaranteed to be one buffer @@ -209,11 +220,11 @@ status_t GLConsumer::updateTexImage() { if (err != NO_ERROR) { if (err == BufferQueue::NO_BUFFER_AVAILABLE) { // We always bind the texture even if we don't update its contents. - ST_LOGV("updateTexImage: no buffers were available"); + GLC_LOGV("updateTexImage: no buffers were available"); glBindTexture(mTexTarget, mTexName); err = NO_ERROR; } else { - ST_LOGE("updateTexImage: acquire failed: %s (%d)", + GLC_LOGE("updateTexImage: acquire failed: %s (%d)", strerror(-err), err); } return err; @@ -234,11 +245,11 @@ status_t GLConsumer::updateTexImage() { status_t GLConsumer::releaseTexImage() { ATRACE_CALL(); - ST_LOGV("releaseTexImage"); + GLC_LOGV("releaseTexImage"); Mutex::Autolock lock(mMutex); if (mAbandoned) { - ST_LOGE("releaseTexImage: GLConsumer is abandoned!"); + GLC_LOGE("releaseTexImage: GLConsumer is abandoned!"); return NO_INIT; } @@ -258,13 +269,13 @@ status_t GLConsumer::releaseTexImage() { int buf = mCurrentTexture; if (buf != BufferQueue::INVALID_BUFFER_SLOT) { - ST_LOGV("releaseTexImage: (slot=%d, mAttached=%d)", buf, mAttached); + GLC_LOGV("releaseTexImage: (slot=%d, mAttached=%d)", buf, mAttached); if (mAttached) { // Do whatever sync ops we need to do before releasing the slot. err = syncForReleaseLocked(mEglDisplay); if (err != NO_ERROR) { - ST_LOGE("syncForReleaseLocked failed (slot=%d), err=%d", buf, err); + GLC_LOGE("syncForReleaseLocked failed (slot=%d), err=%d", buf, err); return err; } } else { @@ -274,7 +285,7 @@ status_t GLConsumer::releaseTexImage() { err = releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR); if (err < NO_ERROR) { - ST_LOGE("releaseTexImage: failed to release buffer: %s (%d)", + GLC_LOGE("releaseTexImage: failed to release buffer: %s (%d)", strerror(-err), err); return err; } @@ -293,9 +304,9 @@ status_t GLConsumer::releaseTexImage() { if (mAttached) { // This binds a dummy buffer (mReleasedTexImage). - status_t err = bindTextureImageLocked(); - if (err != NO_ERROR) { - return err; + status_t result = bindTextureImageLocked(); + if (result != NO_ERROR) { + return result; } } else { // detached, don't touch the texture (and we may not even have an @@ -316,14 +327,15 @@ sp<GraphicBuffer> GLConsumer::getDebugTexImageBuffer() { GraphicBuffer::USAGE_SW_WRITE_RARELY); uint32_t* bits; buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&bits)); - size_t w = buffer->getStride(); - size_t h = buffer->getHeight(); - memset(bits, 0, w*h*4); - for (size_t y=0 ; y<kDebugData.height ; y++) { - for (size_t x=0 ; x<kDebugData.width ; x++) { - bits[x] = (kDebugData.bits[y*kDebugData.width+x] == 'X') ? 0xFF000000 : 0xFFFFFFFF; + uint32_t stride = buffer->getStride(); + uint32_t height = buffer->getHeight(); + memset(bits, 0, stride * height * 4); + for (uint32_t y = 0; y < kDebugData.height; y++) { + for (uint32_t x = 0; x < kDebugData.width; x++) { + bits[x] = (kDebugData.bits[y + kDebugData.width + x] == 'X') ? + 0xFF000000 : 0xFFFFFFFF; } - bits += w; + bits += stride; } buffer->unlock(); sReleasedTexImageBuffer = buffer; @@ -331,9 +343,10 @@ sp<GraphicBuffer> GLConsumer::getDebugTexImageBuffer() { return sReleasedTexImageBuffer; } -status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item, - nsecs_t presentWhen) { - status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen); +status_t GLConsumer::acquireBufferLocked(BufferItem *item, + nsecs_t presentWhen, uint64_t maxFrameNumber) { + status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen, + maxFrameNumber); if (err != NO_ERROR) { return err; } @@ -362,14 +375,14 @@ status_t GLConsumer::releaseBufferLocked(int buf, return err; } -status_t GLConsumer::updateAndReleaseLocked(const BufferQueue::BufferItem& item) +status_t GLConsumer::updateAndReleaseLocked(const BufferItem& item) { status_t err = NO_ERROR; int buf = item.mBuf; if (!mAttached) { - ST_LOGE("updateAndRelease: GLConsumer is not attached to an OpenGL " + GLC_LOGE("updateAndRelease: GLConsumer is not attached to an OpenGL " "ES context"); releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR); @@ -391,7 +404,7 @@ status_t GLConsumer::updateAndReleaseLocked(const BufferQueue::BufferItem& item) // means the buffer was previously acquired). err = mEglSlots[buf].mEglImage->createIfNeeded(mEglDisplay, item.mCrop); if (err != NO_ERROR) { - ST_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d", + GLC_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d", mEglDisplay, buf); releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR); @@ -410,7 +423,7 @@ status_t GLConsumer::updateAndReleaseLocked(const BufferQueue::BufferItem& item) return err; } - ST_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", + GLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture, mCurrentTextureImage != NULL ? mCurrentTextureImage->graphicBufferHandle() : 0, buf, mSlots[buf].mGraphicBuffer->handle); @@ -421,7 +434,7 @@ status_t GLConsumer::updateAndReleaseLocked(const BufferQueue::BufferItem& item) mCurrentTexture, mCurrentTextureImage->graphicBuffer(), mEglDisplay, mEglSlots[mCurrentTexture].mEglFence); if (status < NO_ERROR) { - ST_LOGE("updateAndRelease: failed to release buffer: %s (%d)", + GLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status), status); err = status; // keep going, with error raised [?] @@ -449,22 +462,22 @@ status_t GLConsumer::bindTextureImageLocked() { return INVALID_OPERATION; } - GLint error; + GLenum error; while ((error = glGetError()) != GL_NO_ERROR) { - ST_LOGW("bindTextureImage: clearing GL error: %#04x", error); + GLC_LOGW("bindTextureImage: clearing GL error: %#04x", error); } glBindTexture(mTexTarget, mTexName); if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureImage == NULL) { - ST_LOGE("bindTextureImage: no currently-bound texture"); + GLC_LOGE("bindTextureImage: no currently-bound texture"); return NO_INIT; } status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay, mCurrentCrop); if (err != NO_ERROR) { - ST_LOGW("bindTextureImage: can't create image on display=%p slot=%d", + GLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay, mCurrentTexture); return UNKNOWN_ERROR; } @@ -476,17 +489,17 @@ status_t GLConsumer::bindTextureImageLocked() { // forcing the creation of a new image. if ((error = glGetError()) != GL_NO_ERROR) { glBindTexture(mTexTarget, mTexName); - status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay, - mCurrentCrop, - true); - if (err != NO_ERROR) { - ST_LOGW("bindTextureImage: can't create image on display=%p slot=%d", + status_t result = mCurrentTextureImage->createIfNeeded(mEglDisplay, + mCurrentCrop, + true); + if (result != NO_ERROR) { + GLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay, mCurrentTexture); return UNKNOWN_ERROR; } mCurrentTextureImage->bindToTextureTarget(mTexTarget); if ((error = glGetError()) != GL_NO_ERROR) { - ST_LOGE("bindTextureImage: error binding external image: %#04x", error); + GLC_LOGE("bindTextureImage: error binding external image: %#04x", error); return UNKNOWN_ERROR; } } @@ -511,12 +524,12 @@ status_t GLConsumer::checkAndUpdateEglStateLocked(bool contextCheck) { } if (mEglDisplay != dpy || dpy == EGL_NO_DISPLAY) { - ST_LOGE("checkAndUpdateEglState: invalid current EGLDisplay"); + GLC_LOGE("checkAndUpdateEglState: invalid current EGLDisplay"); return INVALID_OPERATION; } if (mEglContext != ctx || ctx == EGL_NO_CONTEXT) { - ST_LOGE("checkAndUpdateEglState: invalid current EGLContext"); + GLC_LOGE("checkAndUpdateEglState: invalid current EGLContext"); return INVALID_OPERATION; } @@ -531,7 +544,7 @@ void GLConsumer::setReleaseFence(const sp<Fence>& fence) { status_t err = addReleaseFence(mCurrentTexture, mCurrentTextureImage->graphicBuffer(), fence); if (err != OK) { - ST_LOGE("setReleaseFence: failed to add the fence: %s (%d)", + GLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err); } } @@ -539,16 +552,16 @@ void GLConsumer::setReleaseFence(const sp<Fence>& fence) { status_t GLConsumer::detachFromContext() { ATRACE_CALL(); - ST_LOGV("detachFromContext"); + GLC_LOGV("detachFromContext"); Mutex::Autolock lock(mMutex); if (mAbandoned) { - ST_LOGE("detachFromContext: abandoned GLConsumer"); + GLC_LOGE("detachFromContext: abandoned GLConsumer"); return NO_INIT; } if (!mAttached) { - ST_LOGE("detachFromContext: GLConsumer is not attached to a " + GLC_LOGE("detachFromContext: GLConsumer is not attached to a " "context"); return INVALID_OPERATION; } @@ -557,12 +570,12 @@ status_t GLConsumer::detachFromContext() { EGLContext ctx = eglGetCurrentContext(); if (mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) { - ST_LOGE("detachFromContext: invalid current EGLDisplay"); + GLC_LOGE("detachFromContext: invalid current EGLDisplay"); return INVALID_OPERATION; } if (mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) { - ST_LOGE("detachFromContext: invalid current EGLContext"); + GLC_LOGE("detachFromContext: invalid current EGLContext"); return INVALID_OPERATION; } @@ -584,16 +597,16 @@ status_t GLConsumer::detachFromContext() { status_t GLConsumer::attachToContext(uint32_t tex) { ATRACE_CALL(); - ST_LOGV("attachToContext"); + GLC_LOGV("attachToContext"); Mutex::Autolock lock(mMutex); if (mAbandoned) { - ST_LOGE("attachToContext: abandoned GLConsumer"); + GLC_LOGE("attachToContext: abandoned GLConsumer"); return NO_INIT; } if (mAttached) { - ST_LOGE("attachToContext: GLConsumer is already attached to a " + GLC_LOGE("attachToContext: GLConsumer is already attached to a " "context"); return INVALID_OPERATION; } @@ -602,12 +615,12 @@ status_t GLConsumer::attachToContext(uint32_t tex) { EGLContext ctx = eglGetCurrentContext(); if (dpy == EGL_NO_DISPLAY) { - ST_LOGE("attachToContext: invalid current EGLDisplay"); + GLC_LOGE("attachToContext: invalid current EGLDisplay"); return INVALID_OPERATION; } if (ctx == EGL_NO_CONTEXT) { - ST_LOGE("attachToContext: invalid current EGLContext"); + GLC_LOGE("attachToContext: invalid current EGLContext"); return INVALID_OPERATION; } @@ -636,14 +649,14 @@ status_t GLConsumer::attachToContext(uint32_t tex) { status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { - ST_LOGV("syncForReleaseLocked"); + GLC_LOGV("syncForReleaseLocked"); if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { if (SyncFeatures::getInstance().useNativeFenceSync()) { EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); if (sync == EGL_NO_SYNC_KHR) { - ST_LOGE("syncForReleaseLocked: error creating EGL fence: %#x", + GLC_LOGE("syncForReleaseLocked: error creating EGL fence: %#x", eglGetError()); return UNKNOWN_ERROR; } @@ -651,7 +664,7 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync); eglDestroySyncKHR(dpy, sync); if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { - ST_LOGE("syncForReleaseLocked: error dup'ing native fence " + GLC_LOGE("syncForReleaseLocked: error dup'ing native fence " "fd: %#x", eglGetError()); return UNKNOWN_ERROR; } @@ -659,7 +672,7 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { status_t err = addReleaseFenceLocked(mCurrentTexture, mCurrentTextureImage->graphicBuffer(), fence); if (err != OK) { - ST_LOGE("syncForReleaseLocked: error adding release fence: " + GLC_LOGE("syncForReleaseLocked: error adding release fence: " "%s (%d)", strerror(-err), err); return err; } @@ -672,11 +685,11 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { // before the producer accesses it. EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000); if (result == EGL_FALSE) { - ST_LOGE("syncForReleaseLocked: error waiting for previous " + GLC_LOGE("syncForReleaseLocked: error waiting for previous " "fence: %#x", eglGetError()); return UNKNOWN_ERROR; } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { - ST_LOGE("syncForReleaseLocked: timeout waiting for previous " + GLC_LOGE("syncForReleaseLocked: timeout waiting for previous " "fence"); return TIMED_OUT; } @@ -687,7 +700,7 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { // OpenGL ES context. fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL); if (fence == EGL_NO_SYNC_KHR) { - ST_LOGE("syncForReleaseLocked: error creating fence: %#x", + GLC_LOGE("syncForReleaseLocked: error creating fence: %#x", eglGetError()); return UNKNOWN_ERROR; } @@ -699,7 +712,7 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { return OK; } -bool GLConsumer::isExternalFormat(uint32_t format) +bool GLConsumer::isExternalFormat(PixelFormat format) { switch (format) { // supported YUV formats @@ -730,14 +743,14 @@ void GLConsumer::getTransformMatrix(float mtx[16]) { void GLConsumer::setFilteringEnabled(bool enabled) { Mutex::Autolock lock(mMutex); if (mAbandoned) { - ST_LOGE("setFilteringEnabled: GLConsumer is abandoned!"); + GLC_LOGE("setFilteringEnabled: GLConsumer is abandoned!"); return; } bool needsRecompute = mFilteringEnabled != enabled; mFilteringEnabled = enabled; if (needsRecompute && mCurrentTextureImage==NULL) { - ST_LOGD("setFilteringEnabled called with mCurrentTextureImage == NULL"); + GLC_LOGD("setFilteringEnabled called with mCurrentTextureImage == NULL"); } if (needsRecompute && mCurrentTextureImage != NULL) { @@ -746,7 +759,7 @@ void GLConsumer::setFilteringEnabled(bool enabled) { } void GLConsumer::computeCurrentTransformMatrixLocked() { - ST_LOGV("computeCurrentTransformMatrixLocked"); + GLC_LOGV("computeCurrentTransformMatrixLocked"); float xform[16]; for (int i = 0; i < 16; i++) { @@ -778,7 +791,7 @@ void GLConsumer::computeCurrentTransformMatrixLocked() { NULL : mCurrentTextureImage->graphicBuffer(); if (buf == NULL) { - ST_LOGD("computeCurrentTransformMatrixLocked: mCurrentTextureImage is NULL"); + GLC_LOGD("computeCurrentTransformMatrixLocked: mCurrentTextureImage is NULL"); } float mtxBeforeFlipV[16]; @@ -850,13 +863,13 @@ void GLConsumer::computeCurrentTransformMatrixLocked() { } nsecs_t GLConsumer::getTimestamp() { - ST_LOGV("getTimestamp"); + GLC_LOGV("getTimestamp"); Mutex::Autolock lock(mMutex); return mCurrentTimestamp; } -nsecs_t GLConsumer::getFrameNumber() { - ST_LOGV("getFrameNumber"); +uint64_t GLConsumer::getFrameNumber() { + GLC_LOGV("getFrameNumber"); Mutex::Autolock lock(mMutex); return mCurrentFrameNumber; } @@ -872,30 +885,37 @@ Rect GLConsumer::getCurrentCrop() const { Rect outCrop = mCurrentCrop; if (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) { - int32_t newWidth = mCurrentCrop.width(); - int32_t newHeight = mCurrentCrop.height(); + 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; - ST_LOGV("too wide: newWidth = %d", newWidth); + GLC_LOGV("too wide: newWidth = %d", newWidth); } else if (newWidth * mDefaultHeight < newHeight * mDefaultWidth) { newHeight = newWidth * mDefaultHeight / mDefaultWidth; - ST_LOGV("too tall: newHeight = %d", newHeight); + 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 < mCurrentCrop.width()) { - int32_t dw = (newWidth - mCurrentCrop.width())/2; - outCrop.left -=dw; - outCrop.right += dw; + 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 < mCurrentCrop.height()) { - int32_t dh = (newHeight - mCurrentCrop.height())/2; - outCrop.top -= dh; - outCrop.bottom += dh; + } 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); } - ST_LOGV("getCurrentCrop final crop [%d,%d,%d,%d]", + GLC_LOGV("getCurrentCrop final crop [%d,%d,%d,%d]", outCrop.left, outCrop.top, outCrop.right,outCrop.bottom); } @@ -929,12 +949,12 @@ status_t GLConsumer::doGLFenceWaitLocked() const { EGLContext ctx = eglGetCurrentContext(); if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) { - ST_LOGE("doGLFenceWait: invalid current EGLDisplay"); + GLC_LOGE("doGLFenceWait: invalid current EGLDisplay"); return INVALID_OPERATION; } if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) { - ST_LOGE("doGLFenceWait: invalid current EGLContext"); + GLC_LOGE("doGLFenceWait: invalid current EGLContext"); return INVALID_OPERATION; } @@ -943,7 +963,7 @@ status_t GLConsumer::doGLFenceWaitLocked() const { // Create an EGLSyncKHR from the current fence. int fenceFd = mCurrentFence->dup(); if (fenceFd == -1) { - ST_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno); + GLC_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno); return -errno; } EGLint attribs[] = { @@ -954,7 +974,7 @@ status_t GLConsumer::doGLFenceWaitLocked() const { EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); if (sync == EGL_NO_SYNC_KHR) { close(fenceFd); - ST_LOGE("doGLFenceWait: error creating EGL fence: %#x", + GLC_LOGE("doGLFenceWait: error creating EGL fence: %#x", eglGetError()); return UNKNOWN_ERROR; } @@ -966,7 +986,7 @@ status_t GLConsumer::doGLFenceWaitLocked() const { EGLint eglErr = eglGetError(); eglDestroySyncKHR(dpy, sync); if (eglErr != EGL_SUCCESS) { - ST_LOGE("doGLFenceWait: error waiting for EGL fence: %#x", + GLC_LOGE("doGLFenceWait: error waiting for EGL fence: %#x", eglErr); return UNKNOWN_ERROR; } @@ -974,7 +994,7 @@ status_t GLConsumer::doGLFenceWaitLocked() const { status_t err = mCurrentFence->waitForever( "GLConsumer::doGLFenceWaitLocked"); if (err != NO_ERROR) { - ST_LOGE("doGLFenceWait: error waiting for fence: %d", err); + GLC_LOGE("doGLFenceWait: error waiting for fence: %d", err); return err; } } @@ -984,7 +1004,7 @@ status_t GLConsumer::doGLFenceWaitLocked() const { } void GLConsumer::freeBufferLocked(int slotIndex) { - ST_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); + GLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); if (slotIndex == mCurrentTexture) { mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT; } @@ -993,7 +1013,7 @@ void GLConsumer::freeBufferLocked(int slotIndex) { } void GLConsumer::abandonLocked() { - ST_LOGV("abandonLocked"); + GLC_LOGV("abandonLocked"); mCurrentTextureImage.clear(); ConsumerBase::abandonLocked(); } @@ -1004,11 +1024,17 @@ void GLConsumer::setName(const String8& name) { mConsumer->setConsumerName(name); } -status_t GLConsumer::setDefaultBufferFormat(uint32_t defaultFormat) { +status_t GLConsumer::setDefaultBufferFormat(PixelFormat defaultFormat) { Mutex::Autolock lock(mMutex); return mConsumer->setDefaultBufferFormat(defaultFormat); } +status_t GLConsumer::setDefaultBufferDataSpace( + android_dataspace defaultDataSpace) { + Mutex::Autolock lock(mMutex); + return mConsumer->setDefaultBufferDataSpace(defaultDataSpace); +} + status_t GLConsumer::setConsumerUsageBits(uint32_t usage) { Mutex::Autolock lock(mMutex); usage |= DEFAULT_USAGE_FLAGS; @@ -1107,12 +1133,14 @@ status_t GLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay, } void GLConsumer::EglImage::bindToTextureTarget(uint32_t texTarget) { - glEGLImageTargetTexture2DOES(texTarget, (GLeglImageOES)mEglImage); + glEGLImageTargetTexture2DOES(texTarget, + static_cast<GLeglImageOES>(mEglImage)); } EGLImageKHR GLConsumer::EglImage::createImage(EGLDisplay dpy, const sp<GraphicBuffer>& graphicBuffer, const Rect& crop) { - EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer(); + EGLClientBuffer cbuf = + static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer()); EGLint attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_IMAGE_CROP_LEFT_ANDROID, crop.left, diff --git a/libs/gui/GraphicBufferAlloc.cpp b/libs/gui/GraphicBufferAlloc.cpp index b360e81d41..9643402dfa 100644 --- a/libs/gui/GraphicBufferAlloc.cpp +++ b/libs/gui/GraphicBufferAlloc.cpp @@ -31,9 +31,10 @@ GraphicBufferAlloc::GraphicBufferAlloc() { GraphicBufferAlloc::~GraphicBufferAlloc() { } -sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h, - PixelFormat format, uint32_t usage, status_t* error) { - sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage)); +sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t width, + uint32_t height, PixelFormat format, uint32_t usage, status_t* error) { + sp<GraphicBuffer> graphicBuffer( + new GraphicBuffer(width, height, format, usage)); status_t err = graphicBuffer->initCheck(); *error = err; if (err != 0 || graphicBuffer->handle == 0) { @@ -42,7 +43,7 @@ sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h } ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) " "failed (%s), handle=%p", - w, h, strerror(-err), graphicBuffer->handle); + width, height, strerror(-err), graphicBuffer->handle); return 0; } return graphicBuffer; diff --git a/libs/gui/IConsumerListener.cpp b/libs/gui/IConsumerListener.cpp index 409dfe4ee0..cab7dc3d5a 100644 --- a/libs/gui/IConsumerListener.cpp +++ b/libs/gui/IConsumerListener.cpp @@ -40,6 +40,8 @@ public: : BpInterface<IConsumerListener>(impl) { } + virtual ~BpConsumerListener(); + virtual void onFrameAvailable(const BufferItem& item) { Parcel data, reply; data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor()); @@ -60,6 +62,10 @@ public: } }; +// Out-of-line virtual method definition to trigger vtable emission in this +// translation unit (see clang warning -Wweak-vtables) +BpConsumerListener::~BpConsumerListener() {} + IMPLEMENT_META_INTERFACE(ConsumerListener, "android.gui.IConsumerListener"); // ---------------------------------------------------------------------- diff --git a/libs/gui/IDisplayEventConnection.cpp b/libs/gui/IDisplayEventConnection.cpp index 887d176b44..9890f44ef7 100644 --- a/libs/gui/IDisplayEventConnection.cpp +++ b/libs/gui/IDisplayEventConnection.cpp @@ -44,6 +44,8 @@ public: { } + virtual ~BpDisplayEventConnection(); + virtual sp<BitTube> getDataChannel() const { Parcel data, reply; @@ -55,7 +57,7 @@ public: virtual void setVsyncRate(uint32_t count) { Parcel data, reply; data.writeInterfaceToken(IDisplayEventConnection::getInterfaceDescriptor()); - data.writeInt32(count); + data.writeUint32(count); remote()->transact(SET_VSYNC_RATE, data, &reply); } @@ -66,6 +68,10 @@ public: } }; +// Out-of-line virtual method definition to trigger vtable emission in this +// translation unit (see clang warning -Wweak-vtables) +BpDisplayEventConnection::~BpDisplayEventConnection() {} + IMPLEMENT_META_INTERFACE(DisplayEventConnection, "android.gui.DisplayEventConnection"); // ---------------------------------------------------------------------------- @@ -79,17 +85,17 @@ status_t BnDisplayEventConnection::onTransact( sp<BitTube> channel(getDataChannel()); channel->writeToParcel(reply); return NO_ERROR; - } break; + } case SET_VSYNC_RATE: { CHECK_INTERFACE(IDisplayEventConnection, data, reply); - setVsyncRate(data.readInt32()); + setVsyncRate(data.readUint32()); return NO_ERROR; - } break; + } case REQUEST_NEXT_VSYNC: { CHECK_INTERFACE(IDisplayEventConnection, data, reply); requestNextVsync(); return NO_ERROR; - } break; + } } return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp index 139f2199a3..3009989964 100644 --- a/libs/gui/IGraphicBufferAlloc.cpp +++ b/libs/gui/IGraphicBufferAlloc.cpp @@ -42,20 +42,26 @@ public: { } - virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h, - PixelFormat format, uint32_t usage, status_t* error) { + virtual ~BpGraphicBufferAlloc(); + + virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t width, + uint32_t height, PixelFormat format, uint32_t usage, + status_t* error) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferAlloc::getInterfaceDescriptor()); - data.writeInt32(w); - data.writeInt32(h); - data.writeInt32(format); - data.writeInt32(usage); + data.writeUint32(width); + data.writeUint32(height); + data.writeInt32(static_cast<int32_t>(format)); + data.writeUint32(usage); remote()->transact(CREATE_GRAPHIC_BUFFER, data, &reply); sp<GraphicBuffer> graphicBuffer; status_t result = reply.readInt32(); if (result == NO_ERROR) { graphicBuffer = new GraphicBuffer(); result = reply.read(*graphicBuffer); + if (result != NO_ERROR) { + graphicBuffer.clear(); + } // reply.readStrongBinder(); // here we don't even have to read the BufferReference from // the parcel, it'll die with the parcel. @@ -65,6 +71,10 @@ public: } }; +// Out-of-line virtual method definition to trigger vtable emission in this +// translation unit (see clang warning -Wweak-vtables) +BpGraphicBufferAlloc::~BpGraphicBufferAlloc() {} + IMPLEMENT_META_INTERFACE(GraphicBufferAlloc, "android.ui.IGraphicBufferAlloc"); // ---------------------------------------------------------------------- @@ -74,27 +84,26 @@ status_t BnGraphicBufferAlloc::onTransact( { // codes that don't require permission check - /* BufferReference just keeps a strong reference to a - * GraphicBuffer until it is destroyed (that is, until - * no local or remote process have a reference to it). - */ + // BufferReference just keeps a strong reference to a GraphicBuffer until it + // is destroyed (that is, until no local or remote process have a reference + // to it). class BufferReference : public BBinder { - sp<GraphicBuffer> buffer; + sp<GraphicBuffer> mBuffer; public: - BufferReference(const sp<GraphicBuffer>& buffer) : buffer(buffer) { } + BufferReference(const sp<GraphicBuffer>& buffer) : mBuffer(buffer) {} }; - switch(code) { + switch (code) { case CREATE_GRAPHIC_BUFFER: { CHECK_INTERFACE(IGraphicBufferAlloc, data, reply); - uint32_t w = data.readInt32(); - uint32_t h = data.readInt32(); - PixelFormat format = data.readInt32(); - uint32_t usage = data.readInt32(); + uint32_t width = data.readUint32(); + uint32_t height = data.readUint32(); + PixelFormat format = static_cast<PixelFormat>(data.readInt32()); + uint32_t usage = data.readUint32(); status_t error; sp<GraphicBuffer> result = - createGraphicBuffer(w, h, format, usage, &error); + createGraphicBuffer(width, height, format, usage, &error); reply->writeInt32(error); if (result != 0) { reply->write(*result); @@ -107,7 +116,7 @@ status_t BnGraphicBufferAlloc::onTransact( reply->writeStrongBinder( new BufferReference(result) ); } return NO_ERROR; - } break; + } default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp index 590a25e4cc..7ae82e0561 100644 --- a/libs/gui/IGraphicBufferConsumer.cpp +++ b/libs/gui/IGraphicBufferConsumer.cpp @@ -23,6 +23,7 @@ #include <binder/Parcel.h> #include <binder/IInterface.h> +#include <gui/BufferItem.h> #include <gui/IConsumerListener.h> #include <gui/IGraphicBufferConsumer.h> @@ -32,159 +33,6 @@ #include <system/window.h> namespace android { -// --------------------------------------------------------------------------- - -IGraphicBufferConsumer::BufferItem::BufferItem() : - mTransform(0), - mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), - mTimestamp(0), - mIsAutoTimestamp(false), - mFrameNumber(0), - mBuf(INVALID_BUFFER_SLOT), - mIsDroppable(false), - mAcquireCalled(false), - mTransformToDisplayInverse(false) { - mCrop.makeInvalid(); -} - -size_t IGraphicBufferConsumer::BufferItem::getPodSize() const { - size_t c = sizeof(mCrop) + - sizeof(mTransform) + - sizeof(mScalingMode) + - sizeof(mTimestamp) + - sizeof(mIsAutoTimestamp) + - sizeof(mFrameNumber) + - sizeof(mBuf) + - sizeof(mIsDroppable) + - sizeof(mAcquireCalled) + - sizeof(mTransformToDisplayInverse); - return c; -} - -size_t IGraphicBufferConsumer::BufferItem::getFlattenedSize() const { - size_t c = 0; - if (mGraphicBuffer != 0) { - c += mGraphicBuffer->getFlattenedSize(); - c = FlattenableUtils::align<4>(c); - } - if (mFence != 0) { - c += mFence->getFlattenedSize(); - c = FlattenableUtils::align<4>(c); - } - return sizeof(int32_t) + c + getPodSize(); -} - -size_t IGraphicBufferConsumer::BufferItem::getFdCount() const { - size_t c = 0; - if (mGraphicBuffer != 0) { - c += mGraphicBuffer->getFdCount(); - } - if (mFence != 0) { - c += mFence->getFdCount(); - } - return c; -} - -static void writeBoolAsInt(void*& buffer, size_t& size, bool b) { - FlattenableUtils::write(buffer, size, static_cast<int32_t>(b)); -} - -static bool readBoolFromInt(void const*& buffer, size_t& size) { - int32_t i; - FlattenableUtils::read(buffer, size, i); - return static_cast<bool>(i); -} - -status_t IGraphicBufferConsumer::BufferItem::flatten( - void*& buffer, size_t& size, int*& fds, size_t& count) const { - - // make sure we have enough space - if (size < BufferItem::getFlattenedSize()) { - return NO_MEMORY; - } - - // content flags are stored first - uint32_t& flags = *static_cast<uint32_t*>(buffer); - - // advance the pointer - FlattenableUtils::advance(buffer, size, sizeof(uint32_t)); - - flags = 0; - 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 != 0) { - status_t err = mFence->flatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - flags |= 2; - } - - // check we have enough space (in case flattening the fence/graphicbuffer lied to us) - if (size < getPodSize()) { - return NO_MEMORY; - } - - FlattenableUtils::write(buffer, size, mCrop); - FlattenableUtils::write(buffer, size, mTransform); - FlattenableUtils::write(buffer, size, mScalingMode); - FlattenableUtils::write(buffer, size, mTimestamp); - writeBoolAsInt(buffer, size, mIsAutoTimestamp); - FlattenableUtils::write(buffer, size, mFrameNumber); - FlattenableUtils::write(buffer, size, mBuf); - writeBoolAsInt(buffer, size, mIsDroppable); - writeBoolAsInt(buffer, size, mAcquireCalled); - writeBoolAsInt(buffer, size, mTransformToDisplayInverse); - - return NO_ERROR; -} - -status_t IGraphicBufferConsumer::BufferItem::unflatten( - void const*& buffer, size_t& size, int const*& fds, size_t& count) { - - if (size < sizeof(uint32_t)) - return NO_MEMORY; - - uint32_t flags = 0; - FlattenableUtils::read(buffer, size, flags); - - if (flags & 1) { - mGraphicBuffer = new GraphicBuffer(); - status_t err = mGraphicBuffer->unflatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - } - - if (flags & 2) { - mFence = new Fence(); - status_t err = mFence->unflatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - } - - // check we have enough space - if (size < getPodSize()) { - return NO_MEMORY; - } - - FlattenableUtils::read(buffer, size, mCrop); - FlattenableUtils::read(buffer, size, mTransform); - FlattenableUtils::read(buffer, size, mScalingMode); - FlattenableUtils::read(buffer, size, mTimestamp); - mIsAutoTimestamp = readBoolFromInt(buffer, size); - FlattenableUtils::read(buffer, size, mFrameNumber); - FlattenableUtils::read(buffer, size, mBuf); - mIsDroppable = readBoolFromInt(buffer, size); - mAcquireCalled = readBoolFromInt(buffer, size); - mTransformToDisplayInverse = readBoolFromInt(buffer, size); - - return NO_ERROR; -} - -// --------------------------------------------------------------------------- enum { ACQUIRE_BUFFER = IBinder::FIRST_CALL_TRANSACTION, @@ -200,6 +48,7 @@ enum { SET_MAX_ACQUIRED_BUFFER_COUNT, SET_CONSUMER_NAME, SET_DEFAULT_BUFFER_FORMAT, + SET_DEFAULT_BUFFER_DATA_SPACE, SET_CONSUMER_USAGE_BITS, SET_TRANSFORM_HINT, GET_SIDEBAND_STREAM, @@ -215,10 +64,14 @@ public: { } - virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) { + virtual ~BpGraphicBufferConsumer(); + + virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen, + uint64_t maxFrameNumber) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); data.writeInt64(presentWhen); + data.writeUint64(maxFrameNumber); status_t result = remote()->transact(ACQUIRE_BUFFER, data, &reply); if (result != NO_ERROR) { return result; @@ -261,7 +114,7 @@ public: Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); data.writeInt32(buf); - data.writeInt64(frameNumber); + data.writeInt64(static_cast<int64_t>(frameNumber)); data.write(*releaseFence); status_t result = remote()->transact(RELEASE_BUFFER, data, &reply); if (result != NO_ERROR) { @@ -273,7 +126,7 @@ public: virtual status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeStrongBinder(consumer->asBinder()); + data.writeStrongBinder(IInterface::asBinder(consumer)); data.writeInt32(controlledByApp); status_t result = remote()->transact(CONSUMER_CONNECT, data, &reply); if (result != NO_ERROR) { @@ -303,15 +156,15 @@ public: if (result != NO_ERROR) { return result; } - *slotMask = reply.readInt64(); + *slotMask = static_cast<uint64_t>(reply.readInt64()); return reply.readInt32(); } - virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) { + virtual status_t setDefaultBufferSize(uint32_t width, uint32_t height) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(w); - data.writeInt32(h); + data.writeUint32(width); + data.writeUint32(height); status_t result = remote()->transact(SET_DEFAULT_BUFFER_SIZE, data, &reply); if (result != NO_ERROR) { return result; @@ -358,10 +211,10 @@ public: remote()->transact(SET_CONSUMER_NAME, data, &reply); } - virtual status_t setDefaultBufferFormat(uint32_t defaultFormat) { + virtual status_t setDefaultBufferFormat(PixelFormat defaultFormat) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(defaultFormat); + data.writeInt32(static_cast<int32_t>(defaultFormat)); status_t result = remote()->transact(SET_DEFAULT_BUFFER_FORMAT, data, &reply); if (result != NO_ERROR) { return result; @@ -369,10 +222,23 @@ public: return reply.readInt32(); } + virtual status_t setDefaultBufferDataSpace( + android_dataspace defaultDataSpace) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInt32(static_cast<int32_t>(defaultDataSpace)); + status_t result = remote()->transact(SET_DEFAULT_BUFFER_DATA_SPACE, + data, &reply); + if (result != NO_ERROR) { + return result; + } + return reply.readInt32(); + } + virtual status_t setConsumerUsageBits(uint32_t usage) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(usage); + data.writeUint32(usage); status_t result = remote()->transact(SET_CONSUMER_USAGE_BITS, data, &reply); if (result != NO_ERROR) { return result; @@ -383,7 +249,7 @@ public: virtual status_t setTransformHint(uint32_t hint) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(hint); + data.writeUint32(hint); status_t result = remote()->transact(SET_TRANSFORM_HINT, data, &reply); if (result != NO_ERROR) { return result; @@ -415,6 +281,10 @@ public: } }; +// Out-of-line virtual method definition to trigger vtable emission in this +// translation unit (see clang warning -Wweak-vtables) +BpGraphicBufferConsumer::~BpGraphicBufferConsumer() {} + IMPLEMENT_META_INTERFACE(GraphicBufferConsumer, "android.gui.IGraphicBufferConsumer"); // ---------------------------------------------------------------------- @@ -427,19 +297,20 @@ status_t BnGraphicBufferConsumer::onTransact( CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); BufferItem item; int64_t presentWhen = data.readInt64(); - status_t result = acquireBuffer(&item, presentWhen); + uint64_t maxFrameNumber = data.readUint64(); + status_t result = acquireBuffer(&item, presentWhen, maxFrameNumber); status_t err = reply->write(item); if (err) return err; reply->writeInt32(result); return NO_ERROR; - } break; + } case DETACH_BUFFER: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); int slot = data.readInt32(); int result = detachBuffer(slot); reply->writeInt32(result); return NO_ERROR; - } break; + } case ATTACH_BUFFER: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); sp<GraphicBuffer> buffer = new GraphicBuffer(); @@ -449,11 +320,11 @@ status_t BnGraphicBufferConsumer::onTransact( reply->writeInt32(slot); reply->writeInt32(result); return NO_ERROR; - } break; + } case RELEASE_BUFFER: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); int buf = data.readInt32(); - uint64_t frameNumber = data.readInt64(); + uint64_t frameNumber = static_cast<uint64_t>(data.readInt64()); sp<Fence> releaseFence = new Fence(); status_t err = data.read(*releaseFence); if (err) return err; @@ -461,7 +332,7 @@ status_t BnGraphicBufferConsumer::onTransact( EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, releaseFence); reply->writeInt32(result); return NO_ERROR; - } break; + } case CONSUMER_CONNECT: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); sp<IConsumerListener> consumer = IConsumerListener::asInterface( data.readStrongBinder() ); @@ -469,75 +340,92 @@ status_t BnGraphicBufferConsumer::onTransact( status_t result = consumerConnect(consumer, controlledByApp); reply->writeInt32(result); return NO_ERROR; - } break; + } case CONSUMER_DISCONNECT: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); status_t result = consumerDisconnect(); reply->writeInt32(result); return NO_ERROR; - } break; + } case GET_RELEASED_BUFFERS: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); uint64_t slotMask = 0; status_t result = getReleasedBuffers(&slotMask); - reply->writeInt64(slotMask); + reply->writeInt64(static_cast<int64_t>(slotMask)); reply->writeInt32(result); return NO_ERROR; - } break; + } case SET_DEFAULT_BUFFER_SIZE: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); - uint32_t w = data.readInt32(); - uint32_t h = data.readInt32(); - status_t result = setDefaultBufferSize(w, h); + uint32_t width = data.readUint32(); + uint32_t height = data.readUint32(); + status_t result = setDefaultBufferSize(width, height); reply->writeInt32(result); return NO_ERROR; - } break; + } case SET_DEFAULT_MAX_BUFFER_COUNT: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); - uint32_t bufferCount = data.readInt32(); + int bufferCount = data.readInt32(); status_t result = setDefaultMaxBufferCount(bufferCount); reply->writeInt32(result); return NO_ERROR; - } break; + } case DISABLE_ASYNC_BUFFER: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); status_t result = disableAsyncBuffer(); reply->writeInt32(result); return NO_ERROR; - } break; + } case SET_MAX_ACQUIRED_BUFFER_COUNT: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); - uint32_t maxAcquiredBuffers = data.readInt32(); + int maxAcquiredBuffers = data.readInt32(); status_t result = setMaxAcquiredBufferCount(maxAcquiredBuffers); reply->writeInt32(result); return NO_ERROR; - } break; + } case SET_CONSUMER_NAME: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); setConsumerName( data.readString8() ); return NO_ERROR; - } break; + } case SET_DEFAULT_BUFFER_FORMAT: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); - uint32_t defaultFormat = data.readInt32(); + PixelFormat defaultFormat = static_cast<PixelFormat>(data.readInt32()); status_t result = setDefaultBufferFormat(defaultFormat); reply->writeInt32(result); return NO_ERROR; - } break; + } + case SET_DEFAULT_BUFFER_DATA_SPACE: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + android_dataspace defaultDataSpace = + static_cast<android_dataspace>(data.readInt32()); + status_t result = setDefaultBufferDataSpace(defaultDataSpace); + reply->writeInt32(result); + return NO_ERROR; + } case SET_CONSUMER_USAGE_BITS: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); - uint32_t usage = data.readInt32(); + uint32_t usage = data.readUint32(); status_t result = setConsumerUsageBits(usage); reply->writeInt32(result); return NO_ERROR; - } break; + } case SET_TRANSFORM_HINT: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); - uint32_t hint = data.readInt32(); + uint32_t hint = data.readUint32(); status_t result = setTransformHint(hint); reply->writeInt32(result); return NO_ERROR; - } break; + } + case GET_SIDEBAND_STREAM: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + sp<NativeHandle> stream = getSidebandStream(); + reply->writeInt32(static_cast<int32_t>(stream != NULL)); + if (stream != NULL) { + reply->writeNativeHandle(stream->handle()); + } + return NO_ERROR; + } case DUMP: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); String8 result = data.readString8(); diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index b5ec604a96..c3c62358fa 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -46,6 +46,9 @@ enum { DISCONNECT, SET_SIDEBAND_STREAM, ALLOCATE_BUFFERS, + ALLOW_ALLOCATION, + SET_GENERATION_NUMBER, + GET_CONSUMER_NAME, }; class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer> @@ -56,6 +59,8 @@ public: { } + virtual ~BpGraphicBufferProducer(); + virtual status_t requestBuffer(int bufferIdx, sp<GraphicBuffer>* buf) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); @@ -91,14 +96,15 @@ public: } virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, bool async, - uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { + uint32_t width, uint32_t height, PixelFormat format, + uint32_t usage) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); - data.writeInt32(async); - data.writeInt32(w); - data.writeInt32(h); - data.writeInt32(format); - data.writeInt32(usage); + data.writeInt32(static_cast<int32_t>(async)); + data.writeUint32(width); + data.writeUint32(height); + data.writeInt32(static_cast<int32_t>(format)); + data.writeUint32(usage); status_t result = remote()->transact(DEQUEUE_BUFFER, data, &reply); if (result != NO_ERROR) { return result; @@ -211,7 +217,7 @@ public: data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); if (listener != NULL) { data.writeInt32(1); - data.writeStrongBinder(listener->asBinder()); + data.writeStrongBinder(IInterface::asBinder(listener)); } else { data.writeInt32(0); } @@ -255,21 +261,59 @@ public: } virtual void allocateBuffers(bool async, uint32_t width, uint32_t height, - uint32_t format, uint32_t usage) { + PixelFormat format, uint32_t usage) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(static_cast<int32_t>(async)); - data.writeInt32(static_cast<int32_t>(width)); - data.writeInt32(static_cast<int32_t>(height)); + data.writeUint32(width); + data.writeUint32(height); data.writeInt32(static_cast<int32_t>(format)); - data.writeInt32(static_cast<int32_t>(usage)); + data.writeUint32(usage); status_t result = remote()->transact(ALLOCATE_BUFFERS, data, &reply); if (result != NO_ERROR) { ALOGE("allocateBuffers failed to transact: %d", result); } } + + virtual status_t allowAllocation(bool allow) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); + data.writeInt32(static_cast<int32_t>(allow)); + status_t result = remote()->transact(ALLOW_ALLOCATION, data, &reply); + if (result != NO_ERROR) { + return result; + } + result = reply.readInt32(); + return result; + } + + virtual status_t setGenerationNumber(uint32_t generationNumber) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); + data.writeUint32(generationNumber); + status_t result = remote()->transact(SET_GENERATION_NUMBER, data, &reply); + if (result == NO_ERROR) { + result = reply.readInt32(); + } + return result; + } + + virtual String8 getConsumerName() const { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); + status_t result = remote()->transact(GET_CONSUMER_NAME, data, &reply); + if (result != NO_ERROR) { + ALOGE("getConsumerName failed to transact: %d", result); + return String8("TransactFailed"); + } + return reply.readString8(); + } }; +// Out-of-line virtual method definition to trigger vtable emission in this +// translation unit (see clang warning -Wweak-vtables) +BpGraphicBufferProducer::~BpGraphicBufferProducer() {} + IMPLEMENT_META_INTERFACE(GraphicBufferProducer, "android.gui.IGraphicBufferProducer"); // ---------------------------------------------------------------------- @@ -289,24 +333,25 @@ status_t BnGraphicBufferProducer::onTransact( } reply->writeInt32(result); return NO_ERROR; - } break; + } case SET_BUFFER_COUNT: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int bufferCount = data.readInt32(); int result = setBufferCount(bufferCount); reply->writeInt32(result); return NO_ERROR; - } break; + } case DEQUEUE_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); - bool async = data.readInt32(); - uint32_t w = data.readInt32(); - uint32_t h = data.readInt32(); - uint32_t format = data.readInt32(); - uint32_t usage = data.readInt32(); + bool async = static_cast<bool>(data.readInt32()); + uint32_t width = data.readUint32(); + uint32_t height = data.readUint32(); + PixelFormat format = static_cast<PixelFormat>(data.readInt32()); + uint32_t usage = data.readUint32(); int buf = 0; sp<Fence> fence; - int result = dequeueBuffer(&buf, &fence, async, w, h, format, usage); + int result = dequeueBuffer(&buf, &fence, async, width, height, + format, usage); reply->writeInt32(buf); reply->writeInt32(fence != NULL); if (fence != NULL) { @@ -314,14 +359,14 @@ status_t BnGraphicBufferProducer::onTransact( } reply->writeInt32(result); return NO_ERROR; - } break; + } case DETACH_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int slot = data.readInt32(); int result = detachBuffer(slot); reply->writeInt32(result); return NO_ERROR; - } break; + } case DETACH_NEXT_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); sp<GraphicBuffer> buffer; @@ -339,7 +384,7 @@ status_t BnGraphicBufferProducer::onTransact( } } return NO_ERROR; - } break; + } case ATTACH_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); sp<GraphicBuffer> buffer = new GraphicBuffer(); @@ -349,7 +394,7 @@ status_t BnGraphicBufferProducer::onTransact( reply->writeInt32(slot); reply->writeInt32(result); return NO_ERROR; - } break; + } case QUEUE_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int buf = data.readInt32(); @@ -361,7 +406,7 @@ status_t BnGraphicBufferProducer::onTransact( status_t result = queueBuffer(buf, input, output); reply->writeInt32(result); return NO_ERROR; - } break; + } case CANCEL_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int buf = data.readInt32(); @@ -369,7 +414,7 @@ status_t BnGraphicBufferProducer::onTransact( data.read(*fence.get()); cancelBuffer(buf, fence); return NO_ERROR; - } break; + } case QUERY: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int value = 0; @@ -378,7 +423,7 @@ status_t BnGraphicBufferProducer::onTransact( reply->writeInt32(value); reply->writeInt32(res); return NO_ERROR; - } break; + } case CONNECT: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); sp<IProducerListener> listener; @@ -394,14 +439,14 @@ status_t BnGraphicBufferProducer::onTransact( status_t res = connect(listener, api, producerControlledByApp, output); reply->writeInt32(res); return NO_ERROR; - } break; + } case DISCONNECT: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int api = data.readInt32(); status_t res = disconnect(api); reply->writeInt32(res); return NO_ERROR; - } break; + } case SET_SIDEBAND_STREAM: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); sp<NativeHandle> stream; @@ -411,16 +456,36 @@ status_t BnGraphicBufferProducer::onTransact( status_t result = setSidebandStream(stream); reply->writeInt32(result); return NO_ERROR; - } break; - case ALLOCATE_BUFFERS: + } + case ALLOCATE_BUFFERS: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); bool async = static_cast<bool>(data.readInt32()); - uint32_t width = static_cast<uint32_t>(data.readInt32()); - uint32_t height = static_cast<uint32_t>(data.readInt32()); - uint32_t format = static_cast<uint32_t>(data.readInt32()); - uint32_t usage = static_cast<uint32_t>(data.readInt32()); + uint32_t width = data.readUint32(); + uint32_t height = data.readUint32(); + PixelFormat format = static_cast<PixelFormat>(data.readInt32()); + uint32_t usage = data.readUint32(); allocateBuffers(async, width, height, format, usage); return NO_ERROR; + } + case ALLOW_ALLOCATION: { + CHECK_INTERFACE(IGraphicBufferProducer, data, reply); + bool allow = static_cast<bool>(data.readInt32()); + status_t result = allowAllocation(allow); + reply->writeInt32(result); + return NO_ERROR; + } + case SET_GENERATION_NUMBER: { + CHECK_INTERFACE(IGraphicBufferProducer, data, reply); + uint32_t generationNumber = data.readUint32(); + status_t result = setGenerationNumber(generationNumber); + reply->writeInt32(result); + return NO_ERROR; + } + case GET_CONSUMER_NAME: { + CHECK_INTERFACE(IGraphicBufferProducer, data, reply); + reply->writeString8(getConsumerName()); + return NO_ERROR; + } } return BBinder::onTransact(code, data, reply, flags); } @@ -434,12 +499,14 @@ IGraphicBufferProducer::QueueBufferInput::QueueBufferInput(const Parcel& parcel) size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const { return sizeof(timestamp) + sizeof(isAutoTimestamp) + + sizeof(dataSpace) + sizeof(crop) + sizeof(scalingMode) + sizeof(transform) + sizeof(stickyTransform) + sizeof(async) - + fence->getFlattenedSize(); + + fence->getFlattenedSize() + + surfaceDamage.getFlattenedSize(); } size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const { @@ -454,12 +521,17 @@ status_t IGraphicBufferProducer::QueueBufferInput::flatten( } FlattenableUtils::write(buffer, size, timestamp); FlattenableUtils::write(buffer, size, isAutoTimestamp); + FlattenableUtils::write(buffer, size, dataSpace); FlattenableUtils::write(buffer, size, crop); FlattenableUtils::write(buffer, size, scalingMode); FlattenableUtils::write(buffer, size, transform); FlattenableUtils::write(buffer, size, stickyTransform); FlattenableUtils::write(buffer, size, async); - return fence->flatten(buffer, size, fds, count); + status_t result = fence->flatten(buffer, size, fds, count); + if (result != NO_ERROR) { + return result; + } + return surfaceDamage.flatten(buffer, size); } status_t IGraphicBufferProducer::QueueBufferInput::unflatten( @@ -468,6 +540,7 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten( size_t minNeeded = sizeof(timestamp) + sizeof(isAutoTimestamp) + + sizeof(dataSpace) + sizeof(crop) + sizeof(scalingMode) + sizeof(transform) @@ -480,6 +553,7 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten( FlattenableUtils::read(buffer, size, timestamp); FlattenableUtils::read(buffer, size, isAutoTimestamp); + FlattenableUtils::read(buffer, size, dataSpace); FlattenableUtils::read(buffer, size, crop); FlattenableUtils::read(buffer, size, scalingMode); FlattenableUtils::read(buffer, size, transform); @@ -487,7 +561,11 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten( FlattenableUtils::read(buffer, size, async); fence = new Fence(); - return fence->unflatten(buffer, size, fds, count); + status_t result = fence->unflatten(buffer, size, fds, count); + if (result != NO_ERROR) { + return result; + } + return surfaceDamage.unflatten(buffer, size); } }; // namespace android diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp index efe4069e28..81adc95449 100644 --- a/libs/gui/IProducerListener.cpp +++ b/libs/gui/IProducerListener.cpp @@ -30,6 +30,8 @@ public: BpProducerListener(const sp<IBinder>& impl) : BpInterface<IProducerListener>(impl) {} + virtual ~BpProducerListener(); + virtual void onBufferReleased() { Parcel data, reply; data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor()); @@ -37,6 +39,10 @@ public: } }; +// Out-of-line virtual method definition to trigger vtable emission in this +// translation unit (see clang warning -Wweak-vtables) +BpProducerListener::~BpProducerListener() {} + IMPLEMENT_META_INTERFACE(ProducerListener, "android.gui.IProducerListener") status_t BnProducerListener::onTransact(uint32_t code, const Parcel& data, diff --git a/libs/gui/ISensorEventConnection.cpp b/libs/gui/ISensorEventConnection.cpp index 28fcb53d8f..dc7a35cef9 100644 --- a/libs/gui/ISensorEventConnection.cpp +++ b/libs/gui/ISensorEventConnection.cpp @@ -45,6 +45,8 @@ public: { } + virtual ~BpSensorEventConnection(); + virtual sp<BitTube> getSensorChannel() const { Parcel data, reply; @@ -85,6 +87,10 @@ public: } }; +// Out-of-line virtual method definition to trigger vtable emission in this +// translation unit (see clang warning -Wweak-vtables) +BpSensorEventConnection::~BpSensorEventConnection() {} + IMPLEMENT_META_INTERFACE(SensorEventConnection, "android.gui.SensorEventConnection"); // ---------------------------------------------------------------------------- @@ -98,7 +104,7 @@ status_t BnSensorEventConnection::onTransact( sp<BitTube> channel(getSensorChannel()); channel->writeToParcel(reply); return NO_ERROR; - } break; + } case ENABLE_DISABLE: { CHECK_INTERFACE(ISensorEventConnection, data, reply); int handle = data.readInt32(); @@ -110,21 +116,21 @@ status_t BnSensorEventConnection::onTransact( maxBatchReportLatencyNs, reservedFlags); reply->writeInt32(result); return NO_ERROR; - } break; + } case SET_EVENT_RATE: { CHECK_INTERFACE(ISensorEventConnection, data, reply); int handle = data.readInt32(); - int ns = data.readInt64(); + nsecs_t ns = data.readInt64(); status_t result = setEventRate(handle, ns); reply->writeInt32(result); return NO_ERROR; - } break; + } case FLUSH_SENSOR: { CHECK_INTERFACE(ISensorEventConnection, data, reply); status_t result = flush(); reply->writeInt32(result); return NO_ERROR; - } break; + } } return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/ISensorServer.cpp b/libs/gui/ISensorServer.cpp index 0b76f3788c..f581b5c1d4 100644 --- a/libs/gui/ISensorServer.cpp +++ b/libs/gui/ISensorServer.cpp @@ -35,6 +35,7 @@ namespace android { enum { GET_SENSOR_LIST = IBinder::FIRST_CALL_TRANSACTION, CREATE_SENSOR_EVENT_CONNECTION, + ENABLE_DATA_INJECTION }; class BpSensorServer : public BpInterface<ISensorServer> @@ -45,14 +46,17 @@ public: { } - virtual Vector<Sensor> getSensorList() + virtual ~BpSensorServer(); + + virtual Vector<Sensor> getSensorList(const String16& opPackageName) { Parcel data, reply; data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor()); + data.writeString16(opPackageName); remote()->transact(GET_SENSOR_LIST, data, &reply); Sensor s; Vector<Sensor> v; - int32_t n = reply.readInt32(); + uint32_t n = reply.readUint32(); v.setCapacity(n); while (n--) { reply.read(s); @@ -61,15 +65,30 @@ public: return v; } - virtual sp<ISensorEventConnection> createSensorEventConnection() + virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName, + int mode, const String16& opPackageName) { Parcel data, reply; data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor()); + data.writeString8(packageName); + data.writeInt32(mode); + data.writeString16(opPackageName); remote()->transact(CREATE_SENSOR_EVENT_CONNECTION, data, &reply); return interface_cast<ISensorEventConnection>(reply.readStrongBinder()); } + + virtual int isDataInjectionEnabled() { + Parcel data, reply; + data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor()); + remote()->transact(ENABLE_DATA_INJECTION, data, &reply); + return reply.readInt32(); + } }; +// Out-of-line virtual method definition to trigger vtable emission in this +// translation unit (see clang warning -Wweak-vtables) +BpSensorServer::~BpSensorServer() {} + IMPLEMENT_META_INTERFACE(SensorServer, "android.gui.SensorServer"); // ---------------------------------------------------------------------- @@ -80,20 +99,31 @@ status_t BnSensorServer::onTransact( switch(code) { case GET_SENSOR_LIST: { CHECK_INTERFACE(ISensorServer, data, reply); - Vector<Sensor> v(getSensorList()); + const String16& opPackageName = data.readString16(); + Vector<Sensor> v(getSensorList(opPackageName)); size_t n = v.size(); - reply->writeInt32(n); - for (size_t i=0 ; i<n ; i++) { + reply->writeUint32(static_cast<uint32_t>(n)); + for (size_t i = 0; i < n; i++) { reply->write(v[i]); } return NO_ERROR; - } break; + } case CREATE_SENSOR_EVENT_CONNECTION: { CHECK_INTERFACE(ISensorServer, data, reply); - sp<ISensorEventConnection> connection(createSensorEventConnection()); - reply->writeStrongBinder(connection->asBinder()); + String8 packageName = data.readString8(); + int32_t mode = data.readInt32(); + const String16& opPackageName = data.readString16(); + sp<ISensorEventConnection> connection(createSensorEventConnection(packageName, mode, + opPackageName)); + reply->writeStrongBinder(IInterface::asBinder(connection)); return NO_ERROR; - } break; + } + case ENABLE_DATA_INJECTION: { + CHECK_INTERFACE(ISensorServer, data, reply); + int32_t ret = isDataInjectionEnabled(); + reply->writeInt32(static_cast<int32_t>(ret)); + return NO_ERROR; + } } return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index ebb687a28a..78886d5bb6 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -51,9 +51,10 @@ public: { } + virtual ~BpSurfaceComposer(); + virtual sp<ISurfaceComposerClient> createConnection() { - uint32_t n; Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); remote()->transact(BnSurfaceComposer::CREATE_CONNECTION, data, &reply); @@ -62,7 +63,6 @@ public: virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc() { - uint32_t n; Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); remote()->transact(BnSurfaceComposer::CREATE_GRAPHIC_BUFFER_ALLOC, data, &reply); @@ -76,23 +76,18 @@ public: { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - { - Vector<ComposerState>::const_iterator b(state.begin()); - Vector<ComposerState>::const_iterator e(state.end()); - data.writeInt32(state.size()); - for ( ; b != e ; ++b ) { - b->write(data); - } + + data.writeUint32(static_cast<uint32_t>(state.size())); + for (const auto& s : state) { + s.write(data); } - { - Vector<DisplayState>::const_iterator b(displays.begin()); - Vector<DisplayState>::const_iterator e(displays.end()); - data.writeInt32(displays.size()); - for ( ; b != e ; ++b ) { - b->write(data); - } + + data.writeUint32(static_cast<uint32_t>(displays.size())); + for (const auto& d : displays) { + d.write(data); } - data.writeInt32(flags); + + data.writeUint32(flags); remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply); } @@ -113,12 +108,12 @@ public: Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); - data.writeStrongBinder(producer->asBinder()); + data.writeStrongBinder(IInterface::asBinder(producer)); data.write(sourceCrop); - data.writeInt32(reqWidth); - data.writeInt32(reqHeight); - data.writeInt32(minLayerZ); - data.writeInt32(maxLayerZ); + data.writeUint32(reqWidth); + data.writeUint32(reqHeight); + data.writeUint32(minLayerZ); + data.writeUint32(maxLayerZ); data.writeInt32(static_cast<int32_t>(useIdentityTransform)); data.writeInt32(static_cast<int32_t>(rotation)); remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply); @@ -137,7 +132,7 @@ public: "interface descriptor: %s (%d)", strerror(-err), -err); return false; } - err = data.writeStrongBinder(bufferProducer->asBinder()); + err = data.writeStrongBinder(IInterface::asBinder(bufferProducer)); if (err != NO_ERROR) { ALOGE("ISurfaceComposer::authenticateSurfaceTexture: error writing " "strong binder to parcel: %s (%d)", strerror(-err), -err); @@ -226,7 +221,7 @@ public: remote()->transact(BnSurfaceComposer::GET_DISPLAY_CONFIGS, data, &reply); status_t result = reply.readInt32(); if (result == NO_ERROR) { - size_t numConfigs = static_cast<size_t>(reply.readInt32()); + size_t numConfigs = reply.readUint32(); configs->clear(); configs->resize(numConfigs); for (size_t c = 0; c < numConfigs; ++c) { @@ -289,6 +284,10 @@ public: } }; +// Out-of-line virtual method definition to trigger vtable emission in this +// translation unit (see clang warning -Wweak-vtables) +BpSurfaceComposer::~BpSurfaceComposer() {} + IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer"); // ---------------------------------------------------------------------- @@ -299,46 +298,49 @@ status_t BnSurfaceComposer::onTransact( switch(code) { case CREATE_CONNECTION: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IBinder> b = createConnection()->asBinder(); + sp<IBinder> b = IInterface::asBinder(createConnection()); reply->writeStrongBinder(b); return NO_ERROR; } case CREATE_GRAPHIC_BUFFER_ALLOC: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IBinder> b = createGraphicBufferAlloc()->asBinder(); + sp<IBinder> b = IInterface::asBinder(createGraphicBufferAlloc()); reply->writeStrongBinder(b); return NO_ERROR; } case SET_TRANSACTION_STATE: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - size_t count = data.readInt32(); + + size_t count = data.readUint32(); if (count > data.dataSize()) { return BAD_VALUE; } ComposerState s; Vector<ComposerState> state; state.setCapacity(count); - for (size_t i=0 ; i<count ; i++) { + for (size_t i = 0; i < count; i++) { if (s.read(data) == BAD_VALUE) { return BAD_VALUE; } state.add(s); } - count = data.readInt32(); + + count = data.readUint32(); if (count > data.dataSize()) { return BAD_VALUE; } DisplayState d; Vector<DisplayState> displays; displays.setCapacity(count); - for (size_t i=0 ; i<count ; i++) { + for (size_t i = 0; i < count; i++) { if (d.read(data) == BAD_VALUE) { return BAD_VALUE; } displays.add(d); } - uint32_t flags = data.readInt32(); - setTransactionState(state, displays, flags); + + uint32_t stateFlags = data.readUint32(); + setTransactionState(state, displays, stateFlags); return NO_ERROR; } case BOOT_FINISHED: { @@ -353,12 +355,12 @@ status_t BnSurfaceComposer::onTransact( interface_cast<IGraphicBufferProducer>(data.readStrongBinder()); Rect sourceCrop; data.read(sourceCrop); - uint32_t reqWidth = data.readInt32(); - uint32_t reqHeight = data.readInt32(); - uint32_t minLayerZ = data.readInt32(); - uint32_t maxLayerZ = data.readInt32(); + uint32_t reqWidth = data.readUint32(); + uint32_t reqHeight = data.readUint32(); + uint32_t minLayerZ = data.readUint32(); + uint32_t maxLayerZ = data.readUint32(); bool useIdentityTransform = static_cast<bool>(data.readInt32()); - uint32_t rotation = data.readInt32(); + int32_t rotation = data.readInt32(); status_t res = captureScreen(display, producer, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, @@ -378,7 +380,7 @@ status_t BnSurfaceComposer::onTransact( case CREATE_DISPLAY_EVENT_CONNECTION: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp<IDisplayEventConnection> connection(createDisplayEventConnection()); - reply->writeStrongBinder(connection->asBinder()); + reply->writeStrongBinder(IInterface::asBinder(connection)); return NO_ERROR; } case CREATE_DISPLAY: { @@ -409,7 +411,7 @@ status_t BnSurfaceComposer::onTransact( status_t result = getDisplayConfigs(display, &configs); reply->writeInt32(result); if (result == NO_ERROR) { - reply->writeInt32(static_cast<int32_t>(configs.size())); + reply->writeUint32(static_cast<uint32_t>(configs.size())); for (size_t c = 0; c < configs.size(); ++c) { memcpy(reply->writeInplace(sizeof(DisplayInfo)), &configs[c], sizeof(DisplayInfo)); @@ -469,8 +471,6 @@ status_t BnSurfaceComposer::onTransact( return BBinder::onTransact(code, data, reply, flags); } } - // should be unreachable - return NO_ERROR; } // ---------------------------------------------------------------------------- diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp index 3da6423f42..2ecb9083ff 100644 --- a/libs/gui/ISurfaceComposerClient.cpp +++ b/libs/gui/ISurfaceComposerClient.cpp @@ -51,17 +51,19 @@ public: : BpInterface<ISurfaceComposerClient>(impl) { } - virtual status_t createSurface(const String8& name, uint32_t w, - uint32_t h, PixelFormat format, uint32_t flags, + virtual ~BpSurfaceComposerClient(); + + virtual status_t createSurface(const String8& name, uint32_t width, + uint32_t height, PixelFormat format, uint32_t flags, sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); data.writeString8(name); - data.writeInt32(w); - data.writeInt32(h); - data.writeInt32(format); - data.writeInt32(flags); + data.writeUint32(width); + data.writeUint32(height); + data.writeInt32(static_cast<int32_t>(format)); + data.writeUint32(flags); remote()->transact(CREATE_SURFACE, data, &reply); *handle = reply.readStrongBinder(); *gbp = interface_cast<IGraphicBufferProducer>(reply.readStrongBinder()); @@ -94,6 +96,10 @@ public: } }; +// Out-of-line virtual method definition to trigger vtable emission in this +// translation unit (see clang warning -Wweak-vtables) +BpSurfaceComposerClient::~BpSurfaceComposerClient() {} + IMPLEMENT_META_INTERFACE(SurfaceComposerClient, "android.ui.ISurfaceComposerClient"); // ---------------------------------------------------------------------- @@ -105,31 +111,31 @@ status_t BnSurfaceComposerClient::onTransact( case CREATE_SURFACE: { CHECK_INTERFACE(ISurfaceComposerClient, data, reply); String8 name = data.readString8(); - uint32_t w = data.readInt32(); - uint32_t h = data.readInt32(); - PixelFormat format = data.readInt32(); - uint32_t flags = data.readInt32(); + uint32_t width = data.readUint32(); + uint32_t height = data.readUint32(); + PixelFormat format = static_cast<PixelFormat>(data.readInt32()); + uint32_t createFlags = data.readUint32(); sp<IBinder> handle; sp<IGraphicBufferProducer> gbp; - status_t result = createSurface(name, w, h, format, flags, - &handle, &gbp); + status_t result = createSurface(name, width, height, format, + createFlags, &handle, &gbp); reply->writeStrongBinder(handle); - reply->writeStrongBinder(gbp->asBinder()); + reply->writeStrongBinder(IInterface::asBinder(gbp)); reply->writeInt32(result); return NO_ERROR; - } break; + } case DESTROY_SURFACE: { CHECK_INTERFACE(ISurfaceComposerClient, data, reply); reply->writeInt32(destroySurface( data.readStrongBinder() ) ); return NO_ERROR; - } break; + } case CLEAR_LAYER_FRAME_STATS: { CHECK_INTERFACE(ISurfaceComposerClient, data, reply); sp<IBinder> handle = data.readStrongBinder(); status_t result = clearLayerFrameStats(handle); reply->writeInt32(result); return NO_ERROR; - } break; + } case GET_LAYER_FRAME_STATS: { CHECK_INTERFACE(ISurfaceComposerClient, data, reply); sp<IBinder> handle = data.readStrongBinder(); @@ -138,7 +144,7 @@ status_t BnSurfaceComposerClient::onTransact( reply->write(stats); reply->writeInt32(result); return NO_ERROR; - } break; + } default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 1183d59215..00323dc4f2 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -25,16 +25,16 @@ namespace android { status_t layer_state_t::write(Parcel& output) const { output.writeStrongBinder(surface); - output.writeInt32(what); + output.writeUint32(what); output.writeFloat(x); output.writeFloat(y); - output.writeInt32(z); - output.writeInt32(w); - output.writeInt32(h); - output.writeInt32(layerStack); + output.writeUint32(z); + output.writeUint32(w); + output.writeUint32(h); + output.writeUint32(layerStack); output.writeFloat(alpha); - output.writeInt32(flags); - output.writeInt32(mask); + output.writeUint32(flags); + output.writeUint32(mask); *reinterpret_cast<layer_state_t::matrix22_t *>( output.writeInplace(sizeof(layer_state_t::matrix22_t))) = matrix; output.write(crop); @@ -45,16 +45,16 @@ status_t layer_state_t::write(Parcel& output) const status_t layer_state_t::read(const Parcel& input) { surface = input.readStrongBinder(); - what = input.readInt32(); + what = input.readUint32(); x = input.readFloat(); y = input.readFloat(); - z = input.readInt32(); - w = input.readInt32(); - h = input.readInt32(); - layerStack = input.readInt32(); + z = input.readUint32(); + w = input.readUint32(); + h = input.readUint32(); + layerStack = input.readUint32(); alpha = input.readFloat(); - flags = input.readInt32(); - mask = input.readInt32(); + flags = static_cast<uint8_t>(input.readUint32()); + mask = static_cast<uint8_t>(input.readUint32()); const void* matrix_data = input.readInplace(sizeof(layer_state_t::matrix22_t)); if (matrix_data) { matrix = *reinterpret_cast<layer_state_t::matrix22_t const *>(matrix_data); @@ -67,7 +67,7 @@ status_t layer_state_t::read(const Parcel& input) } status_t ComposerState::write(Parcel& output) const { - output.writeStrongBinder(client->asBinder()); + output.writeStrongBinder(IInterface::asBinder(client)); return state.write(output); } @@ -79,27 +79,27 @@ status_t ComposerState::read(const Parcel& input) { status_t DisplayState::write(Parcel& output) const { output.writeStrongBinder(token); - output.writeStrongBinder(surface->asBinder()); - output.writeInt32(what); - output.writeInt32(layerStack); - output.writeInt32(orientation); + output.writeStrongBinder(IInterface::asBinder(surface)); + output.writeUint32(what); + output.writeUint32(layerStack); + output.writeUint32(orientation); output.write(viewport); output.write(frame); - output.writeInt32(width); - output.writeInt32(height); + output.writeUint32(width); + output.writeUint32(height); return NO_ERROR; } status_t DisplayState::read(const Parcel& input) { token = input.readStrongBinder(); surface = interface_cast<IGraphicBufferProducer>(input.readStrongBinder()); - what = input.readInt32(); - layerStack = input.readInt32(); - orientation = input.readInt32(); + what = input.readUint32(); + layerStack = input.readUint32(); + orientation = input.readUint32(); input.read(viewport); input.read(frame); - width = input.readInt32(); - height = input.readInt32(); + width = input.readUint32(); + height = input.readUint32(); return NO_ERROR; } diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp index b4291bb7ca..4b3603ee12 100644 --- a/libs/gui/Sensor.cpp +++ b/libs/gui/Sensor.cpp @@ -25,6 +25,9 @@ #include <hardware/sensors.h> +#include <binder/AppOpsManager.h> +#include <binder/IServiceManager.h> + #include <gui/Sensor.h> #include <log/log.h> @@ -72,7 +75,7 @@ Sensor::Sensor(struct sensor_t const* hwSensor, int halVersion) static_cast<int64_t>(hwSensor->maxDelay)); mMaxDelay = INT_MAX; } else { - mMaxDelay = (int32_t) hwSensor->maxDelay; + mMaxDelay = static_cast<int32_t>(hwSensor->maxDelay); } } else { // For older hals set maxDelay to 0. @@ -113,11 +116,13 @@ Sensor::Sensor(struct sensor_t const* hwSensor, int halVersion) mStringType = SENSOR_STRING_TYPE_GYROSCOPE_UNCALIBRATED; mFlags |= SENSOR_FLAG_CONTINUOUS_MODE; break; - case SENSOR_TYPE_HEART_RATE: + case SENSOR_TYPE_HEART_RATE: { mStringType = SENSOR_STRING_TYPE_HEART_RATE; mRequiredPermission = SENSOR_PERMISSION_BODY_SENSORS; + AppOpsManager appOps; + mRequiredAppOp = appOps.permissionToOpCode(String16(SENSOR_PERMISSION_BODY_SENSORS)); mFlags |= SENSOR_FLAG_ON_CHANGE_MODE; - break; + } break; case SENSOR_TYPE_LIGHT: mStringType = SENSOR_STRING_TYPE_LIGHT; mFlags |= SENSOR_FLAG_ON_CHANGE_MODE; @@ -204,6 +209,13 @@ Sensor::Sensor(struct sensor_t const* hwSensor, int halVersion) mFlags |= SENSOR_FLAG_WAKE_UP; } break; + case SENSOR_TYPE_WRIST_TILT_GESTURE: + mStringType = SENSOR_STRING_TYPE_WRIST_TILT_GESTURE; + mFlags |= SENSOR_FLAG_SPECIAL_REPORTING_MODE; + if (halVersion < SENSORS_DEVICE_API_VERSION_1_3) { + mFlags |= SENSOR_FLAG_WAKE_UP; + } + break; default: // Only pipe the stringType, requiredPermission and flags for custom sensors. if (halVersion > SENSORS_DEVICE_API_VERSION_1_0 && hwSensor->stringType) { @@ -211,10 +223,14 @@ Sensor::Sensor(struct sensor_t const* hwSensor, int halVersion) } if (halVersion > SENSORS_DEVICE_API_VERSION_1_0 && hwSensor->requiredPermission) { mRequiredPermission = hwSensor->requiredPermission; + if (!strcmp(mRequiredPermission, SENSOR_PERMISSION_BODY_SENSORS)) { + AppOpsManager appOps; + mRequiredAppOp = appOps.permissionToOpCode(String16(SENSOR_PERMISSION_BODY_SENSORS)); + } } if (halVersion >= SENSORS_DEVICE_API_VERSION_1_3) { - mFlags = (int32_t) hwSensor->flags; + mFlags = static_cast<uint32_t>(hwSensor->flags); } else { // This is an OEM defined sensor on an older HAL. Use minDelay to determine the // reporting mode of the sensor. @@ -245,6 +261,17 @@ Sensor::Sensor(struct sensor_t const* hwSensor, int halVersion) } } + + if (mRequiredPermission.length() > 0) { + // If the sensor is protected by a permission we need to know if it is + // a runtime one to determine whether we can use the permission cache. + sp<IBinder> binder = defaultServiceManager()->getService(String16("permission")); + if (binder != 0) { + sp<IPermissionController> permCtrl = interface_cast<IPermissionController>(binder); + mRequiredPermissionRuntime = permCtrl->isRuntimePermission( + String16(mRequiredPermission)); + } + } } Sensor::~Sensor() @@ -295,11 +322,11 @@ int32_t Sensor::getVersion() const { return mVersion; } -int32_t Sensor::getFifoReservedEventCount() const { +uint32_t Sensor::getFifoReservedEventCount() const { return mFifoReservedEventCount; } -int32_t Sensor::getFifoMaxEventCount() const { +uint32_t Sensor::getFifoMaxEventCount() const { return mFifoMaxEventCount; } @@ -311,11 +338,19 @@ const String8& Sensor::getRequiredPermission() const { return mRequiredPermission; } +bool Sensor::isRequiredPermissionRuntime() const { + return mRequiredPermissionRuntime; +} + +int32_t Sensor::getRequiredAppOp() const { + return mRequiredAppOp; +} + int32_t Sensor::getMaxDelay() const { return mMaxDelay; } -int32_t Sensor::getFlags() const { +uint32_t Sensor::getFlags() const { return mFlags; } @@ -332,7 +367,8 @@ size_t Sensor::getFlattenedSize() const size_t fixedSize = sizeof(int32_t) * 3 + sizeof(float) * 4 + - sizeof(int32_t) * 5; + sizeof(int32_t) * 6 + + sizeof(bool); size_t variableSize = sizeof(uint32_t) + FlattenableUtils::align<4>(mName.length()) + @@ -362,6 +398,8 @@ status_t Sensor::flatten(void* buffer, size_t size) const { FlattenableUtils::write(buffer, size, mFifoMaxEventCount); flattenString8(buffer, size, mStringType); flattenString8(buffer, size, mRequiredPermission); + FlattenableUtils::write(buffer, size, mRequiredPermissionRuntime); + FlattenableUtils::write(buffer, size, mRequiredAppOp); FlattenableUtils::write(buffer, size, mMaxDelay); FlattenableUtils::write(buffer, size, mFlags); return NO_ERROR; @@ -400,6 +438,8 @@ status_t Sensor::unflatten(void const* buffer, size_t size) { if (!unflattenString8(buffer, size, mRequiredPermission)) { return NO_MEMORY; } + FlattenableUtils::read(buffer, size, mRequiredPermissionRuntime); + FlattenableUtils::read(buffer, size, mRequiredAppOp); FlattenableUtils::read(buffer, size, mMaxDelay); FlattenableUtils::read(buffer, size, mFlags); return NO_ERROR; @@ -407,7 +447,7 @@ status_t Sensor::unflatten(void const* buffer, size_t size) { void Sensor::flattenString8(void*& buffer, size_t& size, const String8& string8) { - uint32_t len = string8.length(); + uint32_t len = static_cast<uint32_t>(string8.length()); FlattenableUtils::write(buffer, size, len); memcpy(static_cast<char*>(buffer), string8.string(), len); FlattenableUtils::advance(buffer, size, FlattenableUtils::align<4>(len)); diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp index 1305e9f63a..4b7986e1d2 100644 --- a/libs/gui/SensorEventQueue.cpp +++ b/libs/gui/SensorEventQueue.cpp @@ -16,9 +16,11 @@ #define LOG_TAG "Sensors" +#include <algorithm> #include <stdint.h> #include <sys/types.h> #include <sys/socket.h> +#include <linux/errno.h> #include <utils/Errors.h> #include <utils/RefBase.h> @@ -31,6 +33,8 @@ #include <android/sensor.h> +using std::min; + // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- @@ -68,14 +72,14 @@ ssize_t SensorEventQueue::read(ASensorEvent* events, size_t numEvents) { if (err < 0) { return err; } - mAvailable = err; + mAvailable = static_cast<size_t>(err); mConsumed = 0; } - size_t count = numEvents < mAvailable ? numEvents : mAvailable; - memcpy(events, mRecBuffer + mConsumed, count*sizeof(ASensorEvent)); + size_t count = min(numEvents, mAvailable); + memcpy(events, mRecBuffer + mConsumed, count * sizeof(ASensorEvent)); mAvailable -= count; mConsumed += count; - return count; + return static_cast<ssize_t>(count); } sp<Looper> SensorEventQueue::getLooper() const @@ -146,6 +150,23 @@ status_t SensorEventQueue::setEventRate(Sensor const* sensor, nsecs_t ns) const return mSensorEventConnection->setEventRate(sensor->getHandle(), ns); } +status_t SensorEventQueue::injectSensorEvent(const ASensorEvent& event) { + do { + // Blocking call. + ssize_t size = ::send(mSensorChannel->getFd(), &event, sizeof(event), MSG_NOSIGNAL); + if (size >= 0) { + return NO_ERROR; + } else if (size < 0 && errno == EAGAIN) { + // If send is returning a "Try again" error, sleep for 100ms and try again. In all + // other cases log a failure and exit. + usleep(100000); + } else { + ALOGE("injectSensorEvent failure %s %zd", strerror(errno), size); + return INVALID_OPERATION; + } + } while (true); +} + void SensorEventQueue::sendAck(const ASensorEvent* events, int count) { for (int i = 0; i < count; ++i) { if (events[i].flags & WAKE_UP_SENSOR_EVENT_NEEDS_ACK) { @@ -157,7 +178,7 @@ void SensorEventQueue::sendAck(const ASensorEvent* events, int count) { ssize_t size = ::send(mSensorChannel->getFd(), &mNumAcksToSend, sizeof(mNumAcksToSend), MSG_DONTWAIT | MSG_NOSIGNAL); if (size < 0) { - ALOGE("sendAck failure %d %d", size, mNumAcksToSend); + ALOGE("sendAck failure %zd %d", size, mNumAcksToSend); } else { mNumAcksToSend = 0; } diff --git a/libs/gui/SensorManager.cpp b/libs/gui/SensorManager.cpp index 7b4fa2f560..dd3778137a 100644 --- a/libs/gui/SensorManager.cpp +++ b/libs/gui/SensorManager.cpp @@ -36,10 +36,8 @@ namespace android { // ---------------------------------------------------------------------------- -ANDROID_SINGLETON_STATIC_INSTANCE(SensorManager) - -SensorManager::SensorManager() - : mSensorList(0) +SensorManager::SensorManager(const String16& opPackageName) + : mSensorList(0), mOpPackageName(opPackageName) { // okay we're not locked here, but it's not needed during construction assertStateLocked(); @@ -86,11 +84,12 @@ status_t SensorManager::assertStateLocked() const { }; mDeathObserver = new DeathObserver(*const_cast<SensorManager *>(this)); - mSensorServer->asBinder()->linkToDeath(mDeathObserver); + IInterface::asBinder(mSensorServer)->linkToDeath(mDeathObserver); - mSensors = mSensorServer->getSensorList(); + mSensors = mSensorServer->getSensorList(mOpPackageName); size_t count = mSensors.size(); - mSensorList = (Sensor const**)malloc(count * sizeof(Sensor*)); + mSensorList = + static_cast<Sensor const**>(malloc(count * sizeof(Sensor*))); for (size_t i=0 ; i<count ; i++) { mSensorList[i] = mSensors.array() + i; } @@ -99,17 +98,15 @@ status_t SensorManager::assertStateLocked() const { return NO_ERROR; } - - ssize_t SensorManager::getSensorList(Sensor const* const** list) const { Mutex::Autolock _l(mLock); status_t err = assertStateLocked(); if (err < 0) { - return ssize_t(err); + return static_cast<ssize_t>(err); } *list = mSensorList; - return mSensors.size(); + return static_cast<ssize_t>(mSensors.size()); } Sensor const* SensorManager::getDefaultSensor(int type) @@ -138,18 +135,17 @@ Sensor const* SensorManager::getDefaultSensor(int type) return NULL; } -sp<SensorEventQueue> SensorManager::createEventQueue() -{ +sp<SensorEventQueue> SensorManager::createEventQueue(String8 packageName, int mode) { sp<SensorEventQueue> queue; Mutex::Autolock _l(mLock); while (assertStateLocked() == NO_ERROR) { sp<ISensorEventConnection> connection = - mSensorServer->createSensorEventConnection(); + mSensorServer->createSensorEventConnection(packageName, mode, mOpPackageName); if (connection == NULL) { - // SensorService just died. - ALOGE("createEventQueue: connection is NULL. SensorService died."); - continue; + // SensorService just died or the app doesn't have required permissions. + ALOGE("createEventQueue: connection is NULL."); + return NULL; } queue = new SensorEventQueue(connection); break; @@ -157,5 +153,13 @@ sp<SensorEventQueue> SensorManager::createEventQueue() return queue; } +bool SensorManager::isDataInjectionEnabled() { + Mutex::Autolock _l(mLock); + if (assertStateLocked() == NO_ERROR) { + return mSensorServer->isDataInjectionEnabled(); + } + return false; +} + // ---------------------------------------------------------------------------- }; // namespace android diff --git a/libs/gui/StreamSplitter.cpp b/libs/gui/StreamSplitter.cpp index 5f39905e5e..43f9214fc7 100644 --- a/libs/gui/StreamSplitter.cpp +++ b/libs/gui/StreamSplitter.cpp @@ -20,6 +20,7 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 +#include <gui/BufferItem.h> #include <gui/IGraphicBufferConsumer.h> #include <gui/IGraphicBufferProducer.h> #include <gui/StreamSplitter.h> @@ -80,7 +81,7 @@ status_t StreamSplitter::addOutput( IGraphicBufferProducer::QueueBufferOutput queueBufferOutput; sp<OutputListener> listener(new OutputListener(this, outputQueue)); - outputQueue->asBinder()->linkToDeath(listener); + IInterface::asBinder(outputQueue)->linkToDeath(listener); status_t status = outputQueue->connect(listener, NATIVE_WINDOW_API_CPU, /* producerControlledByApp */ false, &queueBufferOutput); if (status != NO_ERROR) { @@ -123,7 +124,7 @@ void StreamSplitter::onFrameAvailable(const BufferItem& /* item */) { ++mOutstandingBuffers; // Acquire and detach the buffer from the input - IGraphicBufferConsumer::BufferItem bufferItem; + BufferItem bufferItem; status_t status = mInput->acquireBuffer(&bufferItem, /* presentWhen */ 0); LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "acquiring buffer from input failed (%d)", status); @@ -141,7 +142,8 @@ void StreamSplitter::onFrameAvailable(const BufferItem& /* item */) { IGraphicBufferProducer::QueueBufferInput queueInput( bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp, - bufferItem.mCrop, bufferItem.mScalingMode, + bufferItem.mDataSpace, bufferItem.mCrop, + static_cast<int32_t>(bufferItem.mScalingMode), bufferItem.mTransform, bufferItem.mIsDroppable, bufferItem.mFence); diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 0e2baa28fd..4b76f9834c 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -27,6 +27,7 @@ #include <utils/NativeHandle.h> #include <ui/Fence.h> +#include <ui/Region.h> #include <gui/IProducerListener.h> #include <gui/ISurfaceComposer.h> @@ -41,7 +42,8 @@ namespace android { Surface::Surface( const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp) - : mGraphicBufferProducer(bufferProducer) + : mGraphicBufferProducer(bufferProducer), + mGenerationNumber(0) { // Initialize the ANativeWindow function pointers. ANativeWindow::setSwapInterval = hook_setSwapInterval; @@ -64,6 +66,7 @@ Surface::Surface( mReqFormat = 0; mReqUsage = 0; mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO; + mDataSpace = HAL_DATASPACE_UNKNOWN; mCrop.clear(); mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; mTransform = 0; @@ -96,8 +99,20 @@ void Surface::setSidebandStream(const sp<NativeHandle>& stream) { void Surface::allocateBuffers() { uint32_t reqWidth = mReqWidth ? mReqWidth : mUserWidth; uint32_t reqHeight = mReqHeight ? mReqHeight : mUserHeight; - mGraphicBufferProducer->allocateBuffers(mSwapIntervalZero, mReqWidth, - mReqHeight, mReqFormat, mReqUsage); + mGraphicBufferProducer->allocateBuffers(mSwapIntervalZero, reqWidth, + reqHeight, mReqFormat, mReqUsage); +} + +status_t Surface::setGenerationNumber(uint32_t generation) { + status_t result = mGraphicBufferProducer->setGenerationNumber(generation); + if (result == NO_ERROR) { + mGenerationNumber = generation; + } + return result; +} + +String8 Surface::getConsumerName() const { + return mGraphicBufferProducer->getConsumerName(); } int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) { @@ -193,17 +208,17 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { ATRACE_CALL(); ALOGV("Surface::dequeueBuffer"); - int reqW; - int reqH; + uint32_t reqWidth; + uint32_t reqHeight; bool swapIntervalZero; - uint32_t reqFormat; + PixelFormat reqFormat; uint32_t reqUsage; { Mutex::Autolock lock(mMutex); - reqW = mReqWidth ? mReqWidth : mUserWidth; - reqH = mReqHeight ? mReqHeight : mUserHeight; + reqWidth = mReqWidth ? mReqWidth : mUserWidth; + reqHeight = mReqHeight ? mReqHeight : mUserHeight; swapIntervalZero = mSwapIntervalZero; reqFormat = mReqFormat; @@ -213,12 +228,12 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { int buf = -1; sp<Fence> fence; status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, swapIntervalZero, - reqW, reqH, reqFormat, reqUsage); + reqWidth, reqHeight, reqFormat, reqUsage); if (result < 0) { ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d, %d)" - "failed: %d", swapIntervalZero, reqW, reqH, reqFormat, reqUsage, - result); + "failed: %d", swapIntervalZero, reqWidth, reqHeight, reqFormat, + reqUsage, result); return result; } @@ -265,6 +280,9 @@ int Surface::cancelBuffer(android_native_buffer_t* buffer, Mutex::Autolock lock(mMutex); int i = getSlotFromBufferLocked(buffer); if (i < 0) { + if (fenceFd >= 0) { + close(fenceFd); + } return i; } sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); @@ -274,7 +292,6 @@ int Surface::cancelBuffer(android_native_buffer_t* buffer, int Surface::getSlotFromBufferLocked( android_native_buffer_t* buffer) const { - bool dumpedState = false; for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { if (mSlots[i].buffer != NULL && mSlots[i].buffer->handle == buffer->handle) { @@ -307,6 +324,9 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { } int i = getSlotFromBufferLocked(buffer); if (i < 0) { + if (fenceFd >= 0) { + close(fenceFd); + } return i; } @@ -318,8 +338,72 @@ 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, - crop, mScalingMode, mTransform ^ mStickyTransform, mSwapIntervalZero, - fence, mStickyTransform); + mDataSpace, crop, mScalingMode, mTransform ^ mStickyTransform, + mSwapIntervalZero, fence, mStickyTransform); + + if (mConnectedToCpu || mDirtyRegion.bounds() == Rect::INVALID_RECT) { + input.setSurfaceDamage(Region::INVALID_REGION); + } else { + // Here we do two things: + // 1) The surface damage was specified using the OpenGL ES convention of + // the origin being in the bottom-left corner. Here we flip to the + // convention that the rest of the system uses (top-left corner) by + // subtracting all top/bottom coordinates from the buffer height. + // 2) If the buffer is coming in rotated (for example, because the EGL + // implementation is reacting to the transform hint coming back from + // SurfaceFlinger), the surface damage needs to be rotated the + // opposite direction, since it was generated assuming an unrotated + // buffer (the app doesn't know that the EGL implementation is + // reacting to the transform hint behind its back). The + // transformations in the switch statement below apply those + // complementary rotations (e.g., if 90 degrees, rotate 270 degrees). + + int width = buffer->width; + int height = buffer->height; + bool rotated90 = (mTransform ^ mStickyTransform) & + NATIVE_WINDOW_TRANSFORM_ROT_90; + if (rotated90) { + std::swap(width, height); + } + + Region flippedRegion; + for (auto rect : mDirtyRegion) { + int left = rect.left; + int right = rect.right; + int top = height - rect.bottom; // Flip from OpenGL convention + int bottom = height - rect.top; // Flip from OpenGL convention + switch (mTransform ^ mStickyTransform) { + case NATIVE_WINDOW_TRANSFORM_ROT_90: { + // Rotate 270 degrees + Rect flippedRect{top, width - right, bottom, width - left}; + flippedRegion.orSelf(flippedRect); + break; + } + case NATIVE_WINDOW_TRANSFORM_ROT_180: { + // Rotate 180 degrees + Rect flippedRect{width - right, height - bottom, + width - left, height - top}; + flippedRegion.orSelf(flippedRect); + break; + } + case NATIVE_WINDOW_TRANSFORM_ROT_270: { + // Rotate 90 degrees + Rect flippedRect{height - bottom, left, + height - top, right}; + flippedRegion.orSelf(flippedRect); + break; + } + default: { + Rect flippedRect{left, top, right, bottom}; + flippedRegion.orSelf(flippedRect); + break; + } + } + } + + input.setSurfaceDamage(flippedRegion); + } + status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output); if (err != OK) { ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err); @@ -336,6 +420,11 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { mConsumerRunningBehind = (numPendingBuffers >= 2); + if (!mConnectedToCpu) { + // Clear surface damage back to full-buffer + mDirtyRegion = Region::INVALID_REGION; + } + return err; } @@ -347,7 +436,7 @@ int Surface::query(int what, int* value) const { switch (what) { case NATIVE_WINDOW_FORMAT: if (mReqFormat) { - *value = mReqFormat; + *value = static_cast<int>(mReqFormat); return NO_ERROR; } break; @@ -365,13 +454,15 @@ int Surface::query(int what, int* value) const { *value = NATIVE_WINDOW_SURFACE; return NO_ERROR; case NATIVE_WINDOW_DEFAULT_WIDTH: - *value = mUserWidth ? mUserWidth : mDefaultWidth; + *value = static_cast<int>( + mUserWidth ? mUserWidth : mDefaultWidth); return NO_ERROR; case NATIVE_WINDOW_DEFAULT_HEIGHT: - *value = mUserHeight ? mUserHeight : mDefaultHeight; + *value = static_cast<int>( + mUserHeight ? mUserHeight : mDefaultHeight); return NO_ERROR; case NATIVE_WINDOW_TRANSFORM_HINT: - *value = mTransformHint; + *value = static_cast<int>(mTransformHint); return NO_ERROR; case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: { status_t err = NO_ERROR; @@ -448,6 +539,12 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_SET_SIDEBAND_STREAM: res = dispatchSetSidebandStream(args); break; + case NATIVE_WINDOW_SET_BUFFERS_DATASPACE: + res = dispatchSetBuffersDataSpace(args); + break; + case NATIVE_WINDOW_SET_SURFACE_DAMAGE: + res = dispatchSetSurfaceDamage(args); + break; default: res = NAME_NOT_FOUND; break; @@ -467,7 +564,7 @@ int Surface::dispatchDisconnect(va_list args) { int Surface::dispatchSetUsage(va_list args) { int usage = va_arg(args, int); - return setUsage(usage); + return setUsage(static_cast<uint32_t>(usage)); } int Surface::dispatchSetCrop(va_list args) { @@ -477,49 +574,49 @@ int Surface::dispatchSetCrop(va_list args) { int Surface::dispatchSetBufferCount(va_list args) { size_t bufferCount = va_arg(args, size_t); - return setBufferCount(bufferCount); + return setBufferCount(static_cast<int32_t>(bufferCount)); } int Surface::dispatchSetBuffersGeometry(va_list args) { - int w = va_arg(args, int); - int h = va_arg(args, int); - int f = va_arg(args, int); - int err = setBuffersDimensions(w, h); + uint32_t width = va_arg(args, uint32_t); + uint32_t height = va_arg(args, uint32_t); + PixelFormat format = va_arg(args, PixelFormat); + int err = setBuffersDimensions(width, height); if (err != 0) { return err; } - return setBuffersFormat(f); + return setBuffersFormat(format); } int Surface::dispatchSetBuffersDimensions(va_list args) { - int w = va_arg(args, int); - int h = va_arg(args, int); - return setBuffersDimensions(w, h); + uint32_t width = va_arg(args, uint32_t); + uint32_t height = va_arg(args, uint32_t); + return setBuffersDimensions(width, height); } int Surface::dispatchSetBuffersUserDimensions(va_list args) { - int w = va_arg(args, int); - int h = va_arg(args, int); - return setBuffersUserDimensions(w, h); + uint32_t width = va_arg(args, uint32_t); + uint32_t height = va_arg(args, uint32_t); + return setBuffersUserDimensions(width, height); } int Surface::dispatchSetBuffersFormat(va_list args) { - int f = va_arg(args, int); - return setBuffersFormat(f); + PixelFormat format = va_arg(args, PixelFormat); + return setBuffersFormat(format); } int Surface::dispatchSetScalingMode(va_list args) { - int m = va_arg(args, int); - return setScalingMode(m); + int mode = va_arg(args, int); + return setScalingMode(mode); } int Surface::dispatchSetBuffersTransform(va_list args) { - int transform = va_arg(args, int); + uint32_t transform = va_arg(args, uint32_t); return setBuffersTransform(transform); } int Surface::dispatchSetBuffersStickyTransform(va_list args) { - int transform = va_arg(args, int); + uint32_t transform = va_arg(args, uint32_t); return setBuffersStickyTransform(transform); } @@ -545,10 +642,27 @@ int Surface::dispatchSetSidebandStream(va_list args) { return OK; } +int Surface::dispatchSetBuffersDataSpace(va_list args) { + android_dataspace dataspace = + static_cast<android_dataspace>(va_arg(args, int)); + return setBuffersDataSpace(dataspace); +} + +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); + setSurfaceDamage(rects, numRects); + return NO_ERROR; +} + int Surface::connect(int api) { + static sp<IProducerListener> listener = new DummyProducerListener(); + return connect(api, listener); +} + +int Surface::connect(int api, const sp<IProducerListener>& listener) { ATRACE_CALL(); ALOGV("Surface::connect"); - static sp<IProducerListener> listener = new DummyProducerListener(); Mutex::Autolock lock(mMutex); IGraphicBufferProducer::QueueBufferOutput output; int err = mGraphicBufferProducer->connect(listener, api, mProducerControlledByApp, &output); @@ -567,7 +681,13 @@ int Surface::connect(int api) { } if (!err && api == NATIVE_WINDOW_API_CPU) { mConnectedToCpu = true; + // Clear the dirty region in case we're switching from a non-CPU API + mDirtyRegion.clear(); + } else if (!err) { + // Initialize the dirty region for tracking surface damage + mDirtyRegion = Region::INVALID_REGION; } + return err; } @@ -595,6 +715,58 @@ int Surface::disconnect(int api) { return err; } +int Surface::detachNextBuffer(sp<GraphicBuffer>* outBuffer, + sp<Fence>* outFence) { + ATRACE_CALL(); + ALOGV("Surface::detachNextBuffer"); + + if (outBuffer == NULL || outFence == NULL) { + return BAD_VALUE; + } + + Mutex::Autolock lock(mMutex); + + sp<GraphicBuffer> buffer(NULL); + sp<Fence> fence(NULL); + status_t result = mGraphicBufferProducer->detachNextBuffer( + &buffer, &fence); + if (result != NO_ERROR) { + return result; + } + + *outBuffer = buffer; + if (fence != NULL && fence->isValid()) { + *outFence = fence; + } else { + *outFence = Fence::NO_FENCE; + } + + return NO_ERROR; +} + +int Surface::attachBuffer(ANativeWindowBuffer* buffer) +{ + ATRACE_CALL(); + ALOGV("Surface::attachBuffer"); + + Mutex::Autolock lock(mMutex); + + sp<GraphicBuffer> graphicBuffer(static_cast<GraphicBuffer*>(buffer)); + uint32_t priorGeneration = graphicBuffer->mGenerationNumber; + graphicBuffer->mGenerationNumber = mGenerationNumber; + int32_t attachedSlot = -1; + status_t result = mGraphicBufferProducer->attachBuffer( + &attachedSlot, graphicBuffer); + if (result != NO_ERROR) { + ALOGE("attachBuffer: IGraphicBufferProducer call failed (%d)", result); + graphicBuffer->mGenerationNumber = priorGeneration; + return result; + } + mSlots[attachedSlot].buffer = graphicBuffer; + + return NO_ERROR; +} + int Surface::setUsage(uint32_t reqUsage) { ALOGV("Surface::setUsage"); @@ -639,47 +811,38 @@ int Surface::setBufferCount(int bufferCount) return err; } -int Surface::setBuffersDimensions(int w, int h) +int Surface::setBuffersDimensions(uint32_t width, uint32_t height) { ATRACE_CALL(); ALOGV("Surface::setBuffersDimensions"); - if (w<0 || h<0) - return BAD_VALUE; - - if ((w && !h) || (!w && h)) + if ((width && !height) || (!width && height)) return BAD_VALUE; Mutex::Autolock lock(mMutex); - mReqWidth = w; - mReqHeight = h; + mReqWidth = width; + mReqHeight = height; return NO_ERROR; } -int Surface::setBuffersUserDimensions(int w, int h) +int Surface::setBuffersUserDimensions(uint32_t width, uint32_t height) { ATRACE_CALL(); ALOGV("Surface::setBuffersUserDimensions"); - if (w<0 || h<0) - return BAD_VALUE; - - if ((w && !h) || (!w && h)) + if ((width && !height) || (!width && height)) return BAD_VALUE; Mutex::Autolock lock(mMutex); - mUserWidth = w; - mUserHeight = h; + mUserWidth = width; + mUserHeight = height; return NO_ERROR; } -int Surface::setBuffersFormat(int format) +int Surface::setBuffersFormat(PixelFormat format) { ALOGV("Surface::setBuffersFormat"); - if (format<0) - return BAD_VALUE; - Mutex::Autolock lock(mMutex); mReqFormat = format; return NO_ERROR; @@ -705,7 +868,7 @@ int Surface::setScalingMode(int mode) return NO_ERROR; } -int Surface::setBuffersTransform(int transform) +int Surface::setBuffersTransform(uint32_t transform) { ATRACE_CALL(); ALOGV("Surface::setBuffersTransform"); @@ -714,7 +877,7 @@ int Surface::setBuffersTransform(int transform) return NO_ERROR; } -int Surface::setBuffersStickyTransform(int transform) +int Surface::setBuffersStickyTransform(uint32_t transform) { ATRACE_CALL(); ALOGV("Surface::setBuffersStickyTransform"); @@ -731,12 +894,41 @@ int Surface::setBuffersTimestamp(int64_t timestamp) return NO_ERROR; } +int Surface::setBuffersDataSpace(android_dataspace dataSpace) +{ + ALOGV("Surface::setBuffersDataSpace"); + Mutex::Autolock lock(mMutex); + mDataSpace = dataSpace; + return NO_ERROR; +} + void Surface::freeAllBuffers() { for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { mSlots[i].buffer = 0; } } +void Surface::setSurfaceDamage(android_native_rect_t* rects, size_t numRects) { + ATRACE_CALL(); + ALOGV("Surface::setSurfaceDamage"); + Mutex::Autolock lock(mMutex); + + if (mConnectedToCpu || numRects == 0) { + mDirtyRegion = Region::INVALID_REGION; + return; + } + + mDirtyRegion.clear(); + for (size_t r = 0; r < numRects; ++r) { + // We intentionally flip top and bottom here, since because they're + // specified with a bottom-left origin, top > bottom, which fails + // validation in the Region class. We will fix this up when we flip to a + // top-left origin in queueBuffer. + Rect rect(rects[r].left, rects[r].bottom, rects[r].right, rects[r].top); + mDirtyRegion.orSelf(rect); + } +} + // ---------------------------------------------------------------------- // the lock/unlock APIs must be used from the same thread @@ -748,30 +940,34 @@ static status_t copyBlt( // src and dst with, height and format must be identical. no verification // is done here. status_t err; - uint8_t const * src_bits = NULL; - err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits); + 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 = NULL; - err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits); + err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), + reinterpret_cast<void**>(&dst_bits)); ALOGE_IF(err, "error locking dst buffer %s", strerror(-err)); Region::const_iterator head(reg.begin()); Region::const_iterator tail(reg.end()); if (head != tail && src_bits && dst_bits) { const size_t bpp = bytesPerPixel(src->format); - const size_t dbpr = dst->stride * bpp; - const size_t sbpr = src->stride * bpp; + const size_t dbpr = static_cast<uint32_t>(dst->stride) * bpp; + const size_t sbpr = static_cast<uint32_t>(src->stride) * bpp; while (head != tail) { const Rect& r(*head++); - ssize_t h = r.height(); + int32_t h = r.height(); if (h <= 0) continue; - size_t size = r.width() * bpp; - uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp; - uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp; + size_t size = static_cast<uint32_t>(r.width()) * bpp; + uint8_t const * s = src_bits + + static_cast<uint32_t>(r.left + src->stride * r.top) * bpp; + uint8_t * d = dst_bits + + static_cast<uint32_t>(r.left + dst->stride * r.top) * bpp; if (dbpr==sbpr && size==sbpr) { - size *= h; + size *= static_cast<size_t>(h); h = 1; } do { diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 6446926ea5..6ad47d8b71 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -71,7 +71,7 @@ void ComposerService::connectLocked() { }; mDeathObserver = new DeathObserver(*const_cast<ComposerService*>(this)); - mComposerService->asBinder()->linkToDeath(mDeathObserver); + IInterface::asBinder(mComposerService)->linkToDeath(mDeathObserver); } /*static*/ sp<ISurfaceComposer> ComposerService::getComposerService() { @@ -143,7 +143,7 @@ public: 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); + uint32_t z); status_t setFlags(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, uint32_t flags, uint32_t mask); status_t setTransparentRegionHint( @@ -293,7 +293,7 @@ status_t Composer::setSize(const sp<SurfaceComposerClient>& client, } status_t Composer::setLayer(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, int32_t z) { + const sp<IBinder>& id, uint32_t z) { Mutex::Autolock _l(mLock); layer_state_t* s = getLayerStateLocked(client, id); if (!s) @@ -310,11 +310,10 @@ status_t Composer::setFlags(const sp<SurfaceComposerClient>& client, layer_state_t* s = getLayerStateLocked(client, id); if (!s) return BAD_INDEX; - if (mask & layer_state_t::eLayerOpaque) { - s->what |= layer_state_t::eOpacityChanged; - } - if (mask & layer_state_t::eLayerHidden) { - s->what |= layer_state_t::eVisibilityChanged; + if (mask & layer_state_t::eLayerOpaque || + mask & layer_state_t::eLayerHidden || + mask & layer_state_t::eLayerSecure) { + s->what |= layer_state_t::eFlagsChanged; } s->flags &= ~mask; s->flags |= (flags & mask); @@ -395,7 +394,7 @@ DisplayState& Composer::getDisplayStateLocked(const sp<IBinder>& token) { s.what = 0; index = mDisplayStates.add(s); } - return mDisplayStates.editItemAt(index); + return mDisplayStates.editItemAt(static_cast<size_t>(index)); } void Composer::setDisplaySurface(const sp<IBinder>& token, @@ -462,14 +461,14 @@ status_t SurfaceComposerClient::initCheck() const { } sp<IBinder> SurfaceComposerClient::connection() const { - return (mClient != 0) ? mClient->asBinder() : 0; + return IInterface::asBinder(mClient); } status_t SurfaceComposerClient::linkToComposerDeath( const sp<IBinder::DeathRecipient>& recipient, void* cookie, uint32_t flags) { sp<ISurfaceComposer> sm(ComposerService::getComposerService()); - return sm->asBinder()->linkToDeath(recipient, cookie, flags); + return IInterface::asBinder(sm)->linkToDeath(recipient, cookie, flags); } void SurfaceComposerClient::dispose() { @@ -571,7 +570,7 @@ status_t SurfaceComposerClient::setSize(const sp<IBinder>& id, uint32_t w, uint3 return getComposer().setSize(this, id, w, h); } -status_t SurfaceComposerClient::setLayer(const sp<IBinder>& id, int32_t z) { +status_t SurfaceComposerClient::setLayer(const sp<IBinder>& id, uint32_t z) { return getComposer().setLayer(this, id, z); } @@ -657,7 +656,7 @@ status_t SurfaceComposerClient::getDisplayInfo(const sp<IBinder>& display, return NAME_NOT_FOUND; } - *info = configs[activeId]; + *info = configs[static_cast<size_t>(activeId)]; return NO_ERROR; } @@ -752,14 +751,14 @@ status_t ScreenshotClient::update(const sp<IBinder>& display, status_t ScreenshotClient::update(const sp<IBinder>& display, Rect sourceCrop, bool useIdentityTransform) { - return ScreenshotClient::update(display, sourceCrop, 0, 0, 0, -1UL, + return ScreenshotClient::update(display, sourceCrop, 0, 0, 0, -1U, 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, - 0, -1UL, useIdentityTransform, ISurfaceComposer::eRotateNone); + 0, -1U, useIdentityTransform, ISurfaceComposer::eRotateNone); } void ScreenshotClient::release() { diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index 7597c991f8..1983027809 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -89,12 +89,12 @@ bool SurfaceControl::isSameSurface( return lhs->mHandle == rhs->mHandle; } -status_t SurfaceControl::setLayerStack(int32_t layerStack) { +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 SurfaceControl::setLayer(uint32_t layer) { status_t err = validate(); if (err < 0) return err; return mClient->setLayer(mHandle, layer); @@ -176,7 +176,7 @@ status_t SurfaceControl::writeSurfaceToParcel( if (control != NULL) { bp = control->mGraphicBufferProducer; } - return parcel->writeStrongBinder(bp->asBinder()); + return parcel->writeStrongBinder(IInterface::asBinder(bp)); } sp<Surface> SurfaceControl::getSurface() const diff --git a/libs/gui/SyncFeatures.cpp b/libs/gui/SyncFeatures.cpp index e5804a77b1..187b211be8 100644 --- a/libs/gui/SyncFeatures.cpp +++ b/libs/gui/SyncFeatures.cpp @@ -16,7 +16,6 @@ #define LOG_TAG "GLConsumer" -#define GL_GLEXT_PROTOTYPES #define EGL_EGLEXT_PROTOTYPES #include <EGL/egl.h> @@ -78,10 +77,11 @@ bool SyncFeatures::useFenceSync() const { // on some devices it's better to not use EGL_KHR_fence_sync // even if they have it return false; -#endif +#else // currently we shall only attempt to use EGL_KHR_fence_sync if // USE_FENCE_SYNC is set in our makefile return !mHasNativeFenceSync && mHasFenceSync; +#endif } bool SyncFeatures::useWaitSync() const { return (useNativeFenceSync() || useFenceSync()) && mHasWaitSync; diff --git a/libs/gui/tests/Android.mk b/libs/gui/tests/Android.mk index e460290764..6ad9986220 100644 --- a/libs/gui/tests/Android.mk +++ b/libs/gui/tests/Android.mk @@ -1,6 +1,9 @@ # Build the unit tests, LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk + +LOCAL_CLANG := true LOCAL_MODULE := libgui_test @@ -31,17 +34,10 @@ LOCAL_SHARED_LIBRARIES := \ libbinder \ libcutils \ libgui \ - libstlport \ libsync \ libui \ libutils \ -LOCAL_C_INCLUDES := \ - bionic \ - bionic/libstdc++/include \ - external/gtest/include \ - external/stlport/stlport \ - # Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE) # to integrate with auto-test framework. include $(BUILD_NATIVE_TEST) diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 96de11f202..1a54875446 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -17,6 +17,9 @@ #define LOG_TAG "BufferQueue_test" //#define LOG_NDEBUG 0 +#include "DummyConsumer.h" + +#include <gui/BufferItem.h> #include <gui/BufferQueue.h> #include <gui/IProducerListener.h> @@ -66,11 +69,7 @@ protected: sp<IGraphicBufferConsumer> mConsumer; }; -struct DummyConsumer : public BnConsumerListener { - virtual void onFrameAvailable(const BufferItem& /* item */) {} - virtual void onBuffersReleased() {} - virtual void onSidebandStreamChanged() {} -}; +static const uint32_t TEST_DATA = 0x12345678u; // XXX: Tests that fork a process to hold the BufferQueue must run before tests // that use a local BufferQueue, or else Binder will get unhappy @@ -87,8 +86,8 @@ TEST_F(BufferQueueTest, BufferQueueInAnotherProcess) { sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&producer, &consumer); sp<IServiceManager> serviceManager = defaultServiceManager(); - serviceManager->addService(PRODUCER_NAME, producer->asBinder()); - serviceManager->addService(CONSUMER_NAME, consumer->asBinder()); + serviceManager->addService(PRODUCER_NAME, IInterface::asBinder(producer)); + serviceManager->addService(CONSUMER_NAME, IInterface::asBinder(consumer)); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); LOG_ALWAYS_FATAL("Shouldn't be here"); @@ -121,20 +120,21 @@ TEST_F(BufferQueueTest, BufferQueueInAnotherProcess) { uint32_t* dataIn; ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, reinterpret_cast<void**>(&dataIn))); - *dataIn = 0x12345678; + *dataIn = TEST_DATA; ASSERT_EQ(OK, buffer->unlock()); - IGraphicBufferProducer::QueueBufferInput input(0, false, Rect(0, 0, 1, 1), + IGraphicBufferProducer::QueueBufferInput input(0, false, + HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); - IGraphicBufferConsumer::BufferItem item; + BufferItem item; ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); uint32_t* dataOut; ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&dataOut))); - ASSERT_EQ(*dataOut, 0x12345678); + ASSERT_EQ(*dataOut, TEST_DATA); ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); } @@ -150,9 +150,10 @@ TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { int slot; sp<Fence> fence; sp<GraphicBuffer> buf; - IGraphicBufferProducer::QueueBufferInput qbi(0, false, Rect(0, 0, 1, 1), + IGraphicBufferProducer::QueueBufferInput qbi(0, false, + HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE); - BufferQueue::BufferItem item; + BufferItem item; for (int i = 0; i < 2; i++) { ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, @@ -236,7 +237,7 @@ TEST_F(BufferQueueTest, DetachAndReattachOnProducerSide) { uint32_t* dataIn; ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, reinterpret_cast<void**>(&dataIn))); - *dataIn = 0x12345678; + *dataIn = TEST_DATA; ASSERT_EQ(OK, buffer->unlock()); int newSlot; @@ -244,17 +245,18 @@ TEST_F(BufferQueueTest, DetachAndReattachOnProducerSide) { ASSERT_EQ(BAD_VALUE, mProducer->attachBuffer(&newSlot, NULL)); ASSERT_EQ(OK, mProducer->attachBuffer(&newSlot, buffer)); - IGraphicBufferProducer::QueueBufferInput input(0, false, Rect(0, 0, 1, 1), + IGraphicBufferProducer::QueueBufferInput input(0, false, + HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE); ASSERT_EQ(OK, mProducer->queueBuffer(newSlot, input, &output)); - IGraphicBufferConsumer::BufferItem item; + BufferItem item; ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, static_cast<nsecs_t>(0))); uint32_t* dataOut; ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&dataOut))); - ASSERT_EQ(*dataOut, 0x12345678); + ASSERT_EQ(*dataOut, TEST_DATA); ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); } @@ -273,7 +275,8 @@ TEST_F(BufferQueueTest, DetachAndReattachOnConsumerSide) { mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); - IGraphicBufferProducer::QueueBufferInput input(0, false, Rect(0, 0, 1, 1), + IGraphicBufferProducer::QueueBufferInput input(0, false, + HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); @@ -282,7 +285,7 @@ TEST_F(BufferQueueTest, DetachAndReattachOnConsumerSide) { BufferQueueDefs::NUM_BUFFER_SLOTS)); // Index too high ASSERT_EQ(BAD_VALUE, mConsumer->detachBuffer(0)); // Not acquired - IGraphicBufferConsumer::BufferItem item; + BufferItem item; ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, static_cast<nsecs_t>(0))); ASSERT_EQ(OK, mConsumer->detachBuffer(item.mBuf)); @@ -292,7 +295,7 @@ TEST_F(BufferQueueTest, DetachAndReattachOnConsumerSide) { ASSERT_EQ(OK, item.mGraphicBuffer->lock( GraphicBuffer::USAGE_SW_WRITE_OFTEN, reinterpret_cast<void**>(&dataIn))); - *dataIn = 0x12345678; + *dataIn = TEST_DATA; ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); int newSlot; @@ -312,7 +315,7 @@ TEST_F(BufferQueueTest, DetachAndReattachOnConsumerSide) { uint32_t* dataOut; ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&dataOut))); - ASSERT_EQ(*dataOut, 0x12345678); + ASSERT_EQ(*dataOut, TEST_DATA); ASSERT_EQ(OK, buffer->unlock()); } @@ -335,14 +338,15 @@ TEST_F(BufferQueueTest, MoveFromConsumerToProducer) { uint32_t* dataIn; ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, reinterpret_cast<void**>(&dataIn))); - *dataIn = 0x12345678; + *dataIn = TEST_DATA; ASSERT_EQ(OK, buffer->unlock()); - IGraphicBufferProducer::QueueBufferInput input(0, false, Rect(0, 0, 1, 1), + IGraphicBufferProducer::QueueBufferInput input(0, false, + HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); - IGraphicBufferConsumer::BufferItem item; + BufferItem item; ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, static_cast<nsecs_t>(0))); ASSERT_EQ(OK, mConsumer->detachBuffer(item.mBuf)); @@ -354,8 +358,86 @@ TEST_F(BufferQueueTest, MoveFromConsumerToProducer) { uint32_t* dataOut; ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&dataOut))); - ASSERT_EQ(*dataOut, 0x12345678); + ASSERT_EQ(*dataOut, TEST_DATA); ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); } +TEST_F(BufferQueueTest, TestDisallowingAllocation) { + createBufferQueue(); + sp<DummyConsumer> dc(new DummyConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true)); + IGraphicBufferProducer::QueueBufferOutput output; + ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, + NATIVE_WINDOW_API_CPU, true, &output)); + + static const uint32_t WIDTH = 320; + static const uint32_t HEIGHT = 240; + + ASSERT_EQ(OK, mConsumer->setDefaultBufferSize(WIDTH, HEIGHT)); + + int slot; + sp<Fence> fence; + sp<GraphicBuffer> buffer; + // This should return an error since it would require an allocation + ASSERT_EQ(OK, mProducer->allowAllocation(false)); + ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, + 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); + + // This should succeed, now that we've lifted the prohibition + ASSERT_EQ(OK, mProducer->allowAllocation(true)); + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, + mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0, + GRALLOC_USAGE_SW_WRITE_OFTEN)); + + // Release the previous buffer back to the BufferQueue + mProducer->cancelBuffer(slot, fence); + + // This should fail since we're requesting a different size + ASSERT_EQ(OK, mProducer->allowAllocation(false)); + ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence, false, + WIDTH * 2, HEIGHT * 2, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); +} + +TEST_F(BufferQueueTest, TestGenerationNumbers) { + createBufferQueue(); + sp<DummyConsumer> dc(new DummyConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true)); + IGraphicBufferProducer::QueueBufferOutput output; + ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, + NATIVE_WINDOW_API_CPU, true, &output)); + + ASSERT_EQ(OK, mProducer->setGenerationNumber(1)); + + // Get one buffer to play with + int slot; + sp<Fence> fence; + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, + mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0, 0)); + + sp<GraphicBuffer> buffer; + ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); + + // Ensure that the generation number we set propagates to allocated buffers + ASSERT_EQ(1U, buffer->getGenerationNumber()); + + ASSERT_EQ(OK, mProducer->detachBuffer(slot)); + + ASSERT_EQ(OK, mProducer->setGenerationNumber(2)); + + // These should fail, since we've changed the generation number on the queue + int outSlot; + ASSERT_EQ(BAD_VALUE, mProducer->attachBuffer(&outSlot, buffer)); + ASSERT_EQ(BAD_VALUE, mConsumer->attachBuffer(&outSlot, buffer)); + + buffer->setGenerationNumber(2); + + // This should succeed now that we've changed the buffer's generation number + ASSERT_EQ(OK, mProducer->attachBuffer(&outSlot, buffer)); + + ASSERT_EQ(OK, mProducer->detachBuffer(outSlot)); + + // This should also succeed with the new generation number + ASSERT_EQ(OK, mConsumer->attachBuffer(&outSlot, buffer)); +} + } // namespace android diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp index abd372449f..2dc9cccb56 100644 --- a/libs/gui/tests/CpuConsumer_test.cpp +++ b/libs/gui/tests/CpuConsumer_test.cpp @@ -94,7 +94,7 @@ protected: mPendingFrames--; } - virtual void onFrameAvailable() { + virtual void onFrameAvailable(const BufferItem&) { Mutex::Autolock lock(mMutex); mPendingFrames++; mCondition.signal(); @@ -125,7 +125,7 @@ protected: mPendingFrames--; } - virtual void onFrameAvailable() { + virtual void onFrameAvailable(const BufferItem&) { Mutex::Autolock lock(mMutex); mPendingFrames++; mFrameCondition.signal(); @@ -166,7 +166,7 @@ void checkPixel(const CpuConsumer::LockedBuffer &buf, uint32_t x, uint32_t y, uint32_t r, uint32_t g=0, uint32_t b=0) { // Ignores components that don't exist for given pixel switch(buf.format) { - case HAL_PIXEL_FORMAT_RAW_SENSOR: { + case HAL_PIXEL_FORMAT_RAW16: { String8 msg; uint16_t *bPtr = (uint16_t*)buf.data; bPtr += y * buf.stride + x; @@ -429,7 +429,7 @@ void checkBayerRawBuffer(const CpuConsumer::LockedBuffer &buf) { void checkAnyBuffer(const CpuConsumer::LockedBuffer &buf, int format) { switch (format) { - case HAL_PIXEL_FORMAT_RAW_SENSOR: + case HAL_PIXEL_FORMAT_RAW16: checkBayerRawBuffer(buf); break; case HAL_PIXEL_FORMAT_Y8: @@ -457,9 +457,12 @@ void configureANW(const sp<ANativeWindow>& anw, const CpuConsumerTestParams& params, int maxBufferSlack) { status_t err; - err = native_window_set_buffers_geometry(anw.get(), - params.width, params.height, params.format); - ASSERT_NO_ERROR(err, "set_buffers_geometry error: "); + err = native_window_set_buffers_dimensions(anw.get(), + params.width, params.height); + ASSERT_NO_ERROR(err, "set_buffers_dimensions error: "); + + err = native_window_set_buffers_format(anw.get(), params.format); + ASSERT_NO_ERROR(err, "set_buffers_format error: "); err = native_window_set_usage(anw.get(), GRALLOC_USAGE_SW_WRITE_OFTEN); @@ -505,7 +508,7 @@ void produceOneFrame(const sp<ANativeWindow>& anw, case HAL_PIXEL_FORMAT_YV12: fillYV12Buffer(img, params.width, params.height, *stride); break; - case HAL_PIXEL_FORMAT_RAW_SENSOR: + case HAL_PIXEL_FORMAT_RAW16: fillBayerRawBuffer(img, params.width, params.height, buf->getStride()); break; case HAL_PIXEL_FORMAT_Y8: @@ -537,7 +540,7 @@ void produceOneFrame(const sp<ANativeWindow>& anw, ASSERT_NO_ERROR(err, "queueBuffer error:"); }; -// This test is disabled because the HAL_PIXEL_FORMAT_RAW_SENSOR format is not +// This test is disabled because the HAL_PIXEL_FORMAT_RAW16 format is not // supported on all devices. TEST_P(CpuConsumerTest, FromCpuSingle) { status_t err; @@ -571,7 +574,7 @@ TEST_P(CpuConsumerTest, FromCpuSingle) { mCC->unlockBuffer(b); } -// This test is disabled because the HAL_PIXEL_FORMAT_RAW_SENSOR format is not +// This test is disabled because the HAL_PIXEL_FORMAT_RAW16 format is not // supported on all devices. TEST_P(CpuConsumerTest, FromCpuManyInQueue) { status_t err; @@ -614,7 +617,7 @@ TEST_P(CpuConsumerTest, FromCpuManyInQueue) { } } -// This test is disabled because the HAL_PIXEL_FORMAT_RAW_SENSOR format is not +// This test is disabled because the HAL_PIXEL_FORMAT_RAW16 format is not // supported on all devices. TEST_P(CpuConsumerTest, FromCpuLockMax) { status_t err; @@ -710,12 +713,12 @@ CpuConsumerTestParams y16TestSets[] = { }; CpuConsumerTestParams rawTestSets[] = { - { 512, 512, 1, HAL_PIXEL_FORMAT_RAW_SENSOR}, - { 512, 512, 3, HAL_PIXEL_FORMAT_RAW_SENSOR}, - { 2608, 1960, 1, HAL_PIXEL_FORMAT_RAW_SENSOR}, - { 2608, 1960, 3, HAL_PIXEL_FORMAT_RAW_SENSOR}, - { 100, 100, 1, HAL_PIXEL_FORMAT_RAW_SENSOR}, - { 100, 100, 3, HAL_PIXEL_FORMAT_RAW_SENSOR}, + { 512, 512, 1, HAL_PIXEL_FORMAT_RAW16}, + { 512, 512, 3, HAL_PIXEL_FORMAT_RAW16}, + { 2608, 1960, 1, HAL_PIXEL_FORMAT_RAW16}, + { 2608, 1960, 3, HAL_PIXEL_FORMAT_RAW16}, + { 100, 100, 1, HAL_PIXEL_FORMAT_RAW16}, + { 100, 100, 3, HAL_PIXEL_FORMAT_RAW16}, }; CpuConsumerTestParams rgba8888TestSets[] = { diff --git a/libs/gui/tests/DummyConsumer.h b/libs/gui/tests/DummyConsumer.h new file mode 100644 index 0000000000..0511e165c2 --- /dev/null +++ b/libs/gui/tests/DummyConsumer.h @@ -0,0 +1,27 @@ +/* + * Copyright 2015 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/IConsumerListener.h> + +namespace android { + +struct DummyConsumer : public BnConsumerListener { + virtual void onFrameAvailable(const BufferItem& /* item */) {} + virtual void onBuffersReleased() {} + virtual void onSidebandStreamChanged() {} +}; + +} // namespace android diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp index 8d5fd8f58f..4ef9a69844 100644 --- a/libs/gui/tests/IGraphicBufferProducer_test.cpp +++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp @@ -38,30 +38,31 @@ #define TEST_CONTROLLED_BY_APP false #define TEST_PRODUCER_USAGE_BITS (0) -// TODO: Make these public constants in a header -enum { +namespace android { + +namespace { // Default dimensions before setDefaultBufferSize is called - DEFAULT_WIDTH = 1, - DEFAULT_HEIGHT = 1, + const uint32_t DEFAULT_WIDTH = 1; + const uint32_t DEFAULT_HEIGHT = 1; // Default format before setDefaultBufferFormat is called - DEFAULT_FORMAT = HAL_PIXEL_FORMAT_RGBA_8888, + const PixelFormat DEFAULT_FORMAT = HAL_PIXEL_FORMAT_RGBA_8888; // Default transform hint before setTransformHint is called - DEFAULT_TRANSFORM_HINT = 0, -}; + const uint32_t DEFAULT_TRANSFORM_HINT = 0; -namespace android { + // TODO: Make these constants in header + const int DEFAULT_CONSUMER_USAGE_BITS = 0; -namespace { -// Parameters for a generic "valid" input for queueBuffer. -const int64_t QUEUE_BUFFER_INPUT_TIMESTAMP = 1384888611; -const bool QUEUE_BUFFER_INPUT_IS_AUTO_TIMESTAMP = false; -const Rect QUEUE_BUFFER_INPUT_RECT = Rect(DEFAULT_WIDTH, DEFAULT_HEIGHT); -const int QUEUE_BUFFER_INPUT_SCALING_MODE = 0; -const int QUEUE_BUFFER_INPUT_TRANSFORM = 0; -const bool QUEUE_BUFFER_INPUT_ASYNC = false; -const sp<Fence> QUEUE_BUFFER_INPUT_FENCE = Fence::NO_FENCE; + // Parameters for a generic "valid" input for queueBuffer. + const int64_t QUEUE_BUFFER_INPUT_TIMESTAMP = 1384888611; + const bool QUEUE_BUFFER_INPUT_IS_AUTO_TIMESTAMP = false; + const android_dataspace QUEUE_BUFFER_INPUT_DATASPACE = HAL_DATASPACE_UNKNOWN; + const Rect QUEUE_BUFFER_INPUT_RECT = Rect(DEFAULT_WIDTH, DEFAULT_HEIGHT); + const int QUEUE_BUFFER_INPUT_SCALING_MODE = 0; + const int QUEUE_BUFFER_INPUT_TRANSFORM = 0; + const bool QUEUE_BUFFER_INPUT_ASYNC = false; + const sp<Fence> QUEUE_BUFFER_INPUT_FENCE = Fence::NO_FENCE; }; // namespace anonymous struct DummyConsumer : public BnConsumerListener { @@ -126,6 +127,7 @@ protected: QueueBufferInputBuilder() { timestamp = QUEUE_BUFFER_INPUT_TIMESTAMP; isAutoTimestamp = QUEUE_BUFFER_INPUT_IS_AUTO_TIMESTAMP; + dataSpace = QUEUE_BUFFER_INPUT_DATASPACE; crop = QUEUE_BUFFER_INPUT_RECT; scalingMode = QUEUE_BUFFER_INPUT_SCALING_MODE; transform = QUEUE_BUFFER_INPUT_TRANSFORM; @@ -137,6 +139,7 @@ protected: return IGraphicBufferProducer::QueueBufferInput( timestamp, isAutoTimestamp, + dataSpace, crop, scalingMode, transform, @@ -154,6 +157,11 @@ protected: return *this; } + QueueBufferInputBuilder& setDataSpace(android_dataspace dataSpace) { + this->dataSpace = dataSpace; + return *this; + } + QueueBufferInputBuilder& setCrop(Rect crop) { this->crop = crop; return *this; @@ -182,6 +190,7 @@ protected: private: int64_t timestamp; bool isAutoTimestamp; + android_dataspace dataSpace; Rect crop; int scalingMode; uint32_t transform; @@ -264,15 +273,12 @@ TEST_F(IGraphicBufferProducerTest, Disconnect_ReturnsError) { TEST_F(IGraphicBufferProducerTest, Query_Succeeds) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); - // TODO: Make these constants in header - const int DEFAULT_CONSUMER_USAGE_BITS = 0; - - int value = -1; + int32_t value = -1; EXPECT_OK(mProducer->query(NATIVE_WINDOW_WIDTH, &value)); - EXPECT_EQ(DEFAULT_WIDTH, value); + EXPECT_EQ(DEFAULT_WIDTH, static_cast<uint32_t>(value)); EXPECT_OK(mProducer->query(NATIVE_WINDOW_HEIGHT, &value)); - EXPECT_EQ(DEFAULT_HEIGHT, value); + EXPECT_EQ(DEFAULT_HEIGHT, static_cast<uint32_t>(value)); EXPECT_OK(mProducer->query(NATIVE_WINDOW_FORMAT, &value)); EXPECT_EQ(DEFAULT_FORMAT, value); @@ -293,7 +299,7 @@ TEST_F(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. - const int NATIVE_WINDOW_QUERY_LAST_OFF_BY_ONE = NATIVE_WINDOW_CONSUMER_USAGE_BITS + 1; + const int NATIVE_WINDOW_QUERY_LAST_OFF_BY_ONE = NATIVE_WINDOW_BUFFER_AGE + 1; int value; // What was out of range @@ -360,7 +366,7 @@ TEST_F(IGraphicBufferProducerTest, Queue_Succeeds) { EXPECT_EQ(DEFAULT_WIDTH, width); EXPECT_EQ(DEFAULT_HEIGHT, height); EXPECT_EQ(DEFAULT_TRANSFORM_HINT, transformHint); - EXPECT_EQ(1, numPendingBuffers); // since queueBuffer was called exactly once + EXPECT_EQ(1u, numPendingBuffers); // since queueBuffer was called exactly once } // Buffer was not in the dequeued state diff --git a/libs/gui/tests/SRGB_test.cpp b/libs/gui/tests/SRGB_test.cpp index 2d5b8aaf20..3b11b974c6 100644 --- a/libs/gui/tests/SRGB_test.cpp +++ b/libs/gui/tests/SRGB_test.cpp @@ -17,8 +17,14 @@ #define LOG_TAG "SRGB_test" //#define LOG_NDEBUG 0 +// Ignore for this file because it flags every instance of +// ASSERT_EQ(GL_NO_ERROR, glGetError()); +#pragma clang diagnostic ignored "-Wsign-compare" + #include "GLTest.h" +#include <math.h> + #include <gui/CpuConsumer.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> @@ -212,10 +218,11 @@ protected: ASSERT_EQ(GL_NO_ERROR, glGetError()); } - void checkLockedBuffer(PixelFormat format) { + void checkLockedBuffer(PixelFormat format, android_dataspace dataSpace) { ASSERT_EQ(mLockedBuffer.format, format); ASSERT_EQ(mLockedBuffer.width, DISPLAY_WIDTH); ASSERT_EQ(mLockedBuffer.height, DISPLAY_HEIGHT); + ASSERT_EQ(mLockedBuffer.dataSpace, dataSpace); } static bool withinTolerance(int a, int b) { @@ -326,14 +333,15 @@ private: ANativeWindow_Buffer outBuffer; ARect outBufferBounds; mOutputSurface->lock(&outBuffer, &outBufferBounds); - ASSERT_EQ(mLockedBuffer.width, outBuffer.width); - ASSERT_EQ(mLockedBuffer.height, outBuffer.height); - ASSERT_EQ(mLockedBuffer.stride, outBuffer.stride); + ASSERT_EQ(mLockedBuffer.width, static_cast<uint32_t>(outBuffer.width)); + ASSERT_EQ(mLockedBuffer.height, static_cast<uint32_t>(outBuffer.height)); + ASSERT_EQ(mLockedBuffer.stride, static_cast<uint32_t>(outBuffer.stride)); if (mLockedBuffer.format == outBuffer.format) { memcpy(outBuffer.bits, mLockedBuffer.data, bufferSize); } else { - ASSERT_EQ(mLockedBuffer.format, PIXEL_FORMAT_sRGB_A_8888); + ASSERT_EQ(mLockedBuffer.format, PIXEL_FORMAT_RGBA_8888); + ASSERT_EQ(mLockedBuffer.dataSpace, HAL_DATASPACE_SRGB); ASSERT_EQ(outBuffer.format, PIXEL_FORMAT_RGBA_8888); uint8_t* outPointer = reinterpret_cast<uint8_t*>(outBuffer.bits); for (int y = 0; y < outBuffer.height; ++y) { @@ -378,7 +386,8 @@ TEST_F(SRGBTest, GLRenderFromSRGBTexture) { // Lock ASSERT_EQ(NO_ERROR, mCpuConsumer->lockNextBuffer(&mLockedBuffer)); - ASSERT_NO_FATAL_FAILURE(checkLockedBuffer(PIXEL_FORMAT_RGBA_8888)); + ASSERT_NO_FATAL_FAILURE( + checkLockedBuffer(PIXEL_FORMAT_RGBA_8888, HAL_DATASPACE_UNKNOWN)); // Compare a pixel in the middle of each texture int midSRGBOffset = (DISPLAY_HEIGHT / 4) * mLockedBuffer.stride * @@ -396,7 +405,8 @@ TEST_F(SRGBTest, GLRenderFromSRGBTexture) { // the debug surface if necessary } -TEST_F(SRGBTest, RenderToSRGBSurface) { +// XXX: Disabled since we don't currently expect this to work +TEST_F(SRGBTest, DISABLED_RenderToSRGBSurface) { ASSERT_NO_FATAL_FAILURE(initShaders()); // By default, the first buffer we write into will be RGB @@ -409,7 +419,8 @@ TEST_F(SRGBTest, RenderToSRGBSurface) { // Lock ASSERT_EQ(NO_ERROR, mCpuConsumer->lockNextBuffer(&mLockedBuffer)); - ASSERT_NO_FATAL_FAILURE(checkLockedBuffer(PIXEL_FORMAT_RGBA_8888)); + ASSERT_NO_FATAL_FAILURE( + checkLockedBuffer(PIXEL_FORMAT_RGBA_8888, HAL_DATASPACE_UNKNOWN)); // Save the values of the middle pixel for later comparison against SRGB uint8_t values[PIXEL_SIZE] = {}; @@ -458,7 +469,8 @@ TEST_F(SRGBTest, RenderToSRGBSurface) { ASSERT_EQ(NO_ERROR, mCpuConsumer->lockNextBuffer(&mLockedBuffer)); // Make sure we actually got the SRGB buffer on the consumer side - ASSERT_NO_FATAL_FAILURE(checkLockedBuffer(PIXEL_FORMAT_sRGB_A_8888)); + ASSERT_NO_FATAL_FAILURE( + checkLockedBuffer(PIXEL_FORMAT_RGBA_8888, HAL_DATASPACE_SRGB)); // Verify that the stored value is the same, accounting for RGB/SRGB for (int c = 0; c < PIXEL_SIZE; ++c) { diff --git a/libs/gui/tests/StreamSplitter_test.cpp b/libs/gui/tests/StreamSplitter_test.cpp index 4e63a6f4db..00cc39dc06 100644 --- a/libs/gui/tests/StreamSplitter_test.cpp +++ b/libs/gui/tests/StreamSplitter_test.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "StreamSplitter_test" //#define LOG_NDEBUG 0 +#include <gui/BufferItem.h> #include <gui/BufferQueue.h> #include <gui/IConsumerListener.h> #include <gui/ISurfaceComposer.h> @@ -75,6 +76,8 @@ private: int mAllocCount; }; +static const uint32_t TEST_DATA = 0x12345678u; + TEST_F(StreamSplitterTest, OneInputOneOutput) { sp<CountedAllocator> allocator(new CountedAllocator); @@ -107,21 +110,22 @@ TEST_F(StreamSplitterTest, OneInputOneOutput) { uint32_t* dataIn; ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, reinterpret_cast<void**>(&dataIn))); - *dataIn = 0x12345678; + *dataIn = TEST_DATA; ASSERT_EQ(OK, buffer->unlock()); IGraphicBufferProducer::QueueBufferInput qbInput(0, false, + HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE); ASSERT_EQ(OK, inputProducer->queueBuffer(slot, qbInput, &qbOutput)); - IGraphicBufferConsumer::BufferItem item; + BufferItem item; ASSERT_EQ(OK, outputConsumer->acquireBuffer(&item, 0)); uint32_t* dataOut; ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&dataOut))); - ASSERT_EQ(*dataOut, 0x12345678); + ASSERT_EQ(*dataOut, TEST_DATA); ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); ASSERT_EQ(OK, outputConsumer->releaseBuffer(item.mBuf, item.mFrameNumber, @@ -173,22 +177,23 @@ TEST_F(StreamSplitterTest, OneInputMultipleOutputs) { uint32_t* dataIn; ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, reinterpret_cast<void**>(&dataIn))); - *dataIn = 0x12345678; + *dataIn = TEST_DATA; ASSERT_EQ(OK, buffer->unlock()); IGraphicBufferProducer::QueueBufferInput qbInput(0, false, + HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE); ASSERT_EQ(OK, inputProducer->queueBuffer(slot, qbInput, &qbOutput)); for (int output = 0; output < NUM_OUTPUTS; ++output) { - IGraphicBufferConsumer::BufferItem item; + BufferItem item; ASSERT_EQ(OK, outputConsumers[output]->acquireBuffer(&item, 0)); uint32_t* dataOut; ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&dataOut))); - ASSERT_EQ(*dataOut, 0x12345678); + ASSERT_EQ(*dataOut, TEST_DATA); ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); ASSERT_EQ(OK, outputConsumers[output]->releaseBuffer(item.mBuf, @@ -234,6 +239,7 @@ TEST_F(StreamSplitterTest, OutputAbandonment) { outputConsumer->consumerDisconnect(); IGraphicBufferProducer::QueueBufferInput qbInput(0, false, + HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE); ASSERT_EQ(OK, inputProducer->queueBuffer(slot, qbInput, &qbOutput)); diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp index 8cdf3bc349..1a50b2480d 100644 --- a/libs/gui/tests/SurfaceTextureClient_test.cpp +++ b/libs/gui/tests/SurfaceTextureClient_test.cpp @@ -27,6 +27,9 @@ #include <utils/Log.h> #include <utils/Thread.h> +EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); +#define CROP_EXT_STR "EGL_ANDROID_image_crop" + namespace android { class SurfaceTextureClientTest : public ::testing::Test { @@ -207,12 +210,8 @@ TEST_F(SurfaceTextureClientTest, EglSwapBuffersAbandonErrorIsEglBadSurface) { } TEST_F(SurfaceTextureClientTest, BufferGeometryInvalidSizesFail) { - EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(), -1, 0, 0)); - EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(), 0, -1, 0)); - EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(), 0, 0, -1)); - EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(), -1, -1, 0)); - EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(), 0, 8, 0)); - EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(), 8, 0, 0)); + EXPECT_GT(OK, native_window_set_buffers_dimensions(mANW.get(), 0, 8)); + EXPECT_GT(OK, native_window_set_buffers_dimensions(mANW.get(), 8, 0)); } TEST_F(SurfaceTextureClientTest, DefaultGeometryValues) { @@ -226,7 +225,8 @@ TEST_F(SurfaceTextureClientTest, DefaultGeometryValues) { TEST_F(SurfaceTextureClientTest, BufferGeometryCanBeSet) { ANativeWindowBuffer* buf; - EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, PIXEL_FORMAT_RGB_565)); + EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 16, 8)); + EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), PIXEL_FORMAT_RGB_565)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(16, buf->width); EXPECT_EQ(8, buf->height); @@ -236,7 +236,8 @@ TEST_F(SurfaceTextureClientTest, BufferGeometryCanBeSet) { TEST_F(SurfaceTextureClientTest, BufferGeometryDefaultSizeSetFormat) { ANativeWindowBuffer* buf; - EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 0, 0, PIXEL_FORMAT_RGB_565)); + EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 0, 0)); + EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), PIXEL_FORMAT_RGB_565)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(1, buf->width); EXPECT_EQ(1, buf->height); @@ -246,7 +247,8 @@ TEST_F(SurfaceTextureClientTest, BufferGeometryDefaultSizeSetFormat) { TEST_F(SurfaceTextureClientTest, BufferGeometrySetSizeDefaultFormat) { ANativeWindowBuffer* buf; - EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, 0)); + EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 16, 8)); + EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(16, buf->width); EXPECT_EQ(8, buf->height); @@ -256,13 +258,15 @@ TEST_F(SurfaceTextureClientTest, BufferGeometrySetSizeDefaultFormat) { TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeUnset) { ANativeWindowBuffer* buf; - EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, 0)); + EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 16, 8)); + EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(16, buf->width); EXPECT_EQ(8, buf->height); EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1)); - EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 0, 0, 0)); + EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 0, 0)); + EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(1, buf->width); EXPECT_EQ(1, buf->height); @@ -272,7 +276,8 @@ TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeUnset) { TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeChangedWithoutFormat) { ANativeWindowBuffer* buf; - EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 0, 0, PIXEL_FORMAT_RGB_565)); + EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 0, 0)); + EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), PIXEL_FORMAT_RGB_565)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(1, buf->width); EXPECT_EQ(1, buf->height); @@ -330,7 +335,8 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeVsGeometry) { EXPECT_EQ(8, buf[1]->height); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0], -1)); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1], -1)); - EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 12, 24, 0)); + EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 12, 24)); + EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); EXPECT_NE(buf[0], buf[1]); @@ -468,7 +474,8 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeMinUndequeued) { // Once we've queued a buffer, however we should not be able to dequeue more // than (buffer-count - MIN_UNDEQUEUED_BUFFERS), which is 2 in this case. - EXPECT_EQ(-EBUSY, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); + EXPECT_EQ(INVALID_OPERATION, + native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0], -1)); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[2], -1)); @@ -611,6 +618,18 @@ TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffers) } TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWithCrop) { + // Query to see if the image crop extension exists + EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS); + size_t cropExtLen = strlen(CROP_EXT_STR); + size_t extsLen = strlen(exts); + bool equal = !strcmp(CROP_EXT_STR, exts); + bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen+1); + bool atEnd = (cropExtLen+1) < extsLen && + !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen+1)); + bool inMiddle = strstr(exts, " " CROP_EXT_STR " "); + bool hasEglAndroidImageCrop = equal || atStart || atEnd || inMiddle; + android_native_buffer_t* buf[3]; float mtx[16] = {}; android_native_rect_t crop; @@ -620,7 +639,8 @@ TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWi crop.bottom = 5; ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); - ASSERT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 8, 8, 0)); + ASSERT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 8, 8)); + ASSERT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &crop)); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); @@ -628,15 +648,17 @@ TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWi ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 6)); // frees buffers mST->getTransformMatrix(mtx); - // This accounts for the .5 texel shrink for each edge that's included in the - // transform matrix to avoid texturing outside the crop region. - EXPECT_EQ(0.5, mtx[0]); + // If the egl image crop extension is not present, this accounts for the + // .5 texel shrink for each edge that's included in the transform matrix + // to avoid texturing outside the crop region. Otherwise the crop is not + // included in the transform matrix. + EXPECT_EQ(hasEglAndroidImageCrop ? 1 : 0.5, mtx[0]); EXPECT_EQ(0.f, mtx[1]); EXPECT_EQ(0.f, mtx[2]); EXPECT_EQ(0.f, mtx[3]); EXPECT_EQ(0.f, mtx[4]); - EXPECT_EQ(-0.5, mtx[5]); + EXPECT_EQ(hasEglAndroidImageCrop ? -1 : -0.5, mtx[5]); EXPECT_EQ(0.f, mtx[6]); EXPECT_EQ(0.f, mtx[7]); @@ -645,8 +667,8 @@ TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWi EXPECT_EQ(1.f, mtx[10]); EXPECT_EQ(0.f, mtx[11]); - EXPECT_EQ(0.0625f, mtx[12]); - EXPECT_EQ(0.5625f, mtx[13]); + EXPECT_EQ(hasEglAndroidImageCrop ? 0 : 0.0625f, mtx[12]); + EXPECT_EQ(hasEglAndroidImageCrop ? 1 : 0.5625f, mtx[13]); EXPECT_EQ(0.f, mtx[14]); EXPECT_EQ(1.f, mtx[15]); } @@ -668,7 +690,8 @@ TEST_F(SurfaceTextureClientTest, QueryFormatAfterSettingWorks) { const int numFmts = (sizeof(fmts) / sizeof(fmts[0])); for (int i = 0; i < numFmts; i++) { int fmt = -1; - ASSERT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 0, 0, fmts[i])); + ASSERT_EQ(OK, native_window_set_buffers_dimensions(anw.get(), 0, 0)); + ASSERT_EQ(OK, native_window_set_buffers_format(anw.get(), fmts[i])); ASSERT_EQ(OK, anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &fmt)); EXPECT_EQ(fmts[i], fmt); } diff --git a/libs/gui/tests/SurfaceTextureFBO_test.cpp b/libs/gui/tests/SurfaceTextureFBO_test.cpp index b165ae6609..c243fc047e 100644 --- a/libs/gui/tests/SurfaceTextureFBO_test.cpp +++ b/libs/gui/tests/SurfaceTextureFBO_test.cpp @@ -27,8 +27,10 @@ TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) { const int texWidth = 64; const int texHeight = 64; - ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(), - texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), + texWidth, texHeight)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), + HAL_PIXEL_FORMAT_RGBA_8888)); ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)); diff --git a/libs/gui/tests/SurfaceTextureGLToGL_test.cpp b/libs/gui/tests/SurfaceTextureGLToGL_test.cpp index f4c796131b..6edbfb87a6 100644 --- a/libs/gui/tests/SurfaceTextureGLToGL_test.cpp +++ b/libs/gui/tests/SurfaceTextureGLToGL_test.cpp @@ -188,10 +188,10 @@ TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceUnrefsBuffers) { // This test should have the only reference to buffer 0. EXPECT_EQ(1, buffers[0]->getStrongCount()); - // The GLConsumer should hold a single reference to buffer 1 in its - // mCurrentBuffer member. All of the references in the slots should have - // been released. - EXPECT_EQ(2, buffers[1]->getStrongCount()); + // The GLConsumer should hold one reference to buffer 1 in its + // mCurrentTextureImage member and another reference in mEglSlots. The third + // reference is in this test. + EXPECT_EQ(3, buffers[1]->getStrongCount()); } TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) { @@ -235,14 +235,19 @@ TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) { ASSERT_EQ(EGL_SUCCESS, eglGetError()); mProducerEglSurface = EGL_NO_SURFACE; - EXPECT_EQ(1, buffers[0]->getStrongCount()); EXPECT_EQ(1, buffers[1]->getStrongCount()); // Depending on how lazily the GL driver dequeues buffers, we may end up - // with either two or three total buffers. If there are three, make sure - // the last one was properly down-ref'd. + // with either two or three total buffers. If there are three, each entry + // of the buffers array will be unique and there should only be one + // reference (the one in this test). If there are two the first and last + // element in the array will be equal meaning that buffer representing both + // 0 and 2 will have two references (one for 0 and one for 2). if (buffers[2] != buffers[0]) { + EXPECT_EQ(1, buffers[0]->getStrongCount()); EXPECT_EQ(1, buffers[2]->getStrongCount()); + } else { + EXPECT_EQ(2, buffers[0]->getStrongCount()); } } diff --git a/libs/gui/tests/SurfaceTextureGL_test.cpp b/libs/gui/tests/SurfaceTextureGL_test.cpp index fa1e1b78ae..fad133fcb8 100644 --- a/libs/gui/tests/SurfaceTextureGL_test.cpp +++ b/libs/gui/tests/SurfaceTextureGL_test.cpp @@ -28,8 +28,10 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) { const int texWidth = 64; const int texHeight = 66; - ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(), - texWidth, texHeight, HAL_PIXEL_FORMAT_YV12)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), + texWidth, texHeight)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), + HAL_PIXEL_FORMAT_YV12)); ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)); @@ -74,8 +76,10 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferPow2) { const int texWidth = 64; const int texHeight = 64; - ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(), - texWidth, texHeight, HAL_PIXEL_FORMAT_YV12)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), + texWidth, texHeight)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), + HAL_PIXEL_FORMAT_YV12)); ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)); @@ -120,8 +124,10 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) { const int texWidth = 64; const int texHeight = 66; - ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(), - texWidth, texHeight, HAL_PIXEL_FORMAT_YV12)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), + texWidth, texHeight)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), + HAL_PIXEL_FORMAT_YV12)); ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)); @@ -185,8 +191,10 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) { enum { numFrames = 1024 }; ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2)); - ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(), - texWidth, texHeight, HAL_PIXEL_FORMAT_YV12)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), + texWidth, texHeight)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), + HAL_PIXEL_FORMAT_YV12)); ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), GRALLOC_USAGE_SW_WRITE_OFTEN)); @@ -326,8 +334,10 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferNpot) { const int texWidth = 64; const int texHeight = 66; - ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(), - texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), + texWidth, texHeight)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), + HAL_PIXEL_FORMAT_RGBA_8888)); ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)); @@ -368,8 +378,10 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferPow2) { const int texWidth = 64; const int texHeight = 64; - ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(), - texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), + texWidth, texHeight)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), + HAL_PIXEL_FORMAT_RGBA_8888)); ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 5e6aeef356..3f495f8dee 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "DummyConsumer.h" + #include <gtest/gtest.h> #include <binder/IMemory.h> @@ -155,4 +157,75 @@ TEST_F(SurfaceTest, QueryConsumerUsage) { ASSERT_EQ(TEST_USAGE_FLAGS, flags); } +TEST_F(SurfaceTest, QueryDefaultBuffersDataSpace) { + const android_dataspace TEST_DATASPACE = HAL_DATASPACE_SRGB; + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1); + + cpuConsumer->setDefaultBufferDataSpace(TEST_DATASPACE); + + sp<Surface> s = new Surface(producer); + + sp<ANativeWindow> anw(s); + + android_dataspace dataSpace; + + int err = anw->query(anw.get(), NATIVE_WINDOW_DEFAULT_DATASPACE, + reinterpret_cast<int*>(&dataSpace)); + + ASSERT_EQ(NO_ERROR, err); + ASSERT_EQ(TEST_DATASPACE, dataSpace); +} + +TEST_F(SurfaceTest, SettingGenerationNumber) { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1); + sp<Surface> surface = new Surface(producer); + sp<ANativeWindow> window(surface); + + // Allocate a buffer with a generation number of 0 + ANativeWindowBuffer* buffer; + int fenceFd; + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fenceFd)); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fenceFd)); + + // Detach the buffer and check its generation number + sp<GraphicBuffer> graphicBuffer; + sp<Fence> fence; + ASSERT_EQ(NO_ERROR, surface->detachNextBuffer(&graphicBuffer, &fence)); + ASSERT_EQ(0U, graphicBuffer->getGenerationNumber()); + + ASSERT_EQ(NO_ERROR, surface->setGenerationNumber(1)); + buffer = static_cast<ANativeWindowBuffer*>(graphicBuffer.get()); + + // This should change the generation number of the GraphicBuffer + ASSERT_EQ(NO_ERROR, surface->attachBuffer(buffer)); + + // Check that the new generation number sticks with the buffer + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, -1)); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fenceFd)); + graphicBuffer = static_cast<GraphicBuffer*>(buffer); + ASSERT_EQ(1U, graphicBuffer->getGenerationNumber()); +} + +TEST_F(SurfaceTest, GetConsumerName) { + 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); + + EXPECT_STREQ("TestConsumer", surface->getConsumerName().string()); +} + } diff --git a/libs/input/Android.mk b/libs/input/Android.mk index f1921a4e0d..944ac7f653 100644 --- a/libs/input/Android.mk +++ b/libs/input/Android.mk @@ -27,6 +27,7 @@ commonSources := \ deviceSources := \ $(commonSources) \ + IInputFlinger.cpp \ InputTransport.cpp \ VelocityControl.cpp \ VelocityTracker.cpp diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp new file mode 100644 index 0000000000..e00973149c --- /dev/null +++ b/libs/input/IInputFlinger.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2013 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 <stdint.h> +#include <sys/types.h> + +#include <binder/Parcel.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> + +#include <input/IInputFlinger.h> + + +namespace android { + +class BpInputFlinger : public BpInterface<IInputFlinger> { +public: + BpInputFlinger(const sp<IBinder>& impl) : + BpInterface<IInputFlinger>(impl) { } + + virtual status_t doSomething() { + Parcel data, reply; + data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor()); + remote()->transact(BnInputFlinger::DO_SOMETHING_TRANSACTION, data, &reply); + return reply.readInt32(); + } +}; + +IMPLEMENT_META_INTERFACE(InputFlinger, "android.input.IInputFlinger"); + + +status_t BnInputFlinger::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { + switch(code) { + case DO_SOMETHING_TRANSACTION: { + CHECK_INTERFACE(IInputFlinger, data, reply); + reply->writeInt32(0); + break; + } + default: + return BBinder::onTransact(code, data, reply, flags); + } + return NO_ERROR; +} + +}; diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index cd55ee54bf..b64cb2ca9d 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -216,6 +216,7 @@ void MotionEvent::initialize( int32_t deviceId, int32_t source, int32_t action, + int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, @@ -231,6 +232,7 @@ void MotionEvent::initialize( const PointerCoords* pointerCoords) { InputEvent::initialize(deviceId, source); mAction = action; + mActionButton = actionButton; mFlags = flags; mEdgeFlags = edgeFlags; mMetaState = metaState; @@ -250,6 +252,7 @@ void MotionEvent::initialize( void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) { InputEvent::initialize(other->mDeviceId, other->mSource); mAction = other->mAction; + mActionButton = other->mActionButton; mFlags = other->mFlags; mEdgeFlags = other->mEdgeFlags; mMetaState = other->mMetaState; @@ -429,6 +432,7 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) { mDeviceId = parcel->readInt32(); mSource = parcel->readInt32(); mAction = parcel->readInt32(); + mActionButton = parcel->readInt32(); mFlags = parcel->readInt32(); mEdgeFlags = parcel->readInt32(); mMetaState = parcel->readInt32(); @@ -476,6 +480,7 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const { parcel->writeInt32(mDeviceId); parcel->writeInt32(mSource); parcel->writeInt32(mAction); + parcel->writeInt32(mActionButton); parcel->writeInt32(mFlags); parcel->writeInt32(mEdgeFlags); parcel->writeInt32(mMetaState); diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp index b11110a18c..d755ed30ac 100644 --- a/libs/input/InputDevice.cpp +++ b/libs/input/InputDevice.cpp @@ -127,28 +127,31 @@ String8 getInputDeviceConfigurationFilePathByName( // --- InputDeviceInfo --- InputDeviceInfo::InputDeviceInfo() { - initialize(-1, 0, -1, InputDeviceIdentifier(), String8(), false); + initialize(-1, 0, -1, InputDeviceIdentifier(), String8(), false, false); } InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) : mId(other.mId), mGeneration(other.mGeneration), mControllerNumber(other.mControllerNumber), mIdentifier(other.mIdentifier), mAlias(other.mAlias), mIsExternal(other.mIsExternal), - mSources(other.mSources), mKeyboardType(other.mKeyboardType), - mKeyCharacterMap(other.mKeyCharacterMap), mHasVibrator(other.mHasVibrator), - mHasButtonUnderPad(other.mHasButtonUnderPad), mMotionRanges(other.mMotionRanges) { + mHasMic(other.mHasMic), mSources(other.mSources), + mKeyboardType(other.mKeyboardType), mKeyCharacterMap(other.mKeyCharacterMap), + mHasVibrator(other.mHasVibrator), mHasButtonUnderPad(other.mHasButtonUnderPad), + mMotionRanges(other.mMotionRanges) { } InputDeviceInfo::~InputDeviceInfo() { } void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber, - const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal) { + const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal, + bool hasMic) { mId = id; mGeneration = generation; mControllerNumber = controllerNumber; mIdentifier = identifier; mAlias = alias; mIsExternal = isExternal; + mHasMic = hasMic; mSources = 0; mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE; mHasVibrator = false; diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 090ee530d1..0382f5788f 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -283,6 +283,7 @@ status_t InputPublisher::publishMotionEvent( int32_t deviceId, int32_t source, int32_t action, + int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, @@ -298,12 +299,12 @@ status_t InputPublisher::publishMotionEvent( const PointerCoords* pointerCoords) { #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, " - "action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, buttonState=0x%x, " - "xOffset=%f, yOffset=%f, " + "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, " "pointerCount=%" PRIu32, mChannel->getName().string(), seq, - deviceId, source, action, flags, edgeFlags, metaState, buttonState, + deviceId, source, action, actionButton, flags, edgeFlags, metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount); #endif @@ -324,6 +325,7 @@ status_t InputPublisher::publishMotionEvent( msg.body.motion.deviceId = deviceId; msg.body.motion.source = source; msg.body.motion.action = action; + msg.body.motion.actionButton = actionButton; msg.body.motion.flags = flags; msg.body.motion.edgeFlags = edgeFlags; msg.body.motion.metaState = metaState; @@ -907,6 +909,7 @@ void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage msg->body.motion.deviceId, msg->body.motion.source, msg->body.motion.action, + msg->body.motion.actionButton, msg->body.motion.flags, msg->body.motion.edgeFlags, msg->body.motion.metaState, diff --git a/libs/input/tests/Android.mk b/libs/input/tests/Android.mk index 9612a65fed..5bfa3d4808 100644 --- a/libs/input/tests/Android.mk +++ b/libs/input/tests/Android.mk @@ -1,6 +1,5 @@ # Build the unit tests. LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) # Build the unit tests. test_src_files := \ @@ -14,14 +13,10 @@ shared_libraries := \ libutils \ libbinder \ libui \ - libstlport - -static_libraries := \ - libgtest \ - libgtest_main $(foreach file,$(test_src_files), \ $(eval include $(CLEAR_VARS)) \ + $(eval LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk) \ $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \ $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \ $(eval LOCAL_SRC_FILES := $(file)) \ @@ -33,6 +28,7 @@ $(foreach file,$(test_src_files), \ # run. All assertions are static_asserts and will fail during # buildtime if something's wrong. include $(CLEAR_VARS) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_SRC_FILES := StructLayout_test.cpp LOCAL_MODULE := StructLayout_test LOCAL_CFLAGS := -std=c++11 -O0 diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index 9105ae523a..3fb1c6df9b 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -248,7 +248,7 @@ void MotionEventTest::initializeEventWithHistory(MotionEvent* event) { pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 26); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28); - event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE, + event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE, 0, AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY, X_OFFSET, Y_OFFSET, 2.0f, 2.1f, @@ -557,7 +557,7 @@ TEST_F(MotionEventTest, Transform) { pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, angle); } MotionEvent event; - event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, 0, + event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords); float originalRawX = 0 + 3; float originalRawY = -RADIUS + 2; diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index de192f1f57..8e69c9cb30 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -133,6 +133,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { const int32_t deviceId = 1; const int32_t source = AINPUT_SOURCE_TOUCHSCREEN; const int32_t action = AMOTION_EVENT_ACTION_MOVE; + const int32_t actionButton = 0; const int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; const int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP; const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON; @@ -163,8 +164,8 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i); } - status = mPublisher->publishMotionEvent(seq, deviceId, source, action, flags, edgeFlags, - metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision, + status = mPublisher->publishMotionEvent(seq, deviceId, source, action, actionButton, + flags, edgeFlags, metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(OK, status) @@ -255,7 +256,7 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessTha PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; - status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + status = mPublisher->publishMotionEvent(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"; @@ -271,7 +272,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, + status = mPublisher->publishMotionEvent(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/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp index 83bc6ae0b3..8d73f453e0 100644 --- a/libs/input/tests/StructLayout_test.cpp +++ b/libs/input/tests/StructLayout_test.cpp @@ -51,10 +51,11 @@ void TestInputMessageAlignment() { CHECK_OFFSET(InputMessage::Body::Motion, deviceId, 16); CHECK_OFFSET(InputMessage::Body::Motion, source, 20); CHECK_OFFSET(InputMessage::Body::Motion, action, 24); - CHECK_OFFSET(InputMessage::Body::Motion, flags, 28); - CHECK_OFFSET(InputMessage::Body::Motion, metaState, 32); - CHECK_OFFSET(InputMessage::Body::Motion, buttonState, 36); - CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 40); + CHECK_OFFSET(InputMessage::Body::Motion, actionButton, 28); + CHECK_OFFSET(InputMessage::Body::Motion, flags, 32); + CHECK_OFFSET(InputMessage::Body::Motion, metaState, 36); + CHECK_OFFSET(InputMessage::Body::Motion, buttonState, 40); + CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 44); CHECK_OFFSET(InputMessage::Body::Motion, downTime, 48); CHECK_OFFSET(InputMessage::Body::Motion, xOffset, 56); CHECK_OFFSET(InputMessage::Body::Motion, yOffset, 60); diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk index eec97be0cb..1ce8626522 100644 --- a/libs/ui/Android.mk +++ b/libs/ui/Android.mk @@ -12,10 +12,28 @@ # See the License for the specific language governing permissions and # limitations under the License. -LOCAL_PATH:= $(call my-dir) +LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES:= \ +LOCAL_CLANG := true +LOCAL_CPPFLAGS := -std=c++1y -Weverything -Werror + +# The static constructors and destructors in this library have not been noted to +# introduce significant overheads +LOCAL_CPPFLAGS += -Wno-exit-time-destructors +LOCAL_CPPFLAGS += -Wno-global-constructors + +# We only care about compiling as C++14 +LOCAL_CPPFLAGS += -Wno-c++98-compat-pedantic + +# We use four-character constants for the GraphicBuffer header, and don't care +# that they're non-portable as long as they're consistent within one execution +LOCAL_CPPFLAGS += -Wno-four-char-constants + +# Don't warn about struct padding +LOCAL_CPPFLAGS += -Wno-padded + +LOCAL_SRC_FILES := \ Fence.cpp \ FramebufferNativeWindow.cpp \ FrameStats.cpp \ @@ -38,7 +56,7 @@ ifneq ($(BOARD_FRAMEBUFFER_FORCE_FORMAT),) LOCAL_CFLAGS += -DFRAMEBUFFER_FORCE_FORMAT=$(BOARD_FRAMEBUFFER_FORCE_FORMAT) endif -LOCAL_MODULE:= libui +LOCAL_MODULE := libui include $(BUILD_SHARED_LIBRARY) diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp index 3c0306cf0b..bf24ffb7e0 100644 --- a/libs/ui/Fence.cpp +++ b/libs/ui/Fence.cpp @@ -18,10 +18,13 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 - // This is needed for stdint.h to define INT64_MAX in C++ - #define __STDC_LIMIT_MACROS - +// We would eliminate the non-conforming zero-length array, but we can't since +// this is effectively included from the Linux kernel +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wzero-length-array" #include <sync/sync.h> +#pragma clang diagnostic pop + #include <ui/Fence.h> #include <unistd.h> #include <utils/Log.h> @@ -45,7 +48,7 @@ Fence::~Fence() { } } -status_t Fence::wait(unsigned int timeout) { +status_t Fence::wait(int timeout) { ATRACE_CALL(); if (mFenceFd == -1) { return NO_ERROR; @@ -59,7 +62,7 @@ status_t Fence::waitForever(const char* logname) { if (mFenceFd == -1) { return NO_ERROR; } - unsigned int warningTimeout = 3000; + 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, @@ -127,7 +130,7 @@ nsecs_t Fence::getSignalTime() const { } size_t Fence::getFlattenedSize() const { - return 1; + return 4; } size_t Fence::getFdCount() const { @@ -138,7 +141,9 @@ status_t Fence::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) c if (size < getFlattenedSize() || count < getFdCount()) { return NO_MEMORY; } - FlattenableUtils::write(buffer, size, (uint32_t)getFdCount()); + // Cast to uint32_t since the size of a size_t can vary between 32- and + // 64-bit processes + FlattenableUtils::write(buffer, size, static_cast<uint32_t>(getFdCount())); if (isValid()) { *fds++ = mFenceFd; count--; diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp index 918f2e7567..3ead25cfe8 100644 --- a/libs/ui/FramebufferNativeWindow.cpp +++ b/libs/ui/FramebufferNativeWindow.cpp @@ -1,17 +1,17 @@ -/* +/* ** ** Copyright 2007 The Android Open Source Project ** -** Licensed under the Apache License Version 2.0(the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at +** 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 +** 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 +** 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. */ @@ -29,7 +29,9 @@ #include <ui/ANativeObjectBase.h> #include <ui/Fence.h> +#define INCLUDED_FROM_FRAMEBUFFER_NATIVE_WINDOW_CPP #include <ui/FramebufferNativeWindow.h> +#undef INCLUDED_FROM_FRAMEBUFFER_NATIVE_WINDOW_CPP #include <ui/Rect.h> #include <EGL/egl.h> @@ -41,11 +43,11 @@ namespace android { // ---------------------------------------------------------------------------- -class NativeBuffer +class NativeBuffer final : public ANativeObjectBase< - ANativeWindowBuffer, - NativeBuffer, - LightRefBase<NativeBuffer> > + ANativeWindowBuffer, + NativeBuffer, + LightRefBase<NativeBuffer>> { public: NativeBuffer(int w, int h, int f, int u) : BASE() { @@ -55,43 +57,41 @@ public: ANativeWindowBuffer::usage = u; } private: - friend class LightRefBase<NativeBuffer>; - ~NativeBuffer() { }; // this class cannot be overloaded + friend class LightRefBase<NativeBuffer>; }; /* * This implements the (main) framebuffer management. This class is used * mostly by SurfaceFlinger, but also by command line GL application. - * + * * In fact this is an implementation of ANativeWindow on top of * the framebuffer. - * - * Currently it is pretty simple, it manages only two buffers (the front and + * + * Currently it is pretty simple, it manages only two buffers (the front and * back buffer). - * + * */ -FramebufferNativeWindow::FramebufferNativeWindow() +FramebufferNativeWindow::FramebufferNativeWindow() : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false) { hw_module_t const* module; if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) { - int stride; int err; int i; err = framebuffer_open(module, &fbDev); ALOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err)); - + err = gralloc_open(module, &grDev); ALOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err)); // bail out if we can't initialize the modules if (!fbDev || !grDev) return; - + mUpdateOnDemand = (fbDev->setUpdateRect != 0); - + // initialize the buffer FIFO if(fbDev->numFramebuffers >= MIN_NUM_FRAME_BUFFERS && fbDev->numFramebuffers <= MAX_NUM_FRAME_BUFFERS){ @@ -114,36 +114,37 @@ FramebufferNativeWindow::FramebufferNativeWindow() *((uint32_t *)&fbDev->format) = FRAMEBUFFER_FORCE_FORMAT; #endif - for (i = 0; i < mNumBuffers; i++) - { - buffers[i] = new NativeBuffer( - fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB); + for (i = 0; i < mNumBuffers; i++) { + buffers[i] = new NativeBuffer( + static_cast<int>(fbDev->width), + static_cast<int>(fbDev->height), + fbDev->format, GRALLOC_USAGE_HW_FB); } - for (i = 0; i < mNumBuffers; i++) - { - err = grDev->alloc(grDev, - fbDev->width, fbDev->height, fbDev->format, - GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride); - - ALOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s", - i, fbDev->width, fbDev->height, strerror(-err)); - - if (err) - { - mNumBuffers = i; - mNumFreeBuffers = i; - mBufferHead = mNumBuffers-1; - break; - } + for (i = 0; i < mNumBuffers; i++) { + err = grDev->alloc(grDev, + static_cast<int>(fbDev->width), + static_cast<int>(fbDev->height), + fbDev->format, GRALLOC_USAGE_HW_FB, + &buffers[i]->handle, &buffers[i]->stride); + + ALOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s", + i, fbDev->width, fbDev->height, strerror(-err)); + + if (err) { + mNumBuffers = i; + mNumFreeBuffers = i; + mBufferHead = mNumBuffers-1; + break; + } } - const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags; + const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags; const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi; const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi; - const_cast<int&>(ANativeWindow::minSwapInterval) = + const_cast<int&>(ANativeWindow::minSwapInterval) = fbDev->minSwapInterval; - const_cast<int&>(ANativeWindow::maxSwapInterval) = + const_cast<int&>(ANativeWindow::maxSwapInterval) = fbDev->maxSwapInterval; } else { ALOGE("Couldn't get gralloc module"); @@ -160,7 +161,7 @@ FramebufferNativeWindow::FramebufferNativeWindow() ANativeWindow::queueBuffer_DEPRECATED = queueBuffer_DEPRECATED; } -FramebufferNativeWindow::~FramebufferNativeWindow() +FramebufferNativeWindow::~FramebufferNativeWindow() { if (grDev) { for(int i = 0; i < mNumBuffers; i++) { @@ -176,7 +177,7 @@ FramebufferNativeWindow::~FramebufferNativeWindow() } } -status_t FramebufferNativeWindow::setUpdateRectangle(const Rect& r) +status_t FramebufferNativeWindow::setUpdateRectangle(const Rect& r) { if (!mUpdateOnDemand) { return INVALID_OPERATION; @@ -193,7 +194,7 @@ status_t FramebufferNativeWindow::compositionComplete() } int FramebufferNativeWindow::setSwapInterval( - ANativeWindow* window, int interval) + ANativeWindow* window, int interval) { framebuffer_device_t* fb = getSelf(window)->fbDev; return fb->setSwapInterval(fb, interval); @@ -217,7 +218,7 @@ int FramebufferNativeWindow::getCurrentBufferIndex() const return index; } -int FramebufferNativeWindow::dequeueBuffer_DEPRECATED(ANativeWindow* window, +int FramebufferNativeWindow::dequeueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer** buffer) { int fenceFd = -1; @@ -232,12 +233,11 @@ int FramebufferNativeWindow::dequeueBuffer_DEPRECATED(ANativeWindow* window, return result; } -int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window, +int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, int* fenceFd) { FramebufferNativeWindow* self = getSelf(window); Mutex::Autolock _l(self->mutex); - framebuffer_device_t* fb = self->fbDev; int index = self->mBufferHead++; if (self->mBufferHead >= self->mNumBuffers) @@ -247,7 +247,7 @@ int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window, while (self->mNumFreeBuffers < 2) { self->mCondition.wait(self->mutex); } - ALOG_ASSERT(self->buffers[index] != self->front); + ALOG_ASSERT(self->buffers[index] != self->front, ""); // get this buffer self->mNumFreeBuffers--; @@ -259,19 +259,19 @@ int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window, return 0; } -int FramebufferNativeWindow::lockBuffer_DEPRECATED(ANativeWindow* /*window*/, +int FramebufferNativeWindow::lockBuffer_DEPRECATED(ANativeWindow* /*window*/, ANativeWindowBuffer* /*buffer*/) { return NO_ERROR; } -int FramebufferNativeWindow::queueBuffer_DEPRECATED(ANativeWindow* window, +int FramebufferNativeWindow::queueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer) { return queueBuffer(window, buffer, -1); } -int FramebufferNativeWindow::queueBuffer(ANativeWindow* window, +int FramebufferNativeWindow::queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) { FramebufferNativeWindow* self = getSelf(window); @@ -282,7 +282,6 @@ int FramebufferNativeWindow::queueBuffer(ANativeWindow* window, sp<Fence> fence(new Fence(fenceFd)); fence->wait(Fence::TIMEOUT_NEVER); - const int index = self->mCurrentBufferIndex; int res = fb->post(fb, handle); self->front = static_cast<NativeBuffer*>(buffer); self->mNumFreeBuffers++; @@ -291,17 +290,17 @@ int FramebufferNativeWindow::queueBuffer(ANativeWindow* window, } int FramebufferNativeWindow::query(const ANativeWindow* window, - int what, int* value) + int what, int* value) { const FramebufferNativeWindow* self = getSelf(window); Mutex::Autolock _l(self->mutex); framebuffer_device_t* fb = self->fbDev; switch (what) { case NATIVE_WINDOW_WIDTH: - *value = fb->width; + *value = static_cast<int>(fb->width); return NO_ERROR; case NATIVE_WINDOW_HEIGHT: - *value = fb->height; + *value = static_cast<int>(fb->height); return NO_ERROR; case NATIVE_WINDOW_FORMAT: *value = fb->format; @@ -313,10 +312,10 @@ int FramebufferNativeWindow::query(const ANativeWindow* window, *value = 0; return NO_ERROR; case NATIVE_WINDOW_DEFAULT_WIDTH: - *value = fb->width; + *value = static_cast<int>(fb->width); return NO_ERROR; case NATIVE_WINDOW_DEFAULT_HEIGHT: - *value = fb->height; + *value = static_cast<int>(fb->height); return NO_ERROR; case NATIVE_WINDOW_TRANSFORM_HINT: *value = 0; @@ -357,7 +356,8 @@ int FramebufferNativeWindow::perform(ANativeWindow* /*window*/, }; // namespace android // ---------------------------------------------------------------------------- -using namespace android; +using android::sp; +using android::FramebufferNativeWindow; EGLNativeWindowType android_createDisplaySurface(void) { @@ -368,5 +368,5 @@ EGLNativeWindowType android_createDisplaySurface(void) sp<FramebufferNativeWindow> ref(w); return NULL; } - return (EGLNativeWindowType)w; + return static_cast<EGLNativeWindowType>(w); } diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index 3ae88408d6..e55db30f8e 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -45,40 +45,40 @@ GraphicBuffer::GraphicBuffer() : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()), mInitCheck(NO_ERROR), mId(getUniqueId()) { - width = - height = - stride = - format = + width = + height = + stride = + format = usage = 0; handle = NULL; } -GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h, - PixelFormat reqFormat, uint32_t reqUsage) +GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, + PixelFormat inFormat, uint32_t inUsage) : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()), mInitCheck(NO_ERROR), mId(getUniqueId()) { - width = - height = - stride = - format = + width = + height = + stride = + format = usage = 0; handle = NULL; - mInitCheck = initSize(w, h, reqFormat, reqUsage); + mInitCheck = initSize(inWidth, inHeight, inFormat, inUsage); } -GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h, - PixelFormat inFormat, uint32_t inUsage, - uint32_t inStride, native_handle_t* inHandle, bool keepOwnership) +GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, + PixelFormat inFormat, uint32_t inUsage, uint32_t inStride, + native_handle_t* inHandle, bool keepOwnership) : BASE(), mOwner(keepOwnership ? ownHandle : ownNone), mBufferMapper(GraphicBufferMapper::get()), mInitCheck(NO_ERROR), mId(getUniqueId()) { - width = w; - height = h; - stride = inStride; + width = static_cast<int>(inWidth); + height = static_cast<int>(inHeight); + stride = static_cast<int>(inStride); format = inFormat; - usage = inUsage; + usage = static_cast<int>(inUsage); handle = inHandle; } @@ -116,7 +116,7 @@ void GraphicBuffer::free_handle() } status_t GraphicBuffer::initCheck() const { - return mInitCheck; + return static_cast<status_t>(mInitCheck); } void GraphicBuffer::dumpAllocationsToSystemLog() @@ -131,13 +131,17 @@ ANativeWindowBuffer* GraphicBuffer::getNativeBuffer() const const_cast<GraphicBuffer*>(this)); } -status_t GraphicBuffer::reallocate(uint32_t w, uint32_t h, PixelFormat f, - uint32_t reqUsage) +status_t GraphicBuffer::reallocate(uint32_t inWidth, uint32_t inHeight, + PixelFormat inFormat, uint32_t inUsage) { if (mOwner != ownData) return INVALID_OPERATION; - if (handle && w==width && h==height && f==format && reqUsage==usage) + if (handle && + static_cast<int>(inWidth) == width && + static_cast<int>(inHeight) == height && + inFormat == format && + static_cast<int>(inUsage) == usage) return NO_ERROR; if (handle) { @@ -145,61 +149,74 @@ status_t GraphicBuffer::reallocate(uint32_t w, uint32_t h, PixelFormat f, allocator.free(handle); handle = 0; } - return initSize(w, h, f, reqUsage); + return initSize(inWidth, inHeight, inFormat, inUsage); } -status_t GraphicBuffer::initSize(uint32_t w, uint32_t h, PixelFormat format, - uint32_t reqUsage) +bool GraphicBuffer::needsReallocation(uint32_t inWidth, uint32_t inHeight, + PixelFormat inFormat, uint32_t inUsage) +{ + if (static_cast<int>(inWidth) != width) return true; + if (static_cast<int>(inHeight) != height) return true; + if (inFormat != format) return true; + if ((static_cast<uint32_t>(usage) & inUsage) != inUsage) return true; + return false; +} + +status_t GraphicBuffer::initSize(uint32_t inWidth, uint32_t inHeight, + PixelFormat inFormat, uint32_t inUsage) { GraphicBufferAllocator& allocator = GraphicBufferAllocator::get(); - status_t err = allocator.alloc(w, h, format, reqUsage, &handle, &stride); + uint32_t outStride = 0; + status_t err = allocator.alloc(inWidth, inHeight, inFormat, inUsage, + &handle, &outStride); if (err == NO_ERROR) { - this->width = w; - this->height = h; - this->format = format; - this->usage = reqUsage; + width = static_cast<int>(inWidth); + height = static_cast<int>(inHeight); + format = inFormat; + usage = static_cast<int>(inUsage); + stride = static_cast<int>(outStride); } return err; } -status_t GraphicBuffer::lock(uint32_t usage, void** vaddr) +status_t GraphicBuffer::lock(uint32_t inUsage, void** vaddr) { const Rect lockBounds(width, height); - status_t res = lock(usage, lockBounds, vaddr); + status_t res = lock(inUsage, lockBounds, vaddr); return res; } -status_t GraphicBuffer::lock(uint32_t usage, const Rect& rect, void** vaddr) +status_t GraphicBuffer::lock(uint32_t inUsage, const Rect& rect, void** vaddr) { - if (rect.left < 0 || rect.right > this->width || - rect.top < 0 || rect.bottom > this->height) { + if (rect.left < 0 || rect.right > width || + rect.top < 0 || rect.bottom > height) { ALOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)", - rect.left, rect.top, rect.right, rect.bottom, - this->width, this->height); + rect.left, rect.top, rect.right, rect.bottom, + width, height); return BAD_VALUE; } - status_t res = getBufferMapper().lock(handle, usage, rect, vaddr); + status_t res = getBufferMapper().lock(handle, inUsage, rect, vaddr); return res; } -status_t GraphicBuffer::lockYCbCr(uint32_t usage, android_ycbcr *ycbcr) +status_t GraphicBuffer::lockYCbCr(uint32_t inUsage, android_ycbcr* ycbcr) { const Rect lockBounds(width, height); - status_t res = lockYCbCr(usage, lockBounds, ycbcr); + status_t res = lockYCbCr(inUsage, lockBounds, ycbcr); return res; } -status_t GraphicBuffer::lockYCbCr(uint32_t usage, const Rect& rect, - android_ycbcr *ycbcr) +status_t GraphicBuffer::lockYCbCr(uint32_t inUsage, const Rect& rect, + android_ycbcr* ycbcr) { - if (rect.left < 0 || rect.right > this->width || - rect.top < 0 || rect.bottom > this->height) { + if (rect.left < 0 || rect.right > width || + rect.top < 0 || rect.bottom > height) { ALOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)", rect.left, rect.top, rect.right, rect.bottom, - this->width, this->height); + width, height); return BAD_VALUE; } - status_t res = getBufferMapper().lockYCbCr(handle, usage, rect, ycbcr); + status_t res = getBufferMapper().lockYCbCr(handle, inUsage, rect, ycbcr); return res; } @@ -209,43 +226,48 @@ status_t GraphicBuffer::unlock() return res; } -status_t GraphicBuffer::lockAsync(uint32_t usage, void** vaddr, int fenceFd) +status_t GraphicBuffer::lockAsync(uint32_t inUsage, void** vaddr, int fenceFd) { const Rect lockBounds(width, height); - status_t res = lockAsync(usage, lockBounds, vaddr, fenceFd); + status_t res = lockAsync(inUsage, lockBounds, vaddr, fenceFd); return res; } -status_t GraphicBuffer::lockAsync(uint32_t usage, const Rect& rect, void** vaddr, int fenceFd) +status_t GraphicBuffer::lockAsync(uint32_t inUsage, const Rect& rect, + void** vaddr, int fenceFd) { - if (rect.left < 0 || rect.right > this->width || - rect.top < 0 || rect.bottom > this->height) { + if (rect.left < 0 || rect.right > width || + rect.top < 0 || rect.bottom > height) { ALOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)", rect.left, rect.top, rect.right, rect.bottom, - this->width, this->height); + width, height); return BAD_VALUE; } - status_t res = getBufferMapper().lockAsync(handle, usage, rect, vaddr, fenceFd); + status_t res = getBufferMapper().lockAsync(handle, inUsage, rect, vaddr, + fenceFd); return res; } -status_t GraphicBuffer::lockAsyncYCbCr(uint32_t usage, android_ycbcr *ycbcr, int fenceFd) +status_t GraphicBuffer::lockAsyncYCbCr(uint32_t inUsage, android_ycbcr* ycbcr, + int fenceFd) { const Rect lockBounds(width, height); - status_t res = lockAsyncYCbCr(usage, lockBounds, ycbcr, fenceFd); + status_t res = lockAsyncYCbCr(inUsage, lockBounds, ycbcr, fenceFd); return res; } -status_t GraphicBuffer::lockAsyncYCbCr(uint32_t usage, const Rect& rect, android_ycbcr *ycbcr, int fenceFd) +status_t GraphicBuffer::lockAsyncYCbCr(uint32_t inUsage, const Rect& rect, + android_ycbcr* ycbcr, int fenceFd) { - if (rect.left < 0 || rect.right > this->width || - rect.top < 0 || rect.bottom > this->height) { + if (rect.left < 0 || rect.right > width || + rect.top < 0 || rect.bottom > height) { ALOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)", rect.left, rect.top, rect.right, rect.bottom, - this->width, this->height); + width, height); return BAD_VALUE; } - status_t res = getBufferMapper().lockAsyncYCbCr(handle, usage, rect, ycbcr, fenceFd); + status_t res = getBufferMapper().lockAsyncYCbCr(handle, inUsage, rect, + ycbcr, fenceFd); return res; } @@ -256,11 +278,11 @@ status_t GraphicBuffer::unlockAsync(int *fenceFd) } size_t GraphicBuffer::getFlattenedSize() const { - return (10 + (handle ? handle->numInts : 0))*sizeof(int); + return static_cast<size_t>(11 + (handle ? handle->numInts : 0)) * sizeof(int); } size_t GraphicBuffer::getFdCount() const { - return handle ? handle->numFds : 0; + return static_cast<size_t>(handle ? handle->numFds : 0); } status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const { @@ -279,22 +301,24 @@ status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& buf[5] = usage; buf[6] = static_cast<int32_t>(mId >> 32); buf[7] = static_cast<int32_t>(mId & 0xFFFFFFFFull); - buf[8] = 0; + buf[8] = static_cast<int32_t>(mGenerationNumber); buf[9] = 0; + buf[10] = 0; if (handle) { - buf[8] = handle->numFds; - buf[9] = handle->numInts; - native_handle_t const* const h = handle; - memcpy(fds, h->data, h->numFds*sizeof(int)); - memcpy(&buf[10], h->data + h->numFds, h->numInts*sizeof(int)); + buf[9] = handle->numFds; + buf[10] = handle->numInts; + memcpy(fds, handle->data, + static_cast<size_t>(handle->numFds) * sizeof(int)); + memcpy(&buf[11], handle->data + handle->numFds, + static_cast<size_t>(handle->numInts) * sizeof(int)); } - buffer = reinterpret_cast<void*>(static_cast<int*>(buffer) + sizeNeeded); + buffer = static_cast<void*>(static_cast<uint8_t*>(buffer) + sizeNeeded); size -= sizeNeeded; if (handle) { fds += handle->numFds; - count -= handle->numFds; + count -= static_cast<size_t>(handle->numFds); } return NO_ERROR; @@ -302,28 +326,28 @@ status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& status_t GraphicBuffer::unflatten( void const*& buffer, size_t& size, int const*& fds, size_t& count) { - if (size < 8*sizeof(int)) return NO_MEMORY; + if (size < 11 * sizeof(int)) return NO_MEMORY; int const* buf = static_cast<int const*>(buffer); if (buf[0] != 'GBFR') return BAD_TYPE; - const size_t numFds = buf[8]; - const size_t numInts = buf[9]; + const size_t numFds = static_cast<size_t>(buf[9]); + const size_t numInts = static_cast<size_t>(buf[10]); // Limit the maxNumber to be relatively small. The number of fds or ints // should not come close to this number, and the number itself was simply // chosen to be high enough to not cause issues and low enough to prevent // overflow problems. const size_t maxNumber = 4096; - if (numFds >= maxNumber || numInts >= (maxNumber - 10)) { + if (numFds >= maxNumber || numInts >= (maxNumber - 11)) { width = height = stride = format = usage = 0; handle = NULL; - ALOGE("unflatten: numFds or numInts is too large: %d, %d", + ALOGE("unflatten: numFds or numInts is too large: %zd, %zd", numFds, numInts); return BAD_VALUE; } - const size_t sizeNeeded = (10 + numInts) * sizeof(int); + const size_t sizeNeeded = (11 + numInts) * sizeof(int); if (size < sizeNeeded) return NO_MEMORY; size_t fdCountNeeded = numFds; @@ -340,15 +364,16 @@ status_t GraphicBuffer::unflatten( stride = buf[3]; format = buf[4]; usage = buf[5]; - native_handle* h = native_handle_create(numFds, numInts); + native_handle* h = native_handle_create( + static_cast<int>(numFds), static_cast<int>(numInts)); if (!h) { width = height = stride = format = usage = 0; handle = NULL; ALOGE("unflatten: native_handle_create failed"); return NO_MEMORY; } - memcpy(h->data, fds, numFds*sizeof(int)); - memcpy(h->data + numFds, &buf[10], numInts*sizeof(int)); + memcpy(h->data, fds, numFds * sizeof(int)); + memcpy(h->data + numFds, &buf[11], numInts * sizeof(int)); handle = h; } else { width = height = stride = format = usage = 0; @@ -358,6 +383,8 @@ status_t GraphicBuffer::unflatten( mId = static_cast<uint64_t>(buf[6]) << 32; mId |= static_cast<uint32_t>(buf[7]); + mGenerationNumber = static_cast<uint32_t>(buf[8]); + mOwner = ownHandle; if (handle != 0) { @@ -371,7 +398,7 @@ status_t GraphicBuffer::unflatten( } } - buffer = reinterpret_cast<void const*>(static_cast<int const*>(buffer) + sizeNeeded); + buffer = static_cast<void const*>(static_cast<uint8_t const*>(buffer) + sizeNeeded); size -= sizeNeeded; fds += numFds; count -= numFds; diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp index ff550d961e..9b265af2b4 100644 --- a/libs/ui/GraphicBufferAllocator.cpp +++ b/libs/ui/GraphicBufferAllocator.cpp @@ -1,17 +1,17 @@ -/* +/* ** ** Copyright 2009, 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 +** 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 +** 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 +** 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. */ @@ -66,11 +66,11 @@ void GraphicBufferAllocator::dump(String8& result) const if (rec.size) { snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %8X | 0x%08x\n", list.keyAt(i), rec.size/1024.0f, - rec.w, rec.s, rec.h, rec.format, rec.usage); + rec.width, rec.stride, rec.height, rec.format, rec.usage); } else { snprintf(buffer, SIZE, "%10p: unknown | %4u (%4u) x %4u | %8X | 0x%08x\n", list.keyAt(i), - rec.w, rec.s, rec.h, rec.format, rec.usage); + rec.width, rec.stride, rec.height, rec.format, rec.usage); } result.append(buffer); total += rec.size; @@ -90,39 +90,43 @@ void GraphicBufferAllocator::dumpToSystemLog() ALOGD("%s", s.string()); } -status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format, - int usage, buffer_handle_t* handle, int32_t* stride) +status_t GraphicBufferAllocator::alloc(uint32_t width, uint32_t height, + PixelFormat format, uint32_t usage, buffer_handle_t* handle, + uint32_t* stride) { ATRACE_CALL(); + // make sure to not allocate a N x 0 or 0 x N buffer, since this is // allowed from an API stand-point allocate a 1x1 buffer instead. - if (!w || !h) - w = h = 1; + if (!width || !height) + width = height = 1; // we have a h/w allocator and h/w buffer is requested - status_t err; - - err = mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride); + status_t err; + + // Filter out any usage bits that should not be passed to the gralloc module + usage &= GRALLOC_USAGE_ALLOC_MASK; + + int outStride = 0; + err = mAllocDev->alloc(mAllocDev, static_cast<int>(width), + static_cast<int>(height), format, static_cast<int>(usage), handle, + &outStride); + *stride = static_cast<uint32_t>(outStride); ALOGW_IF(err, "alloc(%u, %u, %d, %08x, ...) failed %d (%s)", - w, h, format, usage, err, strerror(-err)); - + width, height, format, usage, err, strerror(-err)); + if (err == NO_ERROR) { Mutex::Autolock _l(sLock); KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList); - int bpp = bytesPerPixel(format); - if (bpp < 0) { - // probably a HAL custom format. in any case, we don't know - // what its pixel size is. - bpp = 0; - } + uint32_t bpp = bytesPerPixel(format); alloc_rec_t rec; - rec.w = w; - rec.h = h; - rec.s = *stride; + rec.width = width; + rec.height = height; + rec.stride = *stride; rec.format = format; rec.usage = usage; - rec.size = h * stride[0] * bpp; + rec.size = static_cast<size_t>(height * (*stride) * bpp); list.add(*handle, rec); } diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp index e949b0c9b1..90a1c1110d 100644 --- a/libs/ui/GraphicBufferMapper.cpp +++ b/libs/ui/GraphicBufferMapper.cpp @@ -20,7 +20,12 @@ #include <stdint.h> #include <errno.h> +// We would eliminate the non-conforming zero-length array, but we can't since +// this is effectively included from the Linux kernel +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wzero-length-array" #include <sync/sync.h> +#pragma clang diagnostic pop #include <utils/Errors.h> #include <utils/Log.h> @@ -44,7 +49,7 @@ GraphicBufferMapper::GraphicBufferMapper() int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID); if (err == 0) { - mAllocMod = (gralloc_module_t const *)module; + mAllocMod = reinterpret_cast<gralloc_module_t const *>(module); } } @@ -72,13 +77,13 @@ status_t GraphicBufferMapper::unregisterBuffer(buffer_handle_t handle) return err; } -status_t GraphicBufferMapper::lock(buffer_handle_t handle, - int usage, const Rect& bounds, void** vaddr) +status_t GraphicBufferMapper::lock(buffer_handle_t handle, + uint32_t usage, const Rect& bounds, void** vaddr) { ATRACE_CALL(); status_t err; - err = mAllocMod->lock(mAllocMod, handle, usage, + err = mAllocMod->lock(mAllocMod, handle, static_cast<int>(usage), bounds.left, bounds.top, bounds.width(), bounds.height(), vaddr); @@ -87,7 +92,7 @@ status_t GraphicBufferMapper::lock(buffer_handle_t handle, } status_t GraphicBufferMapper::lockYCbCr(buffer_handle_t handle, - int usage, const Rect& bounds, android_ycbcr *ycbcr) + uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr) { ATRACE_CALL(); status_t err; @@ -96,7 +101,7 @@ status_t GraphicBufferMapper::lockYCbCr(buffer_handle_t handle, return -EINVAL; // do not log failure } - err = mAllocMod->lock_ycbcr(mAllocMod, handle, usage, + err = mAllocMod->lock_ycbcr(mAllocMod, handle, static_cast<int>(usage), bounds.left, bounds.top, bounds.width(), bounds.height(), ycbcr); @@ -116,19 +121,21 @@ status_t GraphicBufferMapper::unlock(buffer_handle_t handle) } status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle, - int usage, const Rect& bounds, void** vaddr, int fenceFd) + uint32_t usage, const Rect& bounds, void** vaddr, int fenceFd) { ATRACE_CALL(); status_t err; if (mAllocMod->common.module_api_version >= GRALLOC_MODULE_API_VERSION_0_3) { - err = mAllocMod->lockAsync(mAllocMod, handle, usage, + err = mAllocMod->lockAsync(mAllocMod, handle, static_cast<int>(usage), bounds.left, bounds.top, bounds.width(), bounds.height(), vaddr, fenceFd); } else { - sync_wait(fenceFd, -1); - close(fenceFd); - err = mAllocMod->lock(mAllocMod, handle, usage, + if (fenceFd >= 0) { + sync_wait(fenceFd, -1); + close(fenceFd); + } + err = mAllocMod->lock(mAllocMod, handle, static_cast<int>(usage), bounds.left, bounds.top, bounds.width(), bounds.height(), vaddr); } @@ -138,23 +145,28 @@ status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle, } status_t GraphicBufferMapper::lockAsyncYCbCr(buffer_handle_t handle, - int usage, const Rect& bounds, android_ycbcr *ycbcr, int fenceFd) + uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr, int fenceFd) { ATRACE_CALL(); status_t err; if (mAllocMod->common.module_api_version >= GRALLOC_MODULE_API_VERSION_0_3 && mAllocMod->lockAsync_ycbcr != NULL) { - err = mAllocMod->lockAsync_ycbcr(mAllocMod, handle, usage, - bounds.left, bounds.top, bounds.width(), bounds.height(), - ycbcr, fenceFd); + err = mAllocMod->lockAsync_ycbcr(mAllocMod, handle, + static_cast<int>(usage), bounds.left, bounds.top, + bounds.width(), bounds.height(), ycbcr, fenceFd); } else if (mAllocMod->lock_ycbcr != NULL) { - sync_wait(fenceFd, -1); - close(fenceFd); - err = mAllocMod->lock_ycbcr(mAllocMod, handle, usage, + if (fenceFd >= 0) { + sync_wait(fenceFd, -1); + close(fenceFd); + } + err = mAllocMod->lock_ycbcr(mAllocMod, handle, static_cast<int>(usage), bounds.left, bounds.top, bounds.width(), bounds.height(), ycbcr); } else { + if (fenceFd >= 0) { + close(fenceFd); + } return -EINVAL; // do not log failure } diff --git a/libs/ui/PixelFormat.cpp b/libs/ui/PixelFormat.cpp index 5ce7fba54e..cab1dde3fa 100644 --- a/libs/ui/PixelFormat.cpp +++ b/libs/ui/PixelFormat.cpp @@ -15,19 +15,16 @@ */ #include <ui/PixelFormat.h> -#include <hardware/hardware.h> // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- -ssize_t bytesPerPixel(PixelFormat format) { +uint32_t bytesPerPixel(PixelFormat format) { switch (format) { case PIXEL_FORMAT_RGBA_8888: case PIXEL_FORMAT_RGBX_8888: case PIXEL_FORMAT_BGRA_8888: - case PIXEL_FORMAT_sRGB_A_8888: - case PIXEL_FORMAT_sRGB_X_8888: return 4; case PIXEL_FORMAT_RGB_888: return 3; @@ -36,10 +33,10 @@ ssize_t bytesPerPixel(PixelFormat format) { case PIXEL_FORMAT_RGBA_4444: return 2; } - return BAD_VALUE; + return 0; } -ssize_t bitsPerPixel(PixelFormat format) { +uint32_t bitsPerPixel(PixelFormat format) { switch (format) { case PIXEL_FORMAT_RGBA_8888: case PIXEL_FORMAT_RGBX_8888: @@ -52,10 +49,9 @@ ssize_t bitsPerPixel(PixelFormat format) { case PIXEL_FORMAT_RGBA_4444: return 16; } - return BAD_VALUE; + return 0; } // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- - diff --git a/libs/ui/Rect.cpp b/libs/ui/Rect.cpp index b480f3a62b..dcce21f15a 100644 --- a/libs/ui/Rect.cpp +++ b/libs/ui/Rect.cpp @@ -19,6 +19,8 @@ namespace android { +const Rect Rect::INVALID_RECT{0, 0, -1, -1}; + static inline int32_t min(int32_t a, int32_t b) { return (a < b) ? a : b; } diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp index fa812f4dae..cfed7a984c 100644 --- a/libs/ui/Region.cpp +++ b/libs/ui/Region.cpp @@ -53,6 +53,8 @@ enum { direction_RTL }; +const Region Region::INVALID_REGION(Rect::INVALID_RECT); + // ---------------------------------------------------------------------------- Region::Region() { @@ -102,8 +104,8 @@ static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, current--; } while (current->top == lastTop && current >= begin); - unsigned int beginLastSpan = -1; - unsigned int endLastSpan = -1; + int beginLastSpan = -1; + int endLastSpan = -1; int top = -1; int bottom = -1; @@ -118,7 +120,7 @@ static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, } else { beginLastSpan = endLastSpan + 1; } - endLastSpan = dst.size() - 1; + endLastSpan = static_cast<int>(dst.size()) - 1; top = current->top; bottom = current->bottom; @@ -126,43 +128,46 @@ static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, int left = current->left; int right = current->right; - for (unsigned int prevIndex = beginLastSpan; prevIndex <= endLastSpan; prevIndex++) { - const Rect* prev = &dst[prevIndex]; + for (int prevIndex = beginLastSpan; prevIndex <= endLastSpan; prevIndex++) { + // prevIndex can't be -1 here because if endLastSpan is set to a + // value greater than -1 (allowing the loop to execute), + // beginLastSpan (and therefore prevIndex) will also be increased + const Rect prev = dst[static_cast<size_t>(prevIndex)]; if (spanDirection == direction_RTL) { // iterating over previous span RTL, quit if it's too far left - if (prev->right <= left) break; + if (prev.right <= left) break; - if (prev->right > left && prev->right < right) { - dst.add(Rect(prev->right, top, right, bottom)); - right = prev->right; + if (prev.right > left && prev.right < right) { + dst.add(Rect(prev.right, top, right, bottom)); + right = prev.right; } - if (prev->left > left && prev->left < right) { - dst.add(Rect(prev->left, top, right, bottom)); - right = prev->left; + if (prev.left > left && prev.left < right) { + dst.add(Rect(prev.left, top, right, bottom)); + right = prev.left; } // if an entry in the previous span is too far right, nothing further left in the // current span will need it - if (prev->left >= right) { + if (prev.left >= right) { beginLastSpan = prevIndex; } } else { // iterating over previous span LTR, quit if it's too far right - if (prev->left >= right) break; + if (prev.left >= right) break; - if (prev->left > left && prev->left < right) { - dst.add(Rect(left, top, prev->left, bottom)); - left = prev->left; + if (prev.left > left && prev.left < right) { + dst.add(Rect(left, top, prev.left, bottom)); + left = prev.left; } - if (prev->right > left && prev->right < right) { - dst.add(Rect(left, top, prev->right, bottom)); - left = prev->right; + if (prev.right > left && prev.right < right) { + dst.add(Rect(left, top, prev.right, bottom)); + left = prev.right; } // if an entry in the previous span is too far left, nothing further right in the // current span will need it - if (prev->right <= left) { + if (prev.right <= left) { beginLastSpan = prevIndex; } } @@ -250,10 +255,16 @@ void Region::set(const Rect& r) mStorage.add(r); } +void Region::set(int32_t w, int32_t h) +{ + mStorage.clear(); + mStorage.add(Rect(w, h)); +} + void Region::set(uint32_t w, uint32_t h) { mStorage.clear(); - mStorage.add(Rect(w,h)); + mStorage.add(Rect(w, h)); } bool Region::isTriviallyEqual(const Region& region) const { @@ -404,7 +415,7 @@ const Region Region::operation(const Region& rhs, int dx, int dy, int op) const // This is our region rasterizer, which merges rects and spans together // to obtain an optimal region. -class Region::rasterizer : public region_operator<Rect>::region_rasterizer +class Region::rasterizer : public region_operator<Rect>::region_rasterizer { Rect bounds; Vector<Rect>& storage; @@ -413,80 +424,91 @@ class Region::rasterizer : public region_operator<Rect>::region_rasterizer Vector<Rect> span; Rect* cur; public: - rasterizer(Region& reg) + rasterizer(Region& reg) : bounds(INT_MAX, 0, INT_MIN, 0), storage(reg.mStorage), head(), tail(), cur() { storage.clear(); } - ~rasterizer() { - if (span.size()) { - flushSpan(); - } - if (storage.size()) { - bounds.top = storage.itemAt(0).top; - bounds.bottom = storage.top().bottom; - if (storage.size() == 1) { - storage.clear(); - } - } else { - bounds.left = 0; - bounds.right = 0; + virtual ~rasterizer(); + + virtual void operator()(const Rect& rect); + +private: + template<typename T> + static inline T min(T rhs, T lhs) { return rhs < lhs ? rhs : lhs; } + template<typename T> + static inline T max(T rhs, T lhs) { return rhs > lhs ? rhs : lhs; } + + void flushSpan(); +}; + +Region::rasterizer::~rasterizer() +{ + if (span.size()) { + flushSpan(); + } + if (storage.size()) { + bounds.top = storage.itemAt(0).top; + bounds.bottom = storage.top().bottom; + if (storage.size() == 1) { + storage.clear(); } - storage.add(bounds); + } else { + bounds.left = 0; + bounds.right = 0; } - - virtual void operator()(const Rect& rect) { - //ALOGD(">>> %3d, %3d, %3d, %3d", - // rect.left, rect.top, rect.right, rect.bottom); - if (span.size()) { - if (cur->top != rect.top) { - flushSpan(); - } else if (cur->right == rect.left) { - cur->right = rect.right; - return; - } + storage.add(bounds); +} + +void Region::rasterizer::operator()(const Rect& rect) +{ + //ALOGD(">>> %3d, %3d, %3d, %3d", + // rect.left, rect.top, rect.right, rect.bottom); + if (span.size()) { + if (cur->top != rect.top) { + flushSpan(); + } else if (cur->right == rect.left) { + cur->right = rect.right; + return; } - span.add(rect); - cur = span.editArray() + (span.size() - 1); } -private: - template<typename T> - static inline T min(T rhs, T lhs) { return rhs < lhs ? rhs : lhs; } - template<typename T> - static inline T max(T rhs, T lhs) { return rhs > lhs ? rhs : lhs; } - void flushSpan() { - bool merge = false; - if (tail-head == ssize_t(span.size())) { - Rect const* p = span.editArray(); - Rect const* q = head; - if (p->top == q->bottom) { - merge = true; - while (q != tail) { - if ((p->left != q->left) || (p->right != q->right)) { - merge = false; - break; - } - p++, q++; + span.add(rect); + cur = span.editArray() + (span.size() - 1); +} + +void Region::rasterizer::flushSpan() +{ + bool merge = false; + if (tail-head == ssize_t(span.size())) { + Rect const* p = span.editArray(); + Rect const* q = head; + if (p->top == q->bottom) { + merge = true; + while (q != tail) { + if ((p->left != q->left) || (p->right != q->right)) { + merge = false; + break; } + p++, q++; } } - if (merge) { - const int bottom = span[0].bottom; - Rect* r = head; - while (r != tail) { - r->bottom = bottom; - r++; - } - } else { - bounds.left = min(span.itemAt(0).left, bounds.left); - bounds.right = max(span.top().right, bounds.right); - storage.appendVector(span); - tail = storage.editArray() + storage.size(); - head = tail - span.size(); + } + if (merge) { + const int bottom = span[0].bottom; + Rect* r = head; + while (r != tail) { + r->bottom = bottom; + r++; } - span.clear(); + } else { + bounds.left = min(span.itemAt(0).left, bounds.left); + bounds.right = max(span.top().right, bounds.right); + storage.appendVector(span); + tail = storage.editArray() + storage.size(); + head = tail - span.size(); } -}; + span.clear(); +} bool Region::validate(const Region& reg, const char* name, bool silent) { @@ -497,8 +519,12 @@ bool Region::validate(const Region& reg, const char* name, bool silent) Rect b(*prev); while (cur != tail) { if (cur->isValid() == false) { - ALOGE_IF(!silent, "%s: region contains an invalid Rect", name); - result = false; + // We allow this particular flavor of invalid Rect, since it is used + // as a signal value in various parts of the system + if (*cur != Rect::INVALID_RECT) { + ALOGE_IF(!silent, "%s: region contains an invalid Rect", name); + result = false; + } } if (cur->right > region_operator<Rect>::max_value) { ALOGE_IF(!silent, "%s: rect->right > max_value", name); @@ -670,7 +696,9 @@ void Region::boolean_operation(int op, Region& dst, const Region& lhs, const Rect& rhs, int dx, int dy) { - if (!rhs.isValid()) { + // We allow this particular flavor of invalid Rect, since it is used as a + // signal value in various parts of the system + if (!rhs.isValid() && rhs != Rect::INVALID_RECT) { ALOGE("Region::boolean_operation(op=%d) invalid Rect={%d,%d,%d,%d}", op, rhs.left, rhs.top, rhs.right, rhs.bottom); return; @@ -733,35 +761,57 @@ void Region::translate(Region& dst, const Region& reg, int dx, int dy) // ---------------------------------------------------------------------------- size_t Region::getFlattenedSize() const { - return mStorage.size() * sizeof(Rect); + return sizeof(uint32_t) + mStorage.size() * sizeof(Rect); } status_t Region::flatten(void* buffer, size_t size) const { #if VALIDATE_REGIONS validate(*this, "Region::flatten"); #endif - if (size < mStorage.size() * sizeof(Rect)) { + if (size < getFlattenedSize()) { return NO_MEMORY; } - Rect* rects = reinterpret_cast<Rect*>(buffer); - memcpy(rects, mStorage.array(), mStorage.size() * sizeof(Rect)); + // Cast to uint32_t since the size of a size_t can vary between 32- and + // 64-bit processes + FlattenableUtils::write(buffer, size, static_cast<uint32_t>(mStorage.size())); + for (auto rect : mStorage) { + status_t result = rect.flatten(buffer, size); + if (result != NO_ERROR) { + return result; + } + FlattenableUtils::advance(buffer, size, sizeof(rect)); + } return NO_ERROR; } status_t Region::unflatten(void const* buffer, size_t size) { + if (size < sizeof(uint32_t)) { + return NO_MEMORY; + } + + uint32_t numRects = 0; + FlattenableUtils::read(buffer, size, numRects); + if (size < numRects * sizeof(Rect)) { + return NO_MEMORY; + } + + if (numRects > (UINT32_MAX / sizeof(Rect))) { + android_errorWriteWithInfoLog(0x534e4554, "29983260", -1, NULL, 0); + return NO_MEMORY; + } + Region result; - if (size >= sizeof(Rect)) { - Rect const* rects = reinterpret_cast<Rect const*>(buffer); - size_t count = size / sizeof(Rect); - if (count > 0) { - result.mStorage.clear(); - ssize_t err = result.mStorage.insertAt(0, count); - if (err < 0) { - return status_t(err); - } - memcpy(result.mStorage.editArray(), rects, count*sizeof(Rect)); + result.mStorage.clear(); + for (size_t r = 0; r < numRects; ++r) { + Rect rect; + status_t status = rect.unflatten(buffer, size); + if (status != NO_ERROR) { + return status; } + FlattenableUtils::advance(buffer, size, sizeof(rect)); + result.mStorage.push_back(rect); } + #if VALIDATE_REGIONS validate(result, "Region::unflatten"); #endif @@ -786,10 +836,8 @@ Region::const_iterator Region::end() const { } Rect const* Region::getArray(size_t* count) const { - const_iterator const b(begin()); - const_iterator const e(end()); - if (count) *count = e-b; - return b; + if (count) *count = static_cast<size_t>(end() - begin()); + return begin(); } SharedBuffer const* Region::getSharedBuffer(size_t* count) const { @@ -806,29 +854,22 @@ SharedBuffer const* Region::getSharedBuffer(size_t* count) const { // ---------------------------------------------------------------------------- -void Region::dump(String8& out, const char* what, uint32_t flags) const +void Region::dump(String8& out, const char* what, uint32_t /* flags */) const { - (void)flags; const_iterator head = begin(); const_iterator const tail = end(); - size_t SIZE = 256; - char buffer[SIZE]; - - snprintf(buffer, SIZE, " Region %s (this=%p, count=%" PRIdPTR ")\n", - what, this, tail-head); - out.append(buffer); + out.appendFormat(" Region %s (this=%p, count=%" PRIdPTR ")\n", + what, this, tail - head); while (head != tail) { - snprintf(buffer, SIZE, " [%3d, %3d, %3d, %3d]\n", - head->left, head->top, head->right, head->bottom); - out.append(buffer); - head++; + out.appendFormat(" [%3d, %3d, %3d, %3d]\n", head->left, head->top, + head->right, head->bottom); + ++head; } } -void Region::dump(const char* what, uint32_t flags) const +void Region::dump(const char* what, uint32_t /* flags */) const { - (void)flags; const_iterator head = begin(); const_iterator const tail = end(); ALOGD(" Region %s (this=%p, count=%" PRIdPTR ")\n", what, this, tail-head); diff --git a/libs/ui/UiConfig.cpp b/libs/ui/UiConfig.cpp index 8b2130e702..9e7ba8e886 100644 --- a/libs/ui/UiConfig.cpp +++ b/libs/ui/UiConfig.cpp @@ -18,8 +18,11 @@ namespace android { +#ifdef FRAMEBUFFER_FORCE_FORMAT +// We need the two-level macro to stringify the contents of a macro argument #define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) +#endif void appendUiConfigString(String8& configStr) { diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk index b0c57db984..6438b1f9a4 100644 --- a/libs/ui/tests/Android.mk +++ b/libs/ui/tests/Android.mk @@ -1,31 +1,36 @@ -# Build the unit tests. -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -# Build the unit tests. -test_src_files := \ - Region_test.cpp \ - vec_test.cpp \ - mat_test.cpp - -shared_libraries := \ - libutils \ - libui +# +# Copyright (C) 2014 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. +# -static_libraries := \ - libgtest \ - libgtest_main +LOCAL_PATH := $(call my-dir) -$(foreach file,$(test_src_files), \ - $(eval include $(CLEAR_VARS)) \ - $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \ - $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \ - $(eval LOCAL_SRC_FILES := $(file)) \ - $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \ - $(eval include $(BUILD_NATIVE_TEST)) \ -) +include $(CLEAR_VARS) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk +LOCAL_SHARED_LIBRARIES := libui +LOCAL_SRC_FILES := Region_test.cpp +LOCAL_MODULE := Region_test +include $(BUILD_NATIVE_TEST) -# Build the unit tests. +include $(CLEAR_VARS) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk +LOCAL_SRC_FILES := vec_test.cpp +LOCAL_MODULE := vec_test +include $(BUILD_NATIVE_TEST) -# Build the manual test programs. -include $(call all-makefiles-under, $(LOCAL_PATH)) +include $(CLEAR_VARS) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk +LOCAL_SRC_FILES := mat_test.cpp +LOCAL_MODULE := mat_test +include $(BUILD_NATIVE_TEST) diff --git a/libs/ui/tests/vec_test.cpp b/libs/ui/tests/vec_test.cpp index 00f737e2f8..454c999ec4 100644 --- a/libs/ui/tests/vec_test.cpp +++ b/libs/ui/tests/vec_test.cpp @@ -16,17 +16,18 @@ #define LOG_TAG "RegionTest" +#include <math.h> #include <stdlib.h> + #include <ui/Region.h> #include <ui/Rect.h> -#include <gtest/gtest.h> - #include <ui/vec4.h> +#include <gtest/gtest.h> + namespace android { class VecTest : public testing::Test { -protected: }; TEST_F(VecTest, Basics) { |