diff options
Diffstat (limited to 'libutils')
36 files changed, 281 insertions, 1649 deletions
diff --git a/libutils/Android.bp b/libutils/Android.bp index 109ac3326..7d293efa7 100644 --- a/libutils/Android.bp +++ b/libutils/Android.bp @@ -18,12 +18,10 @@ cc_library_headers { host_supported: true, header_libs: [ - "liblog_headers", "libsystem_headers", "libcutils_headers" ], export_header_lib_headers: [ - "liblog_headers", "libsystem_headers", "libcutils_headers" ], @@ -52,7 +50,6 @@ cc_library { "CallStack.cpp", "FileMap.cpp", "JenkinsHash.cpp", - "LinearTransform.cpp", "NativeHandle.cpp", "Printer.cpp", "PropertyMap.cpp", @@ -74,11 +71,11 @@ cc_library { cflags: ["-Werror"], include_dirs: ["external/safe-iop/include"], - header_libs: ["libutils_headers"], - export_header_lib_headers: ["libutils_headers"], - - shared_libs: [ - "liblog", + header_libs: [ + "libutils_headers", + ], + export_header_lib_headers: [ + "libutils_headers", ], arch: { @@ -90,7 +87,6 @@ cc_library { target: { android: { srcs: [ - "BlobCache.cpp", "Looper.cpp", "ProcessCallStack.cpp", "Trace.cpp", @@ -102,6 +98,8 @@ cc_library { "libbacktrace", "libcutils", "libdl", + "liblog", + "libvndksupport", ], sanitize: { diff --git a/libutils/BlobCache.cpp b/libutils/BlobCache.cpp deleted file mode 100644 index 126995b8c..000000000 --- a/libutils/BlobCache.cpp +++ /dev/null @@ -1,379 +0,0 @@ -/* - ** Copyright 2011, The Android Open Source Project - ** - ** Licensed under the Apache License, Version 2.0 (the "License"); - ** you may not use this file except in compliance with the License. - ** You may obtain a copy of the License at - ** - ** http://www.apache.org/licenses/LICENSE-2.0 - ** - ** Unless required by applicable law or agreed to in writing, software - ** distributed under the License is distributed on an "AS IS" BASIS, - ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ** See the License for the specific language governing permissions and - ** limitations under the License. - */ - -#define LOG_TAG "BlobCache" -//#define LOG_NDEBUG 0 - -#include <inttypes.h> -#include <stdlib.h> -#include <string.h> - -#include <utils/BlobCache.h> -#include <utils/Errors.h> -#include <utils/Log.h> - -#include <cutils/properties.h> - -namespace android { - -// BlobCache::Header::mMagicNumber value -static const uint32_t blobCacheMagic = ('_' << 24) + ('B' << 16) + ('b' << 8) + '$'; - -// BlobCache::Header::mBlobCacheVersion value -static const uint32_t blobCacheVersion = 3; - -// BlobCache::Header::mDeviceVersion value -static const uint32_t blobCacheDeviceVersion = 1; - -BlobCache::BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize): - mMaxKeySize(maxKeySize), - mMaxValueSize(maxValueSize), - mMaxTotalSize(maxTotalSize), - mTotalSize(0) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); -#ifdef _WIN32 - srand(now); -#else - mRandState[0] = (now >> 0) & 0xFFFF; - mRandState[1] = (now >> 16) & 0xFFFF; - mRandState[2] = (now >> 32) & 0xFFFF; -#endif - ALOGV("initializing random seed using %lld", (unsigned long long)now); -} - -void BlobCache::set(const void* key, size_t keySize, const void* value, - size_t valueSize) { - if (mMaxKeySize < keySize) { - ALOGV("set: not caching because the key is too large: %zu (limit: %zu)", - keySize, mMaxKeySize); - return; - } - if (mMaxValueSize < valueSize) { - ALOGV("set: not caching because the value is too large: %zu (limit: %zu)", - valueSize, mMaxValueSize); - return; - } - if (mMaxTotalSize < keySize + valueSize) { - ALOGV("set: not caching because the combined key/value size is too " - "large: %zu (limit: %zu)", keySize + valueSize, mMaxTotalSize); - return; - } - if (keySize == 0) { - ALOGW("set: not caching because keySize is 0"); - return; - } - if (valueSize <= 0) { - ALOGW("set: not caching because valueSize is 0"); - return; - } - - sp<Blob> dummyKey(new Blob(key, keySize, false)); - CacheEntry dummyEntry(dummyKey, NULL); - - while (true) { - ssize_t index = mCacheEntries.indexOf(dummyEntry); - if (index < 0) { - // Create a new cache entry. - sp<Blob> keyBlob(new Blob(key, keySize, true)); - sp<Blob> valueBlob(new Blob(value, valueSize, true)); - size_t newTotalSize = mTotalSize + keySize + valueSize; - if (mMaxTotalSize < newTotalSize) { - if (isCleanable()) { - // Clean the cache and try again. - clean(); - continue; - } else { - ALOGV("set: not caching new key/value pair because the " - "total cache size limit would be exceeded: %zu " - "(limit: %zu)", - keySize + valueSize, mMaxTotalSize); - break; - } - } - mCacheEntries.add(CacheEntry(keyBlob, valueBlob)); - mTotalSize = newTotalSize; - ALOGV("set: created new cache entry with %zu byte key and %zu byte value", - keySize, valueSize); - } else { - // Update the existing cache entry. - sp<Blob> valueBlob(new Blob(value, valueSize, true)); - sp<Blob> oldValueBlob(mCacheEntries[index].getValue()); - size_t newTotalSize = mTotalSize + valueSize - oldValueBlob->getSize(); - if (mMaxTotalSize < newTotalSize) { - if (isCleanable()) { - // Clean the cache and try again. - clean(); - continue; - } else { - ALOGV("set: not caching new value because the total cache " - "size limit would be exceeded: %zu (limit: %zu)", - keySize + valueSize, mMaxTotalSize); - break; - } - } - mCacheEntries.editItemAt(index).setValue(valueBlob); - mTotalSize = newTotalSize; - ALOGV("set: updated existing cache entry with %zu byte key and %zu byte " - "value", keySize, valueSize); - } - break; - } -} - -size_t BlobCache::get(const void* key, size_t keySize, void* value, - size_t valueSize) { - if (mMaxKeySize < keySize) { - ALOGV("get: not searching because the key is too large: %zu (limit %zu)", - keySize, mMaxKeySize); - return 0; - } - sp<Blob> dummyKey(new Blob(key, keySize, false)); - CacheEntry dummyEntry(dummyKey, NULL); - ssize_t index = mCacheEntries.indexOf(dummyEntry); - if (index < 0) { - ALOGV("get: no cache entry found for key of size %zu", keySize); - return 0; - } - - // The key was found. Return the value if the caller's buffer is large - // enough. - sp<Blob> valueBlob(mCacheEntries[index].getValue()); - size_t valueBlobSize = valueBlob->getSize(); - if (valueBlobSize <= valueSize) { - ALOGV("get: copying %zu bytes to caller's buffer", valueBlobSize); - memcpy(value, valueBlob->getData(), valueBlobSize); - } else { - ALOGV("get: caller's buffer is too small for value: %zu (needs %zu)", - valueSize, valueBlobSize); - } - return valueBlobSize; -} - -static inline size_t align4(size_t size) { - return (size + 3) & ~3; -} - -size_t BlobCache::getFlattenedSize() const { - size_t size = align4(sizeof(Header) + PROPERTY_VALUE_MAX); - for (size_t i = 0; i < mCacheEntries.size(); i++) { - const CacheEntry& e(mCacheEntries[i]); - sp<Blob> keyBlob = e.getKey(); - sp<Blob> valueBlob = e.getValue(); - size += align4(sizeof(EntryHeader) + keyBlob->getSize() + - valueBlob->getSize()); - } - return size; -} - -status_t BlobCache::flatten(void* buffer, size_t size) const { - // Write the cache header - if (size < sizeof(Header)) { - ALOGE("flatten: not enough room for cache header"); - return BAD_VALUE; - } - Header* header = reinterpret_cast<Header*>(buffer); - header->mMagicNumber = blobCacheMagic; - header->mBlobCacheVersion = blobCacheVersion; - header->mDeviceVersion = blobCacheDeviceVersion; - header->mNumEntries = mCacheEntries.size(); - char buildId[PROPERTY_VALUE_MAX]; - header->mBuildIdLength = property_get("ro.build.id", buildId, ""); - memcpy(header->mBuildId, buildId, header->mBuildIdLength); - - // Write cache entries - uint8_t* byteBuffer = reinterpret_cast<uint8_t*>(buffer); - off_t byteOffset = align4(sizeof(Header) + header->mBuildIdLength); - for (size_t i = 0; i < mCacheEntries.size(); i++) { - const CacheEntry& e(mCacheEntries[i]); - sp<Blob> keyBlob = e.getKey(); - sp<Blob> valueBlob = e.getValue(); - size_t keySize = keyBlob->getSize(); - size_t valueSize = valueBlob->getSize(); - - size_t entrySize = sizeof(EntryHeader) + keySize + valueSize; - size_t totalSize = align4(entrySize); - if (byteOffset + totalSize > size) { - ALOGE("flatten: not enough room for cache entries"); - return BAD_VALUE; - } - - EntryHeader* eheader = reinterpret_cast<EntryHeader*>( - &byteBuffer[byteOffset]); - eheader->mKeySize = keySize; - eheader->mValueSize = valueSize; - - memcpy(eheader->mData, keyBlob->getData(), keySize); - memcpy(eheader->mData + keySize, valueBlob->getData(), valueSize); - - if (totalSize > entrySize) { - // We have padding bytes. Those will get written to storage, and contribute to the CRC, - // so make sure we zero-them to have reproducible results. - memset(eheader->mData + keySize + valueSize, 0, totalSize - entrySize); - } - - byteOffset += totalSize; - } - - return OK; -} - -status_t BlobCache::unflatten(void const* buffer, size_t size) { - // All errors should result in the BlobCache being in an empty state. - mCacheEntries.clear(); - - // Read the cache header - if (size < sizeof(Header)) { - ALOGE("unflatten: not enough room for cache header"); - return BAD_VALUE; - } - const Header* header = reinterpret_cast<const Header*>(buffer); - if (header->mMagicNumber != blobCacheMagic) { - ALOGE("unflatten: bad magic number: %" PRIu32, header->mMagicNumber); - return BAD_VALUE; - } - char buildId[PROPERTY_VALUE_MAX]; - int len = property_get("ro.build.id", buildId, ""); - if (header->mBlobCacheVersion != blobCacheVersion || - header->mDeviceVersion != blobCacheDeviceVersion || - len != header->mBuildIdLength || - strncmp(buildId, header->mBuildId, len)) { - // We treat version mismatches as an empty cache. - return OK; - } - - // Read cache entries - const uint8_t* byteBuffer = reinterpret_cast<const uint8_t*>(buffer); - off_t byteOffset = align4(sizeof(Header) + header->mBuildIdLength); - size_t numEntries = header->mNumEntries; - for (size_t i = 0; i < numEntries; i++) { - if (byteOffset + sizeof(EntryHeader) > size) { - mCacheEntries.clear(); - ALOGE("unflatten: not enough room for cache entry headers"); - return BAD_VALUE; - } - - const EntryHeader* eheader = reinterpret_cast<const EntryHeader*>( - &byteBuffer[byteOffset]); - size_t keySize = eheader->mKeySize; - size_t valueSize = eheader->mValueSize; - size_t entrySize = sizeof(EntryHeader) + keySize + valueSize; - - size_t totalSize = align4(entrySize); - if (byteOffset + totalSize > size) { - mCacheEntries.clear(); - ALOGE("unflatten: not enough room for cache entry headers"); - return BAD_VALUE; - } - - const uint8_t* data = eheader->mData; - set(data, keySize, data + keySize, valueSize); - - byteOffset += totalSize; - } - - return OK; -} - -long int BlobCache::blob_random() { -#ifdef _WIN32 - return rand(); -#else - return nrand48(mRandState); -#endif -} - -void BlobCache::clean() { - // Remove a random cache entry until the total cache size gets below half - // the maximum total cache size. - while (mTotalSize > mMaxTotalSize / 2) { - size_t i = size_t(blob_random() % (mCacheEntries.size())); - const CacheEntry& entry(mCacheEntries[i]); - mTotalSize -= entry.getKey()->getSize() + entry.getValue()->getSize(); - mCacheEntries.removeAt(i); - } -} - -bool BlobCache::isCleanable() const { - return mTotalSize > mMaxTotalSize / 2; -} - -BlobCache::Blob::Blob(const void* data, size_t size, bool copyData): - mData(copyData ? malloc(size) : data), - mSize(size), - mOwnsData(copyData) { - if (data != NULL && copyData) { - memcpy(const_cast<void*>(mData), data, size); - } -} - -BlobCache::Blob::~Blob() { - if (mOwnsData) { - free(const_cast<void*>(mData)); - } -} - -bool BlobCache::Blob::operator<(const Blob& rhs) const { - if (mSize == rhs.mSize) { - return memcmp(mData, rhs.mData, mSize) < 0; - } else { - return mSize < rhs.mSize; - } -} - -const void* BlobCache::Blob::getData() const { - return mData; -} - -size_t BlobCache::Blob::getSize() const { - return mSize; -} - -BlobCache::CacheEntry::CacheEntry() { -} - -BlobCache::CacheEntry::CacheEntry(const sp<Blob>& key, const sp<Blob>& value): - mKey(key), - mValue(value) { -} - -BlobCache::CacheEntry::CacheEntry(const CacheEntry& ce): - mKey(ce.mKey), - mValue(ce.mValue) { -} - -bool BlobCache::CacheEntry::operator<(const CacheEntry& rhs) const { - return *mKey < *rhs.mKey; -} - -const BlobCache::CacheEntry& BlobCache::CacheEntry::operator=(const CacheEntry& rhs) { - mKey = rhs.mKey; - mValue = rhs.mValue; - return *this; -} - -sp<BlobCache::Blob> BlobCache::CacheEntry::getKey() const { - return mKey; -} - -sp<BlobCache::Blob> BlobCache::CacheEntry::getValue() const { - return mValue; -} - -void BlobCache::CacheEntry::setValue(const sp<Blob>& value) { - mValue = value; -} - -} // namespace android diff --git a/libutils/CallStack.cpp b/libutils/CallStack.cpp index 699da7469..bd6015e79 100644 --- a/libutils/CallStack.cpp +++ b/libutils/CallStack.cpp @@ -16,9 +16,10 @@ #define LOG_TAG "CallStack" +#include <utils/CallStack.h> + #include <memory> -#include <utils/CallStack.h> #include <utils/Printer.h> #include <utils/Errors.h> #include <utils/Log.h> diff --git a/libutils/LinearTransform.cpp b/libutils/LinearTransform.cpp deleted file mode 100644 index 138ce8be7..000000000 --- a/libutils/LinearTransform.cpp +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define __STDC_LIMIT_MACROS - -#include <assert.h> -#include <stdint.h> - -#include <utils/LinearTransform.h> - -// disable sanitize as these functions may intentionally overflow (see comments below). -// the ifdef can be removed when host builds use clang. -#if defined(__clang__) -#define ATTRIBUTE_NO_SANITIZE_INTEGER __attribute__((no_sanitize("integer"))) -#else -#define ATTRIBUTE_NO_SANITIZE_INTEGER -#endif - -namespace android { - -// sanitize failure with T = int32_t and x = 0x80000000 -template<class T> -ATTRIBUTE_NO_SANITIZE_INTEGER -static inline T ABS(T x) { return (x < 0) ? -x : x; } - -// Static math methods involving linear transformations -// remote sanitize failure on overflow case. -ATTRIBUTE_NO_SANITIZE_INTEGER -static bool scale_u64_to_u64( - uint64_t val, - uint32_t N, - uint32_t D, - uint64_t* res, - bool round_up_not_down) { - uint64_t tmp1, tmp2; - uint32_t r; - - assert(res); - assert(D); - - // Let U32(X) denote a uint32_t containing the upper 32 bits of a 64 bit - // integer X. - // Let L32(X) denote a uint32_t containing the lower 32 bits of a 64 bit - // integer X. - // Let X[A, B] with A <= B denote bits A through B of the integer X. - // Let (A | B) denote the concatination of two 32 bit ints, A and B. - // IOW X = (A | B) => U32(X) == A && L32(X) == B - // - // compute M = val * N (a 96 bit int) - // --------------------------------- - // tmp2 = U32(val) * N (a 64 bit int) - // tmp1 = L32(val) * N (a 64 bit int) - // which means - // M = val * N = (tmp2 << 32) + tmp1 - tmp2 = (val >> 32) * N; - tmp1 = (val & UINT32_MAX) * N; - - // compute M[32, 95] - // tmp2 = tmp2 + U32(tmp1) - // = (U32(val) * N) + U32(L32(val) * N) - // = M[32, 95] - tmp2 += tmp1 >> 32; - - // if M[64, 95] >= D, then M/D has bits > 63 set and we have - // an overflow. - if ((tmp2 >> 32) >= D) { - *res = UINT64_MAX; - return false; - } - - // Divide. Going in we know - // tmp2 = M[32, 95] - // U32(tmp2) < D - r = tmp2 % D; - tmp2 /= D; - - // At this point - // tmp1 = L32(val) * N - // tmp2 = M[32, 95] / D - // = (M / D)[32, 95] - // r = M[32, 95] % D - // U32(tmp2) = 0 - // - // compute tmp1 = (r | M[0, 31]) - tmp1 = (tmp1 & UINT32_MAX) | ((uint64_t)r << 32); - - // Divide again. Keep the remainder around in order to round properly. - r = tmp1 % D; - tmp1 /= D; - - // At this point - // tmp2 = (M / D)[32, 95] - // tmp1 = (M / D)[ 0, 31] - // r = M % D - // U32(tmp1) = 0 - // U32(tmp2) = 0 - - // Pack the result and deal with the round-up case (As well as the - // remote possiblility over overflow in such a case). - *res = (tmp2 << 32) | tmp1; - if (r && round_up_not_down) { - ++(*res); - if (!(*res)) { - *res = UINT64_MAX; - return false; - } - } - - return true; -} - -// at least one known sanitize failure (see comment below) -ATTRIBUTE_NO_SANITIZE_INTEGER -static bool linear_transform_s64_to_s64( - int64_t val, - int64_t basis1, - int32_t N, - uint32_t D, - bool invert_frac, - int64_t basis2, - int64_t* out) { - uint64_t scaled, res; - uint64_t abs_val; - bool is_neg; - - if (!out) - return false; - - // Compute abs(val - basis_64). Keep track of whether or not this delta - // will be negative after the scale opertaion. - if (val < basis1) { - is_neg = true; - abs_val = basis1 - val; - } else { - is_neg = false; - abs_val = val - basis1; - } - - if (N < 0) - is_neg = !is_neg; - - if (!scale_u64_to_u64(abs_val, - invert_frac ? D : ABS(N), - invert_frac ? ABS(N) : D, - &scaled, - is_neg)) - return false; // overflow/undeflow - - // if scaled is >= 0x8000<etc>, then we are going to overflow or - // underflow unless ABS(basis2) is large enough to pull us back into the - // non-overflow/underflow region. - if (scaled & INT64_MIN) { - if (is_neg && (basis2 < 0)) - return false; // certain underflow - - if (!is_neg && (basis2 >= 0)) - return false; // certain overflow - - if (ABS(basis2) <= static_cast<int64_t>(scaled & INT64_MAX)) - return false; // not enough - - // Looks like we are OK - *out = (is_neg ? (-scaled) : scaled) + basis2; - } else { - // Scaled fits within signed bounds, so we just need to check for - // over/underflow for two signed integers. Basically, if both scaled - // and basis2 have the same sign bit, and the result has a different - // sign bit, then we have under/overflow. An easy way to compute this - // is - // (scaled_signbit XNOR basis_signbit) && - // (scaled_signbit XOR res_signbit) - // == - // (scaled_signbit XOR basis_signbit XOR 1) && - // (scaled_signbit XOR res_signbit) - - if (is_neg) - scaled = -scaled; // known sanitize failure - res = scaled + basis2; - - if ((scaled ^ basis2 ^ INT64_MIN) & (scaled ^ res) & INT64_MIN) - return false; - - *out = res; - } - - return true; -} - -bool LinearTransform::doForwardTransform(int64_t a_in, int64_t* b_out) const { - if (0 == a_to_b_denom) - return false; - - return linear_transform_s64_to_s64(a_in, - a_zero, - a_to_b_numer, - a_to_b_denom, - false, - b_zero, - b_out); -} - -bool LinearTransform::doReverseTransform(int64_t b_in, int64_t* a_out) const { - if (0 == a_to_b_numer) - return false; - - return linear_transform_s64_to_s64(b_in, - b_zero, - a_to_b_numer, - a_to_b_denom, - true, - a_zero, - a_out); -} - -template <class T> void LinearTransform::reduce(T* N, T* D) { - T a, b; - if (!N || !D || !(*D)) { - assert(false); - return; - } - - a = *N; - b = *D; - - if (a == 0) { - *D = 1; - return; - } - - // This implements Euclid's method to find GCD. - if (a < b) { - T tmp = a; - a = b; - b = tmp; - } - - while (1) { - // a is now the greater of the two. - const T remainder = a % b; - if (remainder == 0) { - *N /= b; - *D /= b; - return; - } - // by swapping remainder and b, we are guaranteeing that a is - // still the greater of the two upon entrance to the loop. - a = b; - b = remainder; - } -}; - -template void LinearTransform::reduce<uint64_t>(uint64_t* N, uint64_t* D); -template void LinearTransform::reduce<uint32_t>(uint32_t* N, uint32_t* D); - -// sanitize failure if *N = 0x80000000 -ATTRIBUTE_NO_SANITIZE_INTEGER -void LinearTransform::reduce(int32_t* N, uint32_t* D) { - if (N && D && *D) { - if (*N < 0) { - *N = -(*N); - reduce(reinterpret_cast<uint32_t*>(N), D); - *N = -(*N); - } else { - reduce(reinterpret_cast<uint32_t*>(N), D); - } - } -} - -} // namespace android diff --git a/libutils/Looper.cpp b/libutils/Looper.cpp index 77e69e4b3..6c57b2e54 100644 --- a/libutils/Looper.cpp +++ b/libutils/Looper.cpp @@ -13,17 +13,8 @@ // Debugs callback registration and invocation. #define DEBUG_CALLBACKS 0 -#include <errno.h> -#include <fcntl.h> -#include <inttypes.h> -#include <limits.h> -#include <string.h> -#include <sys/eventfd.h> -#include <unistd.h> - -#include <log/log.h> #include <utils/Looper.h> -#include <utils/Timers.h> +#include <sys/eventfd.h> namespace android { @@ -83,6 +74,7 @@ Looper::Looper(bool allowNonCallbacks) : Looper::~Looper() { close(mWakeEventFd); + mWakeEventFd = -1; if (mEpollFd >= 0) { close(mEpollFd); } @@ -412,7 +404,8 @@ void Looper::wake() { ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t))); if (nWrite != sizeof(uint64_t)) { if (errno != EAGAIN) { - ALOGW("Could not write wake signal: %s", strerror(errno)); + LOG_ALWAYS_FATAL("Could not write wake signal to fd %d: %s", + mWakeEventFd, strerror(errno)); } } } diff --git a/libutils/NativeHandle.cpp b/libutils/NativeHandle.cpp index e4daca7ff..97d06b8bd 100644 --- a/libutils/NativeHandle.cpp +++ b/libutils/NativeHandle.cpp @@ -19,14 +19,14 @@ namespace android { -sp<NativeHandle> NativeHandle::create( - native_handle_t* handle, bool ownsHandle) { +sp<NativeHandle> NativeHandle::create(native_handle_t* handle, bool ownsHandle) { return handle ? new NativeHandle(handle, ownsHandle) : NULL; } NativeHandle::NativeHandle(native_handle_t* handle, bool ownsHandle) -: mHandle(handle), mOwnsHandle(ownsHandle) -{} + : mHandle(handle), mOwnsHandle(ownsHandle) { + +} NativeHandle::~NativeHandle() { if (mOwnsHandle) { diff --git a/libutils/Printer.cpp b/libutils/Printer.cpp index 84af2930b..cbf042eb5 100644 --- a/libutils/Printer.cpp +++ b/libutils/Printer.cpp @@ -21,8 +21,6 @@ #include <utils/String8.h> #include <utils/Log.h> -#include <string.h> -#include <stdio.h> #include <stdlib.h> namespace android { diff --git a/libutils/ProcessCallStack.cpp b/libutils/ProcessCallStack.cpp index 983847c4c..b8fb6dc2a 100644 --- a/libutils/ProcessCallStack.cpp +++ b/libutils/ProcessCallStack.cpp @@ -17,20 +17,15 @@ #define LOG_TAG "ProcessCallStack" // #define LOG_NDEBUG 0 +#include <utils/ProcessCallStack.h> + #include <dirent.h> -#include <errno.h> -#include <stdio.h> -#include <string.h> #include <unistd.h> + #include <memory> -#include <utils/Log.h> -#include <utils/Errors.h> -#include <utils/ProcessCallStack.h> #include <utils/Printer.h> -#include <limits.h> - namespace android { enum { diff --git a/libutils/PropertyMap.cpp b/libutils/PropertyMap.cpp index 55207027b..4bcdd0f7f 100644 --- a/libutils/PropertyMap.cpp +++ b/libutils/PropertyMap.cpp @@ -16,11 +16,7 @@ #define LOG_TAG "PropertyMap" -#include <stdlib.h> -#include <string.h> - #include <utils/PropertyMap.h> -#include <utils/Log.h> // Enables debug output for the parser. #define DEBUG_PARSER 0 diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp index 4252ba6b2..24737b985 100644 --- a/libutils/RefBase.cpp +++ b/libutils/RefBase.cpp @@ -17,18 +17,9 @@ #define LOG_TAG "RefBase" // #define LOG_NDEBUG 0 -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - #include <utils/RefBase.h> #include <utils/CallStack.h> -#include <utils/Log.h> -#include <utils/threads.h> #ifndef __unused #define __unused __attribute__((__unused__)) @@ -769,6 +760,4 @@ void RefBase::renameRefId(RefBase* ref, ref->mRefs->renameWeakRefId(old_id, new_id); } -VirtualLightRefBase::~VirtualLightRefBase() {} - }; // namespace android diff --git a/libutils/SharedBuffer.cpp b/libutils/SharedBuffer.cpp index 957aedb8f..bad98b274 100644 --- a/libutils/SharedBuffer.cpp +++ b/libutils/SharedBuffer.cpp @@ -16,13 +16,13 @@ #define LOG_TAG "sharedbuffer" +#include "SharedBuffer.h" + #include <stdlib.h> #include <string.h> #include <log/log.h> -#include "SharedBuffer.h" - // --------------------------------------------------------------------------- namespace android { @@ -113,16 +113,26 @@ void SharedBuffer::acquire() const { int32_t SharedBuffer::release(uint32_t flags) const { - int32_t prev = 1; - if (onlyOwner() - || (((prev = mRefs.fetch_sub(1, std::memory_order_release)) == 1) - && (atomic_thread_fence(std::memory_order_acquire), true))) { + const bool useDealloc = ((flags & eKeepStorage) == 0); + if (onlyOwner()) { + // Since we're the only owner, our reference count goes to zero. mRefs.store(0, std::memory_order_relaxed); - if ((flags & eKeepStorage) == 0) { - free(const_cast<SharedBuffer*>(this)); + if (useDealloc) { + dealloc(this); + } + // As the only owner, our previous reference count was 1. + return 1; + } + // There's multiple owners, we need to use an atomic decrement. + int32_t prevRefCount = mRefs.fetch_sub(1, std::memory_order_release); + if (prevRefCount == 1) { + // We're the last reference, we need the acquire fence. + atomic_thread_fence(std::memory_order_acquire); + if (useDealloc) { + dealloc(this); } } - return prev; + return prevRefCount; } diff --git a/libutils/StopWatch.cpp b/libutils/StopWatch.cpp index 8c7b59645..219c13c67 100644 --- a/libutils/StopWatch.cpp +++ b/libutils/StopWatch.cpp @@ -16,9 +16,7 @@ #define LOG_TAG "StopWatch" -#include <string.h> -#include <stdlib.h> -#include <stdio.h> +#include <utils/StopWatch.h> /* for PRId64 */ #ifndef __STDC_FORMAT_MACROS @@ -27,8 +25,6 @@ #include <inttypes.h> #include <utils/Log.h> -#include <utils/Errors.h> -#include <utils/StopWatch.h> /*****************************************************************************/ diff --git a/libutils/String16.cpp b/libutils/String16.cpp index 9f5cfeab4..ad335c399 100644 --- a/libutils/String16.cpp +++ b/libutils/String16.cpp @@ -17,11 +17,7 @@ #include <utils/String16.h> #include <utils/Log.h> -#include <utils/Unicode.h> -#include <utils/threads.h> -#include <memory.h> -#include <stdio.h> #include <ctype.h> #include "SharedBuffer.h" diff --git a/libutils/String8.cpp b/libutils/String8.cpp index cacaf91b8..ad0e72ec1 100644 --- a/libutils/String8.cpp +++ b/libutils/String8.cpp @@ -21,9 +21,7 @@ #include <utils/Compat.h> #include <utils/Log.h> -#include <utils/Unicode.h> #include <utils/String16.h> -#include <utils/threads.h> #include <ctype.h> diff --git a/libutils/SystemClock.cpp b/libutils/SystemClock.cpp index 965e32c0f..28fc35145 100644 --- a/libutils/SystemClock.cpp +++ b/libutils/SystemClock.cpp @@ -19,17 +19,17 @@ * System clock functions. */ +#define LOG_TAG "SystemClock" + +#include <utils/SystemClock.h> + #include <sys/time.h> -#include <limits.h> -#include <fcntl.h> #include <string.h> #include <errno.h> #include <cutils/compiler.h> -#include <utils/SystemClock.h> -#include <utils/Timers.h> -#define LOG_TAG "SystemClock" +#include <utils/Timers.h> #include <utils/Log.h> namespace android { diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp index def739f9f..6317c32d4 100644 --- a/libutils/Threads.cpp +++ b/libutils/Threads.cpp @@ -18,16 +18,10 @@ #define LOG_TAG "libutils.threads" #include <assert.h> -#include <errno.h> -#include <memory.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> +#include <utils/Thread.h> +#include <utils/AndroidThreads.h> #if !defined(_WIN32) -# include <pthread.h> -# include <sched.h> # include <sys/resource.h> #else # include <windows.h> @@ -40,7 +34,6 @@ #include <sys/prctl.h> #endif -#include <utils/threads.h> #include <utils/Log.h> #include <cutils/sched_policy.h> diff --git a/libutils/Timers.cpp b/libutils/Timers.cpp index 201bc412c..b2df9a58f 100644 --- a/libutils/Timers.cpp +++ b/libutils/Timers.cpp @@ -20,7 +20,6 @@ #include <utils/Timers.h> #include <limits.h> -#include <sys/time.h> #include <time.h> #if defined(__ANDROID__) @@ -53,7 +52,7 @@ nsecs_t systemTime(int /*clock*/) int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime) { - int timeoutDelayMillis; + nsecs_t timeoutDelayMillis; if (timeoutTime > referenceTime) { uint64_t timeoutDelay = uint64_t(timeoutTime - referenceTime); if (timeoutDelay > uint64_t((INT_MAX - 1) * 1000000LL)) { @@ -64,5 +63,5 @@ int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime) } else { timeoutDelayMillis = 0; } - return timeoutDelayMillis; + return (int)timeoutDelayMillis; } diff --git a/libutils/Tokenizer.cpp b/libutils/Tokenizer.cpp index 2d0e83dcd..b68a2cfa3 100644 --- a/libutils/Tokenizer.cpp +++ b/libutils/Tokenizer.cpp @@ -16,14 +16,10 @@ #define LOG_TAG "Tokenizer" -#include <stdlib.h> -#include <unistd.h> +#include <utils/Tokenizer.h> #include <fcntl.h> -#include <errno.h> -#include <sys/types.h> #include <sys/stat.h> #include <utils/Log.h> -#include <utils/Tokenizer.h> // Enables debug output for the tokenizer. #define DEBUG_TOKENIZER 0 diff --git a/libutils/Trace.cpp b/libutils/Trace.cpp index 36fd80214..8530fdca0 100644 --- a/libutils/Trace.cpp +++ b/libutils/Trace.cpp @@ -14,12 +14,11 @@ * limitations under the License. */ -#include <utils/misc.h> #include <utils/Trace.h> +#include <utils/misc.h> static void traceInit() __attribute__((constructor)); -static void traceInit() -{ +static void traceInit() { ::android::add_sysprop_change_callback(atrace_update_tags, 0); } diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp index f1a41b96f..5fd915524 100644 --- a/libutils/Unicode.cpp +++ b/libutils/Unicode.cpp @@ -16,11 +16,10 @@ #define LOG_TAG "unicode" +#include <utils/Unicode.h> #include <limits.h> -#include <stddef.h> #include <log/log.h> -#include <utils/Unicode.h> #if defined(_WIN32) # undef nhtol diff --git a/libutils/VectorImpl.cpp b/libutils/VectorImpl.cpp index f7ca8f4f9..ef3277f42 100644 --- a/libutils/VectorImpl.cpp +++ b/libutils/VectorImpl.cpp @@ -16,13 +16,13 @@ #define LOG_TAG "Vector" +#include <utils/VectorImpl.h> + #include <stdio.h> #include <stdlib.h> #include <string.h> #include <log/log.h> -#include <utils/Errors.h> -#include <utils/VectorImpl.h> #include <safe_iop.h> diff --git a/libutils/include/utils/BlobCache.h b/libutils/include/utils/BlobCache.h deleted file mode 100644 index 65dca9fb4..000000000 --- a/libutils/include/utils/BlobCache.h +++ /dev/null @@ -1,249 +0,0 @@ -/* - ** Copyright 2011, The Android Open Source Project - ** - ** Licensed under the Apache License, Version 2.0 (the "License"); - ** you may not use this file except in compliance with the License. - ** You may obtain a copy of the License at - ** - ** http://www.apache.org/licenses/LICENSE-2.0 - ** - ** Unless required by applicable law or agreed to in writing, software - ** distributed under the License is distributed on an "AS IS" BASIS, - ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ** See the License for the specific language governing permissions and - ** limitations under the License. - */ - -#ifndef ANDROID_BLOB_CACHE_H -#define ANDROID_BLOB_CACHE_H - -#include <stddef.h> - -#include <utils/Flattenable.h> -#include <utils/RefBase.h> -#include <utils/SortedVector.h> -#include <utils/threads.h> - -namespace android { - -// A BlobCache is an in-memory cache for binary key/value pairs. A BlobCache -// does NOT provide any thread-safety guarantees. -// -// The cache contents can be serialized to an in-memory buffer or mmap'd file -// and then reloaded in a subsequent execution of the program. This -// serialization is non-portable and the data should only be used by the device -// that generated it. -class BlobCache : public RefBase { - -public: - - // Create an empty blob cache. The blob cache will cache key/value pairs - // with key and value sizes less than or equal to maxKeySize and - // maxValueSize, respectively. The total combined size of ALL cache entries - // (key sizes plus value sizes) will not exceed maxTotalSize. - BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize); - - // set inserts a new binary value into the cache and associates it with the - // given binary key. If the key or value are too large for the cache then - // the cache remains unchanged. This includes the case where a different - // value was previously associated with the given key - the old value will - // remain in the cache. If the given key and value are small enough to be - // put in the cache (based on the maxKeySize, maxValueSize, and maxTotalSize - // values specified to the BlobCache constructor), then the key/value pair - // will be in the cache after set returns. Note, however, that a subsequent - // call to set may evict old key/value pairs from the cache. - // - // Preconditions: - // key != NULL - // 0 < keySize - // value != NULL - // 0 < valueSize - void set(const void* key, size_t keySize, const void* value, - size_t valueSize); - - // get retrieves from the cache the binary value associated with a given - // binary key. If the key is present in the cache then the length of the - // binary value associated with that key is returned. If the value argument - // is non-NULL and the size of the cached value is less than valueSize bytes - // then the cached value is copied into the buffer pointed to by the value - // argument. If the key is not present in the cache then 0 is returned and - // the buffer pointed to by the value argument is not modified. - // - // Note that when calling get multiple times with the same key, the later - // calls may fail, returning 0, even if earlier calls succeeded. The return - // value must be checked for each call. - // - // Preconditions: - // key != NULL - // 0 < keySize - // 0 <= valueSize - size_t get(const void* key, size_t keySize, void* value, size_t valueSize); - - - // getFlattenedSize returns the number of bytes needed to store the entire - // serialized cache. - size_t getFlattenedSize() const; - - // flatten serializes the current contents of the cache into the memory - // pointed to by 'buffer'. The serialized cache contents can later be - // loaded into a BlobCache object using the unflatten method. The contents - // of the BlobCache object will not be modified. - // - // Preconditions: - // size >= this.getFlattenedSize() - status_t flatten(void* buffer, size_t size) const; - - // unflatten replaces the contents of the cache with the serialized cache - // contents in the memory pointed to by 'buffer'. The previous contents of - // the BlobCache will be evicted from the cache. If an error occurs while - // unflattening the serialized cache contents then the BlobCache will be - // left in an empty state. - // - status_t unflatten(void const* buffer, size_t size); - -private: - // Copying is disallowed. - BlobCache(const BlobCache&); - void operator=(const BlobCache&); - - // A random function helper to get around MinGW not having nrand48() - long int blob_random(); - - // clean evicts a randomly chosen set of entries from the cache such that - // the total size of all remaining entries is less than mMaxTotalSize/2. - void clean(); - - // isCleanable returns true if the cache is full enough for the clean method - // to have some effect, and false otherwise. - bool isCleanable() const; - - // A Blob is an immutable sized unstructured data blob. - class Blob : public RefBase { - public: - Blob(const void* data, size_t size, bool copyData); - ~Blob(); - - bool operator<(const Blob& rhs) const; - - const void* getData() const; - size_t getSize() const; - - private: - // Copying is not allowed. - Blob(const Blob&); - void operator=(const Blob&); - - // mData points to the buffer containing the blob data. - const void* mData; - - // mSize is the size of the blob data in bytes. - size_t mSize; - - // mOwnsData indicates whether or not this Blob object should free the - // memory pointed to by mData when the Blob gets destructed. - bool mOwnsData; - }; - - // A CacheEntry is a single key/value pair in the cache. - class CacheEntry { - public: - CacheEntry(); - CacheEntry(const sp<Blob>& key, const sp<Blob>& value); - CacheEntry(const CacheEntry& ce); - - bool operator<(const CacheEntry& rhs) const; - const CacheEntry& operator=(const CacheEntry&); - - sp<Blob> getKey() const; - sp<Blob> getValue() const; - - void setValue(const sp<Blob>& value); - - private: - - // mKey is the key that identifies the cache entry. - sp<Blob> mKey; - - // mValue is the cached data associated with the key. - sp<Blob> mValue; - }; - - // A Header is the header for the entire BlobCache serialization format. No - // need to make this portable, so we simply write the struct out. - struct Header { - // mMagicNumber is the magic number that identifies the data as - // serialized BlobCache contents. It must always contain 'Blb$'. - uint32_t mMagicNumber; - - // mBlobCacheVersion is the serialization format version. - uint32_t mBlobCacheVersion; - - // mDeviceVersion is the device-specific version of the cache. This can - // be used to invalidate the cache. - uint32_t mDeviceVersion; - - // mNumEntries is number of cache entries following the header in the - // data. - size_t mNumEntries; - - // mBuildId is the build id of the device when the cache was created. - // When an update to the build happens (via an OTA or other update) this - // is used to invalidate the cache. - int mBuildIdLength; - char mBuildId[]; - }; - - // An EntryHeader is the header for a serialized cache entry. No need to - // make this portable, so we simply write the struct out. Each EntryHeader - // is followed imediately by the key data and then the value data. - // - // The beginning of each serialized EntryHeader is 4-byte aligned, so the - // number of bytes that a serialized cache entry will occupy is: - // - // ((sizeof(EntryHeader) + keySize + valueSize) + 3) & ~3 - // - struct EntryHeader { - // mKeySize is the size of the entry key in bytes. - size_t mKeySize; - - // mValueSize is the size of the entry value in bytes. - size_t mValueSize; - - // mData contains both the key and value data for the cache entry. The - // key comes first followed immediately by the value. - uint8_t mData[]; - }; - - // mMaxKeySize is the maximum key size that will be cached. Calls to - // BlobCache::set with a keySize parameter larger than mMaxKeySize will - // simply not add the key/value pair to the cache. - const size_t mMaxKeySize; - - // mMaxValueSize is the maximum value size that will be cached. Calls to - // BlobCache::set with a valueSize parameter larger than mMaxValueSize will - // simply not add the key/value pair to the cache. - const size_t mMaxValueSize; - - // mMaxTotalSize is the maximum size that all cache entries can occupy. This - // includes space for both keys and values. When a call to BlobCache::set - // would otherwise cause this limit to be exceeded, either the key/value - // pair passed to BlobCache::set will not be cached or other cache entries - // will be evicted from the cache to make room for the new entry. - const size_t mMaxTotalSize; - - // mTotalSize is the total combined size of all keys and values currently in - // the cache. - size_t mTotalSize; - - // mRandState is the pseudo-random number generator state. It is passed to - // nrand48 to generate random numbers when needed. - unsigned short mRandState[3]; - - // mCacheEntries stores all the cache entries that are resident in memory. - // Cache entries are added to it by the 'set' method. - SortedVector<CacheEntry> mCacheEntries; -}; - -} - -#endif // ANDROID_BLOB_CACHE_H diff --git a/libutils/include/utils/Flattenable.h b/libutils/include/utils/Flattenable.h index 22b811a14..070c71026 100644 --- a/libutils/include/utils/Flattenable.h +++ b/libutils/include/utils/Flattenable.h @@ -189,11 +189,11 @@ public: } inline status_t flatten(void* buffer, size_t size) const { if (size < sizeof(T)) return NO_MEMORY; - *reinterpret_cast<T*>(buffer) = *static_cast<T const*>(this); + memcpy(buffer, static_cast<T const*>(this), sizeof(T)); return NO_ERROR; } inline status_t unflatten(void const* buffer, size_t) { - *static_cast<T*>(this) = *reinterpret_cast<T const*>(buffer); + memcpy(static_cast<T*>(this), buffer, sizeof(T)); return NO_ERROR; } }; diff --git a/libutils/include/utils/LightRefBase.h b/libutils/include/utils/LightRefBase.h new file mode 100644 index 000000000..65257edb9 --- /dev/null +++ b/libutils/include/utils/LightRefBase.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +/* + * See documentation in RefBase.h + */ + +#include <atomic> + +#include <sys/types.h> + +namespace android { + +class ReferenceRenamer; + +template <class T> +class LightRefBase +{ +public: + inline LightRefBase() : mCount(0) { } + inline void incStrong(__attribute__((unused)) const void* id) const { + mCount.fetch_add(1, std::memory_order_relaxed); + } + inline void decStrong(__attribute__((unused)) const void* id) const { + if (mCount.fetch_sub(1, std::memory_order_release) == 1) { + std::atomic_thread_fence(std::memory_order_acquire); + delete static_cast<const T*>(this); + } + } + //! DEBUGGING ONLY: Get current strong ref count. + inline int32_t getStrongCount() const { + return mCount.load(std::memory_order_relaxed); + } + + typedef LightRefBase<T> basetype; + +protected: + inline ~LightRefBase() { } + +private: + friend class ReferenceMover; + inline static void renameRefs(size_t /*n*/, const ReferenceRenamer& /*renamer*/) { } + inline static void renameRefId(T* /*ref*/, const void* /*old_id*/ , const void* /*new_id*/) { } + +private: + mutable std::atomic<int32_t> mCount; +}; + + +// This is a wrapper around LightRefBase that simply enforces a virtual +// destructor to eliminate the template requirement of LightRefBase +class VirtualLightRefBase : public LightRefBase<VirtualLightRefBase> { +public: + virtual ~VirtualLightRefBase() = default; +}; + +}; // namespace android diff --git a/libutils/include/utils/LinearTransform.h b/libutils/include/utils/LinearTransform.h deleted file mode 100644 index 04cb355c7..000000000 --- a/libutils/include/utils/LinearTransform.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _LIBS_UTILS_LINEAR_TRANSFORM_H -#define _LIBS_UTILS_LINEAR_TRANSFORM_H - -#include <stdint.h> - -namespace android { - -// LinearTransform defines a structure which hold the definition of a -// transformation from single dimensional coordinate system A into coordinate -// system B (and back again). Values in A and in B are 64 bit, the linear -// scale factor is expressed as a rational number using two 32 bit values. -// -// Specifically, let -// f(a) = b -// F(b) = f^-1(b) = a -// then -// -// f(a) = (((a - a_zero) * a_to_b_numer) / a_to_b_denom) + b_zero; -// -// and -// -// F(b) = (((b - b_zero) * a_to_b_denom) / a_to_b_numer) + a_zero; -// -struct LinearTransform { - int64_t a_zero; - int64_t b_zero; - int32_t a_to_b_numer; - uint32_t a_to_b_denom; - - // Transform from A->B - // Returns true on success, or false in the case of a singularity or an - // overflow. - bool doForwardTransform(int64_t a_in, int64_t* b_out) const; - - // Transform from B->A - // Returns true on success, or false in the case of a singularity or an - // overflow. - bool doReverseTransform(int64_t b_in, int64_t* a_out) const; - - // Helpers which will reduce the fraction N/D using Euclid's method. - template <class T> static void reduce(T* N, T* D); - static void reduce(int32_t* N, uint32_t* D); -}; - - -} - -#endif // _LIBS_UTILS_LINEAR_TRANSFORM_H diff --git a/libutils/include/utils/NativeHandle.h b/libutils/include/utils/NativeHandle.h index b82516879..73fe804cc 100644 --- a/libutils/include/utils/NativeHandle.h +++ b/libutils/include/utils/NativeHandle.h @@ -24,7 +24,7 @@ typedef struct native_handle native_handle_t; namespace android { -class NativeHandle: public LightRefBase<NativeHandle> { +class NativeHandle : public LightRefBase<NativeHandle> { public: // Create a refcounted wrapper around a native_handle_t, and declare // whether the wrapper owns the handle (so that it should clean up the @@ -41,7 +41,7 @@ private: friend class LightRefBase<NativeHandle>; NativeHandle(native_handle_t* handle, bool ownsHandle); - virtual ~NativeHandle(); + ~NativeHandle(); native_handle_t* mHandle; bool mOwnsHandle; diff --git a/libutils/include/utils/RefBase.h b/libutils/include/utils/RefBase.h index 36016cde6..223b6669d 100644 --- a/libutils/include/utils/RefBase.h +++ b/libutils/include/utils/RefBase.h @@ -177,6 +177,9 @@ #include <stdlib.h> #include <string.h> +// LightRefBase used to be declared in this header, so we have to include it +#include <utils/LightRefBase.h> + #include <utils/StrongPointer.h> #include <utils/TypeHelpers.h> @@ -216,7 +219,7 @@ inline bool operator _op_ (const U* o) const { \ class ReferenceRenamer { protected: - // destructor is purposedly not virtual so we avoid code overhead from + // destructor is purposely not virtual so we avoid code overhead from // subclasses; we have to make it protected to guarantee that it // cannot be called from this base class (and to make strict compilers // happy). @@ -246,13 +249,13 @@ public: { public: RefBase* refBase() const; - + void incWeak(const void* id); void decWeak(const void* id); - + // acquires a strong reference if there is already one. bool attemptIncStrong(const void* id); - + // acquires a weak reference if there is already one. // This is not always safe. see ProcessState.cpp and BpBinder.cpp // for proper use. @@ -268,12 +271,12 @@ public: // enable -- enable/disable tracking // retain -- when tracking is enable, if true, then we save a stack trace // for each reference and dereference; when retain == false, we - // match up references and dereferences and keep only the + // match up references and dereferences and keep only the // outstanding ones. - + void trackMe(bool enable, bool retain); }; - + weakref_type* createWeak(const void* id) const; weakref_type* getWeakRefs() const; @@ -345,56 +348,12 @@ private: // --------------------------------------------------------------------------- -template <class T> -class LightRefBase -{ -public: - inline LightRefBase() : mCount(0) { } - inline void incStrong(__attribute__((unused)) const void* id) const { - mCount.fetch_add(1, std::memory_order_relaxed); - } - inline void decStrong(__attribute__((unused)) const void* id) const { - if (mCount.fetch_sub(1, std::memory_order_release) == 1) { - std::atomic_thread_fence(std::memory_order_acquire); - delete static_cast<const T*>(this); - } - } - //! DEBUGGING ONLY: Get current strong ref count. - inline int32_t getStrongCount() const { - return mCount.load(std::memory_order_relaxed); - } - - typedef LightRefBase<T> basetype; - -protected: - inline ~LightRefBase() { } - -private: - friend class ReferenceMover; - inline static void renameRefs(size_t /*n*/, - const ReferenceRenamer& /*renamer*/) { } - inline static void renameRefId(T* /*ref*/, - const void* /*old_id*/ , const void* /*new_id*/) { } - -private: - mutable std::atomic<int32_t> mCount; -}; - -// This is a wrapper around LightRefBase that simply enforces a virtual -// destructor to eliminate the template requirement of LightRefBase -class VirtualLightRefBase : public LightRefBase<VirtualLightRefBase> { -public: - virtual ~VirtualLightRefBase(); -}; - -// --------------------------------------------------------------------------- - template <typename T> class wp { public: typedef typename RefBase::weakref_type weakref_type; - + inline wp() : m_ptr(0) { } wp(T* other); // NOLINT(implicit) @@ -405,31 +364,31 @@ public: template<typename U> wp(const wp<U>& other); // NOLINT(implicit) ~wp(); - + // Assignment wp& operator = (T* other); wp& operator = (const wp<T>& other); wp& operator = (const sp<T>& other); - + template<typename U> wp& operator = (U* other); template<typename U> wp& operator = (const wp<U>& other); template<typename U> wp& operator = (const sp<U>& other); - + void set_object_and_refs(T* other, weakref_type* refs); // promotion to sp - + sp<T> promote() const; // Reset - + void clear(); // Accessors - + inline weakref_type* get_refs() const { return m_refs; } - + inline T* unsafe_get() const { return m_ptr; } // Operators diff --git a/libutils/include/utils/Singleton.h b/libutils/include/utils/Singleton.h index abb72f510..9afedd4a0 100644 --- a/libutils/include/utils/Singleton.h +++ b/libutils/include/utils/Singleton.h @@ -18,9 +18,12 @@ #define ANDROID_UTILS_SINGLETON_H #include <stdint.h> + +// some vendor code assumes they have atoi() after including this file. +#include <stdlib.h> + #include <sys/types.h> #include <utils/Mutex.h> -#include <utils/threads.h> #include <cutils/compiler.h> namespace android { diff --git a/libutils/include/utils/SortedVector.h b/libutils/include/utils/SortedVector.h index 86f349645..5b2a23200 100644 --- a/libutils/include/utils/SortedVector.h +++ b/libutils/include/utils/SortedVector.h @@ -37,18 +37,18 @@ class SortedVector : private SortedVectorImpl public: typedef TYPE value_type; - - /*! + + /*! * Constructors and destructors */ - + SortedVector(); SortedVector(const SortedVector<TYPE>& rhs); virtual ~SortedVector(); /*! copy operator */ - const SortedVector<TYPE>& operator = (const SortedVector<TYPE>& rhs) const; - SortedVector<TYPE>& operator = (const SortedVector<TYPE>& rhs); + const SortedVector<TYPE>& operator = (const SortedVector<TYPE>& rhs) const; + SortedVector<TYPE>& operator = (const SortedVector<TYPE>& rhs); /* * empty the vector @@ -56,7 +56,7 @@ public: inline void clear() { VectorImpl::clear(); } - /*! + /*! * vector stats */ @@ -69,11 +69,11 @@ public: //! sets the capacity. capacity can never be reduced less than size() inline ssize_t setCapacity(size_t size) { return VectorImpl::setCapacity(size); } - /*! + /*! * C-style array access */ - - //! read-only C-style access + + //! read-only C-style access inline const TYPE* array() const; //! read-write C-style access. BE VERY CAREFUL when modifying the array @@ -82,12 +82,12 @@ public: //! finds the index of an item ssize_t indexOf(const TYPE& item) const; - + //! finds where this item should be inserted size_t orderOf(const TYPE& item) const; - - - /*! + + + /*! * accessors */ @@ -104,7 +104,7 @@ public: //! add an item in the right place (and replace the one that is there) ssize_t add(const TYPE& item); - + //! editItemAt() MUST NOT change the order of this item TYPE& editItemAt(size_t index) { return *( static_cast<TYPE *>(VectorImpl::editItemLocation(index)) ); @@ -113,7 +113,7 @@ public: //! merges a vector into this one ssize_t merge(const Vector<TYPE>& vector); ssize_t merge(const SortedVector<TYPE>& vector); - + //! removes an item ssize_t remove(const TYPE&); @@ -121,7 +121,24 @@ public: inline ssize_t removeItemsAt(size_t index, size_t count = 1); //! remove one item inline ssize_t removeAt(size_t index) { return removeItemsAt(index); } - + + /* + * these inlines add some level of compatibility with STL. + */ + typedef TYPE* iterator; + typedef TYPE const* const_iterator; + + inline iterator begin() { return editArray(); } + inline iterator end() { return editArray() + size(); } + inline const_iterator begin() const { return array(); } + inline const_iterator end() const { return array() + size(); } + inline void reserve(size_t n) { setCapacity(n); } + inline bool empty() const{ return isEmpty(); } + inline iterator erase(iterator pos) { + ssize_t index = removeItemsAt(pos-array()); + return begin() + index; + } + protected: virtual void do_construct(void* storage, size_t num) const; virtual void do_destroy(void* storage, size_t num) const; @@ -159,13 +176,13 @@ SortedVector<TYPE>::~SortedVector() { template<class TYPE> inline SortedVector<TYPE>& SortedVector<TYPE>::operator = (const SortedVector<TYPE>& rhs) { SortedVectorImpl::operator = (rhs); - return *this; + return *this; } template<class TYPE> inline const SortedVector<TYPE>& SortedVector<TYPE>::operator = (const SortedVector<TYPE>& rhs) const { SortedVectorImpl::operator = (rhs); - return *this; + return *this; } template<class TYPE> inline @@ -235,7 +252,7 @@ ssize_t SortedVector<TYPE>::removeItemsAt(size_t index, size_t count) { // --------------------------------------------------------------------------- template<class TYPE> -void SortedVector<TYPE>::do_construct(void* storage, size_t num) const { +UTILS_VECTOR_NO_CFI void SortedVector<TYPE>::do_construct(void* storage, size_t num) const { construct_type( reinterpret_cast<TYPE*>(storage), num ); } @@ -245,22 +262,22 @@ void SortedVector<TYPE>::do_destroy(void* storage, size_t num) const { } template<class TYPE> -void SortedVector<TYPE>::do_copy(void* dest, const void* from, size_t num) const { +UTILS_VECTOR_NO_CFI void SortedVector<TYPE>::do_copy(void* dest, const void* from, size_t num) const { copy_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num ); } template<class TYPE> -void SortedVector<TYPE>::do_splat(void* dest, const void* item, size_t num) const { +UTILS_VECTOR_NO_CFI void SortedVector<TYPE>::do_splat(void* dest, const void* item, size_t num) const { splat_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(item), num ); } template<class TYPE> -void SortedVector<TYPE>::do_move_forward(void* dest, const void* from, size_t num) const { +UTILS_VECTOR_NO_CFI void SortedVector<TYPE>::do_move_forward(void* dest, const void* from, size_t num) const { move_forward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num ); } template<class TYPE> -void SortedVector<TYPE>::do_move_backward(void* dest, const void* from, size_t num) const { +UTILS_VECTOR_NO_CFI void SortedVector<TYPE>::do_move_backward(void* dest, const void* from, size_t num) const { move_backward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num ); } diff --git a/libutils/include/utils/StrongPointer.h b/libutils/include/utils/StrongPointer.h index c2f772222..0c2060791 100644 --- a/libutils/include/utils/StrongPointer.h +++ b/libutils/include/utils/StrongPointer.h @@ -17,12 +17,6 @@ #ifndef ANDROID_STRONG_POINTER_H #define ANDROID_STRONG_POINTER_H -#include <cutils/atomic.h> - -#include <stdint.h> -#include <sys/types.h> -#include <stdlib.h> - // --------------------------------------------------------------------------- namespace android { diff --git a/libutils/include/utils/Trace.h b/libutils/include/utils/Trace.h index eeba40d65..5e9229c1e 100644 --- a/libutils/include/utils/Trace.h +++ b/libutils/include/utils/Trace.h @@ -19,16 +19,8 @@ #if defined(__ANDROID__) -#include <fcntl.h> #include <stdint.h> -#include <stdio.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include <cutils/compiler.h> -#include <utils/threads.h> + #include <cutils/trace.h> // See <cutils/trace.h> for more ATRACE_* macros. @@ -37,6 +29,7 @@ #define _PASTE(x, y) x ## y #define PASTE(x, y) _PASTE(x,y) #define ATRACE_NAME(name) android::ScopedTrace PASTE(___tracer, __LINE__) (ATRACE_TAG, name) + // ATRACE_CALL is an ATRACE_NAME that uses the current function name. #define ATRACE_CALL() ATRACE_NAME(__FUNCTION__) @@ -44,14 +37,13 @@ namespace android { class ScopedTrace { public: -inline ScopedTrace(uint64_t tag, const char* name) - : mTag(tag) { - atrace_begin(mTag,name); -} - -inline ~ScopedTrace() { - atrace_end(mTag); -} + inline ScopedTrace(uint64_t tag, const char* name) : mTag(tag) { + atrace_begin(mTag, name); + } + + inline ~ScopedTrace() { + atrace_end(mTag); + } private: uint64_t mTag; diff --git a/libutils/include/utils/TypeHelpers.h b/libutils/include/utils/TypeHelpers.h index 2a2522722..28fbca508 100644 --- a/libutils/include/utils/TypeHelpers.h +++ b/libutils/include/utils/TypeHelpers.h @@ -36,7 +36,7 @@ template <typename T> struct trait_trivial_ctor { enum { value = false }; }; template <typename T> struct trait_trivial_dtor { enum { value = false }; }; template <typename T> struct trait_trivial_copy { enum { value = false }; }; template <typename T> struct trait_trivial_move { enum { value = false }; }; -template <typename T> struct trait_pointer { enum { value = false }; }; +template <typename T> struct trait_pointer { enum { value = false }; }; template <typename T> struct trait_pointer<T*> { enum { value = true }; }; template <typename TYPE> @@ -59,13 +59,13 @@ template <typename T, typename U> struct aggregate_traits { enum { is_pointer = false, - has_trivial_ctor = + has_trivial_ctor = traits<T>::has_trivial_ctor && traits<U>::has_trivial_ctor, - has_trivial_dtor = + has_trivial_dtor = traits<T>::has_trivial_dtor && traits<U>::has_trivial_dtor, - has_trivial_copy = + has_trivial_copy = traits<T>::has_trivial_copy && traits<U>::has_trivial_copy, - has_trivial_move = + has_trivial_move = traits<T>::has_trivial_move && traits<U>::has_trivial_move }; }; diff --git a/libutils/include/utils/Vector.h b/libutils/include/utils/Vector.h index 9a643f9b0..7e00123f7 100644 --- a/libutils/include/utils/Vector.h +++ b/libutils/include/utils/Vector.h @@ -24,6 +24,20 @@ #include <utils/TypeHelpers.h> #include <utils/VectorImpl.h> +/* + * Used to blacklist some functions from CFI. + * + */ +#ifndef __has_attribute +#define __has_attribute(x) 0 +#endif + +#if __has_attribute(no_sanitize) +#define UTILS_VECTOR_NO_CFI __attribute__((no_sanitize("cfi"))) +#else +#define UTILS_VECTOR_NO_CFI +#endif + // --------------------------------------------------------------------------- namespace android { @@ -42,11 +56,11 @@ class Vector : private VectorImpl { public: typedef TYPE value_type; - - /*! + + /*! * Constructors and destructors */ - + Vector(); Vector(const Vector<TYPE>& rhs); explicit Vector(const SortedVector<TYPE>& rhs); @@ -54,7 +68,7 @@ public: /*! copy operator */ const Vector<TYPE>& operator = (const Vector<TYPE>& rhs) const; - Vector<TYPE>& operator = (const Vector<TYPE>& rhs); + Vector<TYPE>& operator = (const Vector<TYPE>& rhs); const Vector<TYPE>& operator = (const SortedVector<TYPE>& rhs) const; Vector<TYPE>& operator = (const SortedVector<TYPE>& rhs); @@ -65,7 +79,7 @@ public: inline void clear() { VectorImpl::clear(); } - /*! + /*! * vector stats */ @@ -87,13 +101,13 @@ public: /*! * C-style array access */ - - //! read-only C-style access + + //! read-only C-style access inline const TYPE* array() const; //! read-write C-style access TYPE* editArray(); - - /*! + + /*! * accessors */ @@ -113,10 +127,10 @@ public: //! grants right access to the top of the stack (last element) TYPE& editTop(); - /*! + /*! * append/insert another vector */ - + //! insert another vector at a given index ssize_t insertVectorAt(const Vector<TYPE>& vector, size_t index); @@ -130,10 +144,10 @@ public: //! append an array at the end of this vector ssize_t appendArray(const TYPE* array, size_t length); - /*! + /*! * add/insert/replace items */ - + //! insert one or several items initialized with their default constructor inline ssize_t insertAt(size_t index, size_t numItems = 1); //! insert one or several items initialized from a prototype item @@ -147,7 +161,7 @@ public: //! same as push() but returns the index the item was added at (or an error) inline ssize_t add(); //! same as push() but returns the index the item was added at (or an error) - ssize_t add(const TYPE& item); + ssize_t add(const TYPE& item); //! replace an item with a new one initialized with its default constructor inline ssize_t replaceAt(size_t index); //! replace an item with a new one @@ -165,10 +179,10 @@ public: /*! * sort (stable) the array */ - + typedef int (*compar_t)(const TYPE* lhs, const TYPE* rhs); typedef int (*compar_r_t)(const TYPE* lhs, const TYPE* rhs, void* state); - + inline status_t sort(compar_t cmp); inline status_t sort(compar_r_t cmp, void* state); @@ -237,7 +251,7 @@ Vector<TYPE>::~Vector() { template<class TYPE> inline Vector<TYPE>& Vector<TYPE>::operator = (const Vector<TYPE>& rhs) { VectorImpl::operator = (rhs); - return *this; + return *this; } template<class TYPE> inline @@ -255,7 +269,7 @@ Vector<TYPE>& Vector<TYPE>::operator = (const SortedVector<TYPE>& rhs) { template<class TYPE> inline const Vector<TYPE>& Vector<TYPE>::operator = (const SortedVector<TYPE>& rhs) const { VectorImpl::operator = (rhs); - return *this; + return *this; } template<class TYPE> inline @@ -380,7 +394,7 @@ status_t Vector<TYPE>::sort(Vector<TYPE>::compar_r_t cmp, void* state) { // --------------------------------------------------------------------------- template<class TYPE> -void Vector<TYPE>::do_construct(void* storage, size_t num) const { +UTILS_VECTOR_NO_CFI void Vector<TYPE>::do_construct(void* storage, size_t num) const { construct_type( reinterpret_cast<TYPE*>(storage), num ); } @@ -390,22 +404,22 @@ void Vector<TYPE>::do_destroy(void* storage, size_t num) const { } template<class TYPE> -void Vector<TYPE>::do_copy(void* dest, const void* from, size_t num) const { +UTILS_VECTOR_NO_CFI void Vector<TYPE>::do_copy(void* dest, const void* from, size_t num) const { copy_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num ); } template<class TYPE> -void Vector<TYPE>::do_splat(void* dest, const void* item, size_t num) const { +UTILS_VECTOR_NO_CFI void Vector<TYPE>::do_splat(void* dest, const void* item, size_t num) const { splat_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(item), num ); } template<class TYPE> -void Vector<TYPE>::do_move_forward(void* dest, const void* from, size_t num) const { +UTILS_VECTOR_NO_CFI void Vector<TYPE>::do_move_forward(void* dest, const void* from, size_t num) const { move_forward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num ); } template<class TYPE> -void Vector<TYPE>::do_move_backward(void* dest, const void* from, size_t num) const { +UTILS_VECTOR_NO_CFI void Vector<TYPE>::do_move_backward(void* dest, const void* from, size_t num) const { move_backward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num ); } diff --git a/libutils/misc.cpp b/libutils/misc.cpp index 216dc1430..d95fd056b 100644 --- a/libutils/misc.cpp +++ b/libutils/misc.cpp @@ -16,21 +16,19 @@ #define LOG_TAG "misc" -// -// Miscellaneous utility functions. -// #include <utils/misc.h> -#include <utils/Log.h> -#include <sys/stat.h> -#include <string.h> -#include <stdio.h> +#include <pthread.h> -#if !defined(_WIN32) -# include <pthread.h> +#include <utils/Log.h> +#include <utils/Vector.h> + +#if defined(__ANDROID__) +#include <dlfcn.h> +#include <vndksupport/linker.h> #endif -#include <utils/Vector.h> +extern "C" void do_report_sysprop_change(); using namespace android; @@ -70,7 +68,36 @@ void add_sysprop_change_callback(sysprop_change_callback cb, int priority) { #endif } +#if defined(__ANDROID__) +void (*get_report_sysprop_change_func())() { + void (*func)() = nullptr; + void* handle = android_load_sphal_library("libutils.so", RTLD_NOW); + if (handle != nullptr) { + func = reinterpret_cast<decltype(func)>(dlsym(handle, "do_report_sysprop_change")); + } + + return func; +} +#endif + void report_sysprop_change() { + do_report_sysprop_change(); + +#if defined(__ANDROID__) + // libutils.so is double loaded; from the default namespace and from the + // 'sphal' namespace. Redirect the sysprop change event to the other instance + // of libutils.so loaded in the 'sphal' namespace so that listeners attached + // to that instance is also notified with this event. + static auto func = get_report_sysprop_change_func(); + if (func != nullptr) { + (*func)(); + } +#endif +} + +}; // namespace android + +void do_report_sysprop_change() { #if !defined(_WIN32) pthread_mutex_lock(&gSyspropMutex); Vector<sysprop_change_callback_info> listeners; @@ -85,5 +112,3 @@ void report_sysprop_change() { } #endif } - -}; // namespace android diff --git a/libutils/tests/Android.bp b/libutils/tests/Android.bp index 7cae13351..08691756a 100644 --- a/libutils/tests/Android.bp +++ b/libutils/tests/Android.bp @@ -34,7 +34,6 @@ cc_test { target: { android: { srcs: [ - "BlobCache_test.cpp", "Looper_test.cpp", "RefBase_test.cpp", "SystemClock_test.cpp", diff --git a/libutils/tests/BlobCache_test.cpp b/libutils/tests/BlobCache_test.cpp deleted file mode 100644 index 1e2ff9828..000000000 --- a/libutils/tests/BlobCache_test.cpp +++ /dev/null @@ -1,425 +0,0 @@ -/* - ** Copyright 2011, 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 <fcntl.h> -#include <stdio.h> - -#include <gtest/gtest.h> - -#include <utils/BlobCache.h> -#include <utils/Errors.h> - -namespace android { - -class BlobCacheTest : public ::testing::Test { -protected: - enum { - MAX_KEY_SIZE = 6, - MAX_VALUE_SIZE = 8, - MAX_TOTAL_SIZE = 13, - }; - - virtual void SetUp() { - mBC = new BlobCache(MAX_KEY_SIZE, MAX_VALUE_SIZE, MAX_TOTAL_SIZE); - } - - virtual void TearDown() { - mBC.clear(); - } - - sp<BlobCache> mBC; -}; - -TEST_F(BlobCacheTest, CacheSingleValueSucceeds) { - unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; - mBC->set("abcd", 4, "efgh", 4); - ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4)); - ASSERT_EQ('e', buf[0]); - ASSERT_EQ('f', buf[1]); - ASSERT_EQ('g', buf[2]); - ASSERT_EQ('h', buf[3]); -} - -TEST_F(BlobCacheTest, CacheTwoValuesSucceeds) { - unsigned char buf[2] = { 0xee, 0xee }; - mBC->set("ab", 2, "cd", 2); - mBC->set("ef", 2, "gh", 2); - ASSERT_EQ(size_t(2), mBC->get("ab", 2, buf, 2)); - ASSERT_EQ('c', buf[0]); - ASSERT_EQ('d', buf[1]); - ASSERT_EQ(size_t(2), mBC->get("ef", 2, buf, 2)); - ASSERT_EQ('g', buf[0]); - ASSERT_EQ('h', buf[1]); -} - -TEST_F(BlobCacheTest, GetOnlyWritesInsideBounds) { - unsigned char buf[6] = { 0xee, 0xee, 0xee, 0xee, 0xee, 0xee }; - mBC->set("abcd", 4, "efgh", 4); - ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf+1, 4)); - ASSERT_EQ(0xee, buf[0]); - ASSERT_EQ('e', buf[1]); - ASSERT_EQ('f', buf[2]); - ASSERT_EQ('g', buf[3]); - ASSERT_EQ('h', buf[4]); - ASSERT_EQ(0xee, buf[5]); -} - -TEST_F(BlobCacheTest, GetOnlyWritesIfBufferIsLargeEnough) { - unsigned char buf[3] = { 0xee, 0xee, 0xee }; - mBC->set("abcd", 4, "efgh", 4); - ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 3)); - ASSERT_EQ(0xee, buf[0]); - ASSERT_EQ(0xee, buf[1]); - ASSERT_EQ(0xee, buf[2]); -} - -TEST_F(BlobCacheTest, GetDoesntAccessNullBuffer) { - mBC->set("abcd", 4, "efgh", 4); - ASSERT_EQ(size_t(4), mBC->get("abcd", 4, NULL, 0)); -} - -TEST_F(BlobCacheTest, MultipleSetsCacheLatestValue) { - unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; - mBC->set("abcd", 4, "efgh", 4); - mBC->set("abcd", 4, "ijkl", 4); - ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4)); - ASSERT_EQ('i', buf[0]); - ASSERT_EQ('j', buf[1]); - ASSERT_EQ('k', buf[2]); - ASSERT_EQ('l', buf[3]); -} - -TEST_F(BlobCacheTest, SecondSetKeepsFirstValueIfTooLarge) { - unsigned char buf[MAX_VALUE_SIZE+1] = { 0xee, 0xee, 0xee, 0xee }; - mBC->set("abcd", 4, "efgh", 4); - mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1); - ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4)); - ASSERT_EQ('e', buf[0]); - ASSERT_EQ('f', buf[1]); - ASSERT_EQ('g', buf[2]); - ASSERT_EQ('h', buf[3]); -} - -TEST_F(BlobCacheTest, DoesntCacheIfKeyIsTooBig) { - char key[MAX_KEY_SIZE+1]; - unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; - for (int i = 0; i < MAX_KEY_SIZE+1; i++) { - key[i] = 'a'; - } - mBC->set(key, MAX_KEY_SIZE+1, "bbbb", 4); - ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE+1, buf, 4)); - ASSERT_EQ(0xee, buf[0]); - ASSERT_EQ(0xee, buf[1]); - ASSERT_EQ(0xee, buf[2]); - ASSERT_EQ(0xee, buf[3]); -} - -TEST_F(BlobCacheTest, DoesntCacheIfValueIsTooBig) { - char buf[MAX_VALUE_SIZE+1]; - for (int i = 0; i < MAX_VALUE_SIZE+1; i++) { - buf[i] = 'b'; - } - mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1); - for (int i = 0; i < MAX_VALUE_SIZE+1; i++) { - buf[i] = 0xee; - } - ASSERT_EQ(size_t(0), mBC->get("abcd", 4, buf, MAX_VALUE_SIZE+1)); - for (int i = 0; i < MAX_VALUE_SIZE+1; i++) { - SCOPED_TRACE(i); - ASSERT_EQ(0xee, buf[i]); - } -} - -TEST_F(BlobCacheTest, DoesntCacheIfKeyValuePairIsTooBig) { - // Check a testing assumptions - ASSERT_TRUE(MAX_TOTAL_SIZE < MAX_KEY_SIZE + MAX_VALUE_SIZE); - ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE); - - enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE + 1 }; - - char key[MAX_KEY_SIZE]; - char buf[bufSize]; - for (int i = 0; i < MAX_KEY_SIZE; i++) { - key[i] = 'a'; - } - for (int i = 0; i < bufSize; i++) { - buf[i] = 'b'; - } - - mBC->set(key, MAX_KEY_SIZE, buf, MAX_VALUE_SIZE); - ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE, NULL, 0)); -} - -TEST_F(BlobCacheTest, CacheMaxKeySizeSucceeds) { - char key[MAX_KEY_SIZE]; - unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; - for (int i = 0; i < MAX_KEY_SIZE; i++) { - key[i] = 'a'; - } - mBC->set(key, MAX_KEY_SIZE, "wxyz", 4); - ASSERT_EQ(size_t(4), mBC->get(key, MAX_KEY_SIZE, buf, 4)); - ASSERT_EQ('w', buf[0]); - ASSERT_EQ('x', buf[1]); - ASSERT_EQ('y', buf[2]); - ASSERT_EQ('z', buf[3]); -} - -TEST_F(BlobCacheTest, CacheMaxValueSizeSucceeds) { - char buf[MAX_VALUE_SIZE]; - for (int i = 0; i < MAX_VALUE_SIZE; i++) { - buf[i] = 'b'; - } - mBC->set("abcd", 4, buf, MAX_VALUE_SIZE); - for (int i = 0; i < MAX_VALUE_SIZE; i++) { - buf[i] = 0xee; - } - ASSERT_EQ(size_t(MAX_VALUE_SIZE), mBC->get("abcd", 4, buf, - MAX_VALUE_SIZE)); - for (int i = 0; i < MAX_VALUE_SIZE; i++) { - SCOPED_TRACE(i); - ASSERT_EQ('b', buf[i]); - } -} - -TEST_F(BlobCacheTest, CacheMaxKeyValuePairSizeSucceeds) { - // Check a testing assumption - ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE); - - enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE }; - - char key[MAX_KEY_SIZE]; - char buf[bufSize]; - for (int i = 0; i < MAX_KEY_SIZE; i++) { - key[i] = 'a'; - } - for (int i = 0; i < bufSize; i++) { - buf[i] = 'b'; - } - - mBC->set(key, MAX_KEY_SIZE, buf, bufSize); - ASSERT_EQ(size_t(bufSize), mBC->get(key, MAX_KEY_SIZE, NULL, 0)); -} - -TEST_F(BlobCacheTest, CacheMinKeyAndValueSizeSucceeds) { - unsigned char buf[1] = { 0xee }; - mBC->set("x", 1, "y", 1); - ASSERT_EQ(size_t(1), mBC->get("x", 1, buf, 1)); - ASSERT_EQ('y', buf[0]); -} - -TEST_F(BlobCacheTest, CacheSizeDoesntExceedTotalLimit) { - for (int i = 0; i < 256; i++) { - uint8_t k = i; - mBC->set(&k, 1, "x", 1); - } - int numCached = 0; - for (int i = 0; i < 256; i++) { - uint8_t k = i; - if (mBC->get(&k, 1, NULL, 0) == 1) { - numCached++; - } - } - ASSERT_GE(MAX_TOTAL_SIZE / 2, numCached); -} - -TEST_F(BlobCacheTest, ExceedingTotalLimitHalvesCacheSize) { - // Fill up the entire cache with 1 char key/value pairs. - const int maxEntries = MAX_TOTAL_SIZE / 2; - for (int i = 0; i < maxEntries; i++) { - uint8_t k = i; - mBC->set(&k, 1, "x", 1); - } - // Insert one more entry, causing a cache overflow. - { - uint8_t k = maxEntries; - mBC->set(&k, 1, "x", 1); - } - // Count the number of entries in the cache. - int numCached = 0; - for (int i = 0; i < maxEntries+1; i++) { - uint8_t k = i; - if (mBC->get(&k, 1, NULL, 0) == 1) { - numCached++; - } - } - ASSERT_EQ(maxEntries/2 + 1, numCached); -} - -class BlobCacheFlattenTest : public BlobCacheTest { -protected: - virtual void SetUp() { - BlobCacheTest::SetUp(); - mBC2 = new BlobCache(MAX_KEY_SIZE, MAX_VALUE_SIZE, MAX_TOTAL_SIZE); - } - - virtual void TearDown() { - mBC2.clear(); - BlobCacheTest::TearDown(); - } - - void roundTrip() { - size_t size = mBC->getFlattenedSize(); - uint8_t* flat = new uint8_t[size]; - ASSERT_EQ(OK, mBC->flatten(flat, size)); - ASSERT_EQ(OK, mBC2->unflatten(flat, size)); - delete[] flat; - } - - sp<BlobCache> mBC2; -}; - -TEST_F(BlobCacheFlattenTest, FlattenOneValue) { - unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; - mBC->set("abcd", 4, "efgh", 4); - roundTrip(); - ASSERT_EQ(size_t(4), mBC2->get("abcd", 4, buf, 4)); - ASSERT_EQ('e', buf[0]); - ASSERT_EQ('f', buf[1]); - ASSERT_EQ('g', buf[2]); - ASSERT_EQ('h', buf[3]); -} - -TEST_F(BlobCacheFlattenTest, FlattenFullCache) { - // Fill up the entire cache with 1 char key/value pairs. - const int maxEntries = MAX_TOTAL_SIZE / 2; - for (int i = 0; i < maxEntries; i++) { - uint8_t k = i; - mBC->set(&k, 1, &k, 1); - } - - roundTrip(); - - // Verify the deserialized cache - for (int i = 0; i < maxEntries; i++) { - uint8_t k = i; - uint8_t v = 0xee; - ASSERT_EQ(size_t(1), mBC2->get(&k, 1, &v, 1)); - ASSERT_EQ(k, v); - } -} - -TEST_F(BlobCacheFlattenTest, FlattenDoesntChangeCache) { - // Fill up the entire cache with 1 char key/value pairs. - const int maxEntries = MAX_TOTAL_SIZE / 2; - for (int i = 0; i < maxEntries; i++) { - uint8_t k = i; - mBC->set(&k, 1, &k, 1); - } - - size_t size = mBC->getFlattenedSize(); - uint8_t* flat = new uint8_t[size]; - ASSERT_EQ(OK, mBC->flatten(flat, size)); - delete[] flat; - - // Verify the cache that we just serialized - for (int i = 0; i < maxEntries; i++) { - uint8_t k = i; - uint8_t v = 0xee; - ASSERT_EQ(size_t(1), mBC->get(&k, 1, &v, 1)); - ASSERT_EQ(k, v); - } -} - -TEST_F(BlobCacheFlattenTest, FlattenCatchesBufferTooSmall) { - // Fill up the entire cache with 1 char key/value pairs. - const int maxEntries = MAX_TOTAL_SIZE / 2; - for (int i = 0; i < maxEntries; i++) { - uint8_t k = i; - mBC->set(&k, 1, &k, 1); - } - - size_t size = mBC->getFlattenedSize() - 1; - uint8_t* flat = new uint8_t[size]; - // ASSERT_EQ(BAD_VALUE, mBC->flatten(flat, size)); - // TODO: The above fails. I expect this is so because getFlattenedSize() - // overstimates the size by using PROPERTY_VALUE_MAX. - delete[] flat; -} - -TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadMagic) { - unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; - mBC->set("abcd", 4, "efgh", 4); - - size_t size = mBC->getFlattenedSize(); - uint8_t* flat = new uint8_t[size]; - ASSERT_EQ(OK, mBC->flatten(flat, size)); - flat[1] = ~flat[1]; - - // Bad magic should cause an error. - ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size)); - delete[] flat; - - // The error should cause the unflatten to result in an empty cache - ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4)); -} - -TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheVersion) { - unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; - mBC->set("abcd", 4, "efgh", 4); - - size_t size = mBC->getFlattenedSize(); - uint8_t* flat = new uint8_t[size]; - ASSERT_EQ(OK, mBC->flatten(flat, size)); - flat[5] = ~flat[5]; - - // Version mismatches shouldn't cause errors, but should not use the - // serialized entries - ASSERT_EQ(OK, mBC2->unflatten(flat, size)); - delete[] flat; - - // The version mismatch should cause the unflatten to result in an empty - // cache - ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4)); -} - -TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheDeviceVersion) { - unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; - mBC->set("abcd", 4, "efgh", 4); - - size_t size = mBC->getFlattenedSize(); - uint8_t* flat = new uint8_t[size]; - ASSERT_EQ(OK, mBC->flatten(flat, size)); - flat[10] = ~flat[10]; - - // Version mismatches shouldn't cause errors, but should not use the - // serialized entries - ASSERT_EQ(OK, mBC2->unflatten(flat, size)); - delete[] flat; - - // The version mismatch should cause the unflatten to result in an empty - // cache - ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4)); -} - -TEST_F(BlobCacheFlattenTest, UnflattenCatchesBufferTooSmall) { - unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; - mBC->set("abcd", 4, "efgh", 4); - - size_t size = mBC->getFlattenedSize(); - uint8_t* flat = new uint8_t[size]; - ASSERT_EQ(OK, mBC->flatten(flat, size)); - - // A buffer truncation shouldt cause an error - // ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size-1)); - // TODO: The above appears to fail because getFlattenedSize() is - // conservative. - delete[] flat; - - // The error should cause the unflatten to result in an empty cache - ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4)); -} - -} // namespace android |
