diff options
Diffstat (limited to 'libs')
47 files changed, 1387 insertions, 366 deletions
diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk index 79decfe..d5860ef 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 c562c30..e4d8201 100644 --- a/libs/binder/AppOpsManager.cpp +++ b/libs/binder/AppOpsManager.cpp @@ -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/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp index 2d493c1..1339a67 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/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp index 86abdc0..9558376 100644 --- a/libs/binder/IAppOpsService.cpp +++ b/libs/binder/IAppOpsService.cpp @@ -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 8f3b7b4..e32c628 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 8c60dc4..2fcd3d9 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 { @@ -41,6 +43,25 @@ sp<IBinder> IInterface::asBinder(const sp<IInterface>& iface) 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/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 9f68aa8..ef88181 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -399,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; @@ -414,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 diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp index 437113d..6bba996 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 0000000..d86eb27 --- /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/Parcel.cpp b/libs/binder/Parcel.cpp index d769caa..7a4ddc4 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -54,7 +54,17 @@ // --------------------------------------------------------------------------- -#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 (0x40 << 16) @@ -62,9 +72,6 @@ // 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) @@ -438,7 +484,8 @@ status_t Parcel::appendFrom(const Parcel *parcel, size_t offset, size_t len) if (numObjects > 0) { // grow objects if (mObjectsCapacity < mObjectsSize + numObjects) { - int newSize = ((mObjectsSize + numObjects)*3)/2; + size_t newSize = ((mObjectsSize + numObjects)*3)/2; + if (newSize < mObjectsSize) return NO_MEMORY; // overflow binder_size_t *objects = (binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t)); if (objects == (binder_size_t*)0) { @@ -476,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; @@ -561,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); @@ -574,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 @@ -593,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); @@ -603,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) { @@ -652,20 +728,32 @@ status_t Parcel::writeUint32(uint32_t 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)); } @@ -677,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); @@ -805,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; } @@ -851,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; @@ -859,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; } } @@ -879,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; @@ -887,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; @@ -894,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; @@ -923,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)); } @@ -947,6 +1039,7 @@ restart_write: } if (!enoughObjects) { size_t newSize = ((mObjectsSize+2)*3)/2; + if (newSize < mObjectsSize) return NO_MEMORY; // overflow binder_size_t* objects = (binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t)); if (objects == NULL) return NO_MEMORY; mObjects = objects; @@ -968,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; } @@ -980,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; } @@ -992,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; @@ -1016,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: @@ -1060,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; @@ -1147,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; } @@ -1261,46 +1376,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; } @@ -1310,8 +1410,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; @@ -1550,6 +1656,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 @@ -1558,6 +1670,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); @@ -1598,6 +1716,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; @@ -1630,7 +1754,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); @@ -1766,6 +1890,7 @@ void Parcel::initState() mFdsKnown = true; mAllowFds = true; mOwner = NULL; + mBlobAshmemSize = 0; } void Parcel::scanForFds() const @@ -1783,10 +1908,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() { @@ -1794,22 +1924,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 0000000..fb28643 --- /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 303d6cf..016d3c5 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/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp index 5793d40..8f64ae0 100644 --- a/libs/gui/BufferItem.cpp +++ b/libs/gui/BufferItem.cpp @@ -46,15 +46,16 @@ static void addAligned(size_t& size, T /* value */) { } size_t BufferItem::getPodSize() const { - // Must align<8> before writing these fields for this to be correct size_t size = 0; addAligned(size, mCrop); addAligned(size, mTransform); addAligned(size, mScalingMode); - addAligned(size, mTimestamp); + addAligned(size, mTimestampLo); + addAligned(size, mTimestampHi); addAligned(size, mIsAutoTimestamp); addAligned(size, mDataSpace); - addAligned(size, mFrameNumber); + addAligned(size, mFrameNumberLo); + addAligned(size, mFrameNumberHi); addAligned(size, mSlot); addAligned(size, mIsDroppable); addAligned(size, mAcquireCalled); @@ -126,9 +127,6 @@ status_t BufferItem::flatten( if (err) return err; FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize()); - // Must align<8> so that getPodSize returns the correct value - size -= FlattenableUtils::align<8>(buffer); - // Check we still have enough space if (size < getPodSize()) { return NO_MEMORY; @@ -137,10 +135,12 @@ status_t BufferItem::flatten( writeAligned(buffer, size, mCrop); writeAligned(buffer, size, mTransform); writeAligned(buffer, size, mScalingMode); - writeAligned(buffer, size, mTimestamp); + writeAligned(buffer, size, mTimestampLo); + writeAligned(buffer, size, mTimestampHi); writeAligned(buffer, size, mIsAutoTimestamp); writeAligned(buffer, size, mDataSpace); - writeAligned(buffer, size, mFrameNumber); + writeAligned(buffer, size, mFrameNumberLo); + writeAligned(buffer, size, mFrameNumberHi); writeAligned(buffer, size, mSlot); writeAligned(buffer, size, mIsDroppable); writeAligned(buffer, size, mAcquireCalled); @@ -183,9 +183,6 @@ status_t BufferItem::unflatten( if (err) return err; FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize()); - // Must align<8> so that getPodSize returns the correct value - size -= FlattenableUtils::align<8>(buffer); - // Check we still have enough space if (size < getPodSize()) { return NO_MEMORY; @@ -194,10 +191,12 @@ status_t BufferItem::unflatten( readAligned(buffer, size, mCrop); readAligned(buffer, size, mTransform); readAligned(buffer, size, mScalingMode); - readAligned(buffer, size, mTimestamp); + readAligned(buffer, size, mTimestampLo); + readAligned(buffer, size, mTimestampHi); readAligned(buffer, size, mIsAutoTimestamp); readAligned(buffer, size, mDataSpace); - readAligned(buffer, size, mFrameNumber); + readAligned(buffer, size, mFrameNumberLo); + readAligned(buffer, size, mFrameNumberHi); readAligned(buffer, size, mSlot); readAligned(buffer, size, mIsDroppable); readAligned(buffer, size, mAcquireCalled); diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp index 194121f..578b8d9 100644 --- a/libs/gui/BufferItemConsumer.cpp +++ b/libs/gui/BufferItemConsumer.cpp @@ -100,20 +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(PixelFormat defaultFormat) { - Mutex::Autolock _l(mMutex); - return mConsumer->setDefaultBufferFormat(defaultFormat); -} - -status_t BufferItemConsumer::setDefaultBufferDataSpace( - android_dataspace defaultDataSpace) { - Mutex::Autolock _l(mMutex); - return mConsumer->setDefaultBufferDataSpace(defaultDataSpace); -} - } // namespace android diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 2fcbaf2..ccbb5a2 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -39,6 +39,14 @@ void BufferQueue::ProxyConsumerListener::onFrameAvailable( } } +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 c7d5e00..bb3e1b0 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -36,145 +36,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()); - - // 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. + 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. // - // 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; - mCore->mFreeBuffers.push_back(front->mSlot); + // 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(); + } - mCore->validateConsistencyLocked(); + if (listener != NULL) { + for (int i = 0; i < numDroppedBuffers; ++i) { + listener->onBufferReleased(); + } + } return NO_ERROR; } @@ -236,6 +261,13 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot, 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()) { @@ -292,6 +324,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; } @@ -330,7 +364,7 @@ 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; } diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index bc75ca7..851a396 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -70,7 +70,9 @@ BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) : mTransformHint(0), mIsAllocating(false), mIsAllocatingCondition(), - mAllowAllocation(true) + mAllowAllocation(true), + mBufferAge(0), + mGenerationNumber(0) { if (allocator == NULL) { sp<ISurfaceComposer> composer(ComposerService::getComposerService()); @@ -211,6 +213,7 @@ void BufferQueueCore::freeBufferLocked(int slot) { } mSlots[slot].mBufferState = BufferSlot::FREE; mSlots[slot].mAcquireCalled = false; + mSlots[slot].mFrameNumber = 0; // Destroy fence as BufferQueue now takes ownership if (mSlots[slot].mEglFence != EGL_NO_SYNC_KHR) { diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 86e45c8..87e5b4d 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -337,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", @@ -374,6 +383,7 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, return NO_INIT; } + graphicBuffer->setGenerationNumber(mCore->mGenerationNumber); mSlots[*outSlot].mGraphicBuffer = graphicBuffer; } // Autolock scope } @@ -489,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 @@ -784,6 +801,13 @@ int BufferQueueProducer::query(int what, int *outValue) { 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; } @@ -855,6 +879,7 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener, mCore->mBufferHasBeenQueued = false; mCore->mDequeueBufferCannotBlock = mCore->mConsumerControlledByApp && producerControlledByApp; + mCore->mAllowAllocation = true; return status; } @@ -897,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; } @@ -1055,6 +1080,21 @@ status_t BufferQueueProducer::allowAllocation(bool 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(); + 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/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index e576018..04ab06b 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -114,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); @@ -156,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"); @@ -178,6 +198,22 @@ status_t ConsumerBase::detachBuffer(int 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, ""); } @@ -196,8 +232,8 @@ void ConsumerBase::dumpLocked(String8& result, const char* prefix) const { } status_t ConsumerBase::acquireBufferLocked(BufferItem *item, - nsecs_t presentWhen) { - status_t err = mConsumer->acquireBuffer(item, presentWhen); + 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 eb39469..e29b740 100644 --- a/libs/gui/CpuConsumer.cpp +++ b/libs/gui/CpuConsumer.cpp @@ -56,25 +56,6 @@ 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(PixelFormat defaultFormat) -{ - Mutex::Autolock _l(mMutex); - return mConsumer->setDefaultBufferFormat(defaultFormat); -} - -status_t CpuConsumer::setDefaultBufferDataSpace( - android_dataspace defaultDataSpace) -{ - Mutex::Autolock _l(mMutex); - return mConsumer->setDefaultBufferDataSpace(defaultDataSpace); -} - static bool isPossiblyYUV(PixelFormat format) { switch (static_cast<int>(format)) { case HAL_PIXEL_FORMAT_RGBA_8888: diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index 96c0841..757e08a 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -344,8 +344,9 @@ sp<GraphicBuffer> GLConsumer::getDebugTexImageBuffer() { } status_t GLConsumer::acquireBufferLocked(BufferItem *item, - nsecs_t presentWhen) { - status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen); + nsecs_t presentWhen, uint64_t maxFrameNumber) { + status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen, + maxFrameNumber); if (err != NO_ERROR) { return err; } @@ -900,14 +901,18 @@ Rect GLConsumer::getCurrentCrop() const { // The crop is too wide if (newWidth < currentWidth) { - uint32_t dw = (currentWidth - newWidth) / 2; - outCrop.left += dw; - outCrop.right -= dw; + uint32_t dw = currentWidth - newWidth; + auto halfdw = dw / 2; + outCrop.left += halfdw; + // Not halfdw because it would subtract 1 too few when dw is odd + outCrop.right -= (dw - halfdw); // The crop is too tall } else if (newHeight < currentHeight) { - uint32_t dh = (currentHeight - newHeight) / 2; - outCrop.top += dh; - outCrop.bottom -= dh; + uint32_t dh = currentHeight - newHeight; + auto halfdh = dh / 2; + outCrop.top += halfdh; + // Not halfdh because it would subtract 1 too few when dh is odd + outCrop.bottom -= (dh - halfdh); } GLC_LOGV("getCurrentCrop final crop [%d,%d,%d,%d]", diff --git a/libs/gui/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp index 09b63a1..3009989 100644 --- a/libs/gui/IGraphicBufferAlloc.cpp +++ b/libs/gui/IGraphicBufferAlloc.cpp @@ -59,6 +59,9 @@ public: 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. diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp index 3c0907a..c4660ba 100644 --- a/libs/gui/IGraphicBufferConsumer.cpp +++ b/libs/gui/IGraphicBufferConsumer.cpp @@ -66,10 +66,12 @@ public: virtual ~BpGraphicBufferConsumer(); - virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) { + 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; @@ -295,7 +297,8 @@ 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); @@ -414,6 +417,15 @@ status_t BnGraphicBufferConsumer::onTransact( reply->writeInt32(result); return NO_ERROR; } + 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 74a40ee..8bdbc22 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -47,6 +47,8 @@ enum { SET_SIDEBAND_STREAM, ALLOCATE_BUFFERS, ALLOW_ALLOCATION, + SET_GENERATION_NUMBER, + GET_CONSUMER_NAME, }; class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer> @@ -284,6 +286,28 @@ public: 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 @@ -448,6 +472,18 @@ status_t BnGraphicBufferProducer::onTransact( 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); } diff --git a/libs/gui/ISensorServer.cpp b/libs/gui/ISensorServer.cpp index 8e09e7c..f581b5c 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> @@ -47,10 +48,11 @@ public: virtual ~BpSensorServer(); - virtual Vector<Sensor> getSensorList() + 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; @@ -63,13 +65,24 @@ 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 @@ -86,7 +99,8 @@ 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->writeUint32(static_cast<uint32_t>(n)); for (size_t i = 0; i < n; i++) { @@ -96,10 +110,20 @@ status_t BnSensorServer::onTransact( } case CREATE_SENSOR_EVENT_CONNECTION: { CHECK_INTERFACE(ISensorServer, data, reply); - sp<ISensorEventConnection> connection(createSensorEventConnection()); + 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; } + 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/Sensor.cpp b/libs/gui/Sensor.cpp index 35661f2..4b3603e 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> @@ -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; @@ -218,6 +223,10 @@ 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) { @@ -252,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() @@ -318,6 +338,14 @@ 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; } @@ -339,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()) + @@ -369,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; @@ -407,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; diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp index 76ae470..4b7986e 100644 --- a/libs/gui/SensorEventQueue.cpp +++ b/libs/gui/SensorEventQueue.cpp @@ -20,6 +20,7 @@ #include <stdint.h> #include <sys/types.h> #include <sys/socket.h> +#include <linux/errno.h> #include <utils/Errors.h> #include <utils/RefBase.h> @@ -149,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) { diff --git a/libs/gui/SensorManager.cpp b/libs/gui/SensorManager.cpp index d6df404..dd37781 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(); @@ -88,7 +86,7 @@ status_t SensorManager::assertStateLocked() const { mDeathObserver = new DeathObserver(*const_cast<SensorManager *>(this)); IInterface::asBinder(mSensorServer)->linkToDeath(mDeathObserver); - mSensors = mSensorServer->getSensorList(); + mSensors = mSensorServer->getSensorList(mOpPackageName); size_t count = mSensors.size(); mSensorList = static_cast<Sensor const**>(malloc(count * sizeof(Sensor*))); @@ -100,8 +98,6 @@ status_t SensorManager::assertStateLocked() const { return NO_ERROR; } - - ssize_t SensorManager::getSensorList(Sensor const* const** list) const { Mutex::Autolock _l(mLock); @@ -139,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; @@ -158,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/Surface.cpp b/libs/gui/Surface.cpp index b8acad2..4b76f98 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -42,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; @@ -102,6 +103,18 @@ void Surface::allocateBuffers() { 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) { Surface* c = getSelf(window); return c->setSwapInterval(interval); @@ -267,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); @@ -308,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; } @@ -325,16 +344,61 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { if (mConnectedToCpu || mDirtyRegion.bounds() == Rect::INVALID_RECT) { input.setSurfaceDamage(Region::INVALID_REGION); } else { - // 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. + // 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) { - auto top = buffer->height - rect.bottom; - auto bottom = buffer->height - rect.top; - Rect flippedRect{rect.left, top, rect.right, bottom}; - flippedRegion.orSelf(flippedRect); + 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); @@ -651,7 +715,7 @@ int Surface::disconnect(int api) { return err; } -int Surface::detachNextBuffer(ANativeWindowBuffer** outBuffer, +int Surface::detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) { ATRACE_CALL(); ALOGV("Surface::detachNextBuffer"); @@ -670,7 +734,7 @@ int Surface::detachNextBuffer(ANativeWindowBuffer** outBuffer, return result; } - *outBuffer = buffer.get(); + *outBuffer = buffer; if (fence != NULL && fence->isValid()) { *outFence = fence; } else { @@ -688,11 +752,14 @@ int Surface::attachBuffer(ANativeWindowBuffer* buffer) 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; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 707a321..6ad47d8 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -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); diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 1584fef..1a54875 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -17,6 +17,8 @@ #define LOG_TAG "BufferQueue_test" //#define LOG_NDEBUG 0 +#include "DummyConsumer.h" + #include <gui/BufferItem.h> #include <gui/BufferQueue.h> #include <gui/IProducerListener.h> @@ -67,12 +69,6 @@ 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 @@ -402,4 +398,46 @@ TEST_F(BufferQueueTest, TestDisallowingAllocation) { 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/DummyConsumer.h b/libs/gui/tests/DummyConsumer.h new file mode 100644 index 0000000..0511e16 --- /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 ff58420..4ef9a69 100644 --- a/libs/gui/tests/IGraphicBufferProducer_test.cpp +++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp @@ -299,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_DEFAULT_DATASPACE + 1; + const int NATIVE_WINDOW_QUERY_LAST_OFF_BY_ONE = NATIVE_WINDOW_BUFFER_AGE + 1; int value; // What was out of range diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp index d750cd0..1a50b24 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 { @@ -615,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; @@ -633,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]); @@ -650,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]); } diff --git a/libs/gui/tests/SurfaceTextureGLToGL_test.cpp b/libs/gui/tests/SurfaceTextureGLToGL_test.cpp index f4c7961..6edbfb8 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/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 4f87824..3f495f8 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> @@ -177,4 +179,53 @@ TEST_F(SurfaceTest, QueryDefaultBuffersDataSpace) { 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 f1921a4..944ac7f 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 0000000..e009731 --- /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 cd55ee5..b64cb2c 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 b11110a..d755ed3 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 090ee53..0382f57 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/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index 9105ae5..3fb1c6d 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 de192f1..8e69c9c 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 83bc6ae..8d73f45 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/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index 6a42a22..e55db30 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -278,7 +278,7 @@ status_t GraphicBuffer::unlockAsync(int *fenceFd) } size_t GraphicBuffer::getFlattenedSize() const { - return static_cast<size_t>(10 + (handle ? handle->numInts : 0)) * sizeof(int); + return static_cast<size_t>(11 + (handle ? handle->numInts : 0)) * sizeof(int); } size_t GraphicBuffer::getFdCount() const { @@ -301,15 +301,16 @@ 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; + buf[9] = handle->numFds; + buf[10] = handle->numInts; memcpy(fds, handle->data, static_cast<size_t>(handle->numFds) * sizeof(int)); - memcpy(&buf[10], handle->data + handle->numFds, + memcpy(&buf[11], handle->data + handle->numFds, static_cast<size_t>(handle->numInts) * sizeof(int)); } @@ -325,20 +326,20 @@ 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 = static_cast<size_t>(buf[8]); - const size_t numInts = static_cast<size_t>(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: %zd, %zd", @@ -346,7 +347,7 @@ status_t GraphicBuffer::unflatten( 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; @@ -372,7 +373,7 @@ status_t GraphicBuffer::unflatten( return NO_MEMORY; } memcpy(h->data, fds, numFds * sizeof(int)); - memcpy(h->data + numFds, &buf[10], numInts * sizeof(int)); + memcpy(h->data + numFds, &buf[11], numInts * sizeof(int)); handle = h; } else { width = height = stride = format = usage = 0; @@ -382,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) { diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp index 85e9675..9b265af 100644 --- a/libs/ui/GraphicBufferAllocator.cpp +++ b/libs/ui/GraphicBufferAllocator.cpp @@ -104,6 +104,9 @@ status_t GraphicBufferAllocator::alloc(uint32_t width, uint32_t height, // we have a h/w allocator and h/w buffer is requested 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, diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp index 31bfb2d..90a1c11 100644 --- a/libs/ui/GraphicBufferMapper.cpp +++ b/libs/ui/GraphicBufferMapper.cpp @@ -131,8 +131,10 @@ status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle, bounds.left, bounds.top, bounds.width(), bounds.height(), vaddr, fenceFd); } else { - sync_wait(fenceFd, -1); - close(fenceFd); + 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); @@ -154,12 +156,17 @@ status_t GraphicBufferMapper::lockAsyncYCbCr(buffer_handle_t 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); + 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 } |