diff options
Diffstat (limited to 'libs/utils')
38 files changed, 0 insertions, 10610 deletions
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk deleted file mode 100644 index 57c048a..0000000 --- a/libs/utils/Android.mk +++ /dev/null @@ -1,108 +0,0 @@ -# Copyright (C) 2008 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -LOCAL_PATH:= $(call my-dir) - -# libutils is a little unique: It's built twice, once for the host -# and once for the device. - -commonSources:= \ - BasicHashtable.cpp \ - BlobCache.cpp \ - BufferedTextOutput.cpp \ - CallStack.cpp \ - Debug.cpp \ - FileMap.cpp \ - Flattenable.cpp \ - LinearTransform.cpp \ - PropertyMap.cpp \ - RefBase.cpp \ - SharedBuffer.cpp \ - Static.cpp \ - StopWatch.cpp \ - String8.cpp \ - String16.cpp \ - StringArray.cpp \ - SystemClock.cpp \ - TextOutput.cpp \ - Threads.cpp \ - Timers.cpp \ - Tokenizer.cpp \ - Unicode.cpp \ - VectorImpl.cpp \ - misc.cpp - - -# For the host -# ===================================================== - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= $(commonSources) - -LOCAL_MODULE:= libutils - -LOCAL_CFLAGS += -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS) - -ifeq ($(HOST_OS),windows) -ifeq ($(strip $(USE_CYGWIN),),) -# Under MinGW, ctype.h doesn't need multi-byte support -LOCAL_CFLAGS += -DMB_CUR_MAX=1 -endif -endif - -ifeq ($(TARGET_OS),linux) -LOCAL_LDLIBS += -lrt -ldl -endif - -include $(BUILD_HOST_STATIC_LIBRARY) - - -# For the device -# ===================================================== -include $(CLEAR_VARS) - - -# we have the common sources, plus some device-specific stuff -LOCAL_SRC_FILES:= \ - $(commonSources) \ - Looper.cpp \ - Trace.cpp - -ifeq ($(TARGET_OS),linux) -LOCAL_LDLIBS += -lrt -ldl -endif - -LOCAL_C_INCLUDES += \ - bionic/libc/private - -LOCAL_LDLIBS += -lpthread - -LOCAL_SHARED_LIBRARIES := \ - liblog \ - libcutils \ - libdl \ - libcorkscrew - -LOCAL_MODULE:= libutils -include $(BUILD_SHARED_LIBRARY) - -# Include subdirectory makefiles -# ============================================================ - -# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework -# team really wants is to build the stuff defined by this makefile. -ifeq (,$(ONE_SHOT_MAKEFILE)) -include $(call first-makefiles-under,$(LOCAL_PATH)) -endif diff --git a/libs/utils/BasicHashtable.cpp b/libs/utils/BasicHashtable.cpp deleted file mode 100644 index fb8ec9f..0000000 --- a/libs/utils/BasicHashtable.cpp +++ /dev/null @@ -1,338 +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 LOG_TAG "BasicHashtable" - -#include <math.h> - -#include <utils/Log.h> -#include <utils/BasicHashtable.h> -#include <utils/misc.h> - -namespace android { - -BasicHashtableImpl::BasicHashtableImpl(size_t entrySize, bool hasTrivialDestructor, - size_t minimumInitialCapacity, float loadFactor) : - mBucketSize(entrySize + sizeof(Bucket)), mHasTrivialDestructor(hasTrivialDestructor), - mLoadFactor(loadFactor), mSize(0), - mFilledBuckets(0), mBuckets(NULL) { - determineCapacity(minimumInitialCapacity, mLoadFactor, &mBucketCount, &mCapacity); -} - -BasicHashtableImpl::BasicHashtableImpl(const BasicHashtableImpl& other) : - mBucketSize(other.mBucketSize), mHasTrivialDestructor(other.mHasTrivialDestructor), - mCapacity(other.mCapacity), mLoadFactor(other.mLoadFactor), - mSize(other.mSize), mFilledBuckets(other.mFilledBuckets), - mBucketCount(other.mBucketCount), mBuckets(other.mBuckets) { - if (mBuckets) { - SharedBuffer::bufferFromData(mBuckets)->acquire(); - } -} - -void BasicHashtableImpl::dispose() { - if (mBuckets) { - releaseBuckets(mBuckets, mBucketCount); - } -} - -void BasicHashtableImpl::clone() { - if (mBuckets) { - void* newBuckets = allocateBuckets(mBucketCount); - copyBuckets(mBuckets, newBuckets, mBucketCount); - releaseBuckets(mBuckets, mBucketCount); - mBuckets = newBuckets; - } -} - -void BasicHashtableImpl::setTo(const BasicHashtableImpl& other) { - if (mBuckets) { - releaseBuckets(mBuckets, mBucketCount); - } - - mCapacity = other.mCapacity; - mLoadFactor = other.mLoadFactor; - mSize = other.mSize; - mFilledBuckets = other.mFilledBuckets; - mBucketCount = other.mBucketCount; - mBuckets = other.mBuckets; - - if (mBuckets) { - SharedBuffer::bufferFromData(mBuckets)->acquire(); - } -} - -void BasicHashtableImpl::clear() { - if (mBuckets) { - if (mFilledBuckets) { - SharedBuffer* sb = SharedBuffer::bufferFromData(mBuckets); - if (sb->onlyOwner()) { - destroyBuckets(mBuckets, mBucketCount); - for (size_t i = 0; i < mSize; i++) { - Bucket& bucket = bucketAt(mBuckets, i); - bucket.cookie = 0; - } - } else { - releaseBuckets(mBuckets, mBucketCount); - mBuckets = NULL; - } - mFilledBuckets = 0; - } - mSize = 0; - } -} - -ssize_t BasicHashtableImpl::next(ssize_t index) const { - if (mSize) { - while (size_t(++index) < mBucketCount) { - const Bucket& bucket = bucketAt(mBuckets, index); - if (bucket.cookie & Bucket::PRESENT) { - return index; - } - } - } - return -1; -} - -ssize_t BasicHashtableImpl::find(ssize_t index, hash_t hash, - const void* __restrict__ key) const { - if (!mSize) { - return -1; - } - - hash = trimHash(hash); - if (index < 0) { - index = chainStart(hash, mBucketCount); - - const Bucket& bucket = bucketAt(mBuckets, size_t(index)); - if (bucket.cookie & Bucket::PRESENT) { - if (compareBucketKey(bucket, key)) { - return index; - } - } else { - if (!(bucket.cookie & Bucket::COLLISION)) { - return -1; - } - } - } - - size_t inc = chainIncrement(hash, mBucketCount); - for (;;) { - index = chainSeek(index, inc, mBucketCount); - - const Bucket& bucket = bucketAt(mBuckets, size_t(index)); - if (bucket.cookie & Bucket::PRESENT) { - if ((bucket.cookie & Bucket::HASH_MASK) == hash - && compareBucketKey(bucket, key)) { - return index; - } - } - if (!(bucket.cookie & Bucket::COLLISION)) { - return -1; - } - } -} - -size_t BasicHashtableImpl::add(hash_t hash, const void* entry) { - if (!mBuckets) { - mBuckets = allocateBuckets(mBucketCount); - } else { - edit(); - } - - hash = trimHash(hash); - for (;;) { - size_t index = chainStart(hash, mBucketCount); - Bucket* bucket = &bucketAt(mBuckets, size_t(index)); - if (bucket->cookie & Bucket::PRESENT) { - size_t inc = chainIncrement(hash, mBucketCount); - do { - bucket->cookie |= Bucket::COLLISION; - index = chainSeek(index, inc, mBucketCount); - bucket = &bucketAt(mBuckets, size_t(index)); - } while (bucket->cookie & Bucket::PRESENT); - } - - uint32_t collision = bucket->cookie & Bucket::COLLISION; - if (!collision) { - if (mFilledBuckets >= mCapacity) { - rehash(mCapacity * 2, mLoadFactor); - continue; - } - mFilledBuckets += 1; - } - - bucket->cookie = collision | Bucket::PRESENT | hash; - mSize += 1; - initializeBucketEntry(*bucket, entry); - return index; - } -} - -void BasicHashtableImpl::removeAt(size_t index) { - edit(); - - Bucket& bucket = bucketAt(mBuckets, index); - bucket.cookie &= ~Bucket::PRESENT; - if (!(bucket.cookie & Bucket::COLLISION)) { - mFilledBuckets -= 1; - } - mSize -= 1; - if (!mHasTrivialDestructor) { - destroyBucketEntry(bucket); - } -} - -void BasicHashtableImpl::rehash(size_t minimumCapacity, float loadFactor) { - if (minimumCapacity < mSize) { - minimumCapacity = mSize; - } - size_t newBucketCount, newCapacity; - determineCapacity(minimumCapacity, loadFactor, &newBucketCount, &newCapacity); - - if (newBucketCount != mBucketCount || newCapacity != mCapacity) { - if (mBuckets) { - void* newBuckets; - if (mSize) { - newBuckets = allocateBuckets(newBucketCount); - for (size_t i = 0; i < mBucketCount; i++) { - const Bucket& fromBucket = bucketAt(mBuckets, i); - if (fromBucket.cookie & Bucket::PRESENT) { - hash_t hash = fromBucket.cookie & Bucket::HASH_MASK; - size_t index = chainStart(hash, newBucketCount); - Bucket* toBucket = &bucketAt(newBuckets, size_t(index)); - if (toBucket->cookie & Bucket::PRESENT) { - size_t inc = chainIncrement(hash, newBucketCount); - do { - toBucket->cookie |= Bucket::COLLISION; - index = chainSeek(index, inc, newBucketCount); - toBucket = &bucketAt(newBuckets, size_t(index)); - } while (toBucket->cookie & Bucket::PRESENT); - } - toBucket->cookie = Bucket::PRESENT | hash; - initializeBucketEntry(*toBucket, fromBucket.entry); - } - } - } else { - newBuckets = NULL; - } - releaseBuckets(mBuckets, mBucketCount); - mBuckets = newBuckets; - mFilledBuckets = mSize; - } - mBucketCount = newBucketCount; - mCapacity = newCapacity; - } - mLoadFactor = loadFactor; -} - -void* BasicHashtableImpl::allocateBuckets(size_t count) const { - size_t bytes = count * mBucketSize; - SharedBuffer* sb = SharedBuffer::alloc(bytes); - LOG_ALWAYS_FATAL_IF(!sb, "Could not allocate %u bytes for hashtable with %u buckets.", - uint32_t(bytes), uint32_t(count)); - void* buckets = sb->data(); - for (size_t i = 0; i < count; i++) { - Bucket& bucket = bucketAt(buckets, i); - bucket.cookie = 0; - } - return buckets; -} - -void BasicHashtableImpl::releaseBuckets(void* __restrict__ buckets, size_t count) const { - SharedBuffer* sb = SharedBuffer::bufferFromData(buckets); - if (sb->release(SharedBuffer::eKeepStorage) == 1) { - destroyBuckets(buckets, count); - SharedBuffer::dealloc(sb); - } -} - -void BasicHashtableImpl::destroyBuckets(void* __restrict__ buckets, size_t count) const { - if (!mHasTrivialDestructor) { - for (size_t i = 0; i < count; i++) { - Bucket& bucket = bucketAt(buckets, i); - if (bucket.cookie & Bucket::PRESENT) { - destroyBucketEntry(bucket); - } - } - } -} - -void BasicHashtableImpl::copyBuckets(const void* __restrict__ fromBuckets, - void* __restrict__ toBuckets, size_t count) const { - for (size_t i = 0; i < count; i++) { - const Bucket& fromBucket = bucketAt(fromBuckets, i); - Bucket& toBucket = bucketAt(toBuckets, i); - toBucket.cookie = fromBucket.cookie; - if (fromBucket.cookie & Bucket::PRESENT) { - initializeBucketEntry(toBucket, fromBucket.entry); - } - } -} - -// Table of 31-bit primes where each prime is no less than twice as large -// as the previous one. Generated by "primes.py". -static size_t PRIMES[] = { - 5, - 11, - 23, - 47, - 97, - 197, - 397, - 797, - 1597, - 3203, - 6421, - 12853, - 25717, - 51437, - 102877, - 205759, - 411527, - 823117, - 1646237, - 3292489, - 6584983, - 13169977, - 26339969, - 52679969, - 105359939, - 210719881, - 421439783, - 842879579, - 1685759167, - 0, -}; - -void BasicHashtableImpl::determineCapacity(size_t minimumCapacity, float loadFactor, - size_t* __restrict__ outBucketCount, size_t* __restrict__ outCapacity) { - LOG_ALWAYS_FATAL_IF(loadFactor <= 0.0f || loadFactor > 1.0f, - "Invalid load factor %0.3f. Must be in the range (0, 1].", loadFactor); - - size_t count = ceilf(minimumCapacity / loadFactor) + 1; - size_t i = 0; - while (count > PRIMES[i] && i < NELEM(PRIMES)) { - i++; - } - count = PRIMES[i]; - LOG_ALWAYS_FATAL_IF(!count, "Could not determine required number of buckets for " - "hashtable with minimum capacity %u and load factor %0.3f.", - uint32_t(minimumCapacity), loadFactor); - *outBucketCount = count; - *outCapacity = ceilf((count - 1) * loadFactor); -} - -}; // namespace android diff --git a/libs/utils/BlobCache.cpp b/libs/utils/BlobCache.cpp deleted file mode 100644 index be398ee..0000000 --- a/libs/utils/BlobCache.cpp +++ /dev/null @@ -1,378 +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 <stdlib.h> -#include <string.h> - -#include <utils/BlobCache.h> -#include <utils/Errors.h> -#include <utils/Log.h> - -namespace android { - -// BlobCache::Header::mMagicNumber value -static const uint32_t blobCacheMagic = '_Bb$'; - -// BlobCache::Header::mBlobCacheVersion value -static const uint32_t blobCacheVersion = 1; - -// 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", 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: %d (limit: %d)", - keySize, mMaxKeySize); - return; - } - if (mMaxValueSize < valueSize) { - ALOGV("set: not caching because the value is too large: %d (limit: %d)", - valueSize, mMaxValueSize); - return; - } - if (mMaxTotalSize < keySize + valueSize) { - ALOGV("set: not caching because the combined key/value size is too " - "large: %d (limit: %d)", 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: %d " - "(limit: %d)", - keySize + valueSize, mMaxTotalSize); - break; - } - } - mCacheEntries.add(CacheEntry(keyBlob, valueBlob)); - mTotalSize = newTotalSize; - ALOGV("set: created new cache entry with %d byte key and %d 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: %d (limit: %d)", - keySize + valueSize, mMaxTotalSize); - break; - } - } - mCacheEntries.editItemAt(index).setValue(valueBlob); - mTotalSize = newTotalSize; - ALOGV("set: updated existing cache entry with %d byte key and %d 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: %d (limit %d)", - 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 %d", 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 %d bytes to caller's buffer", valueBlobSize); - memcpy(value, valueBlob->getData(), valueBlobSize); - } else { - ALOGV("get: caller's buffer is too small for value: %d (needs %d)", - valueSize, valueBlobSize); - } - return valueBlobSize; -} - -static inline size_t align4(size_t size) { - return (size + 3) & ~3; -} - -size_t BlobCache::getFlattenedSize() const { - size_t size = sizeof(Header); - 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(size); - size += sizeof(EntryHeader) + keyBlob->getSize() + - valueBlob->getSize(); - } - return size; -} - -size_t BlobCache::getFdCount() const { - return 0; -} - -status_t BlobCache::flatten(void* buffer, size_t size, int fds[], size_t count) - const { - if (count != 0) { - ALOGE("flatten: nonzero fd count: %zu", count); - return BAD_VALUE; - } - - // 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(); - - // Write cache entries - uint8_t* byteBuffer = reinterpret_cast<uint8_t*>(buffer); - off_t byteOffset = align4(sizeof(Header)); - 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; - if (byteOffset + entrySize > 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); - - byteOffset += align4(entrySize); - } - - return OK; -} - -status_t BlobCache::unflatten(void const* buffer, size_t size, int fds[], - size_t count) { - // All errors should result in the BlobCache being in an empty state. - mCacheEntries.clear(); - - if (count != 0) { - ALOGE("unflatten: nonzero fd count: %zu", count); - return BAD_VALUE; - } - - // 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: %d", header->mMagicNumber); - return BAD_VALUE; - } - if (header->mBlobCacheVersion != blobCacheVersion || - header->mDeviceVersion != blobCacheDeviceVersion) { - // 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)); - 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; - - if (byteOffset + entrySize > 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 += align4(entrySize); - } - - 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/libs/utils/BufferedTextOutput.cpp b/libs/utils/BufferedTextOutput.cpp deleted file mode 100644 index 989662e..0000000 --- a/libs/utils/BufferedTextOutput.cpp +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright (C) 2006 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 <utils/BufferedTextOutput.h> - -#include <utils/Atomic.h> -#include <utils/Debug.h> -#include <utils/Log.h> -#include <utils/RefBase.h> -#include <utils/Vector.h> -#include <cutils/threads.h> - -#include <private/utils/Static.h> - -#include <stdio.h> -#include <stdlib.h> - -// --------------------------------------------------------------------------- - -namespace android { - -struct BufferedTextOutput::BufferState : public RefBase -{ - BufferState(int32_t _seq) - : seq(_seq) - , buffer(NULL) - , bufferPos(0) - , bufferSize(0) - , atFront(true) - , indent(0) - , bundle(0) { - } - ~BufferState() { - free(buffer); - } - - status_t append(const char* txt, size_t len) { - if ((len+bufferPos) > bufferSize) { - void* b = realloc(buffer, ((len+bufferPos)*3)/2); - if (!b) return NO_MEMORY; - buffer = (char*)b; - } - memcpy(buffer+bufferPos, txt, len); - bufferPos += len; - return NO_ERROR; - } - - void restart() { - bufferPos = 0; - atFront = true; - if (bufferSize > 256) { - void* b = realloc(buffer, 256); - if (b) { - buffer = (char*)b; - bufferSize = 256; - } - } - } - - const int32_t seq; - char* buffer; - size_t bufferPos; - size_t bufferSize; - bool atFront; - int32_t indent; - int32_t bundle; -}; - -struct BufferedTextOutput::ThreadState -{ - Vector<sp<BufferedTextOutput::BufferState> > states; -}; - -static mutex_t gMutex; - -static thread_store_t tls; - -BufferedTextOutput::ThreadState* BufferedTextOutput::getThreadState() -{ - ThreadState* ts = (ThreadState*) thread_store_get( &tls ); - if (ts) return ts; - ts = new ThreadState; - thread_store_set( &tls, ts, threadDestructor ); - return ts; -} - -void BufferedTextOutput::threadDestructor(void *st) -{ - delete ((ThreadState*)st); -} - -static volatile int32_t gSequence = 0; - -static volatile int32_t gFreeBufferIndex = -1; - -static int32_t allocBufferIndex() -{ - int32_t res = -1; - - mutex_lock(&gMutex); - - if (gFreeBufferIndex >= 0) { - res = gFreeBufferIndex; - gFreeBufferIndex = gTextBuffers[res]; - gTextBuffers.editItemAt(res) = -1; - - } else { - res = gTextBuffers.size(); - gTextBuffers.add(-1); - } - - mutex_unlock(&gMutex); - - return res; -} - -static void freeBufferIndex(int32_t idx) -{ - mutex_lock(&gMutex); - gTextBuffers.editItemAt(idx) = gFreeBufferIndex; - gFreeBufferIndex = idx; - mutex_unlock(&gMutex); -} - -// --------------------------------------------------------------------------- - -BufferedTextOutput::BufferedTextOutput(uint32_t flags) - : mFlags(flags) - , mSeq(android_atomic_inc(&gSequence)) - , mIndex(allocBufferIndex()) -{ - mGlobalState = new BufferState(mSeq); - if (mGlobalState) mGlobalState->incStrong(this); -} - -BufferedTextOutput::~BufferedTextOutput() -{ - if (mGlobalState) mGlobalState->decStrong(this); - freeBufferIndex(mIndex); -} - -status_t BufferedTextOutput::print(const char* txt, size_t len) -{ - //printf("BufferedTextOutput: printing %d\n", len); - - AutoMutex _l(mLock); - BufferState* b = getBuffer(); - - const char* const end = txt+len; - - status_t err; - - while (txt < end) { - // Find the next line. - const char* first = txt; - while (txt < end && *txt != '\n') txt++; - - // Include this and all following empty lines. - while (txt < end && *txt == '\n') txt++; - - // Special cases for first data on a line. - if (b->atFront) { - if (b->indent > 0) { - // If this is the start of a line, add the indent. - const char* prefix = stringForIndent(b->indent); - err = b->append(prefix, strlen(prefix)); - if (err != NO_ERROR) return err; - - } else if (*(txt-1) == '\n' && !b->bundle) { - // Fast path: if we are not indenting or bundling, and - // have been given one or more complete lines, just write - // them out without going through the buffer. - - // Slurp up all of the lines. - const char* lastLine = txt+1; - while (txt < end) { - if (*txt++ == '\n') lastLine = txt; - } - struct iovec vec; - vec.iov_base = (void*)first; - vec.iov_len = lastLine-first; - //printf("Writing %d bytes of data!\n", vec.iov_len); - writeLines(vec, 1); - txt = lastLine; - continue; - } - } - - // Append the new text to the buffer. - err = b->append(first, txt-first); - if (err != NO_ERROR) return err; - b->atFront = *(txt-1) == '\n'; - - // If we have finished a line and are not bundling, write - // it out. - //printf("Buffer is now %d bytes\n", b->bufferPos); - if (b->atFront && !b->bundle) { - struct iovec vec; - vec.iov_base = b->buffer; - vec.iov_len = b->bufferPos; - //printf("Writing %d bytes of data!\n", vec.iov_len); - writeLines(vec, 1); - b->restart(); - } - } - - return NO_ERROR; -} - -void BufferedTextOutput::moveIndent(int delta) -{ - AutoMutex _l(mLock); - BufferState* b = getBuffer(); - b->indent += delta; - if (b->indent < 0) b->indent = 0; -} - -void BufferedTextOutput::pushBundle() -{ - AutoMutex _l(mLock); - BufferState* b = getBuffer(); - b->bundle++; -} - -void BufferedTextOutput::popBundle() -{ - AutoMutex _l(mLock); - BufferState* b = getBuffer(); - b->bundle--; - LOG_FATAL_IF(b->bundle < 0, - "TextOutput::popBundle() called more times than pushBundle()"); - if (b->bundle < 0) b->bundle = 0; - - if (b->bundle == 0) { - // Last bundle, write out data if it is complete. If it is not - // complete, don't write until the last line is done... this may - // or may not be the write thing to do, but it's the easiest. - if (b->bufferPos > 0 && b->atFront) { - struct iovec vec; - vec.iov_base = b->buffer; - vec.iov_len = b->bufferPos; - writeLines(vec, 1); - b->restart(); - } - } -} - -BufferedTextOutput::BufferState* BufferedTextOutput::getBuffer() const -{ - if ((mFlags&MULTITHREADED) != 0) { - ThreadState* ts = getThreadState(); - if (ts) { - while (ts->states.size() <= (size_t)mIndex) ts->states.add(NULL); - BufferState* bs = ts->states[mIndex].get(); - if (bs != NULL && bs->seq == mSeq) return bs; - - ts->states.editItemAt(mIndex) = new BufferState(mIndex); - bs = ts->states[mIndex].get(); - if (bs != NULL) return bs; - } - } - - return mGlobalState; -} - -}; // namespace android diff --git a/libs/utils/CallStack.cpp b/libs/utils/CallStack.cpp deleted file mode 100644 index 18fd84f..0000000 --- a/libs/utils/CallStack.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "CallStack" - -#include <string.h> - -#include <utils/Log.h> -#include <utils/Errors.h> -#include <utils/CallStack.h> -#include <corkscrew/backtrace.h> - -/*****************************************************************************/ -namespace android { - -CallStack::CallStack() : - mCount(0) { -} - -CallStack::CallStack(const CallStack& rhs) : - mCount(rhs.mCount) { - if (mCount) { - memcpy(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t)); - } -} - -CallStack::~CallStack() { -} - -CallStack& CallStack::operator = (const CallStack& rhs) { - mCount = rhs.mCount; - if (mCount) { - memcpy(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t)); - } - return *this; -} - -bool CallStack::operator == (const CallStack& rhs) const { - if (mCount != rhs.mCount) - return false; - return !mCount || memcmp(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t)) == 0; -} - -bool CallStack::operator != (const CallStack& rhs) const { - return !operator == (rhs); -} - -bool CallStack::operator < (const CallStack& rhs) const { - if (mCount != rhs.mCount) - return mCount < rhs.mCount; - return memcmp(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t)) < 0; -} - -bool CallStack::operator >= (const CallStack& rhs) const { - return !operator < (rhs); -} - -bool CallStack::operator > (const CallStack& rhs) const { - if (mCount != rhs.mCount) - return mCount > rhs.mCount; - return memcmp(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t)) > 0; -} - -bool CallStack::operator <= (const CallStack& rhs) const { - return !operator > (rhs); -} - -const void* CallStack::operator [] (int index) const { - if (index >= int(mCount)) - return 0; - return reinterpret_cast<const void*>(mStack[index].absolute_pc); -} - -void CallStack::clear() { - mCount = 0; -} - -void CallStack::update(int32_t ignoreDepth, int32_t maxDepth) { - if (maxDepth > MAX_DEPTH) { - maxDepth = MAX_DEPTH; - } - ssize_t count = unwind_backtrace(mStack, ignoreDepth + 1, maxDepth); - mCount = count > 0 ? count : 0; -} - -void CallStack::dump(const char* prefix) const { - backtrace_symbol_t symbols[mCount]; - - get_backtrace_symbols(mStack, mCount, symbols); - for (size_t i = 0; i < mCount; i++) { - char line[MAX_BACKTRACE_LINE_LENGTH]; - format_backtrace_line(i, &mStack[i], &symbols[i], - line, MAX_BACKTRACE_LINE_LENGTH); - ALOGD("%s%s", prefix, line); - } - free_backtrace_symbols(symbols, mCount); -} - -String8 CallStack::toString(const char* prefix) const { - String8 str; - backtrace_symbol_t symbols[mCount]; - - get_backtrace_symbols(mStack, mCount, symbols); - for (size_t i = 0; i < mCount; i++) { - char line[MAX_BACKTRACE_LINE_LENGTH]; - format_backtrace_line(i, &mStack[i], &symbols[i], - line, MAX_BACKTRACE_LINE_LENGTH); - str.append(prefix); - str.append(line); - str.append("\n"); - } - free_backtrace_symbols(symbols, mCount); - return str; -} - -}; // namespace android diff --git a/libs/utils/Debug.cpp b/libs/utils/Debug.cpp deleted file mode 100644 index e8ac983..0000000 --- a/libs/utils/Debug.cpp +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright (C) 2005 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 <utils/Debug.h> - -#include <utils/misc.h> - -#include <stdio.h> -#include <stdlib.h> -#include <ctype.h> - -namespace android { - -// --------------------------------------------------------------------- - -static const char indentStr[] = -" " -" "; - -const char* stringForIndent(int32_t indentLevel) -{ - ssize_t off = sizeof(indentStr)-1-(indentLevel*2); - return indentStr + (off < 0 ? 0 : off); -} - -// --------------------------------------------------------------------- - -static void defaultPrintFunc(void* cookie, const char* txt) -{ - printf("%s", txt); -} - -// --------------------------------------------------------------------- - -static inline int isident(int c) -{ - return isalnum(c) || c == '_'; -} - -static inline bool isasciitype(char c) -{ - if( c >= ' ' && c < 127 && c != '\'' && c != '\\' ) return true; - return false; -} - -static inline char makehexdigit(uint32_t val) -{ - return "0123456789abcdef"[val&0xF]; -} - -static char* appendhexnum(uint32_t val, char* out) -{ - for( int32_t i=28; i>=0; i-=4 ) { - *out++ = makehexdigit( val>>i ); - } - *out = 0; - return out; -} - -static inline char makeupperhexdigit(uint32_t val) -{ - return "0123456789ABCDEF"[val&0xF]; -} - -static char* appendupperhexnum(uint32_t val, char* out) -{ - for( int32_t i=28; i>=0; i-=4 ) { - *out++ = makeupperhexdigit( val>>i ); - } - *out = 0; - return out; -} - -static char* appendcharornum(char c, char* out, bool skipzero = true) -{ - if (skipzero && c == 0) return out; - - if (isasciitype(c)) { - *out++ = c; - return out; - } - - *out++ = '\\'; - *out++ = 'x'; - *out++ = makehexdigit(c>>4); - *out++ = makehexdigit(c); - return out; -} - -static char* typetostring(uint32_t type, char* out, - bool fullContext = true, - bool strict = false) -{ - char* pos = out; - char c[4]; - c[0] = (char)((type>>24)&0xFF); - c[1] = (char)((type>>16)&0xFF); - c[2] = (char)((type>>8)&0xFF); - c[3] = (char)(type&0xFF); - bool valid; - if( !strict ) { - // now even less strict! - // valid = isasciitype(c[3]); - valid = true; - int32_t i = 0; - bool zero = true; - while (valid && i<3) { - if (c[i] == 0) { - if (!zero) valid = false; - } else { - zero = false; - //if (!isasciitype(c[i])) valid = false; - } - i++; - } - // if all zeros, not a valid type code. - if (zero) valid = false; - } else { - valid = isident(c[3]) ? true : false; - int32_t i = 0; - bool zero = true; - while (valid && i<3) { - if (c[i] == 0) { - if (!zero) valid = false; - } else { - zero = false; - if (!isident(c[i])) valid = false; - } - i++; - } - } - if( valid && (!fullContext || c[0] != '0' || c[1] != 'x') ) { - if( fullContext ) *pos++ = '\''; - pos = appendcharornum(c[0], pos); - pos = appendcharornum(c[1], pos); - pos = appendcharornum(c[2], pos); - pos = appendcharornum(c[3], pos); - if( fullContext ) *pos++ = '\''; - *pos = 0; - return pos; - } - - if( fullContext ) { - *pos++ = '0'; - *pos++ = 'x'; - } - return appendhexnum(type, pos); -} - -void printTypeCode(uint32_t typeCode, debugPrintFunc func, void* cookie) -{ - char buffer[32]; - char* end = typetostring(typeCode, buffer); - *end = 0; - func ? (*func)(cookie, buffer) : defaultPrintFunc(cookie, buffer); -} - -void printHexData(int32_t indent, const void *buf, size_t length, - size_t bytesPerLine, int32_t singleLineBytesCutoff, - size_t alignment, bool cStyle, - debugPrintFunc func, void* cookie) -{ - if (alignment == 0) { - if (bytesPerLine >= 16) alignment = 4; - else if (bytesPerLine >= 8) alignment = 2; - else alignment = 1; - } - if (func == NULL) func = defaultPrintFunc; - - size_t offset; - - unsigned char *pos = (unsigned char *)buf; - - if (pos == NULL) { - if (singleLineBytesCutoff < 0) func(cookie, "\n"); - func(cookie, "(NULL)"); - return; - } - - if (length == 0) { - if (singleLineBytesCutoff < 0) func(cookie, "\n"); - func(cookie, "(empty)"); - return; - } - - if ((int32_t)length < 0) { - if (singleLineBytesCutoff < 0) func(cookie, "\n"); - char buf[64]; - sprintf(buf, "(bad length: %zu)", length); - func(cookie, buf); - return; - } - - char buffer[256]; - static const size_t maxBytesPerLine = (sizeof(buffer)-1-11-4)/(3+1); - - if (bytesPerLine > maxBytesPerLine) bytesPerLine = maxBytesPerLine; - - const bool oneLine = (int32_t)length <= singleLineBytesCutoff; - bool newLine = false; - if (cStyle) { - indent++; - func(cookie, "{\n"); - newLine = true; - } else if (!oneLine) { - func(cookie, "\n"); - newLine = true; - } - - for (offset = 0; ; offset += bytesPerLine, pos += bytesPerLine) { - long remain = length; - - char* c = buffer; - if (!oneLine && !cStyle) { - sprintf(c, "0x%08x: ", (int)offset); - c += 12; - } - - size_t index; - size_t word; - - for (word = 0; word < bytesPerLine; ) { - -#ifdef HAVE_LITTLE_ENDIAN - const size_t startIndex = word+(alignment-(alignment?1:0)); - const ssize_t dir = -1; -#else - const size_t startIndex = word; - const ssize_t dir = 1; -#endif - - for (index = 0; index < alignment || (alignment == 0 && index < bytesPerLine); index++) { - - if (!cStyle) { - if (index == 0 && word > 0 && alignment > 0) { - *c++ = ' '; - } - - if (remain-- > 0) { - const unsigned char val = *(pos+startIndex+(index*dir)); - *c++ = makehexdigit(val>>4); - *c++ = makehexdigit(val); - } else if (!oneLine) { - *c++ = ' '; - *c++ = ' '; - } - } else { - if (remain > 0) { - if (index == 0 && word > 0) { - *c++ = ','; - *c++ = ' '; - } - if (index == 0) { - *c++ = '0'; - *c++ = 'x'; - } - const unsigned char val = *(pos+startIndex+(index*dir)); - *c++ = makehexdigit(val>>4); - *c++ = makehexdigit(val); - remain--; - } - } - } - - word += index; - } - - if (!cStyle) { - remain = length; - *c++ = ' '; - *c++ = '\''; - for (index = 0; index < bytesPerLine; index++) { - - if (remain-- > 0) { - const unsigned char val = pos[index]; - *c++ = (val >= ' ' && val < 127) ? val : '.'; - } else if (!oneLine) { - *c++ = ' '; - } - } - - *c++ = '\''; - if (length > bytesPerLine) *c++ = '\n'; - } else { - if (remain > 0) *c++ = ','; - *c++ = '\n'; - } - - if (newLine && indent) func(cookie, stringForIndent(indent)); - *c = 0; - func(cookie, buffer); - newLine = true; - - if (length <= bytesPerLine) break; - length -= bytesPerLine; - } - - if (cStyle) { - if (indent > 0) func(cookie, stringForIndent(indent-1)); - func(cookie, "};"); - } -} - -}; // namespace android - diff --git a/libs/utils/FileMap.cpp b/libs/utils/FileMap.cpp deleted file mode 100644 index 9ce370e..0000000 --- a/libs/utils/FileMap.cpp +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (C) 2006 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. - */ - -// -// Shared file mapping class. -// - -#define LOG_TAG "filemap" - -#include <utils/FileMap.h> -#include <utils/Log.h> - -#include <stdio.h> -#include <stdlib.h> - -#ifdef HAVE_POSIX_FILEMAP -#include <sys/mman.h> -#endif - -#include <string.h> -#include <memory.h> -#include <errno.h> -#include <assert.h> - -using namespace android; - -/*static*/ long FileMap::mPageSize = -1; - - -/* - * Constructor. Create an empty object. - */ -FileMap::FileMap(void) - : mRefCount(1), mFileName(NULL), mBasePtr(NULL), mBaseLength(0), - mDataPtr(NULL), mDataLength(0) -{ -} - -/* - * Destructor. - */ -FileMap::~FileMap(void) -{ - assert(mRefCount == 0); - - //printf("+++ removing FileMap %p %u\n", mDataPtr, mDataLength); - - mRefCount = -100; // help catch double-free - if (mFileName != NULL) { - free(mFileName); - } -#ifdef HAVE_POSIX_FILEMAP - if (mBasePtr && munmap(mBasePtr, mBaseLength) != 0) { - ALOGD("munmap(%p, %d) failed\n", mBasePtr, (int) mBaseLength); - } -#endif -#ifdef HAVE_WIN32_FILEMAP - if (mBasePtr && UnmapViewOfFile(mBasePtr) == 0) { - ALOGD("UnmapViewOfFile(%p) failed, error = %ld\n", mBasePtr, - GetLastError() ); - } - if (mFileMapping != INVALID_HANDLE_VALUE) { - CloseHandle(mFileMapping); - } - CloseHandle(mFileHandle); -#endif -} - - -/* - * Create a new mapping on an open file. - * - * Closing the file descriptor does not unmap the pages, so we don't - * claim ownership of the fd. - * - * Returns "false" on failure. - */ -bool FileMap::create(const char* origFileName, int fd, off64_t offset, size_t length, - bool readOnly) -{ -#ifdef HAVE_WIN32_FILEMAP - int adjust; - off64_t adjOffset; - size_t adjLength; - - if (mPageSize == -1) { - SYSTEM_INFO si; - - GetSystemInfo( &si ); - mPageSize = si.dwAllocationGranularity; - } - - DWORD protect = readOnly ? PAGE_READONLY : PAGE_READWRITE; - - mFileHandle = (HANDLE) _get_osfhandle(fd); - mFileMapping = CreateFileMapping( mFileHandle, NULL, protect, 0, 0, NULL); - if (mFileMapping == NULL) { - ALOGE("CreateFileMapping(%p, %lx) failed with error %ld\n", - mFileHandle, protect, GetLastError() ); - return false; - } - - adjust = offset % mPageSize; - adjOffset = offset - adjust; - adjLength = length + adjust; - - mBasePtr = MapViewOfFile( mFileMapping, - readOnly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS, - 0, - (DWORD)(adjOffset), - adjLength ); - if (mBasePtr == NULL) { - ALOGE("MapViewOfFile(%ld, %ld) failed with error %ld\n", - adjOffset, adjLength, GetLastError() ); - CloseHandle(mFileMapping); - mFileMapping = INVALID_HANDLE_VALUE; - return false; - } -#endif -#ifdef HAVE_POSIX_FILEMAP - int prot, flags, adjust; - off64_t adjOffset; - size_t adjLength; - - void* ptr; - - assert(mRefCount == 1); - assert(fd >= 0); - assert(offset >= 0); - assert(length > 0); - - /* init on first use */ - if (mPageSize == -1) { -#if NOT_USING_KLIBC - mPageSize = sysconf(_SC_PAGESIZE); - if (mPageSize == -1) { - ALOGE("could not get _SC_PAGESIZE\n"); - return false; - } -#else - /* this holds for Linux, Darwin, Cygwin, and doesn't pain the ARM */ - mPageSize = 4096; -#endif - } - - adjust = offset % mPageSize; -try_again: - adjOffset = offset - adjust; - adjLength = length + adjust; - - flags = MAP_SHARED; - prot = PROT_READ; - if (!readOnly) - prot |= PROT_WRITE; - - ptr = mmap(NULL, adjLength, prot, flags, fd, adjOffset); - if (ptr == MAP_FAILED) { - // Cygwin does not seem to like file mapping files from an offset. - // So if we fail, try again with offset zero - if (adjOffset > 0) { - adjust = offset; - goto try_again; - } - - ALOGE("mmap(%ld,%ld) failed: %s\n", - (long) adjOffset, (long) adjLength, strerror(errno)); - return false; - } - mBasePtr = ptr; -#endif /* HAVE_POSIX_FILEMAP */ - - mFileName = origFileName != NULL ? strdup(origFileName) : NULL; - mBaseLength = adjLength; - mDataOffset = offset; - mDataPtr = (char*) mBasePtr + adjust; - mDataLength = length; - - assert(mBasePtr != NULL); - - ALOGV("MAP: base %p/%d data %p/%d\n", - mBasePtr, (int) mBaseLength, mDataPtr, (int) mDataLength); - - return true; -} - -/* - * Provide guidance to the system. - */ -int FileMap::advise(MapAdvice advice) -{ -#if HAVE_MADVISE - int cc, sysAdvice; - - switch (advice) { - case NORMAL: sysAdvice = MADV_NORMAL; break; - case RANDOM: sysAdvice = MADV_RANDOM; break; - case SEQUENTIAL: sysAdvice = MADV_SEQUENTIAL; break; - case WILLNEED: sysAdvice = MADV_WILLNEED; break; - case DONTNEED: sysAdvice = MADV_DONTNEED; break; - default: - assert(false); - return -1; - } - - cc = madvise(mBasePtr, mBaseLength, sysAdvice); - if (cc != 0) - ALOGW("madvise(%d) failed: %s\n", sysAdvice, strerror(errno)); - return cc; -#else - return -1; -#endif // HAVE_MADVISE -} diff --git a/libs/utils/Flattenable.cpp b/libs/utils/Flattenable.cpp deleted file mode 100644 index 1f2ffaa..0000000 --- a/libs/utils/Flattenable.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2006 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 <utils/Flattenable.h> - -namespace android { - -Flattenable::~Flattenable() { -} - -}; // namespace android diff --git a/libs/utils/LinearTransform.cpp b/libs/utils/LinearTransform.cpp deleted file mode 100644 index d752415..0000000 --- a/libs/utils/LinearTransform.cpp +++ /dev/null @@ -1,262 +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> - -namespace android { - -template<class T> static inline T ABS(T x) { return (x < 0) ? -x : x; } - -// Static math methods involving linear transformations -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; -} - -static bool linear_transform_s64_to_s64( - int64_t val, - int64_t basis1, - int32_t N, - uint32_t D, - 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, - 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; - 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, - 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_denom, - a_to_b_numer, - 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); - -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/libs/utils/Looper.cpp b/libs/utils/Looper.cpp deleted file mode 100644 index d1aa664..0000000 --- a/libs/utils/Looper.cpp +++ /dev/null @@ -1,744 +0,0 @@ -// -// Copyright 2010 The Android Open Source Project -// -// A looper implementation based on epoll(). -// -#define LOG_TAG "Looper" - -//#define LOG_NDEBUG 0 - -// Debugs poll and wake interactions. -#define DEBUG_POLL_AND_WAKE 0 - -// Debugs callback registration and invocation. -#define DEBUG_CALLBACKS 0 - -#include <cutils/log.h> -#include <utils/Looper.h> -#include <utils/Timers.h> - -#include <unistd.h> -#include <fcntl.h> -#include <limits.h> - - -namespace android { - -// --- WeakMessageHandler --- - -WeakMessageHandler::WeakMessageHandler(const wp<MessageHandler>& handler) : - mHandler(handler) { -} - -void WeakMessageHandler::handleMessage(const Message& message) { - sp<MessageHandler> handler = mHandler.promote(); - if (handler != NULL) { - handler->handleMessage(message); - } -} - - -// --- Looper --- - -#ifdef LOOPER_USES_EPOLL -// Hint for number of file descriptors to be associated with the epoll instance. -static const int EPOLL_SIZE_HINT = 8; - -// Maximum number of file descriptors for which to retrieve poll events each iteration. -static const int EPOLL_MAX_EVENTS = 16; -#endif - -static pthread_once_t gTLSOnce = PTHREAD_ONCE_INIT; -static pthread_key_t gTLSKey = 0; - -Looper::Looper(bool allowNonCallbacks) : - mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false), - mResponseIndex(0), mNextMessageUptime(LLONG_MAX) { - int wakeFds[2]; - int result = pipe(wakeFds); - LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno); - - mWakeReadPipeFd = wakeFds[0]; - mWakeWritePipeFd = wakeFds[1]; - - result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK); - LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d", - errno); - - result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK); - LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d", - errno); - -#ifdef LOOPER_USES_EPOLL - // Allocate the epoll instance and register the wake pipe. - mEpollFd = epoll_create(EPOLL_SIZE_HINT); - LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno); - - struct epoll_event eventItem; - memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union - eventItem.events = EPOLLIN; - eventItem.data.fd = mWakeReadPipeFd; - result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem); - LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d", - errno); -#else - // Add the wake pipe to the head of the request list with a null callback. - struct pollfd requestedFd; - requestedFd.fd = mWakeReadPipeFd; - requestedFd.events = POLLIN; - mRequestedFds.push(requestedFd); - - Request request; - request.fd = mWakeReadPipeFd; - request.callback = NULL; - request.ident = 0; - request.data = NULL; - mRequests.push(request); - - mPolling = false; - mWaiters = 0; -#endif - -#ifdef LOOPER_STATISTICS - mPendingWakeTime = -1; - mPendingWakeCount = 0; - mSampledWakeCycles = 0; - mSampledWakeCountSum = 0; - mSampledWakeLatencySum = 0; - - mSampledPolls = 0; - mSampledZeroPollCount = 0; - mSampledZeroPollLatencySum = 0; - mSampledTimeoutPollCount = 0; - mSampledTimeoutPollLatencySum = 0; -#endif -} - -Looper::~Looper() { - close(mWakeReadPipeFd); - close(mWakeWritePipeFd); -#ifdef LOOPER_USES_EPOLL - close(mEpollFd); -#endif -} - -void Looper::initTLSKey() { - int result = pthread_key_create(& gTLSKey, threadDestructor); - LOG_ALWAYS_FATAL_IF(result != 0, "Could not allocate TLS key."); -} - -void Looper::threadDestructor(void *st) { - Looper* const self = static_cast<Looper*>(st); - if (self != NULL) { - self->decStrong((void*)threadDestructor); - } -} - -void Looper::setForThread(const sp<Looper>& looper) { - sp<Looper> old = getForThread(); // also has side-effect of initializing TLS - - if (looper != NULL) { - looper->incStrong((void*)threadDestructor); - } - - pthread_setspecific(gTLSKey, looper.get()); - - if (old != NULL) { - old->decStrong((void*)threadDestructor); - } -} - -sp<Looper> Looper::getForThread() { - int result = pthread_once(& gTLSOnce, initTLSKey); - LOG_ALWAYS_FATAL_IF(result != 0, "pthread_once failed"); - - return (Looper*)pthread_getspecific(gTLSKey); -} - -sp<Looper> Looper::prepare(int opts) { - bool allowNonCallbacks = opts & ALOOPER_PREPARE_ALLOW_NON_CALLBACKS; - sp<Looper> looper = Looper::getForThread(); - if (looper == NULL) { - looper = new Looper(allowNonCallbacks); - Looper::setForThread(looper); - } - if (looper->getAllowNonCallbacks() != allowNonCallbacks) { - ALOGW("Looper already prepared for this thread with a different value for the " - "ALOOPER_PREPARE_ALLOW_NON_CALLBACKS option."); - } - return looper; -} - -bool Looper::getAllowNonCallbacks() const { - return mAllowNonCallbacks; -} - -int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) { - int result = 0; - for (;;) { - while (mResponseIndex < mResponses.size()) { - const Response& response = mResponses.itemAt(mResponseIndex++); - ALooper_callbackFunc callback = response.request.callback; - if (!callback) { - int ident = response.request.ident; - int fd = response.request.fd; - int events = response.events; - void* data = response.request.data; -#if DEBUG_POLL_AND_WAKE - ALOGD("%p ~ pollOnce - returning signalled identifier %d: " - "fd=%d, events=0x%x, data=%p", - this, ident, fd, events, data); -#endif - if (outFd != NULL) *outFd = fd; - if (outEvents != NULL) *outEvents = events; - if (outData != NULL) *outData = data; - return ident; - } - } - - if (result != 0) { -#if DEBUG_POLL_AND_WAKE - ALOGD("%p ~ pollOnce - returning result %d", this, result); -#endif - if (outFd != NULL) *outFd = 0; - if (outEvents != NULL) *outEvents = NULL; - if (outData != NULL) *outData = NULL; - return result; - } - - result = pollInner(timeoutMillis); - } -} - -int Looper::pollInner(int timeoutMillis) { -#if DEBUG_POLL_AND_WAKE - ALOGD("%p ~ pollOnce - waiting: timeoutMillis=%d", this, timeoutMillis); -#endif - - // Adjust the timeout based on when the next message is due. - if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime); - if (messageTimeoutMillis >= 0 - && (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) { - timeoutMillis = messageTimeoutMillis; - } -#if DEBUG_POLL_AND_WAKE - ALOGD("%p ~ pollOnce - next message in %lldns, adjusted timeout: timeoutMillis=%d", - this, mNextMessageUptime - now, timeoutMillis); -#endif - } - - // Poll. - int result = ALOOPER_POLL_WAKE; - mResponses.clear(); - mResponseIndex = 0; - -#ifdef LOOPER_STATISTICS - nsecs_t pollStartTime = systemTime(SYSTEM_TIME_MONOTONIC); -#endif - -#ifdef LOOPER_USES_EPOLL - struct epoll_event eventItems[EPOLL_MAX_EVENTS]; - int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis); -#else - // Wait for wakeAndLock() waiters to run then set mPolling to true. - mLock.lock(); - while (mWaiters != 0) { - mResume.wait(mLock); - } - mPolling = true; - mLock.unlock(); - - size_t requestedCount = mRequestedFds.size(); - int eventCount = poll(mRequestedFds.editArray(), requestedCount, timeoutMillis); -#endif - - // Acquire lock. - mLock.lock(); - - // Check for poll error. - if (eventCount < 0) { - if (errno == EINTR) { - goto Done; - } - ALOGW("Poll failed with an unexpected error, errno=%d", errno); - result = ALOOPER_POLL_ERROR; - goto Done; - } - - // Check for poll timeout. - if (eventCount == 0) { -#if DEBUG_POLL_AND_WAKE - ALOGD("%p ~ pollOnce - timeout", this); -#endif - result = ALOOPER_POLL_TIMEOUT; - goto Done; - } - - // Handle all events. -#if DEBUG_POLL_AND_WAKE - ALOGD("%p ~ pollOnce - handling events from %d fds", this, eventCount); -#endif - -#ifdef LOOPER_USES_EPOLL - for (int i = 0; i < eventCount; i++) { - int fd = eventItems[i].data.fd; - uint32_t epollEvents = eventItems[i].events; - if (fd == mWakeReadPipeFd) { - if (epollEvents & EPOLLIN) { - awoken(); - } else { - ALOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents); - } - } else { - ssize_t requestIndex = mRequests.indexOfKey(fd); - if (requestIndex >= 0) { - int events = 0; - if (epollEvents & EPOLLIN) events |= ALOOPER_EVENT_INPUT; - if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT; - if (epollEvents & EPOLLERR) events |= ALOOPER_EVENT_ERROR; - if (epollEvents & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP; - pushResponse(events, mRequests.valueAt(requestIndex)); - } else { - ALOGW("Ignoring unexpected epoll events 0x%x on fd %d that is " - "no longer registered.", epollEvents, fd); - } - } - } -Done: ; -#else - for (size_t i = 0; i < requestedCount; i++) { - const struct pollfd& requestedFd = mRequestedFds.itemAt(i); - - short pollEvents = requestedFd.revents; - if (pollEvents) { - if (requestedFd.fd == mWakeReadPipeFd) { - if (pollEvents & POLLIN) { - awoken(); - } else { - ALOGW("Ignoring unexpected poll events 0x%x on wake read pipe.", pollEvents); - } - } else { - int events = 0; - if (pollEvents & POLLIN) events |= ALOOPER_EVENT_INPUT; - if (pollEvents & POLLOUT) events |= ALOOPER_EVENT_OUTPUT; - if (pollEvents & POLLERR) events |= ALOOPER_EVENT_ERROR; - if (pollEvents & POLLHUP) events |= ALOOPER_EVENT_HANGUP; - if (pollEvents & POLLNVAL) events |= ALOOPER_EVENT_INVALID; - pushResponse(events, mRequests.itemAt(i)); - } - if (--eventCount == 0) { - break; - } - } - } -Done: - // Set mPolling to false and wake up the wakeAndLock() waiters. - mPolling = false; - if (mWaiters != 0) { - mAwake.broadcast(); - } -#endif - -#ifdef LOOPER_STATISTICS - nsecs_t pollEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - mSampledPolls += 1; - if (timeoutMillis == 0) { - mSampledZeroPollCount += 1; - mSampledZeroPollLatencySum += pollEndTime - pollStartTime; - } else if (timeoutMillis > 0 && result == ALOOPER_POLL_TIMEOUT) { - mSampledTimeoutPollCount += 1; - mSampledTimeoutPollLatencySum += pollEndTime - pollStartTime - - milliseconds_to_nanoseconds(timeoutMillis); - } - if (mSampledPolls == SAMPLED_POLLS_TO_AGGREGATE) { - ALOGD("%p ~ poll latency statistics: %0.3fms zero timeout, %0.3fms non-zero timeout", this, - 0.000001f * float(mSampledZeroPollLatencySum) / mSampledZeroPollCount, - 0.000001f * float(mSampledTimeoutPollLatencySum) / mSampledTimeoutPollCount); - mSampledPolls = 0; - mSampledZeroPollCount = 0; - mSampledZeroPollLatencySum = 0; - mSampledTimeoutPollCount = 0; - mSampledTimeoutPollLatencySum = 0; - } -#endif - - // Invoke pending message callbacks. - mNextMessageUptime = LLONG_MAX; - while (mMessageEnvelopes.size() != 0) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0); - if (messageEnvelope.uptime <= now) { - // Remove the envelope from the list. - // We keep a strong reference to the handler until the call to handleMessage - // finishes. Then we drop it so that the handler can be deleted *before* - // we reacquire our lock. - { // obtain handler - sp<MessageHandler> handler = messageEnvelope.handler; - Message message = messageEnvelope.message; - mMessageEnvelopes.removeAt(0); - mSendingMessage = true; - mLock.unlock(); - -#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS - ALOGD("%p ~ pollOnce - sending message: handler=%p, what=%d", - this, handler.get(), message.what); -#endif - handler->handleMessage(message); - } // release handler - - mLock.lock(); - mSendingMessage = false; - result = ALOOPER_POLL_CALLBACK; - } else { - // The last message left at the head of the queue determines the next wakeup time. - mNextMessageUptime = messageEnvelope.uptime; - break; - } - } - - // Release lock. - mLock.unlock(); - - // Invoke all response callbacks. - for (size_t i = 0; i < mResponses.size(); i++) { - const Response& response = mResponses.itemAt(i); - ALooper_callbackFunc callback = response.request.callback; - if (callback) { - int fd = response.request.fd; - int events = response.events; - void* data = response.request.data; -#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS - ALOGD("%p ~ pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p", - this, callback, fd, events, data); -#endif - int callbackResult = callback(fd, events, data); - if (callbackResult == 0) { - removeFd(fd); - } - result = ALOOPER_POLL_CALLBACK; - } - } - return result; -} - -int Looper::pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) { - if (timeoutMillis <= 0) { - int result; - do { - result = pollOnce(timeoutMillis, outFd, outEvents, outData); - } while (result == ALOOPER_POLL_CALLBACK); - return result; - } else { - nsecs_t endTime = systemTime(SYSTEM_TIME_MONOTONIC) - + milliseconds_to_nanoseconds(timeoutMillis); - - for (;;) { - int result = pollOnce(timeoutMillis, outFd, outEvents, outData); - if (result != ALOOPER_POLL_CALLBACK) { - return result; - } - - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - timeoutMillis = toMillisecondTimeoutDelay(now, endTime); - if (timeoutMillis == 0) { - return ALOOPER_POLL_TIMEOUT; - } - } - } -} - -void Looper::wake() { -#if DEBUG_POLL_AND_WAKE - ALOGD("%p ~ wake", this); -#endif - -#ifdef LOOPER_STATISTICS - // FIXME: Possible race with awoken() but this code is for testing only and is rarely enabled. - if (mPendingWakeCount++ == 0) { - mPendingWakeTime = systemTime(SYSTEM_TIME_MONOTONIC); - } -#endif - - ssize_t nWrite; - do { - nWrite = write(mWakeWritePipeFd, "W", 1); - } while (nWrite == -1 && errno == EINTR); - - if (nWrite != 1) { - if (errno != EAGAIN) { - ALOGW("Could not write wake signal, errno=%d", errno); - } - } -} - -void Looper::awoken() { -#if DEBUG_POLL_AND_WAKE - ALOGD("%p ~ awoken", this); -#endif - -#ifdef LOOPER_STATISTICS - if (mPendingWakeCount == 0) { - ALOGD("%p ~ awoken: spurious!", this); - } else { - mSampledWakeCycles += 1; - mSampledWakeCountSum += mPendingWakeCount; - mSampledWakeLatencySum += systemTime(SYSTEM_TIME_MONOTONIC) - mPendingWakeTime; - mPendingWakeCount = 0; - mPendingWakeTime = -1; - if (mSampledWakeCycles == SAMPLED_WAKE_CYCLES_TO_AGGREGATE) { - ALOGD("%p ~ wake statistics: %0.3fms wake latency, %0.3f wakes per cycle", this, - 0.000001f * float(mSampledWakeLatencySum) / mSampledWakeCycles, - float(mSampledWakeCountSum) / mSampledWakeCycles); - mSampledWakeCycles = 0; - mSampledWakeCountSum = 0; - mSampledWakeLatencySum = 0; - } - } -#endif - - char buffer[16]; - ssize_t nRead; - do { - nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer)); - } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer)); -} - -void Looper::pushResponse(int events, const Request& request) { - Response response; - response.events = events; - response.request = request; - mResponses.push(response); -} - -int Looper::addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void* data) { -#if DEBUG_CALLBACKS - ALOGD("%p ~ addFd - fd=%d, ident=%d, events=0x%x, callback=%p, data=%p", this, fd, ident, - events, callback, data); -#endif - - if (! callback) { - if (! mAllowNonCallbacks) { - ALOGE("Invalid attempt to set NULL callback but not allowed for this looper."); - return -1; - } - - if (ident < 0) { - ALOGE("Invalid attempt to set NULL callback with ident <= 0."); - return -1; - } - } - -#ifdef LOOPER_USES_EPOLL - int epollEvents = 0; - if (events & ALOOPER_EVENT_INPUT) epollEvents |= EPOLLIN; - if (events & ALOOPER_EVENT_OUTPUT) epollEvents |= EPOLLOUT; - - { // acquire lock - AutoMutex _l(mLock); - - Request request; - request.fd = fd; - request.ident = ident; - request.callback = callback; - request.data = data; - - struct epoll_event eventItem; - memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union - eventItem.events = epollEvents; - eventItem.data.fd = fd; - - ssize_t requestIndex = mRequests.indexOfKey(fd); - if (requestIndex < 0) { - int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem); - if (epollResult < 0) { - ALOGE("Error adding epoll events for fd %d, errno=%d", fd, errno); - return -1; - } - mRequests.add(fd, request); - } else { - int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem); - if (epollResult < 0) { - ALOGE("Error modifying epoll events for fd %d, errno=%d", fd, errno); - return -1; - } - mRequests.replaceValueAt(requestIndex, request); - } - } // release lock -#else - int pollEvents = 0; - if (events & ALOOPER_EVENT_INPUT) pollEvents |= POLLIN; - if (events & ALOOPER_EVENT_OUTPUT) pollEvents |= POLLOUT; - - wakeAndLock(); // acquire lock - - struct pollfd requestedFd; - requestedFd.fd = fd; - requestedFd.events = pollEvents; - - Request request; - request.fd = fd; - request.ident = ident; - request.callback = callback; - request.data = data; - ssize_t index = getRequestIndexLocked(fd); - if (index < 0) { - mRequestedFds.push(requestedFd); - mRequests.push(request); - } else { - mRequestedFds.replaceAt(requestedFd, size_t(index)); - mRequests.replaceAt(request, size_t(index)); - } - - mLock.unlock(); // release lock -#endif - return 1; -} - -int Looper::removeFd(int fd) { -#if DEBUG_CALLBACKS - ALOGD("%p ~ removeFd - fd=%d", this, fd); -#endif - -#ifdef LOOPER_USES_EPOLL - { // acquire lock - AutoMutex _l(mLock); - ssize_t requestIndex = mRequests.indexOfKey(fd); - if (requestIndex < 0) { - return 0; - } - - int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, NULL); - if (epollResult < 0) { - ALOGE("Error removing epoll events for fd %d, errno=%d", fd, errno); - return -1; - } - - mRequests.removeItemsAt(requestIndex); - } // release lock - return 1; -#else - wakeAndLock(); // acquire lock - - ssize_t index = getRequestIndexLocked(fd); - if (index >= 0) { - mRequestedFds.removeAt(size_t(index)); - mRequests.removeAt(size_t(index)); - } - - mLock.unlock(); // release lock - return index >= 0; -#endif -} - -#ifndef LOOPER_USES_EPOLL -ssize_t Looper::getRequestIndexLocked(int fd) { - size_t requestCount = mRequestedFds.size(); - - for (size_t i = 0; i < requestCount; i++) { - if (mRequestedFds.itemAt(i).fd == fd) { - return i; - } - } - - return -1; -} - -void Looper::wakeAndLock() { - mLock.lock(); - - mWaiters += 1; - while (mPolling) { - wake(); - mAwake.wait(mLock); - } - - mWaiters -= 1; - if (mWaiters == 0) { - mResume.signal(); - } -} -#endif - -void Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - sendMessageAtTime(now, handler, message); -} - -void Looper::sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler, - const Message& message) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - sendMessageAtTime(now + uptimeDelay, handler, message); -} - -void Looper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler, - const Message& message) { -#if DEBUG_CALLBACKS - ALOGD("%p ~ sendMessageAtTime - uptime=%lld, handler=%p, what=%d", - this, uptime, handler.get(), message.what); -#endif - - size_t i = 0; - { // acquire lock - AutoMutex _l(mLock); - - size_t messageCount = mMessageEnvelopes.size(); - while (i < messageCount && uptime >= mMessageEnvelopes.itemAt(i).uptime) { - i += 1; - } - - MessageEnvelope messageEnvelope(uptime, handler, message); - mMessageEnvelopes.insertAt(messageEnvelope, i, 1); - - // Optimization: If the Looper is currently sending a message, then we can skip - // the call to wake() because the next thing the Looper will do after processing - // messages is to decide when the next wakeup time should be. In fact, it does - // not even matter whether this code is running on the Looper thread. - if (mSendingMessage) { - return; - } - } // release lock - - // Wake the poll loop only when we enqueue a new message at the head. - if (i == 0) { - wake(); - } -} - -void Looper::removeMessages(const sp<MessageHandler>& handler) { -#if DEBUG_CALLBACKS - ALOGD("%p ~ removeMessages - handler=%p", this, handler.get()); -#endif - - { // acquire lock - AutoMutex _l(mLock); - - for (size_t i = mMessageEnvelopes.size(); i != 0; ) { - const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(--i); - if (messageEnvelope.handler == handler) { - mMessageEnvelopes.removeAt(i); - } - } - } // release lock -} - -void Looper::removeMessages(const sp<MessageHandler>& handler, int what) { -#if DEBUG_CALLBACKS - ALOGD("%p ~ removeMessages - handler=%p, what=%d", this, handler.get(), what); -#endif - - { // acquire lock - AutoMutex _l(mLock); - - for (size_t i = mMessageEnvelopes.size(); i != 0; ) { - const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(--i); - if (messageEnvelope.handler == handler - && messageEnvelope.message.what == what) { - mMessageEnvelopes.removeAt(i); - } - } - } // release lock -} - -} // namespace android diff --git a/libs/utils/MODULE_LICENSE_APACHE2 b/libs/utils/MODULE_LICENSE_APACHE2 deleted file mode 100644 index e69de29..0000000 --- a/libs/utils/MODULE_LICENSE_APACHE2 +++ /dev/null diff --git a/libs/utils/NOTICE b/libs/utils/NOTICE deleted file mode 100644 index c5b1efa..0000000 --- a/libs/utils/NOTICE +++ /dev/null @@ -1,190 +0,0 @@ - - Copyright (c) 2005-2008, 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. - - 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. - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - diff --git a/libs/utils/PropertyMap.cpp b/libs/utils/PropertyMap.cpp deleted file mode 100644 index 5520702..0000000 --- a/libs/utils/PropertyMap.cpp +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (C) 2008 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 "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 - -// Enables debug output for parser performance. -#define DEBUG_PARSER_PERFORMANCE 0 - - -namespace android { - -static const char* WHITESPACE = " \t\r"; -static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r="; - - -// --- PropertyMap --- - -PropertyMap::PropertyMap() { -} - -PropertyMap::~PropertyMap() { -} - -void PropertyMap::clear() { - mProperties.clear(); -} - -void PropertyMap::addProperty(const String8& key, const String8& value) { - mProperties.add(key, value); -} - -bool PropertyMap::hasProperty(const String8& key) const { - return mProperties.indexOfKey(key) >= 0; -} - -bool PropertyMap::tryGetProperty(const String8& key, String8& outValue) const { - ssize_t index = mProperties.indexOfKey(key); - if (index < 0) { - return false; - } - - outValue = mProperties.valueAt(index); - return true; -} - -bool PropertyMap::tryGetProperty(const String8& key, bool& outValue) const { - int32_t intValue; - if (!tryGetProperty(key, intValue)) { - return false; - } - - outValue = intValue; - return true; -} - -bool PropertyMap::tryGetProperty(const String8& key, int32_t& outValue) const { - String8 stringValue; - if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) { - return false; - } - - char* end; - int value = strtol(stringValue.string(), & end, 10); - if (*end != '\0') { - ALOGW("Property key '%s' has invalid value '%s'. Expected an integer.", - key.string(), stringValue.string()); - return false; - } - outValue = value; - return true; -} - -bool PropertyMap::tryGetProperty(const String8& key, float& outValue) const { - String8 stringValue; - if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) { - return false; - } - - char* end; - float value = strtof(stringValue.string(), & end); - if (*end != '\0') { - ALOGW("Property key '%s' has invalid value '%s'. Expected a float.", - key.string(), stringValue.string()); - return false; - } - outValue = value; - return true; -} - -void PropertyMap::addAll(const PropertyMap* map) { - for (size_t i = 0; i < map->mProperties.size(); i++) { - mProperties.add(map->mProperties.keyAt(i), map->mProperties.valueAt(i)); - } -} - -status_t PropertyMap::load(const String8& filename, PropertyMap** outMap) { - *outMap = NULL; - - Tokenizer* tokenizer; - status_t status = Tokenizer::open(filename, &tokenizer); - if (status) { - ALOGE("Error %d opening property file %s.", status, filename.string()); - } else { - PropertyMap* map = new PropertyMap(); - if (!map) { - ALOGE("Error allocating property map."); - status = NO_MEMORY; - } else { -#if DEBUG_PARSER_PERFORMANCE - nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); -#endif - Parser parser(map, tokenizer); - status = parser.parse(); -#if DEBUG_PARSER_PERFORMANCE - nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; - ALOGD("Parsed property file '%s' %d lines in %0.3fms.", - tokenizer->getFilename().string(), tokenizer->getLineNumber(), - elapsedTime / 1000000.0); -#endif - if (status) { - delete map; - } else { - *outMap = map; - } - } - delete tokenizer; - } - return status; -} - - -// --- PropertyMap::Parser --- - -PropertyMap::Parser::Parser(PropertyMap* map, Tokenizer* tokenizer) : - mMap(map), mTokenizer(tokenizer) { -} - -PropertyMap::Parser::~Parser() { -} - -status_t PropertyMap::Parser::parse() { - while (!mTokenizer->isEof()) { -#if DEBUG_PARSER - ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); -#endif - - mTokenizer->skipDelimiters(WHITESPACE); - - if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { - String8 keyToken = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER); - if (keyToken.isEmpty()) { - ALOGE("%s: Expected non-empty property key.", mTokenizer->getLocation().string()); - return BAD_VALUE; - } - - mTokenizer->skipDelimiters(WHITESPACE); - - if (mTokenizer->nextChar() != '=') { - ALOGE("%s: Expected '=' between property key and value.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - - mTokenizer->skipDelimiters(WHITESPACE); - - String8 valueToken = mTokenizer->nextToken(WHITESPACE); - if (valueToken.find("\\", 0) >= 0 || valueToken.find("\"", 0) >= 0) { - ALOGE("%s: Found reserved character '\\' or '\"' in property value.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - - mTokenizer->skipDelimiters(WHITESPACE); - if (!mTokenizer->isEol()) { - ALOGE("%s: Expected end of line, got '%s'.", - mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); - return BAD_VALUE; - } - - if (mMap->hasProperty(keyToken)) { - ALOGE("%s: Duplicate property value for key '%s'.", - mTokenizer->getLocation().string(), keyToken.string()); - return BAD_VALUE; - } - - mMap->addProperty(keyToken, valueToken); - } - - mTokenizer->nextLine(); - } - return NO_ERROR; -} - -} // namespace android diff --git a/libs/utils/README b/libs/utils/README deleted file mode 100644 index 01741e0..0000000 --- a/libs/utils/README +++ /dev/null @@ -1,289 +0,0 @@ -Android Utility Function Library -================================ - - -If you need a feature that is native to Linux but not present on other -platforms, construct a platform-dependent implementation that shares -the Linux interface. That way the actual device runs as "light" as -possible. - -If that isn't feasible, create a system-independent interface and hide -the details. - -The ultimate goal is *not* to create a super-duper platform abstraction -layer. The goal is to provide an optimized solution for Linux with -reasonable implementations for other platforms. - - - -Resource overlay -================ - - -Introduction ------------- - -Overlay packages are special .apk files which provide no code but -additional resource values (and possibly new configurations) for -resources in other packages. When an application requests resources, -the system will return values from either the application's original -package or any associated overlay package. Any redirection is completely -transparent to the calling application. - -Resource values have the following precedence table, listed in -descending precedence. - - * overlay package, matching config (eg res/values-en-land) - - * original package, matching config - - * overlay package, no config (eg res/values) - - * original package, no config - -During compilation, overlay packages are differentiated from regular -packages by passing the -o flag to aapt. - - -Background ----------- - -This section provides generic background material on resources in -Android. - - -How resources are bundled in .apk files -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Android .apk files are .zip files, usually housing .dex code, -certificates and resources, though packages containing resources but -no code are possible. Resources can be divided into the following -categories; a `configuration' indicates a set of phone language, display -density, network operator, etc. - - * assets: uncompressed, raw files packaged as part of an .apk and - explicitly referenced by filename. These files are - independent of configuration. - - * res/drawable: bitmap or xml graphics. Each file may have different - values depending on configuration. - - * res/values: integers, strings, etc. Each resource may have different - values depending on configuration. - -Resource meta information and information proper is stored in a binary -format in a named file resources.arsc, bundled as part of the .apk. - -Resource IDs and lookup -~~~~~~~~~~~~~~~~~~~~~~~ -During compilation, the aapt tool gathers application resources and -generates a resources.arsc file. Each resource name is assigned an -integer ID 0xppttiii (translated to a symbolic name via R.java), where - - * pp: corresponds to the package namespace (details below). - - * tt: corresponds to the resource type (string, int, etc). Every - resource of the same type within the same package has the same - tt value, but depending on available types, the actual numerical - value may be different between packages. - - * iiii: sequential number, assigned in the order resources are found. - -Resource values are specified paired with a set of configuration -constraints (the default being the empty set), eg res/values-sv-port -which imposes restrictions on language (Swedish) and display orientation -(portrait). During lookup, every constraint set is matched against the -current configuration, and the value corresponding to the best matching -constraint set is returned (ResourceTypes.{h,cpp}). - -Parsing of resources.arsc is handled by ResourceTypes.cpp; this utility -is governed by AssetManager.cpp, which tracks loaded resources per -process. - -Assets are looked up by path and filename in AssetManager.cpp. The path -to resources in res/drawable are located by ResourceTypes.cpp and then -handled like assets by AssetManager.cpp. Other resources are handled -solely by ResourceTypes.cpp. - -Package ID as namespace -~~~~~~~~~~~~~~~~~~~~~~~ -The pp part of a resource ID defines a namespace. Android currently -defines two namespaces: - - * 0x01: system resources (pre-installed in framework-res.apk) - - * 0x7f: application resources (bundled in the application .apk) - -ResourceTypes.cpp supports package IDs between 0x01 and 0x7f -(inclusive); values outside this range are invalid. - -Each running (Dalvik) process is assigned a unique instance of -AssetManager, which in turn keeps a forest structure of loaded -resource.arsc files. Normally, this forest is structured as follows, -where mPackageMap is the internal vector employed in ResourceTypes.cpp. - -mPackageMap[0x00] -> system package -mPackageMap[0x01] -> NULL -mPackageMap[0x02] -> NULL -... -mPackageMap[0x7f - 2] -> NULL -mPackageMap[0x7f - 1] -> application package - - - -The resource overlay extension ------------------------------- - -The resource overlay mechanism aims to (partly) shadow and extend -existing resources with new values for defined and new configurations. -Technically, this is achieved by adding resource-only packages (called -overlay packages) to existing resource namespaces, like so: - -mPackageMap[0x00] -> system package -> system overlay package -mPackageMap[0x01] -> NULL -mPackageMap[0x02] -> NULL -... -mPackageMap[0x7f - 2] -> NULL -mPackageMap[0x7f - 1] -> application package -> overlay 1 -> overlay 2 - -The use of overlay resources is completely transparent to -applications; no additional resource identifiers are introduced, only -configuration/value pairs. Any number of overlay packages may be loaded -at a time; overlay packages are agnostic to what they target -- both -system and application resources are fair game. - -The package targeted by an overlay package is called the target or -original package. - -Resource overlay operates on symbolic resources names. Hence, to -override the string/str1 resources in a package, the overlay package -would include a resource also named string/str1. The end user does not -have to worry about the numeric resources IDs assigned by aapt, as this -is resolved automatically by the system. - -As of this writing, the use of resource overlay has not been fully -explored. Until it has, only OEMs are trusted to use resource overlay. -For this reason, overlay packages must reside in /system/overlay. - - -Resource ID mapping -~~~~~~~~~~~~~~~~~~~ -Resource identifiers must be coherent within the same namespace (ie -PackageGroup in ResourceTypes.cpp). Calling applications will refer to -resources using the IDs defined in the original package, but there is no -guarantee aapt has assigned the same ID to the corresponding resource in -an overlay package. To translate between the two, a resource ID mapping -{original ID -> overlay ID} is created during package installation -(PackageManagerService.java) and used during resource lookup. The -mapping is stored in /data/resource-cache, with a @idmap file name -suffix. - -The idmap file format is documented in a separate section, below. - - -Package management -~~~~~~~~~~~~~~~~~~ -Packages are managed by the PackageManagerService. Addition and removal -of packages are monitored via the inotify framework, exposed via -android.os.FileObserver. - -During initialization of a Dalvik process, ActivityThread.java requests -the process' AssetManager (by proxy, via AssetManager.java and JNI) -to load a list of packages. This list includes overlay packages, if -present. - -When a target package or a corresponding overlay package is installed, -the target package's process is stopped and a new idmap is generated. -This is similar to how applications are stopped when their packages are -upgraded. - - -Creating overlay packages -------------------------- - -Overlay packages should contain no code, define (some) resources with -the same type and name as in the original package, and be compiled with -the -o flag passed to aapt. - -The aapt -o flag instructs aapt to create an overlay package. -Technically, this means the package will be assigned package id 0x00. - -There are no restrictions on overlay packages names, though the naming -convention <original.package.name>.overlay.<name> is recommended. - - -Example overlay package -~~~~~~~~~~~~~~~~~~~~~~~ - -To overlay the resource bool/b in package com.foo.bar, to be applied -when the display is in landscape mode, create a new package with -no source code and a single .xml file under res/values-land, with -an entry for bool/b. Compile with aapt -o and place the results in -/system/overlay by adding the following to Android.mk: - -LOCAL_AAPT_FLAGS := -o com.foo.bar -LOCAL_MODULE_PATH := $(TARGET_OUT)/overlay - - -The ID map (idmap) file format ------------------------------- - -The idmap format is designed for lookup performance. However, leading -and trailing undefined overlay values are discarded to reduce the memory -footprint. - - -idmap grammar -~~~~~~~~~~~~~ -All atoms (names in square brackets) are uint32_t integers. The -idmap-magic constant spells "idmp" in ASCII. Offsets are given relative -to the data_header, not to the beginning of the file. - -map := header data -header := idmap-magic <crc32-original-pkg> <crc32-overlay-pkg> -idmap-magic := <0x706d6469> -data := data_header type_block+ -data_header := <m> header_block{m} -header_block := <0> | <type_block_offset> -type_block := <n> <id_offset> entry{n} -entry := <resource_id_in_target_package> - - -idmap example -~~~~~~~~~~~~~ -Given a pair of target and overlay packages with CRC sums 0x216a8fe2 -and 0x6b9beaec, each defining the following resources - -Name Target package Overlay package -string/str0 0x7f010000 - -string/str1 0x7f010001 0x7f010000 -string/str2 0x7f010002 - -string/str3 0x7f010003 0x7f010001 -string/str4 0x7f010004 - -bool/bool0 0x7f020000 - -integer/int0 0x7f030000 0x7f020000 -integer/int1 0x7f030001 - - -the corresponding resource map is - -0x706d6469 0x216a8fe2 0x6b9beaec 0x00000003 \ -0x00000004 0x00000000 0x00000009 0x00000003 \ -0x00000001 0x7f010000 0x00000000 0x7f010001 \ -0x00000001 0x00000000 0x7f020000 - -or, formatted differently - -0x706d6469 # magic: all idmap files begin with this constant -0x216a8fe2 # CRC32 of the resources.arsc file in the original package -0x6b9beaec # CRC32 of the resources.arsc file in the overlay package -0x00000003 # header; three types (string, bool, integer) in the target package -0x00000004 # header_block for type 0 (string) is located at offset 4 -0x00000000 # no bool type exists in overlay package -> no header_block -0x00000009 # header_block for type 2 (integer) is located at offset 9 -0x00000003 # header_block for string; overlay IDs span 3 elements -0x00000001 # the first string in target package is entry 1 == offset -0x7f010000 # target 0x7f01001 -> overlay 0x7f010000 -0x00000000 # str2 not defined in overlay package -0x7f010001 # target 0x7f010003 -> overlay 0x7f010001 -0x00000001 # header_block for integer; overlay IDs span 1 element -0x00000000 # offset == 0 -0x7f020000 # target 0x7f030000 -> overlay 0x7f020000 diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp deleted file mode 100644 index e80a795..0000000 --- a/libs/utils/RefBase.cpp +++ /dev/null @@ -1,628 +0,0 @@ -/* - * Copyright (C) 2005 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 "RefBase" - -#include <utils/RefBase.h> - -#include <utils/Atomic.h> -#include <utils/CallStack.h> -#include <utils/Log.h> -#include <utils/threads.h> -#include <utils/TextOutput.h> - -#include <stdlib.h> -#include <stdio.h> -#include <typeinfo> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> - -// compile with refcounting debugging enabled -#define DEBUG_REFS 0 -#define DEBUG_REFS_FATAL_SANITY_CHECKS 0 -#define DEBUG_REFS_ENABLED_BY_DEFAULT 1 -#define DEBUG_REFS_CALLSTACK_ENABLED 1 - -// log all reference counting operations -#define PRINT_REFS 0 - -// --------------------------------------------------------------------------- - -namespace android { - -#define INITIAL_STRONG_VALUE (1<<28) - -// --------------------------------------------------------------------------- - -class RefBase::weakref_impl : public RefBase::weakref_type -{ -public: - volatile int32_t mStrong; - volatile int32_t mWeak; - RefBase* const mBase; - volatile int32_t mFlags; - -#if !DEBUG_REFS - - weakref_impl(RefBase* base) - : mStrong(INITIAL_STRONG_VALUE) - , mWeak(0) - , mBase(base) - , mFlags(0) - { - } - - void addStrongRef(const void* /*id*/) { } - void removeStrongRef(const void* /*id*/) { } - void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { } - void addWeakRef(const void* /*id*/) { } - void removeWeakRef(const void* /*id*/) { } - void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { } - void printRefs() const { } - void trackMe(bool, bool) { } - -#else - - weakref_impl(RefBase* base) - : mStrong(INITIAL_STRONG_VALUE) - , mWeak(0) - , mBase(base) - , mFlags(0) - , mStrongRefs(NULL) - , mWeakRefs(NULL) - , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT) - , mRetain(false) - { - } - - ~weakref_impl() - { - bool dumpStack = false; - if (!mRetain && mStrongRefs != NULL) { - dumpStack = true; -#if DEBUG_REFS_FATAL_SANITY_CHECKS - LOG_ALWAYS_FATAL("Strong references remain!"); -#else - ALOGE("Strong references remain:"); -#endif - ref_entry* refs = mStrongRefs; - while (refs) { - char inc = refs->ref >= 0 ? '+' : '-'; - ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref); -#if DEBUG_REFS_CALLSTACK_ENABLED - refs->stack.dump(); -#endif - refs = refs->next; - } - } - - if (!mRetain && mWeakRefs != NULL) { - dumpStack = true; -#if DEBUG_REFS_FATAL_SANITY_CHECKS - LOG_ALWAYS_FATAL("Weak references remain:"); -#else - ALOGE("Weak references remain!"); -#endif - ref_entry* refs = mWeakRefs; - while (refs) { - char inc = refs->ref >= 0 ? '+' : '-'; - ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref); -#if DEBUG_REFS_CALLSTACK_ENABLED - refs->stack.dump(); -#endif - refs = refs->next; - } - } - if (dumpStack) { - ALOGE("above errors at:"); - CallStack stack; - stack.update(); - stack.dump(); - } - } - - void addStrongRef(const void* id) { - //ALOGD_IF(mTrackEnabled, - // "addStrongRef: RefBase=%p, id=%p", mBase, id); - addRef(&mStrongRefs, id, mStrong); - } - - void removeStrongRef(const void* id) { - //ALOGD_IF(mTrackEnabled, - // "removeStrongRef: RefBase=%p, id=%p", mBase, id); - if (!mRetain) { - removeRef(&mStrongRefs, id); - } else { - addRef(&mStrongRefs, id, -mStrong); - } - } - - void renameStrongRefId(const void* old_id, const void* new_id) { - //ALOGD_IF(mTrackEnabled, - // "renameStrongRefId: RefBase=%p, oid=%p, nid=%p", - // mBase, old_id, new_id); - renameRefsId(mStrongRefs, old_id, new_id); - } - - void addWeakRef(const void* id) { - addRef(&mWeakRefs, id, mWeak); - } - - void removeWeakRef(const void* id) { - if (!mRetain) { - removeRef(&mWeakRefs, id); - } else { - addRef(&mWeakRefs, id, -mWeak); - } - } - - void renameWeakRefId(const void* old_id, const void* new_id) { - renameRefsId(mWeakRefs, old_id, new_id); - } - - void trackMe(bool track, bool retain) - { - mTrackEnabled = track; - mRetain = retain; - } - - void printRefs() const - { - String8 text; - - { - Mutex::Autolock _l(mMutex); - char buf[128]; - sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this); - text.append(buf); - printRefsLocked(&text, mStrongRefs); - sprintf(buf, "Weak references on RefBase %p (weakref_type %p):\n", mBase, this); - text.append(buf); - printRefsLocked(&text, mWeakRefs); - } - - { - char name[100]; - snprintf(name, 100, "/data/%p.stack", this); - int rc = open(name, O_RDWR | O_CREAT | O_APPEND); - if (rc >= 0) { - write(rc, text.string(), text.length()); - close(rc); - ALOGD("STACK TRACE for %p saved in %s", this, name); - } - else ALOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this, - name, strerror(errno)); - } - } - -private: - struct ref_entry - { - ref_entry* next; - const void* id; -#if DEBUG_REFS_CALLSTACK_ENABLED - CallStack stack; -#endif - int32_t ref; - }; - - void addRef(ref_entry** refs, const void* id, int32_t mRef) - { - if (mTrackEnabled) { - AutoMutex _l(mMutex); - - ref_entry* ref = new ref_entry; - // Reference count at the time of the snapshot, but before the - // update. Positive value means we increment, negative--we - // decrement the reference count. - ref->ref = mRef; - ref->id = id; -#if DEBUG_REFS_CALLSTACK_ENABLED - ref->stack.update(2); -#endif - ref->next = *refs; - *refs = ref; - } - } - - void removeRef(ref_entry** refs, const void* id) - { - if (mTrackEnabled) { - AutoMutex _l(mMutex); - - ref_entry* const head = *refs; - ref_entry* ref = head; - while (ref != NULL) { - if (ref->id == id) { - *refs = ref->next; - delete ref; - return; - } - refs = &ref->next; - ref = *refs; - } - -#if DEBUG_REFS_FATAL_SANITY_CHECKS - LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p" - "(weakref_type %p) that doesn't exist!", - id, mBase, this); -#endif - - ALOGE("RefBase: removing id %p on RefBase %p" - "(weakref_type %p) that doesn't exist!", - id, mBase, this); - - ref = head; - while (ref) { - char inc = ref->ref >= 0 ? '+' : '-'; - ALOGD("\t%c ID %p (ref %d):", inc, ref->id, ref->ref); - ref = ref->next; - } - - CallStack stack; - stack.update(); - stack.dump(); - } - } - - void renameRefsId(ref_entry* r, const void* old_id, const void* new_id) - { - if (mTrackEnabled) { - AutoMutex _l(mMutex); - ref_entry* ref = r; - while (ref != NULL) { - if (ref->id == old_id) { - ref->id = new_id; - } - ref = ref->next; - } - } - } - - void printRefsLocked(String8* out, const ref_entry* refs) const - { - char buf[128]; - while (refs) { - char inc = refs->ref >= 0 ? '+' : '-'; - sprintf(buf, "\t%c ID %p (ref %d):\n", - inc, refs->id, refs->ref); - out->append(buf); -#if DEBUG_REFS_CALLSTACK_ENABLED - out->append(refs->stack.toString("\t\t")); -#else - out->append("\t\t(call stacks disabled)"); -#endif - refs = refs->next; - } - } - - mutable Mutex mMutex; - ref_entry* mStrongRefs; - ref_entry* mWeakRefs; - - bool mTrackEnabled; - // Collect stack traces on addref and removeref, instead of deleting the stack references - // on removeref that match the address ones. - bool mRetain; - -#endif -}; - -// --------------------------------------------------------------------------- - -void RefBase::incStrong(const void* id) const -{ - weakref_impl* const refs = mRefs; - refs->incWeak(id); - - refs->addStrongRef(id); - const int32_t c = android_atomic_inc(&refs->mStrong); - ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs); -#if PRINT_REFS - ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c); -#endif - if (c != INITIAL_STRONG_VALUE) { - return; - } - - android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong); - refs->mBase->onFirstRef(); -} - -void RefBase::decStrong(const void* id) const -{ - weakref_impl* const refs = mRefs; - refs->removeStrongRef(id); - const int32_t c = android_atomic_dec(&refs->mStrong); -#if PRINT_REFS - ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c); -#endif - ALOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs); - if (c == 1) { - refs->mBase->onLastStrongRef(id); - if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) { - delete this; - } - } - refs->decWeak(id); -} - -void RefBase::forceIncStrong(const void* id) const -{ - weakref_impl* const refs = mRefs; - refs->incWeak(id); - - refs->addStrongRef(id); - const int32_t c = android_atomic_inc(&refs->mStrong); - ALOG_ASSERT(c >= 0, "forceIncStrong called on %p after ref count underflow", - refs); -#if PRINT_REFS - ALOGD("forceIncStrong of %p from %p: cnt=%d\n", this, id, c); -#endif - - switch (c) { - case INITIAL_STRONG_VALUE: - android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong); - // fall through... - case 0: - refs->mBase->onFirstRef(); - } -} - -int32_t RefBase::getStrongCount() const -{ - return mRefs->mStrong; -} - -RefBase* RefBase::weakref_type::refBase() const -{ - return static_cast<const weakref_impl*>(this)->mBase; -} - -void RefBase::weakref_type::incWeak(const void* id) -{ - weakref_impl* const impl = static_cast<weakref_impl*>(this); - impl->addWeakRef(id); - const int32_t c = android_atomic_inc(&impl->mWeak); - ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this); -} - - -void RefBase::weakref_type::decWeak(const void* id) -{ - weakref_impl* const impl = static_cast<weakref_impl*>(this); - impl->removeWeakRef(id); - const int32_t c = android_atomic_dec(&impl->mWeak); - ALOG_ASSERT(c >= 1, "decWeak called on %p too many times", this); - if (c != 1) return; - - if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) { - // This is the regular lifetime case. The object is destroyed - // when the last strong reference goes away. Since weakref_impl - // outlive the object, it is not destroyed in the dtor, and - // we'll have to do it here. - if (impl->mStrong == INITIAL_STRONG_VALUE) { - // Special case: we never had a strong reference, so we need to - // destroy the object now. - delete impl->mBase; - } else { - // ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase); - delete impl; - } - } else { - // less common case: lifetime is OBJECT_LIFETIME_{WEAK|FOREVER} - impl->mBase->onLastWeakRef(id); - if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) { - // this is the OBJECT_LIFETIME_WEAK case. The last weak-reference - // is gone, we can destroy the object. - delete impl->mBase; - } - } -} - -bool RefBase::weakref_type::attemptIncStrong(const void* id) -{ - incWeak(id); - - weakref_impl* const impl = static_cast<weakref_impl*>(this); - - int32_t curCount = impl->mStrong; - ALOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow", - this); - while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) { - if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) { - break; - } - curCount = impl->mStrong; - } - - if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) { - bool allow; - if (curCount == INITIAL_STRONG_VALUE) { - // Attempting to acquire first strong reference... this is allowed - // if the object does NOT have a longer lifetime (meaning the - // implementation doesn't need to see this), or if the implementation - // allows it to happen. - allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK - || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id); - } else { - // Attempting to revive the object... this is allowed - // if the object DOES have a longer lifetime (so we can safely - // call the object with only a weak ref) and the implementation - // allows it to happen. - allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK - && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id); - } - if (!allow) { - decWeak(id); - return false; - } - curCount = android_atomic_inc(&impl->mStrong); - - // If the strong reference count has already been incremented by - // someone else, the implementor of onIncStrongAttempted() is holding - // an unneeded reference. So call onLastStrongRef() here to remove it. - // (No, this is not pretty.) Note that we MUST NOT do this if we - // are in fact acquiring the first reference. - if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) { - impl->mBase->onLastStrongRef(id); - } - } - - impl->addStrongRef(id); - -#if PRINT_REFS - ALOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount); -#endif - - if (curCount == INITIAL_STRONG_VALUE) { - android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong); - impl->mBase->onFirstRef(); - } - - return true; -} - -bool RefBase::weakref_type::attemptIncWeak(const void* id) -{ - weakref_impl* const impl = static_cast<weakref_impl*>(this); - - int32_t curCount = impl->mWeak; - ALOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow", - this); - while (curCount > 0) { - if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mWeak) == 0) { - break; - } - curCount = impl->mWeak; - } - - if (curCount > 0) { - impl->addWeakRef(id); - } - - return curCount > 0; -} - -int32_t RefBase::weakref_type::getWeakCount() const -{ - return static_cast<const weakref_impl*>(this)->mWeak; -} - -void RefBase::weakref_type::printRefs() const -{ - static_cast<const weakref_impl*>(this)->printRefs(); -} - -void RefBase::weakref_type::trackMe(bool enable, bool retain) -{ - static_cast<weakref_impl*>(this)->trackMe(enable, retain); -} - -RefBase::weakref_type* RefBase::createWeak(const void* id) const -{ - mRefs->incWeak(id); - return mRefs; -} - -RefBase::weakref_type* RefBase::getWeakRefs() const -{ - return mRefs; -} - -RefBase::RefBase() - : mRefs(new weakref_impl(this)) -{ -} - -RefBase::~RefBase() -{ - if (mRefs->mStrong == INITIAL_STRONG_VALUE) { - // we never acquired a strong (and/or weak) reference on this object. - delete mRefs; - } else { - // life-time of this object is extended to WEAK or FOREVER, in - // which case weakref_impl doesn't out-live the object and we - // can free it now. - if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) { - // It's possible that the weak count is not 0 if the object - // re-acquired a weak reference in its destructor - if (mRefs->mWeak == 0) { - delete mRefs; - } - } - } - // for debugging purposes, clear this. - const_cast<weakref_impl*&>(mRefs) = NULL; -} - -void RefBase::extendObjectLifetime(int32_t mode) -{ - android_atomic_or(mode, &mRefs->mFlags); -} - -void RefBase::onFirstRef() -{ -} - -void RefBase::onLastStrongRef(const void* /*id*/) -{ -} - -bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id) -{ - return (flags&FIRST_INC_STRONG) ? true : false; -} - -void RefBase::onLastWeakRef(const void* /*id*/) -{ -} - -// --------------------------------------------------------------------------- - -void RefBase::moveReferences(void* dst, void const* src, size_t n, - const ReferenceConverterBase& caster) -{ -#if DEBUG_REFS - const size_t itemSize = caster.getReferenceTypeSize(); - for (size_t i=0 ; i<n ; i++) { - void* d = reinterpret_cast<void *>(intptr_t(dst) + i*itemSize); - void const* s = reinterpret_cast<void const*>(intptr_t(src) + i*itemSize); - RefBase* ref(reinterpret_cast<RefBase*>(caster.getReferenceBase(d))); - ref->mRefs->renameStrongRefId(s, d); - ref->mRefs->renameWeakRefId(s, d); - } -#endif -} - -// --------------------------------------------------------------------------- - -TextOutput& printStrongPointer(TextOutput& to, const void* val) -{ - to << "sp<>(" << val << ")"; - return to; -} - -TextOutput& printWeakPointer(TextOutput& to, const void* val) -{ - to << "wp<>(" << val << ")"; - return to; -} - - -}; // namespace android diff --git a/libs/utils/SharedBuffer.cpp b/libs/utils/SharedBuffer.cpp deleted file mode 100644 index 3555fb7..0000000 --- a/libs/utils/SharedBuffer.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2005 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 <stdlib.h> -#include <string.h> - -#include <utils/SharedBuffer.h> -#include <utils/Atomic.h> - -// --------------------------------------------------------------------------- - -namespace android { - -SharedBuffer* SharedBuffer::alloc(size_t size) -{ - SharedBuffer* sb = static_cast<SharedBuffer *>(malloc(sizeof(SharedBuffer) + size)); - if (sb) { - sb->mRefs = 1; - sb->mSize = size; - } - return sb; -} - - -ssize_t SharedBuffer::dealloc(const SharedBuffer* released) -{ - if (released->mRefs != 0) return -1; // XXX: invalid operation - free(const_cast<SharedBuffer*>(released)); - return 0; -} - -SharedBuffer* SharedBuffer::edit() const -{ - if (onlyOwner()) { - return const_cast<SharedBuffer*>(this); - } - SharedBuffer* sb = alloc(mSize); - if (sb) { - memcpy(sb->data(), data(), size()); - release(); - } - return sb; -} - -SharedBuffer* SharedBuffer::editResize(size_t newSize) const -{ - if (onlyOwner()) { - SharedBuffer* buf = const_cast<SharedBuffer*>(this); - if (buf->mSize == newSize) return buf; - buf = (SharedBuffer*)realloc(buf, sizeof(SharedBuffer) + newSize); - if (buf != NULL) { - buf->mSize = newSize; - return buf; - } - } - SharedBuffer* sb = alloc(newSize); - if (sb) { - const size_t mySize = mSize; - memcpy(sb->data(), data(), newSize < mySize ? newSize : mySize); - release(); - } - return sb; -} - -SharedBuffer* SharedBuffer::attemptEdit() const -{ - if (onlyOwner()) { - return const_cast<SharedBuffer*>(this); - } - return 0; -} - -SharedBuffer* SharedBuffer::reset(size_t new_size) const -{ - // cheap-o-reset. - SharedBuffer* sb = alloc(new_size); - if (sb) { - release(); - } - return sb; -} - -void SharedBuffer::acquire() const { - android_atomic_inc(&mRefs); -} - -int32_t SharedBuffer::release(uint32_t flags) const -{ - int32_t prev = 1; - if (onlyOwner() || ((prev = android_atomic_dec(&mRefs)) == 1)) { - mRefs = 0; - if ((flags & eKeepStorage) == 0) { - free(const_cast<SharedBuffer*>(this)); - } - } - return prev; -} - - -}; // namespace android diff --git a/libs/utils/Static.cpp b/libs/utils/Static.cpp deleted file mode 100644 index 624e917..0000000 --- a/libs/utils/Static.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2008 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. - */ - -// All static variables go here, to control initialization and -// destruction order in the library. - -#include <private/utils/Static.h> - -#include <utils/BufferedTextOutput.h> -#include <utils/Log.h> - -namespace android { - -class LibUtilsFirstStatics -{ -public: - LibUtilsFirstStatics() - { - initialize_string8(); - initialize_string16(); - } - - ~LibUtilsFirstStatics() - { - terminate_string16(); - terminate_string8(); - } -}; - -static LibUtilsFirstStatics gFirstStatics; -int gDarwinCantLoadAllObjects = 1; - -// ------------ Text output streams - -Vector<int32_t> gTextBuffers; - -class LogTextOutput : public BufferedTextOutput -{ -public: - LogTextOutput() : BufferedTextOutput(MULTITHREADED) { } - virtual ~LogTextOutput() { }; - -protected: - virtual status_t writeLines(const struct iovec& vec, size_t N) - { - //android_writevLog(&vec, N); <-- this is now a no-op - if (N != 1) ALOGI("WARNING: writeLines N=%zu\n", N); - ALOGI("%.*s", (int)vec.iov_len, (const char*) vec.iov_base); - return NO_ERROR; - } -}; - -class FdTextOutput : public BufferedTextOutput -{ -public: - FdTextOutput(int fd) : BufferedTextOutput(MULTITHREADED), mFD(fd) { } - virtual ~FdTextOutput() { }; - -protected: - virtual status_t writeLines(const struct iovec& vec, size_t N) - { - writev(mFD, &vec, N); - return NO_ERROR; - } - -private: - int mFD; -}; - -static LogTextOutput gLogTextOutput; -static FdTextOutput gStdoutTextOutput(STDOUT_FILENO); -static FdTextOutput gStderrTextOutput(STDERR_FILENO); - -TextOutput& alog(gLogTextOutput); -TextOutput& aout(gStdoutTextOutput); -TextOutput& aerr(gStderrTextOutput); - -} // namespace android diff --git a/libs/utils/StopWatch.cpp b/libs/utils/StopWatch.cpp deleted file mode 100644 index b1708d6..0000000 --- a/libs/utils/StopWatch.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2005 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 "StopWatch" - -#include <string.h> -#include <stdlib.h> -#include <stdio.h> - -/* for PRId64 */ -#define __STDC_FORMAT_MACROS 1 -#include <inttypes.h> - -#include <utils/Log.h> -#include <utils/Errors.h> -#include <utils/StopWatch.h> - -/*****************************************************************************/ - -namespace android { - - -StopWatch::StopWatch(const char *name, int clock, uint32_t flags) - : mName(name), mClock(clock), mFlags(flags) -{ - reset(); -} - -StopWatch::~StopWatch() -{ - nsecs_t elapsed = elapsedTime(); - const int n = mNumLaps; - ALOGD("StopWatch %s (us): %" PRId64 " ", mName, ns2us(elapsed)); - for (int i=0 ; i<n ; i++) { - const nsecs_t soFar = mLaps[i].soFar; - const nsecs_t thisLap = mLaps[i].thisLap; - ALOGD(" [%d: %" PRId64 ", %" PRId64, i, ns2us(soFar), ns2us(thisLap)); - } -} - -const char* StopWatch::name() const -{ - return mName; -} - -nsecs_t StopWatch::lap() -{ - nsecs_t elapsed = elapsedTime(); - if (mNumLaps >= 8) { - elapsed = 0; - } else { - const int n = mNumLaps; - mLaps[n].soFar = elapsed; - mLaps[n].thisLap = n ? (elapsed - mLaps[n-1].soFar) : elapsed; - mNumLaps = n+1; - } - return elapsed; -} - -nsecs_t StopWatch::elapsedTime() const -{ - return systemTime(mClock) - mStartTime; -} - -void StopWatch::reset() -{ - mNumLaps = 0; - mStartTime = systemTime(mClock); -} - - -/*****************************************************************************/ - -}; // namespace android - diff --git a/libs/utils/String16.cpp b/libs/utils/String16.cpp deleted file mode 100644 index 94e072f..0000000 --- a/libs/utils/String16.cpp +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Copyright (C) 2005 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 <utils/String16.h> - -#include <utils/Debug.h> -#include <utils/Log.h> -#include <utils/Unicode.h> -#include <utils/String8.h> -#include <utils/TextOutput.h> -#include <utils/threads.h> - -#include <private/utils/Static.h> - -#include <memory.h> -#include <stdio.h> -#include <ctype.h> - - -namespace android { - -static SharedBuffer* gEmptyStringBuf = NULL; -static char16_t* gEmptyString = NULL; - -static inline char16_t* getEmptyString() -{ - gEmptyStringBuf->acquire(); - return gEmptyString; -} - -void initialize_string16() -{ - SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t)); - char16_t* str = (char16_t*)buf->data(); - *str = 0; - gEmptyStringBuf = buf; - gEmptyString = str; -} - -void terminate_string16() -{ - SharedBuffer::bufferFromData(gEmptyString)->release(); - gEmptyStringBuf = NULL; - gEmptyString = NULL; -} - -// --------------------------------------------------------------------------- - -static char16_t* allocFromUTF8(const char* u8str, size_t u8len) -{ - if (u8len == 0) return getEmptyString(); - - const uint8_t* u8cur = (const uint8_t*) u8str; - - const ssize_t u16len = utf8_to_utf16_length(u8cur, u8len); - if (u16len < 0) { - return getEmptyString(); - } - - const uint8_t* const u8end = u8cur + u8len; - - SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t)*(u16len+1)); - if (buf) { - u8cur = (const uint8_t*) u8str; - char16_t* u16str = (char16_t*)buf->data(); - - utf8_to_utf16(u8cur, u8len, u16str); - - //printf("Created UTF-16 string from UTF-8 \"%s\":", in); - //printHexData(1, str, buf->size(), 16, 1); - //printf("\n"); - - return u16str; - } - - return getEmptyString(); -} - -// --------------------------------------------------------------------------- - -String16::String16() - : mString(getEmptyString()) -{ -} - -String16::String16(const String16& o) - : mString(o.mString) -{ - SharedBuffer::bufferFromData(mString)->acquire(); -} - -String16::String16(const String16& o, size_t len, size_t begin) - : mString(getEmptyString()) -{ - setTo(o, len, begin); -} - -String16::String16(const char16_t* o) -{ - size_t len = strlen16(o); - SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t)); - ALOG_ASSERT(buf, "Unable to allocate shared buffer"); - if (buf) { - char16_t* str = (char16_t*)buf->data(); - strcpy16(str, o); - mString = str; - return; - } - - mString = getEmptyString(); -} - -String16::String16(const char16_t* o, size_t len) -{ - SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t)); - ALOG_ASSERT(buf, "Unable to allocate shared buffer"); - if (buf) { - char16_t* str = (char16_t*)buf->data(); - memcpy(str, o, len*sizeof(char16_t)); - str[len] = 0; - mString = str; - return; - } - - mString = getEmptyString(); -} - -String16::String16(const String8& o) - : mString(allocFromUTF8(o.string(), o.size())) -{ -} - -String16::String16(const char* o) - : mString(allocFromUTF8(o, strlen(o))) -{ -} - -String16::String16(const char* o, size_t len) - : mString(allocFromUTF8(o, len)) -{ -} - -String16::~String16() -{ - SharedBuffer::bufferFromData(mString)->release(); -} - -void String16::setTo(const String16& other) -{ - SharedBuffer::bufferFromData(other.mString)->acquire(); - SharedBuffer::bufferFromData(mString)->release(); - mString = other.mString; -} - -status_t String16::setTo(const String16& other, size_t len, size_t begin) -{ - const size_t N = other.size(); - if (begin >= N) { - SharedBuffer::bufferFromData(mString)->release(); - mString = getEmptyString(); - return NO_ERROR; - } - if ((begin+len) > N) len = N-begin; - if (begin == 0 && len == N) { - setTo(other); - return NO_ERROR; - } - - if (&other == this) { - LOG_ALWAYS_FATAL("Not implemented"); - } - - return setTo(other.string()+begin, len); -} - -status_t String16::setTo(const char16_t* other) -{ - return setTo(other, strlen16(other)); -} - -status_t String16::setTo(const char16_t* other, size_t len) -{ - SharedBuffer* buf = SharedBuffer::bufferFromData(mString) - ->editResize((len+1)*sizeof(char16_t)); - if (buf) { - char16_t* str = (char16_t*)buf->data(); - memmove(str, other, len*sizeof(char16_t)); - str[len] = 0; - mString = str; - return NO_ERROR; - } - return NO_MEMORY; -} - -status_t String16::append(const String16& other) -{ - const size_t myLen = size(); - const size_t otherLen = other.size(); - if (myLen == 0) { - setTo(other); - return NO_ERROR; - } else if (otherLen == 0) { - return NO_ERROR; - } - - SharedBuffer* buf = SharedBuffer::bufferFromData(mString) - ->editResize((myLen+otherLen+1)*sizeof(char16_t)); - if (buf) { - char16_t* str = (char16_t*)buf->data(); - memcpy(str+myLen, other, (otherLen+1)*sizeof(char16_t)); - mString = str; - return NO_ERROR; - } - return NO_MEMORY; -} - -status_t String16::append(const char16_t* chrs, size_t otherLen) -{ - const size_t myLen = size(); - if (myLen == 0) { - setTo(chrs, otherLen); - return NO_ERROR; - } else if (otherLen == 0) { - return NO_ERROR; - } - - SharedBuffer* buf = SharedBuffer::bufferFromData(mString) - ->editResize((myLen+otherLen+1)*sizeof(char16_t)); - if (buf) { - char16_t* str = (char16_t*)buf->data(); - memcpy(str+myLen, chrs, otherLen*sizeof(char16_t)); - str[myLen+otherLen] = 0; - mString = str; - return NO_ERROR; - } - return NO_MEMORY; -} - -status_t String16::insert(size_t pos, const char16_t* chrs) -{ - return insert(pos, chrs, strlen16(chrs)); -} - -status_t String16::insert(size_t pos, const char16_t* chrs, size_t len) -{ - const size_t myLen = size(); - if (myLen == 0) { - return setTo(chrs, len); - return NO_ERROR; - } else if (len == 0) { - return NO_ERROR; - } - - if (pos > myLen) pos = myLen; - - #if 0 - printf("Insert in to %s: pos=%d, len=%d, myLen=%d, chrs=%s\n", - String8(*this).string(), pos, - len, myLen, String8(chrs, len).string()); - #endif - - SharedBuffer* buf = SharedBuffer::bufferFromData(mString) - ->editResize((myLen+len+1)*sizeof(char16_t)); - if (buf) { - char16_t* str = (char16_t*)buf->data(); - if (pos < myLen) { - memmove(str+pos+len, str+pos, (myLen-pos)*sizeof(char16_t)); - } - memcpy(str+pos, chrs, len*sizeof(char16_t)); - str[myLen+len] = 0; - mString = str; - #if 0 - printf("Result (%d chrs): %s\n", size(), String8(*this).string()); - #endif - return NO_ERROR; - } - return NO_MEMORY; -} - -ssize_t String16::findFirst(char16_t c) const -{ - const char16_t* str = string(); - const char16_t* p = str; - const char16_t* e = p + size(); - while (p < e) { - if (*p == c) { - return p-str; - } - p++; - } - return -1; -} - -ssize_t String16::findLast(char16_t c) const -{ - const char16_t* str = string(); - const char16_t* p = str; - const char16_t* e = p + size(); - while (p < e) { - e--; - if (*e == c) { - return e-str; - } - } - return -1; -} - -bool String16::startsWith(const String16& prefix) const -{ - const size_t ps = prefix.size(); - if (ps > size()) return false; - return strzcmp16(mString, ps, prefix.string(), ps) == 0; -} - -bool String16::startsWith(const char16_t* prefix) const -{ - const size_t ps = strlen16(prefix); - if (ps > size()) return false; - return strncmp16(mString, prefix, ps) == 0; -} - -status_t String16::makeLower() -{ - const size_t N = size(); - const char16_t* str = string(); - char16_t* edit = NULL; - for (size_t i=0; i<N; i++) { - const char16_t v = str[i]; - if (v >= 'A' && v <= 'Z') { - if (!edit) { - SharedBuffer* buf = SharedBuffer::bufferFromData(mString)->edit(); - if (!buf) { - return NO_MEMORY; - } - edit = (char16_t*)buf->data(); - mString = str = edit; - } - edit[i] = tolower((char)v); - } - } - return NO_ERROR; -} - -status_t String16::replaceAll(char16_t replaceThis, char16_t withThis) -{ - const size_t N = size(); - const char16_t* str = string(); - char16_t* edit = NULL; - for (size_t i=0; i<N; i++) { - if (str[i] == replaceThis) { - if (!edit) { - SharedBuffer* buf = SharedBuffer::bufferFromData(mString)->edit(); - if (!buf) { - return NO_MEMORY; - } - edit = (char16_t*)buf->data(); - mString = str = edit; - } - edit[i] = withThis; - } - } - return NO_ERROR; -} - -status_t String16::remove(size_t len, size_t begin) -{ - const size_t N = size(); - if (begin >= N) { - SharedBuffer::bufferFromData(mString)->release(); - mString = getEmptyString(); - return NO_ERROR; - } - if ((begin+len) > N) len = N-begin; - if (begin == 0 && len == N) { - return NO_ERROR; - } - - if (begin > 0) { - SharedBuffer* buf = SharedBuffer::bufferFromData(mString) - ->editResize((N+1)*sizeof(char16_t)); - if (!buf) { - return NO_MEMORY; - } - char16_t* str = (char16_t*)buf->data(); - memmove(str, str+begin, (N-begin+1)*sizeof(char16_t)); - mString = str; - } - SharedBuffer* buf = SharedBuffer::bufferFromData(mString) - ->editResize((len+1)*sizeof(char16_t)); - if (buf) { - char16_t* str = (char16_t*)buf->data(); - str[len] = 0; - mString = str; - return NO_ERROR; - } - return NO_MEMORY; -} - -TextOutput& operator<<(TextOutput& to, const String16& val) -{ - to << String8(val).string(); - return to; -} - -}; // namespace android diff --git a/libs/utils/String8.cpp b/libs/utils/String8.cpp deleted file mode 100644 index 562f026..0000000 --- a/libs/utils/String8.cpp +++ /dev/null @@ -1,634 +0,0 @@ -/* - * Copyright (C) 2005 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 <utils/String8.h> - -#include <utils/Log.h> -#include <utils/Unicode.h> -#include <utils/SharedBuffer.h> -#include <utils/String16.h> -#include <utils/TextOutput.h> -#include <utils/threads.h> - -#include <private/utils/Static.h> - -#include <ctype.h> - -/* - * Functions outside android is below the namespace android, since they use - * functions and constants in android namespace. - */ - -// --------------------------------------------------------------------------- - -namespace android { - -// Separator used by resource paths. This is not platform dependent contrary -// to OS_PATH_SEPARATOR. -#define RES_PATH_SEPARATOR '/' - -static SharedBuffer* gEmptyStringBuf = NULL; -static char* gEmptyString = NULL; - -extern int gDarwinCantLoadAllObjects; -int gDarwinIsReallyAnnoying; - -static inline char* getEmptyString() -{ - gEmptyStringBuf->acquire(); - return gEmptyString; -} - -void initialize_string8() -{ - // HACK: This dummy dependency forces linking libutils Static.cpp, - // which is needed to initialize String8/String16 classes. - // These variables are named for Darwin, but are needed elsewhere too, - // including static linking on any platform. - gDarwinIsReallyAnnoying = gDarwinCantLoadAllObjects; - - SharedBuffer* buf = SharedBuffer::alloc(1); - char* str = (char*)buf->data(); - *str = 0; - gEmptyStringBuf = buf; - gEmptyString = str; -} - -void terminate_string8() -{ - SharedBuffer::bufferFromData(gEmptyString)->release(); - gEmptyStringBuf = NULL; - gEmptyString = NULL; -} - -// --------------------------------------------------------------------------- - -static char* allocFromUTF8(const char* in, size_t len) -{ - if (len > 0) { - SharedBuffer* buf = SharedBuffer::alloc(len+1); - ALOG_ASSERT(buf, "Unable to allocate shared buffer"); - if (buf) { - char* str = (char*)buf->data(); - memcpy(str, in, len); - str[len] = 0; - return str; - } - return NULL; - } - - return getEmptyString(); -} - -static char* allocFromUTF16(const char16_t* in, size_t len) -{ - if (len == 0) return getEmptyString(); - - const ssize_t bytes = utf16_to_utf8_length(in, len); - if (bytes < 0) { - return getEmptyString(); - } - - SharedBuffer* buf = SharedBuffer::alloc(bytes+1); - ALOG_ASSERT(buf, "Unable to allocate shared buffer"); - if (!buf) { - return getEmptyString(); - } - - char* str = (char*)buf->data(); - utf16_to_utf8(in, len, str); - return str; -} - -static char* allocFromUTF32(const char32_t* in, size_t len) -{ - if (len == 0) { - return getEmptyString(); - } - - const ssize_t bytes = utf32_to_utf8_length(in, len); - if (bytes < 0) { - return getEmptyString(); - } - - SharedBuffer* buf = SharedBuffer::alloc(bytes+1); - ALOG_ASSERT(buf, "Unable to allocate shared buffer"); - if (!buf) { - return getEmptyString(); - } - - char* str = (char*) buf->data(); - utf32_to_utf8(in, len, str); - - return str; -} - -// --------------------------------------------------------------------------- - -String8::String8() - : mString(getEmptyString()) -{ -} - -String8::String8(const String8& o) - : mString(o.mString) -{ - SharedBuffer::bufferFromData(mString)->acquire(); -} - -String8::String8(const char* o) - : mString(allocFromUTF8(o, strlen(o))) -{ - if (mString == NULL) { - mString = getEmptyString(); - } -} - -String8::String8(const char* o, size_t len) - : mString(allocFromUTF8(o, len)) -{ - if (mString == NULL) { - mString = getEmptyString(); - } -} - -String8::String8(const String16& o) - : mString(allocFromUTF16(o.string(), o.size())) -{ -} - -String8::String8(const char16_t* o) - : mString(allocFromUTF16(o, strlen16(o))) -{ -} - -String8::String8(const char16_t* o, size_t len) - : mString(allocFromUTF16(o, len)) -{ -} - -String8::String8(const char32_t* o) - : mString(allocFromUTF32(o, strlen32(o))) -{ -} - -String8::String8(const char32_t* o, size_t len) - : mString(allocFromUTF32(o, len)) -{ -} - -String8::~String8() -{ - SharedBuffer::bufferFromData(mString)->release(); -} - -String8 String8::format(const char* fmt, ...) -{ - va_list args; - va_start(args, fmt); - - String8 result(formatV(fmt, args)); - - va_end(args); - return result; -} - -String8 String8::formatV(const char* fmt, va_list args) -{ - String8 result; - result.appendFormatV(fmt, args); - return result; -} - -void String8::clear() { - SharedBuffer::bufferFromData(mString)->release(); - mString = getEmptyString(); -} - -void String8::setTo(const String8& other) -{ - SharedBuffer::bufferFromData(other.mString)->acquire(); - SharedBuffer::bufferFromData(mString)->release(); - mString = other.mString; -} - -status_t String8::setTo(const char* other) -{ - const char *newString = allocFromUTF8(other, strlen(other)); - SharedBuffer::bufferFromData(mString)->release(); - mString = newString; - if (mString) return NO_ERROR; - - mString = getEmptyString(); - return NO_MEMORY; -} - -status_t String8::setTo(const char* other, size_t len) -{ - const char *newString = allocFromUTF8(other, len); - SharedBuffer::bufferFromData(mString)->release(); - mString = newString; - if (mString) return NO_ERROR; - - mString = getEmptyString(); - return NO_MEMORY; -} - -status_t String8::setTo(const char16_t* other, size_t len) -{ - const char *newString = allocFromUTF16(other, len); - SharedBuffer::bufferFromData(mString)->release(); - mString = newString; - if (mString) return NO_ERROR; - - mString = getEmptyString(); - return NO_MEMORY; -} - -status_t String8::setTo(const char32_t* other, size_t len) -{ - const char *newString = allocFromUTF32(other, len); - SharedBuffer::bufferFromData(mString)->release(); - mString = newString; - if (mString) return NO_ERROR; - - mString = getEmptyString(); - return NO_MEMORY; -} - -status_t String8::append(const String8& other) -{ - const size_t otherLen = other.bytes(); - if (bytes() == 0) { - setTo(other); - return NO_ERROR; - } else if (otherLen == 0) { - return NO_ERROR; - } - - return real_append(other.string(), otherLen); -} - -status_t String8::append(const char* other) -{ - return append(other, strlen(other)); -} - -status_t String8::append(const char* other, size_t otherLen) -{ - if (bytes() == 0) { - return setTo(other, otherLen); - } else if (otherLen == 0) { - return NO_ERROR; - } - - return real_append(other, otherLen); -} - -status_t String8::appendFormat(const char* fmt, ...) -{ - va_list args; - va_start(args, fmt); - - status_t result = appendFormatV(fmt, args); - - va_end(args); - return result; -} - -status_t String8::appendFormatV(const char* fmt, va_list args) -{ - int result = NO_ERROR; - int n = vsnprintf(NULL, 0, fmt, args); - if (n != 0) { - size_t oldLength = length(); - char* buf = lockBuffer(oldLength + n); - if (buf) { - vsnprintf(buf + oldLength, n + 1, fmt, args); - } else { - result = NO_MEMORY; - } - } - return result; -} - -status_t String8::real_append(const char* other, size_t otherLen) -{ - const size_t myLen = bytes(); - - SharedBuffer* buf = SharedBuffer::bufferFromData(mString) - ->editResize(myLen+otherLen+1); - if (buf) { - char* str = (char*)buf->data(); - mString = str; - str += myLen; - memcpy(str, other, otherLen); - str[otherLen] = '\0'; - return NO_ERROR; - } - return NO_MEMORY; -} - -char* String8::lockBuffer(size_t size) -{ - SharedBuffer* buf = SharedBuffer::bufferFromData(mString) - ->editResize(size+1); - if (buf) { - char* str = (char*)buf->data(); - mString = str; - return str; - } - return NULL; -} - -void String8::unlockBuffer() -{ - unlockBuffer(strlen(mString)); -} - -status_t String8::unlockBuffer(size_t size) -{ - if (size != this->size()) { - SharedBuffer* buf = SharedBuffer::bufferFromData(mString) - ->editResize(size+1); - if (! buf) { - return NO_MEMORY; - } - - char* str = (char*)buf->data(); - str[size] = 0; - mString = str; - } - - return NO_ERROR; -} - -ssize_t String8::find(const char* other, size_t start) const -{ - size_t len = size(); - if (start >= len) { - return -1; - } - const char* s = mString+start; - const char* p = strstr(s, other); - return p ? p-mString : -1; -} - -void String8::toLower() -{ - toLower(0, size()); -} - -void String8::toLower(size_t start, size_t length) -{ - const size_t len = size(); - if (start >= len) { - return; - } - if (start+length > len) { - length = len-start; - } - char* buf = lockBuffer(len); - buf += start; - while (length > 0) { - *buf = tolower(*buf); - buf++; - length--; - } - unlockBuffer(len); -} - -void String8::toUpper() -{ - toUpper(0, size()); -} - -void String8::toUpper(size_t start, size_t length) -{ - const size_t len = size(); - if (start >= len) { - return; - } - if (start+length > len) { - length = len-start; - } - char* buf = lockBuffer(len); - buf += start; - while (length > 0) { - *buf = toupper(*buf); - buf++; - length--; - } - unlockBuffer(len); -} - -size_t String8::getUtf32Length() const -{ - return utf8_to_utf32_length(mString, length()); -} - -int32_t String8::getUtf32At(size_t index, size_t *next_index) const -{ - return utf32_from_utf8_at(mString, length(), index, next_index); -} - -void String8::getUtf32(char32_t* dst) const -{ - utf8_to_utf32(mString, length(), dst); -} - -TextOutput& operator<<(TextOutput& to, const String8& val) -{ - to << val.string(); - return to; -} - -// --------------------------------------------------------------------------- -// Path functions - -void String8::setPathName(const char* name) -{ - setPathName(name, strlen(name)); -} - -void String8::setPathName(const char* name, size_t len) -{ - char* buf = lockBuffer(len); - - memcpy(buf, name, len); - - // remove trailing path separator, if present - if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR) - len--; - - buf[len] = '\0'; - - unlockBuffer(len); -} - -String8 String8::getPathLeaf(void) const -{ - const char* cp; - const char*const buf = mString; - - cp = strrchr(buf, OS_PATH_SEPARATOR); - if (cp == NULL) - return String8(*this); - else - return String8(cp+1); -} - -String8 String8::getPathDir(void) const -{ - const char* cp; - const char*const str = mString; - - cp = strrchr(str, OS_PATH_SEPARATOR); - if (cp == NULL) - return String8(""); - else - return String8(str, cp - str); -} - -String8 String8::walkPath(String8* outRemains) const -{ - const char* cp; - const char*const str = mString; - const char* buf = str; - - cp = strchr(buf, OS_PATH_SEPARATOR); - if (cp == buf) { - // don't include a leading '/'. - buf = buf+1; - cp = strchr(buf, OS_PATH_SEPARATOR); - } - - if (cp == NULL) { - String8 res = buf != str ? String8(buf) : *this; - if (outRemains) *outRemains = String8(""); - return res; - } - - String8 res(buf, cp-buf); - if (outRemains) *outRemains = String8(cp+1); - return res; -} - -/* - * Helper function for finding the start of an extension in a pathname. - * - * Returns a pointer inside mString, or NULL if no extension was found. - */ -char* String8::find_extension(void) const -{ - const char* lastSlash; - const char* lastDot; - int extLen; - const char* const str = mString; - - // only look at the filename - lastSlash = strrchr(str, OS_PATH_SEPARATOR); - if (lastSlash == NULL) - lastSlash = str; - else - lastSlash++; - - // find the last dot - lastDot = strrchr(lastSlash, '.'); - if (lastDot == NULL) - return NULL; - - // looks good, ship it - return const_cast<char*>(lastDot); -} - -String8 String8::getPathExtension(void) const -{ - char* ext; - - ext = find_extension(); - if (ext != NULL) - return String8(ext); - else - return String8(""); -} - -String8 String8::getBasePath(void) const -{ - char* ext; - const char* const str = mString; - - ext = find_extension(); - if (ext == NULL) - return String8(*this); - else - return String8(str, ext - str); -} - -String8& String8::appendPath(const char* name) -{ - // TODO: The test below will fail for Win32 paths. Fix later or ignore. - if (name[0] != OS_PATH_SEPARATOR) { - if (*name == '\0') { - // nothing to do - return *this; - } - - size_t len = length(); - if (len == 0) { - // no existing filename, just use the new one - setPathName(name); - return *this; - } - - // make room for oldPath + '/' + newPath - int newlen = strlen(name); - - char* buf = lockBuffer(len+1+newlen); - - // insert a '/' if needed - if (buf[len-1] != OS_PATH_SEPARATOR) - buf[len++] = OS_PATH_SEPARATOR; - - memcpy(buf+len, name, newlen+1); - len += newlen; - - unlockBuffer(len); - - return *this; - } else { - setPathName(name); - return *this; - } -} - -String8& String8::convertToResPath() -{ -#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR - size_t len = length(); - if (len > 0) { - char * buf = lockBuffer(len); - for (char * end = buf + len; buf < end; ++buf) { - if (*buf == OS_PATH_SEPARATOR) - *buf = RES_PATH_SEPARATOR; - } - unlockBuffer(len); - } -#endif - return *this; -} - -}; // namespace android diff --git a/libs/utils/StringArray.cpp b/libs/utils/StringArray.cpp deleted file mode 100644 index aa42d68..0000000 --- a/libs/utils/StringArray.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * 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. - */ - -// -// Sortable array of strings. STL-ish, but STL-free. -// - -#include <stdlib.h> -#include <string.h> - -#include <utils/StringArray.h> - -namespace android { - -// -// An expanding array of strings. Add, get, sort, delete. -// -StringArray::StringArray() - : mMax(0), mCurrent(0), mArray(NULL) -{ -} - -StringArray:: ~StringArray() { - for (int i = 0; i < mCurrent; i++) - delete[] mArray[i]; - delete[] mArray; -} - -// -// Add a string. A copy of the string is made. -// -bool StringArray::push_back(const char* str) { - if (mCurrent >= mMax) { - char** tmp; - - if (mMax == 0) - mMax = 16; // initial storage - else - mMax *= 2; - - tmp = new char*[mMax]; - if (tmp == NULL) - return false; - - memcpy(tmp, mArray, mCurrent * sizeof(char*)); - delete[] mArray; - mArray = tmp; - } - - int len = strlen(str); - mArray[mCurrent] = new char[len+1]; - memcpy(mArray[mCurrent], str, len+1); - mCurrent++; - - return true; -} - -// -// Delete an entry. -// -void StringArray::erase(int idx) { - if (idx < 0 || idx >= mCurrent) - return; - delete[] mArray[idx]; - if (idx < mCurrent-1) { - memmove(&mArray[idx], &mArray[idx+1], - (mCurrent-1 - idx) * sizeof(char*)); - } - mCurrent--; -} - -// -// Sort the array. -// -void StringArray::sort(int (*compare)(const void*, const void*)) { - qsort(mArray, mCurrent, sizeof(char*), compare); -} - -// -// Pass this to the sort routine to do an ascending alphabetical sort. -// -int StringArray::cmpAscendingAlpha(const void* pstr1, const void* pstr2) { - return strcmp(*(const char**)pstr1, *(const char**)pstr2); -} - -// -// Set entry N to specified string. -// [should use operator[] here] -// -void StringArray::setEntry(int idx, const char* str) { - if (idx < 0 || idx >= mCurrent) - return; - delete[] mArray[idx]; - int len = strlen(str); - mArray[idx] = new char[len+1]; - memcpy(mArray[idx], str, len+1); -} - - -}; // namespace android diff --git a/libs/utils/SystemClock.cpp b/libs/utils/SystemClock.cpp deleted file mode 100644 index 8b8ac10..0000000 --- a/libs/utils/SystemClock.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (C) 2008 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. - */ - - -/* - * System clock functions. - */ - -#ifdef HAVE_ANDROID_OS -#include <linux/ioctl.h> -#include <linux/rtc.h> -#include <utils/Atomic.h> -#include <linux/android_alarm.h> -#endif - -#include <sys/time.h> -#include <limits.h> -#include <fcntl.h> -#include <errno.h> -#include <string.h> - -#include <utils/SystemClock.h> -#include <utils/Timers.h> - -#define LOG_TAG "SystemClock" -#include "utils/Log.h" - -namespace android { - -/* - * Set the current time. This only works when running as root. - */ -int setCurrentTimeMillis(int64_t millis) -{ -#if WIN32 - // not implemented - return -1; -#else - struct timeval tv; -#ifdef HAVE_ANDROID_OS - struct timespec ts; - int fd; - int res; -#endif - int ret = 0; - - if (millis <= 0 || millis / 1000LL >= INT_MAX) { - return -1; - } - - tv.tv_sec = (time_t) (millis / 1000LL); - tv.tv_usec = (suseconds_t) ((millis % 1000LL) * 1000LL); - - ALOGD("Setting time of day to sec=%d\n", (int) tv.tv_sec); - -#ifdef HAVE_ANDROID_OS - fd = open("/dev/alarm", O_RDWR); - if(fd < 0) { - ALOGW("Unable to open alarm driver: %s\n", strerror(errno)); - return -1; - } - ts.tv_sec = tv.tv_sec; - ts.tv_nsec = tv.tv_usec * 1000; - res = ioctl(fd, ANDROID_ALARM_SET_RTC, &ts); - if(res < 0) { - ALOGW("Unable to set rtc to %ld: %s\n", tv.tv_sec, strerror(errno)); - ret = -1; - } - close(fd); -#else - if (settimeofday(&tv, NULL) != 0) { - ALOGW("Unable to set clock to %d.%d: %s\n", - (int) tv.tv_sec, (int) tv.tv_usec, strerror(errno)); - ret = -1; - } -#endif - - return ret; -#endif // WIN32 -} - -/* - * native public static long uptimeMillis(); - */ -int64_t uptimeMillis() -{ - int64_t when = systemTime(SYSTEM_TIME_MONOTONIC); - return (int64_t) nanoseconds_to_milliseconds(when); -} - -/* - * native public static long elapsedRealtime(); - */ -int64_t elapsedRealtime() -{ -#ifdef HAVE_ANDROID_OS - static int s_fd = -1; - - if (s_fd == -1) { - int fd = open("/dev/alarm", O_RDONLY); - if (android_atomic_cmpxchg(-1, fd, &s_fd)) { - close(fd); - } - } - - struct timespec ts; - int result = ioctl(s_fd, - ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), &ts); - - if (result == 0) { - int64_t when = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec; - return (int64_t) nanoseconds_to_milliseconds(when); - } else { - // XXX: there was an error, probably because the driver didn't - // exist ... this should return - // a real error, like an exception! - int64_t when = systemTime(SYSTEM_TIME_MONOTONIC); - return (int64_t) nanoseconds_to_milliseconds(when); - } -#else - int64_t when = systemTime(SYSTEM_TIME_MONOTONIC); - return (int64_t) nanoseconds_to_milliseconds(when); -#endif -} - -}; // namespace android diff --git a/libs/utils/TextOutput.cpp b/libs/utils/TextOutput.cpp deleted file mode 100644 index e04823d..0000000 --- a/libs/utils/TextOutput.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2005 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 <utils/TextOutput.h> - -#include <utils/Debug.h> - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -namespace android { - -// --------------------------------------------------------------------------- - -TextOutput::TextOutput() { -} - -TextOutput::~TextOutput() { -} - -// --------------------------------------------------------------------------- - -TextOutput& operator<<(TextOutput& to, bool val) -{ - if (val) to.print("true", 4); - else to.print("false", 5); - return to; -} - -TextOutput& operator<<(TextOutput& to, int val) -{ - char buf[16]; - sprintf(buf, "%d", val); - to.print(buf, strlen(buf)); - return to; -} - -TextOutput& operator<<(TextOutput& to, long val) -{ - char buf[16]; - sprintf(buf, "%ld", val); - to.print(buf, strlen(buf)); - return to; -} - -TextOutput& operator<<(TextOutput& to, unsigned int val) -{ - char buf[16]; - sprintf(buf, "%u", val); - to.print(buf, strlen(buf)); - return to; -} - -TextOutput& operator<<(TextOutput& to, unsigned long val) -{ - char buf[16]; - sprintf(buf, "%lu", val); - to.print(buf, strlen(buf)); - return to; -} - -TextOutput& operator<<(TextOutput& to, long long val) -{ - char buf[32]; - sprintf(buf, "%Ld", val); - to.print(buf, strlen(buf)); - return to; -} - -TextOutput& operator<<(TextOutput& to, unsigned long long val) -{ - char buf[32]; - sprintf(buf, "%Lu", val); - to.print(buf, strlen(buf)); - return to; -} - -static TextOutput& print_float(TextOutput& to, double value) -{ - char buf[64]; - sprintf(buf, "%g", value); - if( !strchr(buf, '.') && !strchr(buf, 'e') && - !strchr(buf, 'E') ) { - strncat(buf, ".0", sizeof(buf)-1); - } - to.print(buf, strlen(buf)); - return to; -} - -TextOutput& operator<<(TextOutput& to, float val) -{ - return print_float(to,val); -} - -TextOutput& operator<<(TextOutput& to, double val) -{ - return print_float(to,val); -} - -TextOutput& operator<<(TextOutput& to, const void* val) -{ - char buf[16]; - sprintf(buf, "%p", val); - to.print(buf, strlen(buf)); - return to; -} - -static void textOutputPrinter(void* cookie, const char* txt) -{ - ((TextOutput*)cookie)->print(txt, strlen(txt)); -} - -TextOutput& operator<<(TextOutput& to, const TypeCode& val) -{ - printTypeCode(val.typeCode(), textOutputPrinter, (void*)&to); - return to; -} - -HexDump::HexDump(const void *buf, size_t size, size_t bytesPerLine) - : mBuffer(buf) - , mSize(size) - , mBytesPerLine(bytesPerLine) - , mSingleLineCutoff(16) - , mAlignment(4) - , mCArrayStyle(false) -{ - if (bytesPerLine >= 16) mAlignment = 4; - else if (bytesPerLine >= 8) mAlignment = 2; - else mAlignment = 1; -} - -TextOutput& operator<<(TextOutput& to, const HexDump& val) -{ - printHexData(0, val.buffer(), val.size(), val.bytesPerLine(), - val.singleLineCutoff(), val.alignment(), val.carrayStyle(), - textOutputPrinter, (void*)&to); - return to; -} - -}; // namespace android diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp deleted file mode 100644 index ab207f5..0000000 --- a/libs/utils/Threads.cpp +++ /dev/null @@ -1,952 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// #define LOG_NDEBUG 0 -#define LOG_TAG "libutils.threads" - -#include <utils/threads.h> -#include <utils/Log.h> - -#include <cutils/sched_policy.h> -#include <cutils/properties.h> - -#include <stdio.h> -#include <stdlib.h> -#include <memory.h> -#include <errno.h> -#include <assert.h> -#include <unistd.h> - -#if defined(HAVE_PTHREADS) -# include <pthread.h> -# include <sched.h> -# include <sys/resource.h> -#ifdef HAVE_ANDROID_OS -# include <bionic_pthread.h> -#endif -#elif defined(HAVE_WIN32_THREADS) -# include <windows.h> -# include <stdint.h> -# include <process.h> -# define HAVE_CREATETHREAD // Cygwin, vs. HAVE__BEGINTHREADEX for MinGW -#endif - -#if defined(HAVE_PRCTL) -#include <sys/prctl.h> -#endif - -/* - * =========================================================================== - * Thread wrappers - * =========================================================================== - */ - -using namespace android; - -// ---------------------------------------------------------------------------- -#if defined(HAVE_PTHREADS) -// ---------------------------------------------------------------------------- - -/* - * Create and run a new thread. - * - * We create it "detached", so it cleans up after itself. - */ - -typedef void* (*android_pthread_entry)(void*); - -static pthread_once_t gDoSchedulingGroupOnce = PTHREAD_ONCE_INIT; -static bool gDoSchedulingGroup = true; - -static void checkDoSchedulingGroup(void) { - char buf[PROPERTY_VALUE_MAX]; - int len = property_get("debug.sys.noschedgroups", buf, ""); - if (len > 0) { - int temp; - if (sscanf(buf, "%d", &temp) == 1) { - gDoSchedulingGroup = temp == 0; - } - } -} - -struct thread_data_t { - thread_func_t entryFunction; - void* userData; - int priority; - char * threadName; - - // we use this trampoline when we need to set the priority with - // nice/setpriority, and name with prctl. - static int trampoline(const thread_data_t* t) { - thread_func_t f = t->entryFunction; - void* u = t->userData; - int prio = t->priority; - char * name = t->threadName; - delete t; - setpriority(PRIO_PROCESS, 0, prio); - pthread_once(&gDoSchedulingGroupOnce, checkDoSchedulingGroup); - if (gDoSchedulingGroup) { - if (prio >= ANDROID_PRIORITY_BACKGROUND) { - set_sched_policy(androidGetTid(), SP_BACKGROUND); - } else { - set_sched_policy(androidGetTid(), SP_FOREGROUND); - } - } - - if (name) { -#if defined(HAVE_PRCTL) - // Mac OS doesn't have this, and we build libutil for the host too - int hasAt = 0; - int hasDot = 0; - char *s = name; - while (*s) { - if (*s == '.') hasDot = 1; - else if (*s == '@') hasAt = 1; - s++; - } - int len = s - name; - if (len < 15 || hasAt || !hasDot) { - s = name; - } else { - s = name + len - 15; - } - prctl(PR_SET_NAME, (unsigned long) s, 0, 0, 0); -#endif - free(name); - } - return f(u); - } -}; - -int androidCreateRawThreadEtc(android_thread_func_t entryFunction, - void *userData, - const char* threadName, - int32_t threadPriority, - size_t threadStackSize, - android_thread_id_t *threadId) -{ - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - -#ifdef HAVE_ANDROID_OS /* valgrind is rejecting RT-priority create reqs */ - if (threadPriority != PRIORITY_DEFAULT || threadName != NULL) { - // Now that the pthread_t has a method to find the associated - // android_thread_id_t (pid) from pthread_t, it would be possible to avoid - // this trampoline in some cases as the parent could set the properties - // for the child. However, there would be a race condition because the - // child becomes ready immediately, and it doesn't work for the name. - // prctl(PR_SET_NAME) only works for self; prctl(PR_SET_THREAD_NAME) was - // proposed but not yet accepted. - thread_data_t* t = new thread_data_t; - t->priority = threadPriority; - t->threadName = threadName ? strdup(threadName) : NULL; - t->entryFunction = entryFunction; - t->userData = userData; - entryFunction = (android_thread_func_t)&thread_data_t::trampoline; - userData = t; - } -#endif - - if (threadStackSize) { - pthread_attr_setstacksize(&attr, threadStackSize); - } - - errno = 0; - pthread_t thread; - int result = pthread_create(&thread, &attr, - (android_pthread_entry)entryFunction, userData); - pthread_attr_destroy(&attr); - if (result != 0) { - ALOGE("androidCreateRawThreadEtc failed (entry=%p, res=%d, errno=%d)\n" - "(android threadPriority=%d)", - entryFunction, result, errno, threadPriority); - return 0; - } - - // Note that *threadID is directly available to the parent only, as it is - // assigned after the child starts. Use memory barrier / lock if the child - // or other threads also need access. - if (threadId != NULL) { - *threadId = (android_thread_id_t)thread; // XXX: this is not portable - } - return 1; -} - -#ifdef HAVE_ANDROID_OS -static pthread_t android_thread_id_t_to_pthread(android_thread_id_t thread) -{ - return (pthread_t) thread; -} -#endif - -android_thread_id_t androidGetThreadId() -{ - return (android_thread_id_t)pthread_self(); -} - -// ---------------------------------------------------------------------------- -#elif defined(HAVE_WIN32_THREADS) -// ---------------------------------------------------------------------------- - -/* - * Trampoline to make us __stdcall-compliant. - * - * We're expected to delete "vDetails" when we're done. - */ -struct threadDetails { - int (*func)(void*); - void* arg; -}; -static __stdcall unsigned int threadIntermediary(void* vDetails) -{ - struct threadDetails* pDetails = (struct threadDetails*) vDetails; - int result; - - result = (*(pDetails->func))(pDetails->arg); - - delete pDetails; - - ALOG(LOG_VERBOSE, "thread", "thread exiting\n"); - return (unsigned int) result; -} - -/* - * Create and run a new thread. - */ -static bool doCreateThread(android_thread_func_t fn, void* arg, android_thread_id_t *id) -{ - HANDLE hThread; - struct threadDetails* pDetails = new threadDetails; // must be on heap - unsigned int thrdaddr; - - pDetails->func = fn; - pDetails->arg = arg; - -#if defined(HAVE__BEGINTHREADEX) - hThread = (HANDLE) _beginthreadex(NULL, 0, threadIntermediary, pDetails, 0, - &thrdaddr); - if (hThread == 0) -#elif defined(HAVE_CREATETHREAD) - hThread = CreateThread(NULL, 0, - (LPTHREAD_START_ROUTINE) threadIntermediary, - (void*) pDetails, 0, (DWORD*) &thrdaddr); - if (hThread == NULL) -#endif - { - ALOG(LOG_WARN, "thread", "WARNING: thread create failed\n"); - return false; - } - -#if defined(HAVE_CREATETHREAD) - /* close the management handle */ - CloseHandle(hThread); -#endif - - if (id != NULL) { - *id = (android_thread_id_t)thrdaddr; - } - - return true; -} - -int androidCreateRawThreadEtc(android_thread_func_t fn, - void *userData, - const char* threadName, - int32_t threadPriority, - size_t threadStackSize, - android_thread_id_t *threadId) -{ - return doCreateThread( fn, userData, threadId); -} - -android_thread_id_t androidGetThreadId() -{ - return (android_thread_id_t)GetCurrentThreadId(); -} - -// ---------------------------------------------------------------------------- -#else -#error "Threads not supported" -#endif - -// ---------------------------------------------------------------------------- - -int androidCreateThread(android_thread_func_t fn, void* arg) -{ - return createThreadEtc(fn, arg); -} - -int androidCreateThreadGetID(android_thread_func_t fn, void *arg, android_thread_id_t *id) -{ - return createThreadEtc(fn, arg, "android:unnamed_thread", - PRIORITY_DEFAULT, 0, id); -} - -static android_create_thread_fn gCreateThreadFn = androidCreateRawThreadEtc; - -int androidCreateThreadEtc(android_thread_func_t entryFunction, - void *userData, - const char* threadName, - int32_t threadPriority, - size_t threadStackSize, - android_thread_id_t *threadId) -{ - return gCreateThreadFn(entryFunction, userData, threadName, - threadPriority, threadStackSize, threadId); -} - -void androidSetCreateThreadFunc(android_create_thread_fn func) -{ - gCreateThreadFn = func; -} - -pid_t androidGetTid() -{ -#ifdef HAVE_GETTID - return gettid(); -#else - return getpid(); -#endif -} - -int androidSetThreadSchedulingGroup(pid_t tid, int grp) -{ - if (grp > ANDROID_TGROUP_MAX || grp < 0) { - return BAD_VALUE; - } - -#if defined(HAVE_PTHREADS) - pthread_once(&gDoSchedulingGroupOnce, checkDoSchedulingGroup); - if (gDoSchedulingGroup) { - // set_sched_policy does not support tid == 0 - if (tid == 0) { - tid = androidGetTid(); - } - if (set_sched_policy(tid, (grp == ANDROID_TGROUP_BG_NONINTERACT) ? - SP_BACKGROUND : SP_FOREGROUND)) { - return PERMISSION_DENIED; - } - } -#endif - - return NO_ERROR; -} - -int androidSetThreadPriority(pid_t tid, int pri) -{ - int rc = 0; - -#if defined(HAVE_PTHREADS) - int lasterr = 0; - - pthread_once(&gDoSchedulingGroupOnce, checkDoSchedulingGroup); - if (gDoSchedulingGroup) { - // set_sched_policy does not support tid == 0 - int policy_tid; - if (tid == 0) { - policy_tid = androidGetTid(); - } else { - policy_tid = tid; - } - if (pri >= ANDROID_PRIORITY_BACKGROUND) { - rc = set_sched_policy(policy_tid, SP_BACKGROUND); - } else if (getpriority(PRIO_PROCESS, tid) >= ANDROID_PRIORITY_BACKGROUND) { - rc = set_sched_policy(policy_tid, SP_FOREGROUND); - } - } - - if (rc) { - lasterr = errno; - } - - if (setpriority(PRIO_PROCESS, tid, pri) < 0) { - rc = INVALID_OPERATION; - } else { - errno = lasterr; - } -#endif - - return rc; -} - -int androidGetThreadPriority(pid_t tid) { -#if defined(HAVE_PTHREADS) - return getpriority(PRIO_PROCESS, tid); -#else - return ANDROID_PRIORITY_NORMAL; -#endif -} - -int androidGetThreadSchedulingGroup(pid_t tid) -{ - int ret = ANDROID_TGROUP_DEFAULT; - -#if defined(HAVE_PTHREADS) - // convention is to not call get/set_sched_policy methods if disabled by property - pthread_once(&gDoSchedulingGroupOnce, checkDoSchedulingGroup); - if (gDoSchedulingGroup) { - SchedPolicy policy; - // get_sched_policy does not support tid == 0 - if (tid == 0) { - tid = androidGetTid(); - } - if (get_sched_policy(tid, &policy) < 0) { - ret = INVALID_OPERATION; - } else { - switch (policy) { - case SP_BACKGROUND: - ret = ANDROID_TGROUP_BG_NONINTERACT; - break; - case SP_FOREGROUND: - ret = ANDROID_TGROUP_FG_BOOST; - break; - default: - // should not happen, as enum SchedPolicy does not have any other values - ret = INVALID_OPERATION; - break; - } - } - } -#endif - - return ret; -} - -namespace android { - -/* - * =========================================================================== - * Mutex class - * =========================================================================== - */ - -#if defined(HAVE_PTHREADS) -// implemented as inlines in threads.h -#elif defined(HAVE_WIN32_THREADS) - -Mutex::Mutex() -{ - HANDLE hMutex; - - assert(sizeof(hMutex) == sizeof(mState)); - - hMutex = CreateMutex(NULL, FALSE, NULL); - mState = (void*) hMutex; -} - -Mutex::Mutex(const char* name) -{ - // XXX: name not used for now - HANDLE hMutex; - - assert(sizeof(hMutex) == sizeof(mState)); - - hMutex = CreateMutex(NULL, FALSE, NULL); - mState = (void*) hMutex; -} - -Mutex::Mutex(int type, const char* name) -{ - // XXX: type and name not used for now - HANDLE hMutex; - - assert(sizeof(hMutex) == sizeof(mState)); - - hMutex = CreateMutex(NULL, FALSE, NULL); - mState = (void*) hMutex; -} - -Mutex::~Mutex() -{ - CloseHandle((HANDLE) mState); -} - -status_t Mutex::lock() -{ - DWORD dwWaitResult; - dwWaitResult = WaitForSingleObject((HANDLE) mState, INFINITE); - return dwWaitResult != WAIT_OBJECT_0 ? -1 : NO_ERROR; -} - -void Mutex::unlock() -{ - if (!ReleaseMutex((HANDLE) mState)) - ALOG(LOG_WARN, "thread", "WARNING: bad result from unlocking mutex\n"); -} - -status_t Mutex::tryLock() -{ - DWORD dwWaitResult; - - dwWaitResult = WaitForSingleObject((HANDLE) mState, 0); - if (dwWaitResult != WAIT_OBJECT_0 && dwWaitResult != WAIT_TIMEOUT) - ALOG(LOG_WARN, "thread", "WARNING: bad result from try-locking mutex\n"); - return (dwWaitResult == WAIT_OBJECT_0) ? 0 : -1; -} - -#else -#error "Somebody forgot to implement threads for this platform." -#endif - - -/* - * =========================================================================== - * Condition class - * =========================================================================== - */ - -#if defined(HAVE_PTHREADS) -// implemented as inlines in threads.h -#elif defined(HAVE_WIN32_THREADS) - -/* - * Windows doesn't have a condition variable solution. It's possible - * to create one, but it's easy to get it wrong. For a discussion, and - * the origin of this implementation, see: - * - * http://www.cs.wustl.edu/~schmidt/win32-cv-1.html - * - * The implementation shown on the page does NOT follow POSIX semantics. - * As an optimization they require acquiring the external mutex before - * calling signal() and broadcast(), whereas POSIX only requires grabbing - * it before calling wait(). The implementation here has been un-optimized - * to have the correct behavior. - */ -typedef struct WinCondition { - // Number of waiting threads. - int waitersCount; - - // Serialize access to waitersCount. - CRITICAL_SECTION waitersCountLock; - - // Semaphore used to queue up threads waiting for the condition to - // become signaled. - HANDLE sema; - - // An auto-reset event used by the broadcast/signal thread to wait - // for all the waiting thread(s) to wake up and be released from - // the semaphore. - HANDLE waitersDone; - - // This mutex wouldn't be necessary if we required that the caller - // lock the external mutex before calling signal() and broadcast(). - // I'm trying to mimic pthread semantics though. - HANDLE internalMutex; - - // Keeps track of whether we were broadcasting or signaling. This - // allows us to optimize the code if we're just signaling. - bool wasBroadcast; - - status_t wait(WinCondition* condState, HANDLE hMutex, nsecs_t* abstime) - { - // Increment the wait count, avoiding race conditions. - EnterCriticalSection(&condState->waitersCountLock); - condState->waitersCount++; - //printf("+++ wait: incr waitersCount to %d (tid=%ld)\n", - // condState->waitersCount, getThreadId()); - LeaveCriticalSection(&condState->waitersCountLock); - - DWORD timeout = INFINITE; - if (abstime) { - nsecs_t reltime = *abstime - systemTime(); - if (reltime < 0) - reltime = 0; - timeout = reltime/1000000; - } - - // Atomically release the external mutex and wait on the semaphore. - DWORD res = - SignalObjectAndWait(hMutex, condState->sema, timeout, FALSE); - - //printf("+++ wait: awake (tid=%ld)\n", getThreadId()); - - // Reacquire lock to avoid race conditions. - EnterCriticalSection(&condState->waitersCountLock); - - // No longer waiting. - condState->waitersCount--; - - // Check to see if we're the last waiter after a broadcast. - bool lastWaiter = (condState->wasBroadcast && condState->waitersCount == 0); - - //printf("+++ wait: lastWaiter=%d (wasBc=%d wc=%d)\n", - // lastWaiter, condState->wasBroadcast, condState->waitersCount); - - LeaveCriticalSection(&condState->waitersCountLock); - - // If we're the last waiter thread during this particular broadcast - // then signal broadcast() that we're all awake. It'll drop the - // internal mutex. - if (lastWaiter) { - // Atomically signal the "waitersDone" event and wait until we - // can acquire the internal mutex. We want to do this in one step - // because it ensures that everybody is in the mutex FIFO before - // any thread has a chance to run. Without it, another thread - // could wake up, do work, and hop back in ahead of us. - SignalObjectAndWait(condState->waitersDone, condState->internalMutex, - INFINITE, FALSE); - } else { - // Grab the internal mutex. - WaitForSingleObject(condState->internalMutex, INFINITE); - } - - // Release the internal and grab the external. - ReleaseMutex(condState->internalMutex); - WaitForSingleObject(hMutex, INFINITE); - - return res == WAIT_OBJECT_0 ? NO_ERROR : -1; - } -} WinCondition; - -/* - * Constructor. Set up the WinCondition stuff. - */ -Condition::Condition() -{ - WinCondition* condState = new WinCondition; - - condState->waitersCount = 0; - condState->wasBroadcast = false; - // semaphore: no security, initial value of 0 - condState->sema = CreateSemaphore(NULL, 0, 0x7fffffff, NULL); - InitializeCriticalSection(&condState->waitersCountLock); - // auto-reset event, not signaled initially - condState->waitersDone = CreateEvent(NULL, FALSE, FALSE, NULL); - // used so we don't have to lock external mutex on signal/broadcast - condState->internalMutex = CreateMutex(NULL, FALSE, NULL); - - mState = condState; -} - -/* - * Destructor. Free Windows resources as well as our allocated storage. - */ -Condition::~Condition() -{ - WinCondition* condState = (WinCondition*) mState; - if (condState != NULL) { - CloseHandle(condState->sema); - CloseHandle(condState->waitersDone); - delete condState; - } -} - - -status_t Condition::wait(Mutex& mutex) -{ - WinCondition* condState = (WinCondition*) mState; - HANDLE hMutex = (HANDLE) mutex.mState; - - return ((WinCondition*)mState)->wait(condState, hMutex, NULL); -} - -status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) -{ - WinCondition* condState = (WinCondition*) mState; - HANDLE hMutex = (HANDLE) mutex.mState; - nsecs_t absTime = systemTime()+reltime; - - return ((WinCondition*)mState)->wait(condState, hMutex, &absTime); -} - -/* - * Signal the condition variable, allowing one thread to continue. - */ -void Condition::signal() -{ - WinCondition* condState = (WinCondition*) mState; - - // Lock the internal mutex. This ensures that we don't clash with - // broadcast(). - WaitForSingleObject(condState->internalMutex, INFINITE); - - EnterCriticalSection(&condState->waitersCountLock); - bool haveWaiters = (condState->waitersCount > 0); - LeaveCriticalSection(&condState->waitersCountLock); - - // If no waiters, then this is a no-op. Otherwise, knock the semaphore - // down a notch. - if (haveWaiters) - ReleaseSemaphore(condState->sema, 1, 0); - - // Release internal mutex. - ReleaseMutex(condState->internalMutex); -} - -/* - * Signal the condition variable, allowing all threads to continue. - * - * First we have to wake up all threads waiting on the semaphore, then - * we wait until all of the threads have actually been woken before - * releasing the internal mutex. This ensures that all threads are woken. - */ -void Condition::broadcast() -{ - WinCondition* condState = (WinCondition*) mState; - - // Lock the internal mutex. This keeps the guys we're waking up - // from getting too far. - WaitForSingleObject(condState->internalMutex, INFINITE); - - EnterCriticalSection(&condState->waitersCountLock); - bool haveWaiters = false; - - if (condState->waitersCount > 0) { - haveWaiters = true; - condState->wasBroadcast = true; - } - - if (haveWaiters) { - // Wake up all the waiters. - ReleaseSemaphore(condState->sema, condState->waitersCount, 0); - - LeaveCriticalSection(&condState->waitersCountLock); - - // Wait for all awakened threads to acquire the counting semaphore. - // The last guy who was waiting sets this. - WaitForSingleObject(condState->waitersDone, INFINITE); - - // Reset wasBroadcast. (No crit section needed because nobody - // else can wake up to poke at it.) - condState->wasBroadcast = 0; - } else { - // nothing to do - LeaveCriticalSection(&condState->waitersCountLock); - } - - // Release internal mutex. - ReleaseMutex(condState->internalMutex); -} - -#else -#error "condition variables not supported on this platform" -#endif - -// ---------------------------------------------------------------------------- - -/* - * This is our thread object! - */ - -Thread::Thread(bool canCallJava) - : mCanCallJava(canCallJava), - mThread(thread_id_t(-1)), - mLock("Thread::mLock"), - mStatus(NO_ERROR), - mExitPending(false), mRunning(false) -#ifdef HAVE_ANDROID_OS - , mTid(-1) -#endif -{ -} - -Thread::~Thread() -{ -} - -status_t Thread::readyToRun() -{ - return NO_ERROR; -} - -status_t Thread::run(const char* name, int32_t priority, size_t stack) -{ - Mutex::Autolock _l(mLock); - - if (mRunning) { - // thread already started - return INVALID_OPERATION; - } - - // reset status and exitPending to their default value, so we can - // try again after an error happened (either below, or in readyToRun()) - mStatus = NO_ERROR; - mExitPending = false; - mThread = thread_id_t(-1); - - // hold a strong reference on ourself - mHoldSelf = this; - - mRunning = true; - - bool res; - if (mCanCallJava) { - res = createThreadEtc(_threadLoop, - this, name, priority, stack, &mThread); - } else { - res = androidCreateRawThreadEtc(_threadLoop, - this, name, priority, stack, &mThread); - } - - if (res == false) { - mStatus = UNKNOWN_ERROR; // something happened! - mRunning = false; - mThread = thread_id_t(-1); - mHoldSelf.clear(); // "this" may have gone away after this. - - return UNKNOWN_ERROR; - } - - // Do not refer to mStatus here: The thread is already running (may, in fact - // already have exited with a valid mStatus result). The NO_ERROR indication - // here merely indicates successfully starting the thread and does not - // imply successful termination/execution. - return NO_ERROR; - - // Exiting scope of mLock is a memory barrier and allows new thread to run -} - -int Thread::_threadLoop(void* user) -{ - Thread* const self = static_cast<Thread*>(user); - - sp<Thread> strong(self->mHoldSelf); - wp<Thread> weak(strong); - self->mHoldSelf.clear(); - -#ifdef HAVE_ANDROID_OS - // this is very useful for debugging with gdb - self->mTid = gettid(); -#endif - - bool first = true; - - do { - bool result; - if (first) { - first = false; - self->mStatus = self->readyToRun(); - result = (self->mStatus == NO_ERROR); - - if (result && !self->exitPending()) { - // Binder threads (and maybe others) rely on threadLoop - // running at least once after a successful ::readyToRun() - // (unless, of course, the thread has already been asked to exit - // at that point). - // This is because threads are essentially used like this: - // (new ThreadSubclass())->run(); - // The caller therefore does not retain a strong reference to - // the thread and the thread would simply disappear after the - // successful ::readyToRun() call instead of entering the - // threadLoop at least once. - result = self->threadLoop(); - } - } else { - result = self->threadLoop(); - } - - // establish a scope for mLock - { - Mutex::Autolock _l(self->mLock); - if (result == false || self->mExitPending) { - self->mExitPending = true; - self->mRunning = false; - // clear thread ID so that requestExitAndWait() does not exit if - // called by a new thread using the same thread ID as this one. - self->mThread = thread_id_t(-1); - // note that interested observers blocked in requestExitAndWait are - // awoken by broadcast, but blocked on mLock until break exits scope - self->mThreadExitedCondition.broadcast(); - break; - } - } - - // Release our strong reference, to let a chance to the thread - // to die a peaceful death. - strong.clear(); - // And immediately, re-acquire a strong reference for the next loop - strong = weak.promote(); - } while(strong != 0); - - return 0; -} - -void Thread::requestExit() -{ - Mutex::Autolock _l(mLock); - mExitPending = true; -} - -status_t Thread::requestExitAndWait() -{ - Mutex::Autolock _l(mLock); - if (mThread == getThreadId()) { - ALOGW( - "Thread (this=%p): don't call waitForExit() from this " - "Thread object's thread. It's a guaranteed deadlock!", - this); - - return WOULD_BLOCK; - } - - mExitPending = true; - - while (mRunning == true) { - mThreadExitedCondition.wait(mLock); - } - // This next line is probably not needed any more, but is being left for - // historical reference. Note that each interested party will clear flag. - mExitPending = false; - - return mStatus; -} - -status_t Thread::join() -{ - Mutex::Autolock _l(mLock); - if (mThread == getThreadId()) { - ALOGW( - "Thread (this=%p): don't call join() from this " - "Thread object's thread. It's a guaranteed deadlock!", - this); - - return WOULD_BLOCK; - } - - while (mRunning == true) { - mThreadExitedCondition.wait(mLock); - } - - return mStatus; -} - -#ifdef HAVE_ANDROID_OS -pid_t Thread::getTid() const -{ - // mTid is not defined until the child initializes it, and the caller may need it earlier - Mutex::Autolock _l(mLock); - pid_t tid; - if (mRunning) { - pthread_t pthread = android_thread_id_t_to_pthread(mThread); - tid = __pthread_gettid(pthread); - } else { - ALOGW("Thread (this=%p): getTid() is undefined before run()", this); - tid = -1; - } - return tid; -} -#endif - -bool Thread::exitPending() const -{ - Mutex::Autolock _l(mLock); - return mExitPending; -} - - - -}; // namespace android diff --git a/libs/utils/Timers.cpp b/libs/utils/Timers.cpp deleted file mode 100644 index 64b4701..0000000 --- a/libs/utils/Timers.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2005 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. - */ - -// -// Timer functions. -// -#include <utils/Timers.h> -#include <utils/Log.h> - -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> -#include <sys/time.h> -#include <time.h> -#include <errno.h> -#include <limits.h> - -#ifdef HAVE_WIN32_THREADS -#include <windows.h> -#endif - -nsecs_t systemTime(int clock) -{ -#if defined(HAVE_POSIX_CLOCKS) - static const clockid_t clocks[] = { - CLOCK_REALTIME, - CLOCK_MONOTONIC, - CLOCK_PROCESS_CPUTIME_ID, - CLOCK_THREAD_CPUTIME_ID - }; - struct timespec t; - t.tv_sec = t.tv_nsec = 0; - clock_gettime(clocks[clock], &t); - return nsecs_t(t.tv_sec)*1000000000LL + t.tv_nsec; -#else - // we don't support the clocks here. - struct timeval t; - t.tv_sec = t.tv_usec = 0; - gettimeofday(&t, NULL); - return nsecs_t(t.tv_sec)*1000000000LL + nsecs_t(t.tv_usec)*1000LL; -#endif -} - -int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime) -{ - int timeoutDelayMillis; - if (timeoutTime > referenceTime) { - uint64_t timeoutDelay = uint64_t(timeoutTime - referenceTime); - if (timeoutDelay > uint64_t((INT_MAX - 1) * 1000000LL)) { - timeoutDelayMillis = -1; - } else { - timeoutDelayMillis = (timeoutDelay + 999999LL) / 1000000LL; - } - } else { - timeoutDelayMillis = 0; - } - return timeoutDelayMillis; -} - - -/* - * =========================================================================== - * DurationTimer - * =========================================================================== - */ - -using namespace android; - -// Start the timer. -void DurationTimer::start(void) -{ - gettimeofday(&mStartWhen, NULL); -} - -// Stop the timer. -void DurationTimer::stop(void) -{ - gettimeofday(&mStopWhen, NULL); -} - -// Get the duration in microseconds. -long long DurationTimer::durationUsecs(void) const -{ - return (long) subtractTimevals(&mStopWhen, &mStartWhen); -} - -// Subtract two timevals. Returns the difference (ptv1-ptv2) in -// microseconds. -/*static*/ long long DurationTimer::subtractTimevals(const struct timeval* ptv1, - const struct timeval* ptv2) -{ - long long stop = ((long long) ptv1->tv_sec) * 1000000LL + - ((long long) ptv1->tv_usec); - long long start = ((long long) ptv2->tv_sec) * 1000000LL + - ((long long) ptv2->tv_usec); - return stop - start; -} - -// Add the specified amount of time to the timeval. -/*static*/ void DurationTimer::addToTimeval(struct timeval* ptv, long usec) -{ - if (usec < 0) { - ALOG(LOG_WARN, "", "Negative values not supported in addToTimeval\n"); - return; - } - - // normalize tv_usec if necessary - if (ptv->tv_usec >= 1000000) { - ptv->tv_sec += ptv->tv_usec / 1000000; - ptv->tv_usec %= 1000000; - } - - ptv->tv_usec += usec % 1000000; - if (ptv->tv_usec >= 1000000) { - ptv->tv_usec -= 1000000; - ptv->tv_sec++; - } - ptv->tv_sec += usec / 1000000; -} - diff --git a/libs/utils/Tokenizer.cpp b/libs/utils/Tokenizer.cpp deleted file mode 100644 index efda2bf..0000000 --- a/libs/utils/Tokenizer.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "Tokenizer" - -#include <stdlib.h> -#include <unistd.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 - - -namespace android { - -static inline bool isDelimiter(char ch, const char* delimiters) { - return strchr(delimiters, ch) != NULL; -} - -Tokenizer::Tokenizer(const String8& filename, FileMap* fileMap, char* buffer, size_t length) : - mFilename(filename), mFileMap(fileMap), - mBuffer(buffer), mLength(length), mCurrent(buffer), mLineNumber(1) { -} - -Tokenizer::~Tokenizer() { - if (mFileMap) { - mFileMap->release(); - } else { - delete[] mBuffer; - } -} - -status_t Tokenizer::open(const String8& filename, Tokenizer** outTokenizer) { - *outTokenizer = NULL; - - int result = NO_ERROR; - int fd = ::open(filename.string(), O_RDONLY); - if (fd < 0) { - result = -errno; - ALOGE("Error opening file '%s', %s.", filename.string(), strerror(errno)); - } else { - struct stat stat; - if (fstat(fd, &stat)) { - result = -errno; - ALOGE("Error getting size of file '%s', %s.", filename.string(), strerror(errno)); - } else { - size_t length = size_t(stat.st_size); - - FileMap* fileMap = new FileMap(); - char* buffer; - if (fileMap->create(NULL, fd, 0, length, true)) { - fileMap->advise(FileMap::SEQUENTIAL); - buffer = static_cast<char*>(fileMap->getDataPtr()); - } else { - fileMap->release(); - fileMap = NULL; - - // Fall back to reading into a buffer since we can't mmap files in sysfs. - // The length we obtained from stat is wrong too (it will always be 4096) - // so we must trust that read will read the entire file. - buffer = new char[length]; - ssize_t nrd = read(fd, buffer, length); - if (nrd < 0) { - result = -errno; - ALOGE("Error reading file '%s', %s.", filename.string(), strerror(errno)); - delete[] buffer; - buffer = NULL; - } else { - length = size_t(nrd); - } - } - - if (!result) { - *outTokenizer = new Tokenizer(filename, fileMap, buffer, length); - } - } - close(fd); - } - return result; -} - -String8 Tokenizer::getLocation() const { - String8 result; - result.appendFormat("%s:%d", mFilename.string(), mLineNumber); - return result; -} - -String8 Tokenizer::peekRemainderOfLine() const { - const char* end = getEnd(); - const char* eol = mCurrent; - while (eol != end) { - char ch = *eol; - if (ch == '\n') { - break; - } - eol += 1; - } - return String8(mCurrent, eol - mCurrent); -} - -String8 Tokenizer::nextToken(const char* delimiters) { -#if DEBUG_TOKENIZER - ALOGD("nextToken"); -#endif - const char* end = getEnd(); - const char* tokenStart = mCurrent; - while (mCurrent != end) { - char ch = *mCurrent; - if (ch == '\n' || isDelimiter(ch, delimiters)) { - break; - } - mCurrent += 1; - } - return String8(tokenStart, mCurrent - tokenStart); -} - -void Tokenizer::nextLine() { -#if DEBUG_TOKENIZER - ALOGD("nextLine"); -#endif - const char* end = getEnd(); - while (mCurrent != end) { - char ch = *(mCurrent++); - if (ch == '\n') { - mLineNumber += 1; - break; - } - } -} - -void Tokenizer::skipDelimiters(const char* delimiters) { -#if DEBUG_TOKENIZER - ALOGD("skipDelimiters"); -#endif - const char* end = getEnd(); - while (mCurrent != end) { - char ch = *mCurrent; - if (ch == '\n' || !isDelimiter(ch, delimiters)) { - break; - } - mCurrent += 1; - } -} - -} // namespace android diff --git a/libs/utils/Trace.cpp b/libs/utils/Trace.cpp deleted file mode 100644 index c49278a..0000000 --- a/libs/utils/Trace.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2012 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 <cutils/properties.h> -#include <utils/Log.h> -#include <utils/Trace.h> - -namespace android { - -volatile int32_t Tracer::sIsReady = 0; -int Tracer::sTraceFD = -1; -uint64_t Tracer::sEnabledTags = 0; -Mutex Tracer::sMutex; - -void Tracer::init() { - Mutex::Autolock lock(sMutex); - - if (!sIsReady) { - const char* const traceFileName = - "/sys/kernel/debug/tracing/trace_marker"; - sTraceFD = open(traceFileName, O_WRONLY); - if (sTraceFD == -1) { - ALOGE("error opening trace file: %s (%d)", strerror(errno), errno); - } else { - char value[PROPERTY_VALUE_MAX]; - property_get("atrace.tags.enableflags", value, "0"); - sEnabledTags = strtoll(value, NULL, 0) | ATRACE_TAG_ALWAYS; - } - - android_atomic_release_store(1, &sIsReady); - } -} - -} // namespace andoid diff --git a/libs/utils/Unicode.cpp b/libs/utils/Unicode.cpp deleted file mode 100644 index 41cbf03..0000000 --- a/libs/utils/Unicode.cpp +++ /dev/null @@ -1,576 +0,0 @@ -/* - * Copyright (C) 2005 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 <utils/Unicode.h> - -#include <stddef.h> - -#ifdef HAVE_WINSOCK -# undef nhtol -# undef htonl -# undef nhtos -# undef htons - -# ifdef HAVE_LITTLE_ENDIAN -# define ntohl(x) ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) ) -# define htonl(x) ntohl(x) -# define ntohs(x) ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) ) -# define htons(x) ntohs(x) -# else -# define ntohl(x) (x) -# define htonl(x) (x) -# define ntohs(x) (x) -# define htons(x) (x) -# endif -#else -# include <netinet/in.h> -#endif - -extern "C" { - -static const char32_t kByteMask = 0x000000BF; -static const char32_t kByteMark = 0x00000080; - -// Surrogates aren't valid for UTF-32 characters, so define some -// constants that will let us screen them out. -static const char32_t kUnicodeSurrogateHighStart = 0x0000D800; -static const char32_t kUnicodeSurrogateHighEnd = 0x0000DBFF; -static const char32_t kUnicodeSurrogateLowStart = 0x0000DC00; -static const char32_t kUnicodeSurrogateLowEnd = 0x0000DFFF; -static const char32_t kUnicodeSurrogateStart = kUnicodeSurrogateHighStart; -static const char32_t kUnicodeSurrogateEnd = kUnicodeSurrogateLowEnd; -static const char32_t kUnicodeMaxCodepoint = 0x0010FFFF; - -// Mask used to set appropriate bits in first byte of UTF-8 sequence, -// indexed by number of bytes in the sequence. -// 0xxxxxxx -// -> (00-7f) 7bit. Bit mask for the first byte is 0x00000000 -// 110yyyyx 10xxxxxx -// -> (c0-df)(80-bf) 11bit. Bit mask is 0x000000C0 -// 1110yyyy 10yxxxxx 10xxxxxx -// -> (e0-ef)(80-bf)(80-bf) 16bit. Bit mask is 0x000000E0 -// 11110yyy 10yyxxxx 10xxxxxx 10xxxxxx -// -> (f0-f7)(80-bf)(80-bf)(80-bf) 21bit. Bit mask is 0x000000F0 -static const char32_t kFirstByteMark[] = { - 0x00000000, 0x00000000, 0x000000C0, 0x000000E0, 0x000000F0 -}; - -// -------------------------------------------------------------------------- -// UTF-32 -// -------------------------------------------------------------------------- - -/** - * Return number of UTF-8 bytes required for the character. If the character - * is invalid, return size of 0. - */ -static inline size_t utf32_codepoint_utf8_length(char32_t srcChar) -{ - // Figure out how many bytes the result will require. - if (srcChar < 0x00000080) { - return 1; - } else if (srcChar < 0x00000800) { - return 2; - } else if (srcChar < 0x00010000) { - if ((srcChar < kUnicodeSurrogateStart) || (srcChar > kUnicodeSurrogateEnd)) { - return 3; - } else { - // Surrogates are invalid UTF-32 characters. - return 0; - } - } - // Max code point for Unicode is 0x0010FFFF. - else if (srcChar <= kUnicodeMaxCodepoint) { - return 4; - } else { - // Invalid UTF-32 character. - return 0; - } -} - -// Write out the source character to <dstP>. - -static inline void utf32_codepoint_to_utf8(uint8_t* dstP, char32_t srcChar, size_t bytes) -{ - dstP += bytes; - switch (bytes) - { /* note: everything falls through. */ - case 4: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6; - case 3: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6; - case 2: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6; - case 1: *--dstP = (uint8_t)(srcChar | kFirstByteMark[bytes]); - } -} - -size_t strlen32(const char32_t *s) -{ - const char32_t *ss = s; - while ( *ss ) - ss++; - return ss-s; -} - -size_t strnlen32(const char32_t *s, size_t maxlen) -{ - const char32_t *ss = s; - while ((maxlen > 0) && *ss) { - ss++; - maxlen--; - } - return ss-s; -} - -static inline int32_t utf32_at_internal(const char* cur, size_t *num_read) -{ - const char first_char = *cur; - if ((first_char & 0x80) == 0) { // ASCII - *num_read = 1; - return *cur; - } - cur++; - char32_t mask, to_ignore_mask; - size_t num_to_read = 0; - char32_t utf32 = first_char; - for (num_to_read = 1, mask = 0x40, to_ignore_mask = 0xFFFFFF80; - (first_char & mask); - num_to_read++, to_ignore_mask |= mask, mask >>= 1) { - // 0x3F == 00111111 - utf32 = (utf32 << 6) + (*cur++ & 0x3F); - } - to_ignore_mask |= mask; - utf32 &= ~(to_ignore_mask << (6 * (num_to_read - 1))); - - *num_read = num_to_read; - return static_cast<int32_t>(utf32); -} - -int32_t utf32_from_utf8_at(const char *src, size_t src_len, size_t index, size_t *next_index) -{ - if (index >= src_len) { - return -1; - } - size_t dummy_index; - if (next_index == NULL) { - next_index = &dummy_index; - } - size_t num_read; - int32_t ret = utf32_at_internal(src + index, &num_read); - if (ret >= 0) { - *next_index = index + num_read; - } - - return ret; -} - -ssize_t utf32_to_utf8_length(const char32_t *src, size_t src_len) -{ - if (src == NULL || src_len == 0) { - return -1; - } - - size_t ret = 0; - const char32_t *end = src + src_len; - while (src < end) { - ret += utf32_codepoint_utf8_length(*src++); - } - return ret; -} - -void utf32_to_utf8(const char32_t* src, size_t src_len, char* dst) -{ - if (src == NULL || src_len == 0 || dst == NULL) { - return; - } - - const char32_t *cur_utf32 = src; - const char32_t *end_utf32 = src + src_len; - char *cur = dst; - while (cur_utf32 < end_utf32) { - size_t len = utf32_codepoint_utf8_length(*cur_utf32); - utf32_codepoint_to_utf8((uint8_t *)cur, *cur_utf32++, len); - cur += len; - } - *cur = '\0'; -} - -// -------------------------------------------------------------------------- -// UTF-16 -// -------------------------------------------------------------------------- - -int strcmp16(const char16_t *s1, const char16_t *s2) -{ - char16_t ch; - int d = 0; - - while ( 1 ) { - d = (int)(ch = *s1++) - (int)*s2++; - if ( d || !ch ) - break; - } - - return d; -} - -int strncmp16(const char16_t *s1, const char16_t *s2, size_t n) -{ - char16_t ch; - int d = 0; - - while ( n-- ) { - d = (int)(ch = *s1++) - (int)*s2++; - if ( d || !ch ) - break; - } - - return d; -} - -char16_t *strcpy16(char16_t *dst, const char16_t *src) -{ - char16_t *q = dst; - const char16_t *p = src; - char16_t ch; - - do { - *q++ = ch = *p++; - } while ( ch ); - - return dst; -} - -size_t strlen16(const char16_t *s) -{ - const char16_t *ss = s; - while ( *ss ) - ss++; - return ss-s; -} - - -char16_t *strncpy16(char16_t *dst, const char16_t *src, size_t n) -{ - char16_t *q = dst; - const char16_t *p = src; - char ch; - - while (n) { - n--; - *q++ = ch = *p++; - if ( !ch ) - break; - } - - *q = 0; - - return dst; -} - -size_t strnlen16(const char16_t *s, size_t maxlen) -{ - const char16_t *ss = s; - - /* Important: the maxlen test must precede the reference through ss; - since the byte beyond the maximum may segfault */ - while ((maxlen > 0) && *ss) { - ss++; - maxlen--; - } - return ss-s; -} - -int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2) -{ - const char16_t* e1 = s1+n1; - const char16_t* e2 = s2+n2; - - while (s1 < e1 && s2 < e2) { - const int d = (int)*s1++ - (int)*s2++; - if (d) { - return d; - } - } - - return n1 < n2 - ? (0 - (int)*s2) - : (n1 > n2 - ? ((int)*s1 - 0) - : 0); -} - -int strzcmp16_h_n(const char16_t *s1H, size_t n1, const char16_t *s2N, size_t n2) -{ - const char16_t* e1 = s1H+n1; - const char16_t* e2 = s2N+n2; - - while (s1H < e1 && s2N < e2) { - const char16_t c2 = ntohs(*s2N); - const int d = (int)*s1H++ - (int)c2; - s2N++; - if (d) { - return d; - } - } - - return n1 < n2 - ? (0 - (int)ntohs(*s2N)) - : (n1 > n2 - ? ((int)*s1H - 0) - : 0); -} - -void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst) -{ - if (src == NULL || src_len == 0 || dst == NULL) { - return; - } - - const char16_t* cur_utf16 = src; - const char16_t* const end_utf16 = src + src_len; - char *cur = dst; - while (cur_utf16 < end_utf16) { - char32_t utf32; - // surrogate pairs - if ((*cur_utf16 & 0xFC00) == 0xD800) { - utf32 = (*cur_utf16++ - 0xD800) << 10; - utf32 |= *cur_utf16++ - 0xDC00; - utf32 += 0x10000; - } else { - utf32 = (char32_t) *cur_utf16++; - } - const size_t len = utf32_codepoint_utf8_length(utf32); - utf32_codepoint_to_utf8((uint8_t*)cur, utf32, len); - cur += len; - } - *cur = '\0'; -} - -// -------------------------------------------------------------------------- -// UTF-8 -// -------------------------------------------------------------------------- - -ssize_t utf8_length(const char *src) -{ - const char *cur = src; - size_t ret = 0; - while (*cur != '\0') { - const char first_char = *cur++; - if ((first_char & 0x80) == 0) { // ASCII - ret += 1; - continue; - } - // (UTF-8's character must not be like 10xxxxxx, - // but 110xxxxx, 1110xxxx, ... or 1111110x) - if ((first_char & 0x40) == 0) { - return -1; - } - - int32_t mask, to_ignore_mask; - size_t num_to_read = 0; - char32_t utf32 = 0; - for (num_to_read = 1, mask = 0x40, to_ignore_mask = 0x80; - num_to_read < 5 && (first_char & mask); - num_to_read++, to_ignore_mask |= mask, mask >>= 1) { - if ((*cur & 0xC0) != 0x80) { // must be 10xxxxxx - return -1; - } - // 0x3F == 00111111 - utf32 = (utf32 << 6) + (*cur++ & 0x3F); - } - // "first_char" must be (110xxxxx - 11110xxx) - if (num_to_read == 5) { - return -1; - } - to_ignore_mask |= mask; - utf32 |= ((~to_ignore_mask) & first_char) << (6 * (num_to_read - 1)); - if (utf32 > kUnicodeMaxCodepoint) { - return -1; - } - - ret += num_to_read; - } - return ret; -} - -ssize_t utf16_to_utf8_length(const char16_t *src, size_t src_len) -{ - if (src == NULL || src_len == 0) { - return -1; - } - - size_t ret = 0; - const char16_t* const end = src + src_len; - while (src < end) { - if ((*src & 0xFC00) == 0xD800 && (src + 1) < end - && (*++src & 0xFC00) == 0xDC00) { - // surrogate pairs are always 4 bytes. - ret += 4; - src++; - } else { - ret += utf32_codepoint_utf8_length((char32_t) *src++); - } - } - return ret; -} - -/** - * Returns 1-4 based on the number of leading bits. - * - * 1111 -> 4 - * 1110 -> 3 - * 110x -> 2 - * 10xx -> 1 - * 0xxx -> 1 - */ -static inline size_t utf8_codepoint_len(uint8_t ch) -{ - return ((0xe5000000 >> ((ch >> 3) & 0x1e)) & 3) + 1; -} - -static inline void utf8_shift_and_mask(uint32_t* codePoint, const uint8_t byte) -{ - *codePoint <<= 6; - *codePoint |= 0x3F & byte; -} - -size_t utf8_to_utf32_length(const char *src, size_t src_len) -{ - if (src == NULL || src_len == 0) { - return 0; - } - size_t ret = 0; - const char* cur; - const char* end; - size_t num_to_skip; - for (cur = src, end = src + src_len, num_to_skip = 1; - cur < end; - cur += num_to_skip, ret++) { - const char first_char = *cur; - num_to_skip = 1; - if ((first_char & 0x80) == 0) { // ASCII - continue; - } - int32_t mask; - - for (mask = 0x40; (first_char & mask); num_to_skip++, mask >>= 1) { - } - } - return ret; -} - -void utf8_to_utf32(const char* src, size_t src_len, char32_t* dst) -{ - if (src == NULL || src_len == 0 || dst == NULL) { - return; - } - - const char* cur = src; - const char* const end = src + src_len; - char32_t* cur_utf32 = dst; - while (cur < end) { - size_t num_read; - *cur_utf32++ = static_cast<char32_t>(utf32_at_internal(cur, &num_read)); - cur += num_read; - } - *cur_utf32 = 0; -} - -static inline uint32_t utf8_to_utf32_codepoint(const uint8_t *src, size_t length) -{ - uint32_t unicode; - - switch (length) - { - case 1: - return src[0]; - case 2: - unicode = src[0] & 0x1f; - utf8_shift_and_mask(&unicode, src[1]); - return unicode; - case 3: - unicode = src[0] & 0x0f; - utf8_shift_and_mask(&unicode, src[1]); - utf8_shift_and_mask(&unicode, src[2]); - return unicode; - case 4: - unicode = src[0] & 0x07; - utf8_shift_and_mask(&unicode, src[1]); - utf8_shift_and_mask(&unicode, src[2]); - utf8_shift_and_mask(&unicode, src[3]); - return unicode; - default: - return 0xffff; - } - - //printf("Char at %p: len=%d, utf-16=%p\n", src, length, (void*)result); -} - -ssize_t utf8_to_utf16_length(const uint8_t* u8str, size_t u8len) -{ - const uint8_t* const u8end = u8str + u8len; - const uint8_t* u8cur = u8str; - - /* Validate that the UTF-8 is the correct len */ - size_t u16measuredLen = 0; - while (u8cur < u8end) { - u16measuredLen++; - int u8charLen = utf8_codepoint_len(*u8cur); - uint32_t codepoint = utf8_to_utf32_codepoint(u8cur, u8charLen); - if (codepoint > 0xFFFF) u16measuredLen++; // this will be a surrogate pair in utf16 - u8cur += u8charLen; - } - - /** - * Make sure that we ended where we thought we would and the output UTF-16 - * will be exactly how long we were told it would be. - */ - if (u8cur != u8end) { - return -1; - } - - return u16measuredLen; -} - -char16_t* utf8_to_utf16_no_null_terminator(const uint8_t* u8str, size_t u8len, char16_t* u16str) -{ - const uint8_t* const u8end = u8str + u8len; - const uint8_t* u8cur = u8str; - char16_t* u16cur = u16str; - - while (u8cur < u8end) { - size_t u8len = utf8_codepoint_len(*u8cur); - uint32_t codepoint = utf8_to_utf32_codepoint(u8cur, u8len); - - // Convert the UTF32 codepoint to one or more UTF16 codepoints - if (codepoint <= 0xFFFF) { - // Single UTF16 character - *u16cur++ = (char16_t) codepoint; - } else { - // Multiple UTF16 characters with surrogates - codepoint = codepoint - 0x10000; - *u16cur++ = (char16_t) ((codepoint >> 10) + 0xD800); - *u16cur++ = (char16_t) ((codepoint & 0x3FF) + 0xDC00); - } - - u8cur += u8len; - } - return u16cur; -} - -void utf8_to_utf16(const uint8_t* u8str, size_t u8len, char16_t* u16str) { - char16_t* end = utf8_to_utf16_no_null_terminator(u8str, u8len, u16str); - *end = 0; -} - -} diff --git a/libs/utils/VectorImpl.cpp b/libs/utils/VectorImpl.cpp deleted file mode 100644 index 220ae3e..0000000 --- a/libs/utils/VectorImpl.cpp +++ /dev/null @@ -1,624 +0,0 @@ -/* - * Copyright (C) 2005 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 "Vector" - -#include <string.h> -#include <stdlib.h> -#include <stdio.h> - -#include <utils/Log.h> -#include <utils/Errors.h> -#include <utils/SharedBuffer.h> -#include <utils/VectorImpl.h> - -/*****************************************************************************/ - - -namespace android { - -// ---------------------------------------------------------------------------- - -const size_t kMinVectorCapacity = 4; - -static inline size_t max(size_t a, size_t b) { - return a>b ? a : b; -} - -// ---------------------------------------------------------------------------- - -VectorImpl::VectorImpl(size_t itemSize, uint32_t flags) - : mStorage(0), mCount(0), mFlags(flags), mItemSize(itemSize) -{ -} - -VectorImpl::VectorImpl(const VectorImpl& rhs) - : mStorage(rhs.mStorage), mCount(rhs.mCount), - mFlags(rhs.mFlags), mItemSize(rhs.mItemSize) -{ - if (mStorage) { - SharedBuffer::sharedBuffer(mStorage)->acquire(); - } -} - -VectorImpl::~VectorImpl() -{ - ALOG_ASSERT(!mCount, - "[%p] " - "subclasses of VectorImpl must call finish_vector()" - " in their destructor. Leaking %d bytes.", - this, (int)(mCount*mItemSize)); - // We can't call _do_destroy() here because the vtable is already gone. -} - -VectorImpl& VectorImpl::operator = (const VectorImpl& rhs) -{ - ALOG_ASSERT(mItemSize == rhs.mItemSize, - "Vector<> have different types (this=%p, rhs=%p)", this, &rhs); - if (this != &rhs) { - release_storage(); - if (rhs.mCount) { - mStorage = rhs.mStorage; - mCount = rhs.mCount; - SharedBuffer::sharedBuffer(mStorage)->acquire(); - } else { - mStorage = 0; - mCount = 0; - } - } - return *this; -} - -void* VectorImpl::editArrayImpl() -{ - if (mStorage) { - SharedBuffer* sb = SharedBuffer::sharedBuffer(mStorage)->attemptEdit(); - if (sb == 0) { - sb = SharedBuffer::alloc(capacity() * mItemSize); - if (sb) { - _do_copy(sb->data(), mStorage, mCount); - release_storage(); - mStorage = sb->data(); - } - } - } - return mStorage; -} - -size_t VectorImpl::capacity() const -{ - if (mStorage) { - return SharedBuffer::sharedBuffer(mStorage)->size() / mItemSize; - } - return 0; -} - -ssize_t VectorImpl::insertVectorAt(const VectorImpl& vector, size_t index) -{ - return insertArrayAt(vector.arrayImpl(), index, vector.size()); -} - -ssize_t VectorImpl::appendVector(const VectorImpl& vector) -{ - return insertVectorAt(vector, size()); -} - -ssize_t VectorImpl::insertArrayAt(const void* array, size_t index, size_t length) -{ - if (index > size()) - return BAD_INDEX; - void* where = _grow(index, length); - if (where) { - _do_copy(where, array, length); - } - return where ? index : (ssize_t)NO_MEMORY; -} - -ssize_t VectorImpl::appendArray(const void* array, size_t length) -{ - return insertArrayAt(array, size(), length); -} - -ssize_t VectorImpl::insertAt(size_t index, size_t numItems) -{ - return insertAt(0, index, numItems); -} - -ssize_t VectorImpl::insertAt(const void* item, size_t index, size_t numItems) -{ - if (index > size()) - return BAD_INDEX; - void* where = _grow(index, numItems); - if (where) { - if (item) { - _do_splat(where, item, numItems); - } else { - _do_construct(where, numItems); - } - } - return where ? index : (ssize_t)NO_MEMORY; -} - -static int sortProxy(const void* lhs, const void* rhs, void* func) -{ - return (*(VectorImpl::compar_t)func)(lhs, rhs); -} - -status_t VectorImpl::sort(VectorImpl::compar_t cmp) -{ - return sort(sortProxy, (void*)cmp); -} - -status_t VectorImpl::sort(VectorImpl::compar_r_t cmp, void* state) -{ - // the sort must be stable. we're using insertion sort which - // is well suited for small and already sorted arrays - // for big arrays, it could be better to use mergesort - const ssize_t count = size(); - if (count > 1) { - void* array = const_cast<void*>(arrayImpl()); - void* temp = 0; - ssize_t i = 1; - while (i < count) { - void* item = reinterpret_cast<char*>(array) + mItemSize*(i); - void* curr = reinterpret_cast<char*>(array) + mItemSize*(i-1); - if (cmp(curr, item, state) > 0) { - - if (!temp) { - // we're going to have to modify the array... - array = editArrayImpl(); - if (!array) return NO_MEMORY; - temp = malloc(mItemSize); - if (!temp) return NO_MEMORY; - item = reinterpret_cast<char*>(array) + mItemSize*(i); - curr = reinterpret_cast<char*>(array) + mItemSize*(i-1); - } else { - _do_destroy(temp, 1); - } - - _do_copy(temp, item, 1); - - ssize_t j = i-1; - void* next = reinterpret_cast<char*>(array) + mItemSize*(i); - do { - _do_destroy(next, 1); - _do_copy(next, curr, 1); - next = curr; - --j; - curr = reinterpret_cast<char*>(array) + mItemSize*(j); - } while (j>=0 && (cmp(curr, temp, state) > 0)); - - _do_destroy(next, 1); - _do_copy(next, temp, 1); - } - i++; - } - - if (temp) { - _do_destroy(temp, 1); - free(temp); - } - } - return NO_ERROR; -} - -void VectorImpl::pop() -{ - if (size()) - removeItemsAt(size()-1, 1); -} - -void VectorImpl::push() -{ - push(0); -} - -void VectorImpl::push(const void* item) -{ - insertAt(item, size()); -} - -ssize_t VectorImpl::add() -{ - return add(0); -} - -ssize_t VectorImpl::add(const void* item) -{ - return insertAt(item, size()); -} - -ssize_t VectorImpl::replaceAt(size_t index) -{ - return replaceAt(0, index); -} - -ssize_t VectorImpl::replaceAt(const void* prototype, size_t index) -{ - ALOG_ASSERT(index<size(), - "[%p] replace: index=%d, size=%d", this, (int)index, (int)size()); - - void* item = editItemLocation(index); - if (item != prototype) { - if (item == 0) - return NO_MEMORY; - _do_destroy(item, 1); - if (prototype == 0) { - _do_construct(item, 1); - } else { - _do_copy(item, prototype, 1); - } - } - return ssize_t(index); -} - -ssize_t VectorImpl::removeItemsAt(size_t index, size_t count) -{ - ALOG_ASSERT((index+count)<=size(), - "[%p] remove: index=%d, count=%d, size=%d", - this, (int)index, (int)count, (int)size()); - - if ((index+count) > size()) - return BAD_VALUE; - _shrink(index, count); - return index; -} - -void VectorImpl::finish_vector() -{ - release_storage(); - mStorage = 0; - mCount = 0; -} - -void VectorImpl::clear() -{ - _shrink(0, mCount); -} - -void* VectorImpl::editItemLocation(size_t index) -{ - ALOG_ASSERT(index<capacity(), - "[%p] editItemLocation: index=%d, capacity=%d, count=%d", - this, (int)index, (int)capacity(), (int)mCount); - - void* buffer = editArrayImpl(); - if (buffer) - return reinterpret_cast<char*>(buffer) + index*mItemSize; - return 0; -} - -const void* VectorImpl::itemLocation(size_t index) const -{ - ALOG_ASSERT(index<capacity(), - "[%p] itemLocation: index=%d, capacity=%d, count=%d", - this, (int)index, (int)capacity(), (int)mCount); - - const void* buffer = arrayImpl(); - if (buffer) - return reinterpret_cast<const char*>(buffer) + index*mItemSize; - return 0; -} - -ssize_t VectorImpl::setCapacity(size_t new_capacity) -{ - size_t current_capacity = capacity(); - ssize_t amount = new_capacity - size(); - if (amount <= 0) { - // we can't reduce the capacity - return current_capacity; - } - SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize); - if (sb) { - void* array = sb->data(); - _do_copy(array, mStorage, size()); - release_storage(); - mStorage = const_cast<void*>(array); - } else { - return NO_MEMORY; - } - return new_capacity; -} - -void VectorImpl::release_storage() -{ - if (mStorage) { - const SharedBuffer* sb = SharedBuffer::sharedBuffer(mStorage); - if (sb->release(SharedBuffer::eKeepStorage) == 1) { - _do_destroy(mStorage, mCount); - SharedBuffer::dealloc(sb); - } - } -} - -void* VectorImpl::_grow(size_t where, size_t amount) -{ -// ALOGV("_grow(this=%p, where=%d, amount=%d) count=%d, capacity=%d", -// this, (int)where, (int)amount, (int)mCount, (int)capacity()); - - ALOG_ASSERT(where <= mCount, - "[%p] _grow: where=%d, amount=%d, count=%d", - this, (int)where, (int)amount, (int)mCount); // caller already checked - - const size_t new_size = mCount + amount; - if (capacity() < new_size) { - const size_t new_capacity = max(kMinVectorCapacity, ((new_size*3)+1)/2); -// ALOGV("grow vector %p, new_capacity=%d", this, (int)new_capacity); - if ((mStorage) && - (mCount==where) && - (mFlags & HAS_TRIVIAL_COPY) && - (mFlags & HAS_TRIVIAL_DTOR)) - { - const SharedBuffer* cur_sb = SharedBuffer::sharedBuffer(mStorage); - SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize); - mStorage = sb->data(); - } else { - SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize); - if (sb) { - void* array = sb->data(); - if (where != 0) { - _do_copy(array, mStorage, where); - } - if (where != mCount) { - const void* from = reinterpret_cast<const uint8_t *>(mStorage) + where*mItemSize; - void* dest = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize; - _do_copy(dest, from, mCount-where); - } - release_storage(); - mStorage = const_cast<void*>(array); - } - } - } else { - if (where != mCount) { - void* array = editArrayImpl(); - const void* from = reinterpret_cast<const uint8_t *>(array) + where*mItemSize; - void* to = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize; - _do_move_forward(to, from, mCount - where); - } - } - mCount = new_size; - void* free_space = const_cast<void*>(itemLocation(where)); - return free_space; -} - -void VectorImpl::_shrink(size_t where, size_t amount) -{ - if (!mStorage) - return; - -// ALOGV("_shrink(this=%p, where=%d, amount=%d) count=%d, capacity=%d", -// this, (int)where, (int)amount, (int)mCount, (int)capacity()); - - ALOG_ASSERT(where + amount <= mCount, - "[%p] _shrink: where=%d, amount=%d, count=%d", - this, (int)where, (int)amount, (int)mCount); // caller already checked - - const size_t new_size = mCount - amount; - if (new_size*3 < capacity()) { - const size_t new_capacity = max(kMinVectorCapacity, new_size*2); -// ALOGV("shrink vector %p, new_capacity=%d", this, (int)new_capacity); - if ((where == new_size) && - (mFlags & HAS_TRIVIAL_COPY) && - (mFlags & HAS_TRIVIAL_DTOR)) - { - const SharedBuffer* cur_sb = SharedBuffer::sharedBuffer(mStorage); - SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize); - mStorage = sb->data(); - } else { - SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize); - if (sb) { - void* array = sb->data(); - if (where != 0) { - _do_copy(array, mStorage, where); - } - if (where != new_size) { - const void* from = reinterpret_cast<const uint8_t *>(mStorage) + (where+amount)*mItemSize; - void* dest = reinterpret_cast<uint8_t *>(array) + where*mItemSize; - _do_copy(dest, from, new_size - where); - } - release_storage(); - mStorage = const_cast<void*>(array); - } - } - } else { - void* array = editArrayImpl(); - void* to = reinterpret_cast<uint8_t *>(array) + where*mItemSize; - _do_destroy(to, amount); - if (where != new_size) { - const void* from = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize; - _do_move_backward(to, from, new_size - where); - } - } - mCount = new_size; -} - -size_t VectorImpl::itemSize() const { - return mItemSize; -} - -void VectorImpl::_do_construct(void* storage, size_t num) const -{ - if (!(mFlags & HAS_TRIVIAL_CTOR)) { - do_construct(storage, num); - } -} - -void VectorImpl::_do_destroy(void* storage, size_t num) const -{ - if (!(mFlags & HAS_TRIVIAL_DTOR)) { - do_destroy(storage, num); - } -} - -void VectorImpl::_do_copy(void* dest, const void* from, size_t num) const -{ - if (!(mFlags & HAS_TRIVIAL_COPY)) { - do_copy(dest, from, num); - } else { - memcpy(dest, from, num*itemSize()); - } -} - -void VectorImpl::_do_splat(void* dest, const void* item, size_t num) const { - do_splat(dest, item, num); -} - -void VectorImpl::_do_move_forward(void* dest, const void* from, size_t num) const { - do_move_forward(dest, from, num); -} - -void VectorImpl::_do_move_backward(void* dest, const void* from, size_t num) const { - do_move_backward(dest, from, num); -} - -void VectorImpl::reservedVectorImpl1() { } -void VectorImpl::reservedVectorImpl2() { } -void VectorImpl::reservedVectorImpl3() { } -void VectorImpl::reservedVectorImpl4() { } -void VectorImpl::reservedVectorImpl5() { } -void VectorImpl::reservedVectorImpl6() { } -void VectorImpl::reservedVectorImpl7() { } -void VectorImpl::reservedVectorImpl8() { } - -/*****************************************************************************/ - -SortedVectorImpl::SortedVectorImpl(size_t itemSize, uint32_t flags) - : VectorImpl(itemSize, flags) -{ -} - -SortedVectorImpl::SortedVectorImpl(const VectorImpl& rhs) -: VectorImpl(rhs) -{ -} - -SortedVectorImpl::~SortedVectorImpl() -{ -} - -SortedVectorImpl& SortedVectorImpl::operator = (const SortedVectorImpl& rhs) -{ - return static_cast<SortedVectorImpl&>( VectorImpl::operator = (static_cast<const VectorImpl&>(rhs)) ); -} - -ssize_t SortedVectorImpl::indexOf(const void* item) const -{ - return _indexOrderOf(item); -} - -size_t SortedVectorImpl::orderOf(const void* item) const -{ - size_t o; - _indexOrderOf(item, &o); - return o; -} - -ssize_t SortedVectorImpl::_indexOrderOf(const void* item, size_t* order) const -{ - // binary search - ssize_t err = NAME_NOT_FOUND; - ssize_t l = 0; - ssize_t h = size()-1; - ssize_t mid; - const void* a = arrayImpl(); - const size_t s = itemSize(); - while (l <= h) { - mid = l + (h - l)/2; - const void* const curr = reinterpret_cast<const char *>(a) + (mid*s); - const int c = do_compare(curr, item); - if (c == 0) { - err = l = mid; - break; - } else if (c < 0) { - l = mid + 1; - } else { - h = mid - 1; - } - } - if (order) *order = l; - return err; -} - -ssize_t SortedVectorImpl::add(const void* item) -{ - size_t order; - ssize_t index = _indexOrderOf(item, &order); - if (index < 0) { - index = VectorImpl::insertAt(item, order, 1); - } else { - index = VectorImpl::replaceAt(item, index); - } - return index; -} - -ssize_t SortedVectorImpl::merge(const VectorImpl& vector) -{ - // naive merge... - if (!vector.isEmpty()) { - const void* buffer = vector.arrayImpl(); - const size_t is = itemSize(); - size_t s = vector.size(); - for (size_t i=0 ; i<s ; i++) { - ssize_t err = add( reinterpret_cast<const char*>(buffer) + i*is ); - if (err<0) { - return err; - } - } - } - return NO_ERROR; -} - -ssize_t SortedVectorImpl::merge(const SortedVectorImpl& vector) -{ - // we've merging a sorted vector... nice! - ssize_t err = NO_ERROR; - if (!vector.isEmpty()) { - // first take care of the case where the vectors are sorted together - if (do_compare(vector.itemLocation(vector.size()-1), arrayImpl()) <= 0) { - err = VectorImpl::insertVectorAt(static_cast<const VectorImpl&>(vector), 0); - } else if (do_compare(vector.arrayImpl(), itemLocation(size()-1)) >= 0) { - err = VectorImpl::appendVector(static_cast<const VectorImpl&>(vector)); - } else { - // this could be made a little better - err = merge(static_cast<const VectorImpl&>(vector)); - } - } - return err; -} - -ssize_t SortedVectorImpl::remove(const void* item) -{ - ssize_t i = indexOf(item); - if (i>=0) { - VectorImpl::removeItemsAt(i, 1); - } - return i; -} - -void SortedVectorImpl::reservedSortedVectorImpl1() { }; -void SortedVectorImpl::reservedSortedVectorImpl2() { }; -void SortedVectorImpl::reservedSortedVectorImpl3() { }; -void SortedVectorImpl::reservedSortedVectorImpl4() { }; -void SortedVectorImpl::reservedSortedVectorImpl5() { }; -void SortedVectorImpl::reservedSortedVectorImpl6() { }; -void SortedVectorImpl::reservedSortedVectorImpl7() { }; -void SortedVectorImpl::reservedSortedVectorImpl8() { }; - - -/*****************************************************************************/ - -}; // namespace android - diff --git a/libs/utils/misc.cpp b/libs/utils/misc.cpp deleted file mode 100644 index dc89d15..0000000 --- a/libs/utils/misc.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (C) 2005 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. - */ - -// -// Miscellaneous utility functions. -// -#include <utils/misc.h> - -#include <sys/stat.h> -#include <string.h> -#include <errno.h> -#include <assert.h> -#include <stdio.h> - -using namespace android; - -namespace android { - -/* - * Like strdup(), but uses C++ "new" operator instead of malloc. - */ -char* strdupNew(const char* str) -{ - char* newStr; - int len; - - if (str == NULL) - return NULL; - - len = strlen(str); - newStr = new char[len+1]; - memcpy(newStr, str, len+1); - - return newStr; -} - -/* - * Concatenate an argument vector. - */ -char* concatArgv(int argc, const char* const argv[]) -{ - char* newStr = NULL; - int len, totalLen, posn, idx; - - /* - * First, figure out the total length. - */ - totalLen = idx = 0; - while (1) { - if (idx == argc || argv[idx] == NULL) - break; - if (idx) - totalLen++; // leave a space between args - totalLen += strlen(argv[idx]); - idx++; - } - - /* - * Alloc the string. - */ - newStr = new char[totalLen +1]; - if (newStr == NULL) - return NULL; - - /* - * Finally, allocate the string and copy data over. - */ - idx = posn = 0; - while (1) { - if (idx == argc || argv[idx] == NULL) - break; - if (idx) - newStr[posn++] = ' '; - - len = strlen(argv[idx]); - memcpy(&newStr[posn], argv[idx], len); - posn += len; - - idx++; - } - - assert(posn == totalLen); - newStr[posn] = '\0'; - - return newStr; -} - -/* - * Count the #of args in an argument vector. Don't count the final NULL. - */ -int countArgv(const char* const argv[]) -{ - int count = 0; - - while (argv[count] != NULL) - count++; - - return count; -} - - -#include <stdio.h> -/* - * Get a file's type. - */ -FileType getFileType(const char* fileName) -{ - struct stat sb; - - if (stat(fileName, &sb) < 0) { - if (errno == ENOENT || errno == ENOTDIR) - return kFileTypeNonexistent; - else { - fprintf(stderr, "getFileType got errno=%d on '%s'\n", - errno, fileName); - return kFileTypeUnknown; - } - } else { - if (S_ISREG(sb.st_mode)) - return kFileTypeRegular; - else if (S_ISDIR(sb.st_mode)) - return kFileTypeDirectory; - else if (S_ISCHR(sb.st_mode)) - return kFileTypeCharDev; - else if (S_ISBLK(sb.st_mode)) - return kFileTypeBlockDev; - else if (S_ISFIFO(sb.st_mode)) - return kFileTypeFifo; -#ifdef HAVE_SYMLINKS - else if (S_ISLNK(sb.st_mode)) - return kFileTypeSymlink; - else if (S_ISSOCK(sb.st_mode)) - return kFileTypeSocket; -#endif - else - return kFileTypeUnknown; - } -} - -/* - * Get a file's modification date. - */ -time_t getFileModDate(const char* fileName) -{ - struct stat sb; - - if (stat(fileName, &sb) < 0) - return (time_t) -1; - - return sb.st_mtime; -} - -/* - * Round up to the next highest power of 2. - * - * Found on http://graphics.stanford.edu/~seander/bithacks.html. - */ -unsigned int roundUpPower2(unsigned int val) -{ - val--; - val |= val >> 1; - val |= val >> 2; - val |= val >> 4; - val |= val >> 8; - val |= val >> 16; - val++; - - return val; -} - -}; // namespace android - diff --git a/libs/utils/primes.py b/libs/utils/primes.py deleted file mode 100755 index e161dd8..0000000 --- a/libs/utils/primes.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python2.6 -# -# 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. -# - -# -# Generates a table of prime numbers for use in BasicHashtable.cpp. -# -# Each prime is chosen such that it is a little more than twice as large as -# the previous prime in the table. This makes it easier to choose a new -# hashtable size when the underlying array is grown by as nominal factor -# of two each time. -# - -def is_odd_prime(n): - limit = (n - 1) / 2 - d = 3 - while d <= limit: - if n % d == 0: - return False - d += 2 - return True - -print "static size_t PRIMES[] = {" - -n = 5 -max = 2**31 - 1 -while n < max: - print " %d," % (n) - n = n * 2 + 1 - while not is_odd_prime(n): - n += 2 - -print " 0," -print "};" diff --git a/libs/utils/tests/Android.mk b/libs/utils/tests/Android.mk deleted file mode 100644 index a6811fc..0000000 --- a/libs/utils/tests/Android.mk +++ /dev/null @@ -1,43 +0,0 @@ -# Build the unit tests. -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -# Build the unit tests. -test_src_files := \ - BasicHashtable_test.cpp \ - BlobCache_test.cpp \ - Looper_test.cpp \ - String8_test.cpp \ - Unicode_test.cpp \ - -shared_libraries := \ - libz \ - liblog \ - libcutils \ - libutils \ - libstlport - -static_libraries := \ - libgtest \ - libgtest_main - -c_includes := \ - external/zlib \ - external/icu4c/common \ - bionic \ - bionic/libstdc++/include \ - external/gtest/include \ - external/stlport/stlport - -module_tags := eng tests - -$(foreach file,$(test_src_files), \ - $(eval include $(CLEAR_VARS)) \ - $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \ - $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \ - $(eval LOCAL_C_INCLUDES := $(c_includes)) \ - $(eval LOCAL_SRC_FILES := $(file)) \ - $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \ - $(eval LOCAL_MODULE_TAGS := $(module_tags)) \ - $(eval include $(BUILD_EXECUTABLE)) \ -) diff --git a/libs/utils/tests/BasicHashtable_test.cpp b/libs/utils/tests/BasicHashtable_test.cpp deleted file mode 100644 index 7dcf750..0000000 --- a/libs/utils/tests/BasicHashtable_test.cpp +++ /dev/null @@ -1,577 +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 LOG_TAG "BasicHashtable_test" - -#include <utils/BasicHashtable.h> -#include <cutils/log.h> -#include <gtest/gtest.h> -#include <unistd.h> - -namespace android { - -typedef int SimpleKey; -typedef int SimpleValue; -typedef key_value_pair_t<SimpleKey, SimpleValue> SimpleEntry; -typedef BasicHashtable<SimpleKey, SimpleEntry> SimpleHashtable; - -struct ComplexKey { - int k; - - explicit ComplexKey(int k) : k(k) { - instanceCount += 1; - } - - ComplexKey(const ComplexKey& other) : k(other.k) { - instanceCount += 1; - } - - ~ComplexKey() { - instanceCount -= 1; - } - - bool operator ==(const ComplexKey& other) const { - return k == other.k; - } - - bool operator !=(const ComplexKey& other) const { - return k != other.k; - } - - static ssize_t instanceCount; -}; - -ssize_t ComplexKey::instanceCount = 0; - -template<> inline hash_t hash_type(const ComplexKey& value) { - return hash_type(value.k); -} - -struct ComplexValue { - int v; - - explicit ComplexValue(int v) : v(v) { - instanceCount += 1; - } - - ComplexValue(const ComplexValue& other) : v(other.v) { - instanceCount += 1; - } - - ~ComplexValue() { - instanceCount -= 1; - } - - static ssize_t instanceCount; -}; - -ssize_t ComplexValue::instanceCount = 0; - -typedef key_value_pair_t<ComplexKey, ComplexValue> ComplexEntry; -typedef BasicHashtable<ComplexKey, ComplexEntry> ComplexHashtable; - -class BasicHashtableTest : public testing::Test { -protected: - virtual void SetUp() { - ComplexKey::instanceCount = 0; - ComplexValue::instanceCount = 0; - } - - virtual void TearDown() { - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0)); - } - - void assertInstanceCount(ssize_t keys, ssize_t values) { - if (keys != ComplexKey::instanceCount || values != ComplexValue::instanceCount) { - FAIL() << "Expected " << keys << " keys and " << values << " values " - "but there were actually " << ComplexKey::instanceCount << " keys and " - << ComplexValue::instanceCount << " values"; - } - } - -public: - template <typename TKey, typename TEntry> - static void cookieAt(const BasicHashtable<TKey, TEntry>& h, size_t index, - bool* collision, bool* present, hash_t* hash) { - uint32_t cookie = h.cookieAt(index); - *collision = cookie & BasicHashtable<TKey, TEntry>::Bucket::COLLISION; - *present = cookie & BasicHashtable<TKey, TEntry>::Bucket::PRESENT; - *hash = cookie & BasicHashtable<TKey, TEntry>::Bucket::HASH_MASK; - } - - template <typename TKey, typename TEntry> - static const void* getBuckets(const BasicHashtable<TKey, TEntry>& h) { - return h.mBuckets; - } -}; - -template <typename TKey, typename TValue> -static size_t add(BasicHashtable<TKey, key_value_pair_t<TKey, TValue> >& h, - const TKey& key, const TValue& value) { - return h.add(hash_type(key), key_value_pair_t<TKey, TValue>(key, value)); -} - -template <typename TKey, typename TValue> -static ssize_t find(BasicHashtable<TKey, key_value_pair_t<TKey, TValue> >& h, - ssize_t index, const TKey& key) { - return h.find(index, hash_type(key), key); -} - -template <typename TKey, typename TValue> -static bool remove(BasicHashtable<TKey, key_value_pair_t<TKey, TValue> >& h, - const TKey& key) { - ssize_t index = find(h, -1, key); - if (index >= 0) { - h.removeAt(index); - return true; - } - return false; -} - -template <typename TEntry> -static void getKeyValue(const TEntry& entry, int* key, int* value); - -template <> void getKeyValue(const SimpleEntry& entry, int* key, int* value) { - *key = entry.key; - *value = entry.value; -} - -template <> void getKeyValue(const ComplexEntry& entry, int* key, int* value) { - *key = entry.key.k; - *value = entry.value.v; -} - -template <typename TKey, typename TValue> -static void dump(BasicHashtable<TKey, key_value_pair_t<TKey, TValue> >& h) { - ALOGD("hashtable %p, size=%u, capacity=%u, bucketCount=%u", - &h, h.size(), h.capacity(), h.bucketCount()); - for (size_t i = 0; i < h.bucketCount(); i++) { - bool collision, present; - hash_t hash; - BasicHashtableTest::cookieAt(h, i, &collision, &present, &hash); - if (present) { - int key, value; - getKeyValue(h.entryAt(i), &key, &value); - ALOGD(" [%3u] = collision=%d, present=%d, hash=0x%08x, key=%3d, value=%3d, " - "hash_type(key)=0x%08x", - i, collision, present, hash, key, value, hash_type(key)); - } else { - ALOGD(" [%3u] = collision=%d, present=%d", - i, collision, present); - } - } -} - -TEST_F(BasicHashtableTest, DefaultConstructor_WithDefaultProperties) { - SimpleHashtable h; - - EXPECT_EQ(0U, h.size()); - EXPECT_EQ(3U, h.capacity()); - EXPECT_EQ(5U, h.bucketCount()); - EXPECT_EQ(0.75f, h.loadFactor()); -} - -TEST_F(BasicHashtableTest, Constructor_WithNonUnityLoadFactor) { - SimpleHashtable h(52, 0.8f); - - EXPECT_EQ(0U, h.size()); - EXPECT_EQ(77U, h.capacity()); - EXPECT_EQ(97U, h.bucketCount()); - EXPECT_EQ(0.8f, h.loadFactor()); -} - -TEST_F(BasicHashtableTest, Constructor_WithUnityLoadFactorAndExactCapacity) { - SimpleHashtable h(46, 1.0f); - - EXPECT_EQ(0U, h.size()); - EXPECT_EQ(46U, h.capacity()); // must be one less than bucketCount because loadFactor == 1.0f - EXPECT_EQ(47U, h.bucketCount()); - EXPECT_EQ(1.0f, h.loadFactor()); -} - -TEST_F(BasicHashtableTest, Constructor_WithUnityLoadFactorAndInexactCapacity) { - SimpleHashtable h(42, 1.0f); - - EXPECT_EQ(0U, h.size()); - EXPECT_EQ(46U, h.capacity()); // must be one less than bucketCount because loadFactor == 1.0f - EXPECT_EQ(47U, h.bucketCount()); - EXPECT_EQ(1.0f, h.loadFactor()); -} - -TEST_F(BasicHashtableTest, FindAddFindRemoveFind_OneEntry) { - SimpleHashtable h; - ssize_t index = find(h, -1, 8); - ASSERT_EQ(-1, index); - - index = add(h, 8, 1); - ASSERT_EQ(1U, h.size()); - - ASSERT_EQ(index, find(h, -1, 8)); - ASSERT_EQ(8, h.entryAt(index).key); - ASSERT_EQ(1, h.entryAt(index).value); - - index = find(h, index, 8); - ASSERT_EQ(-1, index); - - ASSERT_TRUE(remove(h, 8)); - ASSERT_EQ(0U, h.size()); - - index = find(h, -1, 8); - ASSERT_EQ(-1, index); -} - -TEST_F(BasicHashtableTest, FindAddFindRemoveFind_MultipleEntryWithUniqueKey) { - const size_t N = 11; - - SimpleHashtable h; - for (size_t i = 0; i < N; i++) { - ssize_t index = find(h, -1, int(i)); - ASSERT_EQ(-1, index); - - index = add(h, int(i), int(i * 10)); - ASSERT_EQ(i + 1, h.size()); - - ASSERT_EQ(index, find(h, -1, int(i))); - ASSERT_EQ(int(i), h.entryAt(index).key); - ASSERT_EQ(int(i * 10), h.entryAt(index).value); - - index = find(h, index, int(i)); - ASSERT_EQ(-1, index); - } - - for (size_t i = N; --i > 0; ) { - ASSERT_TRUE(remove(h, int(i))) << "i = " << i; - ASSERT_EQ(i, h.size()); - - ssize_t index = find(h, -1, int(i)); - ASSERT_EQ(-1, index); - } -} - -TEST_F(BasicHashtableTest, FindAddFindRemoveFind_MultipleEntryWithDuplicateKey) { - const size_t N = 11; - const int K = 1; - - SimpleHashtable h; - for (size_t i = 0; i < N; i++) { - ssize_t index = find(h, -1, K); - if (i == 0) { - ASSERT_EQ(-1, index); - } else { - ASSERT_NE(-1, index); - } - - add(h, K, int(i)); - ASSERT_EQ(i + 1, h.size()); - - index = -1; - int values = 0; - for (size_t j = 0; j <= i; j++) { - index = find(h, index, K); - ASSERT_GE(index, 0); - ASSERT_EQ(K, h.entryAt(index).key); - values |= 1 << h.entryAt(index).value; - } - ASSERT_EQ(values, (1 << (i + 1)) - 1); - - index = find(h, index, K); - ASSERT_EQ(-1, index); - } - - for (size_t i = N; --i > 0; ) { - ASSERT_TRUE(remove(h, K)) << "i = " << i; - ASSERT_EQ(i, h.size()); - - ssize_t index = -1; - for (size_t j = 0; j < i; j++) { - index = find(h, index, K); - ASSERT_GE(index, 0); - ASSERT_EQ(K, h.entryAt(index).key); - } - - index = find(h, index, K); - ASSERT_EQ(-1, index); - } -} - -TEST_F(BasicHashtableTest, Clear_WhenAlreadyEmpty_DoesNothing) { - SimpleHashtable h; - h.clear(); - - EXPECT_EQ(0U, h.size()); - EXPECT_EQ(3U, h.capacity()); - EXPECT_EQ(5U, h.bucketCount()); - EXPECT_EQ(0.75f, h.loadFactor()); -} - -TEST_F(BasicHashtableTest, Clear_AfterElementsAdded_RemovesThem) { - SimpleHashtable h; - add(h, 0, 0); - add(h, 1, 0); - h.clear(); - - EXPECT_EQ(0U, h.size()); - EXPECT_EQ(3U, h.capacity()); - EXPECT_EQ(5U, h.bucketCount()); - EXPECT_EQ(0.75f, h.loadFactor()); -} - -TEST_F(BasicHashtableTest, Clear_AfterElementsAdded_DestroysThem) { - ComplexHashtable h; - add(h, ComplexKey(0), ComplexValue(0)); - add(h, ComplexKey(1), ComplexValue(0)); - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2)); - - h.clear(); - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0)); - - EXPECT_EQ(0U, h.size()); - EXPECT_EQ(3U, h.capacity()); - EXPECT_EQ(5U, h.bucketCount()); - EXPECT_EQ(0.75f, h.loadFactor()); -} - -TEST_F(BasicHashtableTest, Remove_AfterElementsAdded_DestroysThem) { - ComplexHashtable h; - add(h, ComplexKey(0), ComplexValue(0)); - add(h, ComplexKey(1), ComplexValue(0)); - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2)); - - ASSERT_TRUE(remove(h, ComplexKey(0))); - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(1, 1)); - - ASSERT_TRUE(remove(h, ComplexKey(1))); - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0)); - - EXPECT_EQ(0U, h.size()); - EXPECT_EQ(3U, h.capacity()); - EXPECT_EQ(5U, h.bucketCount()); - EXPECT_EQ(0.75f, h.loadFactor()); -} - -TEST_F(BasicHashtableTest, Destructor_AfterElementsAdded_DestroysThem) { - { - ComplexHashtable h; - add(h, ComplexKey(0), ComplexValue(0)); - add(h, ComplexKey(1), ComplexValue(0)); - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2)); - } // h is destroyed here - - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0)); -} - -TEST_F(BasicHashtableTest, Next_WhenEmpty_ReturnsMinusOne) { - SimpleHashtable h; - - ASSERT_EQ(-1, h.next(-1)); -} - -TEST_F(BasicHashtableTest, Next_WhenNonEmpty_IteratesOverAllEntries) { - const int N = 88; - - SimpleHashtable h; - for (int i = 0; i < N; i++) { - add(h, i, i * 10); - } - - bool set[N]; - memset(set, 0, sizeof(bool) * N); - int count = 0; - for (ssize_t index = -1; (index = h.next(index)) != -1; ) { - ASSERT_GE(index, 0); - ASSERT_LT(size_t(index), h.bucketCount()); - - const SimpleEntry& entry = h.entryAt(index); - ASSERT_GE(entry.key, 0); - ASSERT_LT(entry.key, N); - ASSERT_EQ(false, set[entry.key]); - ASSERT_EQ(entry.key * 10, entry.value); - - set[entry.key] = true; - count += 1; - } - ASSERT_EQ(N, count); -} - -TEST_F(BasicHashtableTest, Add_RehashesOnDemand) { - SimpleHashtable h; - size_t initialCapacity = h.capacity(); - size_t initialBucketCount = h.bucketCount(); - - for (size_t i = 0; i < initialCapacity; i++) { - add(h, int(i), 0); - } - - EXPECT_EQ(initialCapacity, h.size()); - EXPECT_EQ(initialCapacity, h.capacity()); - EXPECT_EQ(initialBucketCount, h.bucketCount()); - - add(h, -1, -1); - - EXPECT_EQ(initialCapacity + 1, h.size()); - EXPECT_GT(h.capacity(), initialCapacity); - EXPECT_GT(h.bucketCount(), initialBucketCount); - EXPECT_GT(h.bucketCount(), h.capacity()); -} - -TEST_F(BasicHashtableTest, Rehash_WhenCapacityAndBucketCountUnchanged_DoesNothing) { - ComplexHashtable h; - add(h, ComplexKey(0), ComplexValue(0)); - const void* oldBuckets = getBuckets(h); - ASSERT_NE((void*)NULL, oldBuckets); - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(1, 1)); - - h.rehash(h.capacity(), h.loadFactor()); - - ASSERT_EQ(oldBuckets, getBuckets(h)); - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(1, 1)); -} - -TEST_F(BasicHashtableTest, Rehash_WhenEmptyAndHasNoBuckets_ButDoesNotAllocateBuckets) { - ComplexHashtable h; - ASSERT_EQ((void*)NULL, getBuckets(h)); - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0)); - - h.rehash(9, 1.0f); - - EXPECT_EQ(0U, h.size()); - EXPECT_EQ(10U, h.capacity()); - EXPECT_EQ(11U, h.bucketCount()); - EXPECT_EQ(1.0f, h.loadFactor()); - EXPECT_EQ((void*)NULL, getBuckets(h)); - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0)); -} - -TEST_F(BasicHashtableTest, Rehash_WhenEmptyAndHasBuckets_ReleasesBucketsAndSetsCapacity) { - ComplexHashtable h(10); - add(h, ComplexKey(0), ComplexValue(0)); - ASSERT_TRUE(remove(h, ComplexKey(0))); - ASSERT_NE((void*)NULL, getBuckets(h)); - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0)); - - h.rehash(0, 0.75f); - - EXPECT_EQ(0U, h.size()); - EXPECT_EQ(3U, h.capacity()); - EXPECT_EQ(5U, h.bucketCount()); - EXPECT_EQ(0.75f, h.loadFactor()); - EXPECT_EQ((void*)NULL, getBuckets(h)); - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0)); -} - -TEST_F(BasicHashtableTest, Rehash_WhenLessThanCurrentCapacity_ShrinksBuckets) { - ComplexHashtable h(10); - add(h, ComplexKey(0), ComplexValue(0)); - add(h, ComplexKey(1), ComplexValue(1)); - const void* oldBuckets = getBuckets(h); - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2)); - - h.rehash(0, 0.75f); - - EXPECT_EQ(2U, h.size()); - EXPECT_EQ(3U, h.capacity()); - EXPECT_EQ(5U, h.bucketCount()); - EXPECT_EQ(0.75f, h.loadFactor()); - EXPECT_NE(oldBuckets, getBuckets(h)); - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2)); -} - -TEST_F(BasicHashtableTest, CopyOnWrite) { - ComplexHashtable h1; - add(h1, ComplexKey(0), ComplexValue(0)); - add(h1, ComplexKey(1), ComplexValue(1)); - const void* originalBuckets = getBuckets(h1); - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2)); - ssize_t index0 = find(h1, -1, ComplexKey(0)); - EXPECT_GE(index0, 0); - - // copy constructor acquires shared reference - ComplexHashtable h2(h1); - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2)); - ASSERT_EQ(originalBuckets, getBuckets(h2)); - EXPECT_EQ(h1.size(), h2.size()); - EXPECT_EQ(h1.capacity(), h2.capacity()); - EXPECT_EQ(h1.bucketCount(), h2.bucketCount()); - EXPECT_EQ(h1.loadFactor(), h2.loadFactor()); - EXPECT_EQ(index0, find(h2, -1, ComplexKey(0))); - - // operator= acquires shared reference - ComplexHashtable h3; - h3 = h2; - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2)); - ASSERT_EQ(originalBuckets, getBuckets(h3)); - EXPECT_EQ(h1.size(), h3.size()); - EXPECT_EQ(h1.capacity(), h3.capacity()); - EXPECT_EQ(h1.bucketCount(), h3.bucketCount()); - EXPECT_EQ(h1.loadFactor(), h3.loadFactor()); - EXPECT_EQ(index0, find(h3, -1, ComplexKey(0))); - - // editEntryAt copies shared contents - h1.editEntryAt(index0).value.v = 42; - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(4, 4)); - ASSERT_NE(originalBuckets, getBuckets(h1)); - EXPECT_EQ(42, h1.entryAt(index0).value.v); - EXPECT_EQ(0, h2.entryAt(index0).value.v); - EXPECT_EQ(0, h3.entryAt(index0).value.v); - - // clear releases reference to shared contents - h2.clear(); - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(4, 4)); - EXPECT_EQ(0U, h2.size()); - ASSERT_NE(originalBuckets, getBuckets(h2)); - - // operator= acquires shared reference, destroys unshared contents - h1 = h3; - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2)); - ASSERT_EQ(originalBuckets, getBuckets(h1)); - EXPECT_EQ(h3.size(), h1.size()); - EXPECT_EQ(h3.capacity(), h1.capacity()); - EXPECT_EQ(h3.bucketCount(), h1.bucketCount()); - EXPECT_EQ(h3.loadFactor(), h1.loadFactor()); - EXPECT_EQ(index0, find(h1, -1, ComplexKey(0))); - - // add copies shared contents - add(h1, ComplexKey(2), ComplexValue(2)); - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(5, 5)); - ASSERT_NE(originalBuckets, getBuckets(h1)); - EXPECT_EQ(3U, h1.size()); - EXPECT_EQ(0U, h2.size()); - EXPECT_EQ(2U, h3.size()); - - // remove copies shared contents - h1 = h3; - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2)); - ASSERT_EQ(originalBuckets, getBuckets(h1)); - h1.removeAt(index0); - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(3, 3)); - ASSERT_NE(originalBuckets, getBuckets(h1)); - EXPECT_EQ(1U, h1.size()); - EXPECT_EQ(0U, h2.size()); - EXPECT_EQ(2U, h3.size()); - - // rehash copies shared contents - h1 = h3; - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2)); - ASSERT_EQ(originalBuckets, getBuckets(h1)); - h1.rehash(10, 1.0f); - ASSERT_NO_FATAL_FAILURE(assertInstanceCount(4, 4)); - ASSERT_NE(originalBuckets, getBuckets(h1)); - EXPECT_EQ(2U, h1.size()); - EXPECT_EQ(0U, h2.size()); - EXPECT_EQ(2U, h3.size()); -} - -} // namespace android diff --git a/libs/utils/tests/BlobCache_test.cpp b/libs/utils/tests/BlobCache_test.cpp deleted file mode 100644 index b64cc39..0000000 --- a/libs/utils/tests/BlobCache_test.cpp +++ /dev/null @@ -1,421 +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) { - 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) { - 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) { - 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) { - 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) { - 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) { - 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]; - 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]; - 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) { - 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, NULL, 0)); - ASSERT_EQ(OK, mBC2->unflatten(flat, size, NULL, 0)); - delete[] flat; - } - - sp<BlobCache> mBC2; -}; - -TEST_F(BlobCacheFlattenTest, FlattenOneValue) { - 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, NULL, 0)); - 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, NULL, 0)); - delete[] flat; -} - -TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadMagic) { - 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, NULL, 0)); - flat[1] = ~flat[1]; - - // Bad magic should cause an error. - ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size, NULL, 0)); - 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) { - 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, NULL, 0)); - flat[5] = ~flat[5]; - - // Version mismatches shouldn't cause errors, but should not use the - // serialized entries - ASSERT_EQ(OK, mBC2->unflatten(flat, size, NULL, 0)); - 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) { - 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, NULL, 0)); - flat[10] = ~flat[10]; - - // Version mismatches shouldn't cause errors, but should not use the - // serialized entries - ASSERT_EQ(OK, mBC2->unflatten(flat, size, NULL, 0)); - 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) { - 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, NULL, 0)); - - // A buffer truncation shouldt cause an error - ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size-1, NULL, 0)); - 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 diff --git a/libs/utils/tests/Looper_test.cpp b/libs/utils/tests/Looper_test.cpp deleted file mode 100644 index 8bf2ba2..0000000 --- a/libs/utils/tests/Looper_test.cpp +++ /dev/null @@ -1,693 +0,0 @@ -// -// Copyright 2010 The Android Open Source Project -// - -#include <utils/Looper.h> -#include <utils/Timers.h> -#include <utils/StopWatch.h> -#include <gtest/gtest.h> -#include <unistd.h> -#include <time.h> - -#include "TestHelpers.h" - -// # of milliseconds to fudge stopwatch measurements -#define TIMING_TOLERANCE_MS 25 - -namespace android { - -enum { - MSG_TEST1 = 1, - MSG_TEST2 = 2, - MSG_TEST3 = 3, - MSG_TEST4 = 4, -}; - -class DelayedWake : public DelayedTask { - sp<Looper> mLooper; - -public: - DelayedWake(int delayMillis, const sp<Looper> looper) : - DelayedTask(delayMillis), mLooper(looper) { - } - -protected: - virtual void doTask() { - mLooper->wake(); - } -}; - -class DelayedWriteSignal : public DelayedTask { - Pipe* mPipe; - -public: - DelayedWriteSignal(int delayMillis, Pipe* pipe) : - DelayedTask(delayMillis), mPipe(pipe) { - } - -protected: - virtual void doTask() { - mPipe->writeSignal(); - } -}; - -class CallbackHandler { -public: - void setCallback(const sp<Looper>& looper, int fd, int events) { - looper->addFd(fd, 0, events, staticHandler, this); - } - -protected: - virtual ~CallbackHandler() { } - - virtual int handler(int fd, int events) = 0; - -private: - static int staticHandler(int fd, int events, void* data) { - return static_cast<CallbackHandler*>(data)->handler(fd, events); - } -}; - -class StubCallbackHandler : public CallbackHandler { -public: - int nextResult; - int callbackCount; - - int fd; - int events; - - StubCallbackHandler(int nextResult) : nextResult(nextResult), - callbackCount(0), fd(-1), events(-1) { - } - -protected: - virtual int handler(int fd, int events) { - callbackCount += 1; - this->fd = fd; - this->events = events; - return nextResult; - } -}; - -class StubMessageHandler : public MessageHandler { -public: - Vector<Message> messages; - - virtual void handleMessage(const Message& message) { - messages.push(message); - } -}; - -class LooperTest : public testing::Test { -protected: - sp<Looper> mLooper; - - virtual void SetUp() { - mLooper = new Looper(true); - } - - virtual void TearDown() { - mLooper.clear(); - } -}; - - -TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndNotAwoken_WaitsForTimeout) { - StopWatch stopWatch("pollOnce"); - int result = mLooper->pollOnce(100); - int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS) - << "elapsed time should approx. equal timeout"; - EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result) - << "pollOnce result should be ALOOPER_POLL_TIMEOUT"; -} - -TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndAwokenBeforeWaiting_ImmediatelyReturns) { - mLooper->wake(); - - StopWatch stopWatch("pollOnce"); - int result = mLooper->pollOnce(1000); - int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS) - << "elapsed time should approx. zero because wake() was called before waiting"; - EXPECT_EQ(ALOOPER_POLL_WAKE, result) - << "pollOnce result should be ALOOPER_POLL_CALLBACK because loop was awoken"; -} - -TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndAwokenWhileWaiting_PromptlyReturns) { - sp<DelayedWake> delayedWake = new DelayedWake(100, mLooper); - delayedWake->run(); - - StopWatch stopWatch("pollOnce"); - int result = mLooper->pollOnce(1000); - int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS) - << "elapsed time should approx. equal wake delay"; - EXPECT_EQ(ALOOPER_POLL_WAKE, result) - << "pollOnce result should be ALOOPER_POLL_CALLBACK because loop was awoken"; -} - -TEST_F(LooperTest, PollOnce_WhenZeroTimeoutAndNoRegisteredFDs_ImmediatelyReturns) { - StopWatch stopWatch("pollOnce"); - int result = mLooper->pollOnce(0); - int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS) - << "elapsed time should be approx. zero"; - EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result) - << "pollOnce result should be ALOOPER_POLL_TIMEOUT"; -} - -TEST_F(LooperTest, PollOnce_WhenZeroTimeoutAndNoSignalledFDs_ImmediatelyReturns) { - Pipe pipe; - StubCallbackHandler handler(true); - - handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT); - - StopWatch stopWatch("pollOnce"); - int result = mLooper->pollOnce(0); - int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS) - << "elapsed time should be approx. zero"; - EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result) - << "pollOnce result should be ALOOPER_POLL_TIMEOUT"; - EXPECT_EQ(0, handler.callbackCount) - << "callback should not have been invoked because FD was not signalled"; -} - -TEST_F(LooperTest, PollOnce_WhenZeroTimeoutAndSignalledFD_ImmediatelyInvokesCallbackAndReturns) { - Pipe pipe; - StubCallbackHandler handler(true); - - ASSERT_EQ(OK, pipe.writeSignal()); - handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT); - - StopWatch stopWatch("pollOnce"); - int result = mLooper->pollOnce(0); - int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS) - << "elapsed time should be approx. zero"; - EXPECT_EQ(ALOOPER_POLL_CALLBACK, result) - << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled"; - EXPECT_EQ(1, handler.callbackCount) - << "callback should be invoked exactly once"; - EXPECT_EQ(pipe.receiveFd, handler.fd) - << "callback should have received pipe fd as parameter"; - EXPECT_EQ(ALOOPER_EVENT_INPUT, handler.events) - << "callback should have received ALOOPER_EVENT_INPUT as events"; -} - -TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndNoSignalledFDs_WaitsForTimeoutAndReturns) { - Pipe pipe; - StubCallbackHandler handler(true); - - handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT); - - StopWatch stopWatch("pollOnce"); - int result = mLooper->pollOnce(100); - int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS) - << "elapsed time should approx. equal timeout"; - EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result) - << "pollOnce result should be ALOOPER_POLL_TIMEOUT"; - EXPECT_EQ(0, handler.callbackCount) - << "callback should not have been invoked because FD was not signalled"; -} - -TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDBeforeWaiting_ImmediatelyInvokesCallbackAndReturns) { - Pipe pipe; - StubCallbackHandler handler(true); - - pipe.writeSignal(); - handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT); - - StopWatch stopWatch("pollOnce"); - int result = mLooper->pollOnce(100); - int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - ASSERT_EQ(OK, pipe.readSignal()) - << "signal should actually have been written"; - EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS) - << "elapsed time should be approx. zero"; - EXPECT_EQ(ALOOPER_POLL_CALLBACK, result) - << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled"; - EXPECT_EQ(1, handler.callbackCount) - << "callback should be invoked exactly once"; - EXPECT_EQ(pipe.receiveFd, handler.fd) - << "callback should have received pipe fd as parameter"; - EXPECT_EQ(ALOOPER_EVENT_INPUT, handler.events) - << "callback should have received ALOOPER_EVENT_INPUT as events"; -} - -TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDWhileWaiting_PromptlyInvokesCallbackAndReturns) { - Pipe pipe; - StubCallbackHandler handler(true); - sp<DelayedWriteSignal> delayedWriteSignal = new DelayedWriteSignal(100, & pipe); - - handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT); - delayedWriteSignal->run(); - - StopWatch stopWatch("pollOnce"); - int result = mLooper->pollOnce(1000); - int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - ASSERT_EQ(OK, pipe.readSignal()) - << "signal should actually have been written"; - EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS) - << "elapsed time should approx. equal signal delay"; - EXPECT_EQ(ALOOPER_POLL_CALLBACK, result) - << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled"; - EXPECT_EQ(1, handler.callbackCount) - << "callback should be invoked exactly once"; - EXPECT_EQ(pipe.receiveFd, handler.fd) - << "callback should have received pipe fd as parameter"; - EXPECT_EQ(ALOOPER_EVENT_INPUT, handler.events) - << "callback should have received ALOOPER_EVENT_INPUT as events"; -} - -TEST_F(LooperTest, PollOnce_WhenCallbackAddedThenRemoved_CallbackShouldNotBeInvoked) { - Pipe pipe; - StubCallbackHandler handler(true); - - handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT); - pipe.writeSignal(); // would cause FD to be considered signalled - mLooper->removeFd(pipe.receiveFd); - - StopWatch stopWatch("pollOnce"); - int result = mLooper->pollOnce(100); - int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - ASSERT_EQ(OK, pipe.readSignal()) - << "signal should actually have been written"; - EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS) - << "elapsed time should approx. equal timeout because FD was no longer registered"; - EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result) - << "pollOnce result should be ALOOPER_POLL_TIMEOUT"; - EXPECT_EQ(0, handler.callbackCount) - << "callback should not be invoked"; -} - -TEST_F(LooperTest, PollOnce_WhenCallbackReturnsFalse_CallbackShouldNotBeInvokedAgainLater) { - Pipe pipe; - StubCallbackHandler handler(false); - - handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT); - - // First loop: Callback is registered and FD is signalled. - pipe.writeSignal(); - - StopWatch stopWatch("pollOnce"); - int result = mLooper->pollOnce(0); - int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - ASSERT_EQ(OK, pipe.readSignal()) - << "signal should actually have been written"; - EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS) - << "elapsed time should approx. equal zero because FD was already signalled"; - EXPECT_EQ(ALOOPER_POLL_CALLBACK, result) - << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled"; - EXPECT_EQ(1, handler.callbackCount) - << "callback should be invoked"; - - // Second loop: Callback is no longer registered and FD is signalled. - pipe.writeSignal(); - - stopWatch.reset(); - result = mLooper->pollOnce(0); - elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - ASSERT_EQ(OK, pipe.readSignal()) - << "signal should actually have been written"; - EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS) - << "elapsed time should approx. equal zero because timeout was zero"; - EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result) - << "pollOnce result should be ALOOPER_POLL_TIMEOUT"; - EXPECT_EQ(1, handler.callbackCount) - << "callback should not be invoked this time"; -} - -TEST_F(LooperTest, PollOnce_WhenNonCallbackFdIsSignalled_ReturnsIdent) { - const int expectedIdent = 5; - void* expectedData = this; - - Pipe pipe; - - pipe.writeSignal(); - mLooper->addFd(pipe.receiveFd, expectedIdent, ALOOPER_EVENT_INPUT, NULL, expectedData); - - StopWatch stopWatch("pollOnce"); - int fd; - int events; - void* data; - int result = mLooper->pollOnce(100, &fd, &events, &data); - int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - ASSERT_EQ(OK, pipe.readSignal()) - << "signal should actually have been written"; - EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS) - << "elapsed time should be approx. zero"; - EXPECT_EQ(expectedIdent, result) - << "pollOnce result should be the ident of the FD that was signalled"; - EXPECT_EQ(pipe.receiveFd, fd) - << "pollOnce should have returned the received pipe fd"; - EXPECT_EQ(ALOOPER_EVENT_INPUT, events) - << "pollOnce should have returned ALOOPER_EVENT_INPUT as events"; - EXPECT_EQ(expectedData, data) - << "pollOnce should have returned the data"; -} - -TEST_F(LooperTest, AddFd_WhenCallbackAdded_ReturnsOne) { - Pipe pipe; - int result = mLooper->addFd(pipe.receiveFd, 0, ALOOPER_EVENT_INPUT, NULL, NULL); - - EXPECT_EQ(1, result) - << "addFd should return 1 because FD was added"; -} - -TEST_F(LooperTest, AddFd_WhenIdentIsNegativeAndCallbackIsNull_ReturnsError) { - Pipe pipe; - int result = mLooper->addFd(pipe.receiveFd, -1, ALOOPER_EVENT_INPUT, NULL, NULL); - - EXPECT_EQ(-1, result) - << "addFd should return -1 because arguments were invalid"; -} - -TEST_F(LooperTest, AddFd_WhenNoCallbackAndAllowNonCallbacksIsFalse_ReturnsError) { - Pipe pipe; - sp<Looper> looper = new Looper(false /*allowNonCallbacks*/); - int result = looper->addFd(pipe.receiveFd, 0, 0, NULL, NULL); - - EXPECT_EQ(-1, result) - << "addFd should return -1 because arguments were invalid"; -} - -TEST_F(LooperTest, RemoveFd_WhenCallbackNotAdded_ReturnsZero) { - int result = mLooper->removeFd(1); - - EXPECT_EQ(0, result) - << "removeFd should return 0 because FD not registered"; -} - -TEST_F(LooperTest, RemoveFd_WhenCallbackAddedThenRemovedTwice_ReturnsOnceFirstTimeAndReturnsZeroSecondTime) { - Pipe pipe; - StubCallbackHandler handler(false); - handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT); - - // First time. - int result = mLooper->removeFd(pipe.receiveFd); - - EXPECT_EQ(1, result) - << "removeFd should return 1 first time because FD was registered"; - - // Second time. - result = mLooper->removeFd(pipe.receiveFd); - - EXPECT_EQ(0, result) - << "removeFd should return 0 second time because FD was no longer registered"; -} - -TEST_F(LooperTest, PollOnce_WhenCallbackAddedTwice_OnlySecondCallbackShouldBeInvoked) { - Pipe pipe; - StubCallbackHandler handler1(true); - StubCallbackHandler handler2(true); - - handler1.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT); - handler2.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT); // replace it - pipe.writeSignal(); // would cause FD to be considered signalled - - StopWatch stopWatch("pollOnce"); - int result = mLooper->pollOnce(100); - int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - ASSERT_EQ(OK, pipe.readSignal()) - << "signal should actually have been written"; - EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS) - << "elapsed time should approx. zero because FD was already signalled"; - EXPECT_EQ(ALOOPER_POLL_CALLBACK, result) - << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled"; - EXPECT_EQ(0, handler1.callbackCount) - << "original handler callback should not be invoked because it was replaced"; - EXPECT_EQ(1, handler2.callbackCount) - << "replacement handler callback should be invoked"; -} - -TEST_F(LooperTest, SendMessage_WhenOneMessageIsEnqueue_ShouldInvokeHandlerDuringNextPoll) { - sp<StubMessageHandler> handler = new StubMessageHandler(); - mLooper->sendMessage(handler, Message(MSG_TEST1)); - - StopWatch stopWatch("pollOnce"); - int result = mLooper->pollOnce(100); - int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS) - << "elapsed time should approx. zero because message was already sent"; - EXPECT_EQ(ALOOPER_POLL_CALLBACK, result) - << "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent"; - EXPECT_EQ(size_t(1), handler->messages.size()) - << "handled message"; - EXPECT_EQ(MSG_TEST1, handler->messages[0].what) - << "handled message"; -} - -TEST_F(LooperTest, SendMessage_WhenMultipleMessagesAreEnqueued_ShouldInvokeHandlersInOrderDuringNextPoll) { - sp<StubMessageHandler> handler1 = new StubMessageHandler(); - sp<StubMessageHandler> handler2 = new StubMessageHandler(); - mLooper->sendMessage(handler1, Message(MSG_TEST1)); - mLooper->sendMessage(handler2, Message(MSG_TEST2)); - mLooper->sendMessage(handler1, Message(MSG_TEST3)); - mLooper->sendMessage(handler1, Message(MSG_TEST4)); - - StopWatch stopWatch("pollOnce"); - int result = mLooper->pollOnce(1000); - int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS) - << "elapsed time should approx. zero because message was already sent"; - EXPECT_EQ(ALOOPER_POLL_CALLBACK, result) - << "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent"; - EXPECT_EQ(size_t(3), handler1->messages.size()) - << "handled message"; - EXPECT_EQ(MSG_TEST1, handler1->messages[0].what) - << "handled message"; - EXPECT_EQ(MSG_TEST3, handler1->messages[1].what) - << "handled message"; - EXPECT_EQ(MSG_TEST4, handler1->messages[2].what) - << "handled message"; - EXPECT_EQ(size_t(1), handler2->messages.size()) - << "handled message"; - EXPECT_EQ(MSG_TEST2, handler2->messages[0].what) - << "handled message"; -} - -TEST_F(LooperTest, SendMessageDelayed_WhenSentToTheFuture_ShouldInvokeHandlerAfterDelayTime) { - sp<StubMessageHandler> handler = new StubMessageHandler(); - mLooper->sendMessageDelayed(ms2ns(100), handler, Message(MSG_TEST1)); - - StopWatch stopWatch("pollOnce"); - int result = mLooper->pollOnce(1000); - int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS) - << "first poll should end quickly because next message timeout was computed"; - EXPECT_EQ(ALOOPER_POLL_WAKE, result) - << "pollOnce result should be ALOOPER_POLL_WAKE due to wakeup"; - EXPECT_EQ(size_t(0), handler->messages.size()) - << "no message handled yet"; - - result = mLooper->pollOnce(1000); - elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - EXPECT_EQ(size_t(1), handler->messages.size()) - << "handled message"; - EXPECT_EQ(MSG_TEST1, handler->messages[0].what) - << "handled message"; - EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS) - << "second poll should end around the time of the delayed message dispatch"; - EXPECT_EQ(ALOOPER_POLL_CALLBACK, result) - << "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent"; - - result = mLooper->pollOnce(100); - elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - EXPECT_NEAR(100 + 100, elapsedMillis, TIMING_TOLERANCE_MS) - << "third poll should timeout"; - EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result) - << "pollOnce result should be ALOOPER_POLL_TIMEOUT because there were no messages left"; -} - -TEST_F(LooperTest, SendMessageDelayed_WhenSentToThePast_ShouldInvokeHandlerDuringNextPoll) { - sp<StubMessageHandler> handler = new StubMessageHandler(); - mLooper->sendMessageDelayed(ms2ns(-1000), handler, Message(MSG_TEST1)); - - StopWatch stopWatch("pollOnce"); - int result = mLooper->pollOnce(100); - int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS) - << "elapsed time should approx. zero because message was already sent"; - EXPECT_EQ(ALOOPER_POLL_CALLBACK, result) - << "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent"; - EXPECT_EQ(size_t(1), handler->messages.size()) - << "handled message"; - EXPECT_EQ(MSG_TEST1, handler->messages[0].what) - << "handled message"; -} - -TEST_F(LooperTest, SendMessageDelayed_WhenSentToThePresent_ShouldInvokeHandlerDuringNextPoll) { - sp<StubMessageHandler> handler = new StubMessageHandler(); - mLooper->sendMessageDelayed(0, handler, Message(MSG_TEST1)); - - StopWatch stopWatch("pollOnce"); - int result = mLooper->pollOnce(100); - int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS) - << "elapsed time should approx. zero because message was already sent"; - EXPECT_EQ(ALOOPER_POLL_CALLBACK, result) - << "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent"; - EXPECT_EQ(size_t(1), handler->messages.size()) - << "handled message"; - EXPECT_EQ(MSG_TEST1, handler->messages[0].what) - << "handled message"; -} - -TEST_F(LooperTest, SendMessageAtTime_WhenSentToTheFuture_ShouldInvokeHandlerAfterDelayTime) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - sp<StubMessageHandler> handler = new StubMessageHandler(); - mLooper->sendMessageAtTime(now + ms2ns(100), handler, Message(MSG_TEST1)); - - StopWatch stopWatch("pollOnce"); - int result = mLooper->pollOnce(1000); - int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS) - << "first poll should end quickly because next message timeout was computed"; - EXPECT_EQ(ALOOPER_POLL_WAKE, result) - << "pollOnce result should be ALOOPER_POLL_WAKE due to wakeup"; - EXPECT_EQ(size_t(0), handler->messages.size()) - << "no message handled yet"; - - result = mLooper->pollOnce(1000); - elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - EXPECT_EQ(size_t(1), handler->messages.size()) - << "handled message"; - EXPECT_EQ(MSG_TEST1, handler->messages[0].what) - << "handled message"; - EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS) - << "second poll should end around the time of the delayed message dispatch"; - EXPECT_EQ(ALOOPER_POLL_CALLBACK, result) - << "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent"; - - result = mLooper->pollOnce(100); - elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - EXPECT_NEAR(100 + 100, elapsedMillis, TIMING_TOLERANCE_MS) - << "third poll should timeout"; - EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result) - << "pollOnce result should be ALOOPER_POLL_TIMEOUT because there were no messages left"; -} - -TEST_F(LooperTest, SendMessageAtTime_WhenSentToThePast_ShouldInvokeHandlerDuringNextPoll) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - sp<StubMessageHandler> handler = new StubMessageHandler(); - mLooper->sendMessageAtTime(now - ms2ns(1000), handler, Message(MSG_TEST1)); - - StopWatch stopWatch("pollOnce"); - int result = mLooper->pollOnce(100); - int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS) - << "elapsed time should approx. zero because message was already sent"; - EXPECT_EQ(ALOOPER_POLL_CALLBACK, result) - << "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent"; - EXPECT_EQ(size_t(1), handler->messages.size()) - << "handled message"; - EXPECT_EQ(MSG_TEST1, handler->messages[0].what) - << "handled message"; -} - -TEST_F(LooperTest, SendMessageAtTime_WhenSentToThePresent_ShouldInvokeHandlerDuringNextPoll) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - sp<StubMessageHandler> handler = new StubMessageHandler(); - mLooper->sendMessageAtTime(now, handler, Message(MSG_TEST1)); - - StopWatch stopWatch("pollOnce"); - int result = mLooper->pollOnce(100); - int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS) - << "elapsed time should approx. zero because message was already sent"; - EXPECT_EQ(ALOOPER_POLL_CALLBACK, result) - << "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent"; - EXPECT_EQ(size_t(1), handler->messages.size()) - << "handled message"; - EXPECT_EQ(MSG_TEST1, handler->messages[0].what) - << "handled message"; -} - -TEST_F(LooperTest, RemoveMessage_WhenRemovingAllMessagesForHandler_ShouldRemoveThoseMessage) { - sp<StubMessageHandler> handler = new StubMessageHandler(); - mLooper->sendMessage(handler, Message(MSG_TEST1)); - mLooper->sendMessage(handler, Message(MSG_TEST2)); - mLooper->sendMessage(handler, Message(MSG_TEST3)); - mLooper->removeMessages(handler); - - StopWatch stopWatch("pollOnce"); - int result = mLooper->pollOnce(0); - int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS) - << "elapsed time should approx. zero because message was sent so looper was awoken"; - EXPECT_EQ(ALOOPER_POLL_WAKE, result) - << "pollOnce result should be ALOOPER_POLL_WAKE because looper was awoken"; - EXPECT_EQ(size_t(0), handler->messages.size()) - << "no messages to handle"; - - result = mLooper->pollOnce(0); - - EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result) - << "pollOnce result should be ALOOPER_POLL_TIMEOUT because there was nothing to do"; - EXPECT_EQ(size_t(0), handler->messages.size()) - << "no messages to handle"; -} - -TEST_F(LooperTest, RemoveMessage_WhenRemovingSomeMessagesForHandler_ShouldRemoveThoseMessage) { - sp<StubMessageHandler> handler = new StubMessageHandler(); - mLooper->sendMessage(handler, Message(MSG_TEST1)); - mLooper->sendMessage(handler, Message(MSG_TEST2)); - mLooper->sendMessage(handler, Message(MSG_TEST3)); - mLooper->sendMessage(handler, Message(MSG_TEST4)); - mLooper->removeMessages(handler, MSG_TEST3); - mLooper->removeMessages(handler, MSG_TEST1); - - StopWatch stopWatch("pollOnce"); - int result = mLooper->pollOnce(0); - int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); - - EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS) - << "elapsed time should approx. zero because message was sent so looper was awoken"; - EXPECT_EQ(ALOOPER_POLL_CALLBACK, result) - << "pollOnce result should be ALOOPER_POLL_CALLBACK because two messages were sent"; - EXPECT_EQ(size_t(2), handler->messages.size()) - << "no messages to handle"; - EXPECT_EQ(MSG_TEST2, handler->messages[0].what) - << "handled message"; - EXPECT_EQ(MSG_TEST4, handler->messages[1].what) - << "handled message"; - - result = mLooper->pollOnce(0); - - EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result) - << "pollOnce result should be ALOOPER_POLL_TIMEOUT because there was nothing to do"; - EXPECT_EQ(size_t(2), handler->messages.size()) - << "no more messages to handle"; -} - -} // namespace android diff --git a/libs/utils/tests/String8_test.cpp b/libs/utils/tests/String8_test.cpp deleted file mode 100644 index c42c68d..0000000 --- a/libs/utils/tests/String8_test.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "String8_test" -#include <utils/Log.h> -#include <utils/String8.h> - -#include <gtest/gtest.h> - -namespace android { - -class String8Test : public testing::Test { -protected: - virtual void SetUp() { - } - - virtual void TearDown() { - } -}; - -TEST_F(String8Test, Cstr) { - String8 tmp("Hello, world!"); - - EXPECT_STREQ(tmp.string(), "Hello, world!"); -} - -TEST_F(String8Test, OperatorPlus) { - String8 src1("Hello, "); - - // Test adding String8 + const char* - const char* ccsrc2 = "world!"; - String8 dst1 = src1 + ccsrc2; - EXPECT_STREQ(dst1.string(), "Hello, world!"); - EXPECT_STREQ(src1.string(), "Hello, "); - EXPECT_STREQ(ccsrc2, "world!"); - - // Test adding String8 + String8 - String8 ssrc2("world!"); - String8 dst2 = src1 + ssrc2; - EXPECT_STREQ(dst2.string(), "Hello, world!"); - EXPECT_STREQ(src1.string(), "Hello, "); - EXPECT_STREQ(ssrc2.string(), "world!"); -} - -TEST_F(String8Test, OperatorPlusEquals) { - String8 src1("My voice"); - - // Testing String8 += String8 - String8 src2(" is my passport."); - src1 += src2; - EXPECT_STREQ(src1.string(), "My voice is my passport."); - EXPECT_STREQ(src2.string(), " is my passport."); - - // Adding const char* to the previous string. - const char* src3 = " Verify me."; - src1 += src3; - EXPECT_STREQ(src1.string(), "My voice is my passport. Verify me."); - EXPECT_STREQ(src2.string(), " is my passport."); - EXPECT_STREQ(src3, " Verify me."); -} - -} diff --git a/libs/utils/tests/TestHelpers.h b/libs/utils/tests/TestHelpers.h deleted file mode 100644 index d8e985e..0000000 --- a/libs/utils/tests/TestHelpers.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef TESTHELPERS_H -#define TESTHELPERS_H - -#include <utils/threads.h> - -namespace android { - -class Pipe { -public: - int sendFd; - int receiveFd; - - Pipe() { - int fds[2]; - ::pipe(fds); - - receiveFd = fds[0]; - sendFd = fds[1]; - } - - ~Pipe() { - if (sendFd != -1) { - ::close(sendFd); - } - - if (receiveFd != -1) { - ::close(receiveFd); - } - } - - status_t writeSignal() { - ssize_t nWritten = ::write(sendFd, "*", 1); - return nWritten == 1 ? 0 : -errno; - } - - status_t readSignal() { - char buf[1]; - ssize_t nRead = ::read(receiveFd, buf, 1); - return nRead == 1 ? 0 : nRead == 0 ? -EPIPE : -errno; - } -}; - -class DelayedTask : public Thread { - int mDelayMillis; - -public: - DelayedTask(int delayMillis) : mDelayMillis(delayMillis) { } - -protected: - virtual ~DelayedTask() { } - - virtual void doTask() = 0; - - virtual bool threadLoop() { - usleep(mDelayMillis * 1000); - doTask(); - return false; - } -}; - -} // namespace android - -#endif // TESTHELPERS_H diff --git a/libs/utils/tests/Unicode_test.cpp b/libs/utils/tests/Unicode_test.cpp deleted file mode 100644 index 18c130c..0000000 --- a/libs/utils/tests/Unicode_test.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "Unicode_test" -#include <utils/Log.h> -#include <utils/Unicode.h> - -#include <gtest/gtest.h> - -namespace android { - -class UnicodeTest : public testing::Test { -protected: - virtual void SetUp() { - } - - virtual void TearDown() { - } -}; - -TEST_F(UnicodeTest, UTF8toUTF16ZeroLength) { - ssize_t measured; - - const uint8_t str[] = { }; - - measured = utf8_to_utf16_length(str, 0); - EXPECT_EQ(0, measured) - << "Zero length input should return zero length output."; -} - -TEST_F(UnicodeTest, UTF8toUTF16ASCIILength) { - ssize_t measured; - - // U+0030 or ASCII '0' - const uint8_t str[] = { 0x30 }; - - measured = utf8_to_utf16_length(str, sizeof(str)); - EXPECT_EQ(1, measured) - << "ASCII glyphs should have a length of 1 char16_t"; -} - -TEST_F(UnicodeTest, UTF8toUTF16Plane1Length) { - ssize_t measured; - - // U+2323 SMILE - const uint8_t str[] = { 0xE2, 0x8C, 0xA3 }; - - measured = utf8_to_utf16_length(str, sizeof(str)); - EXPECT_EQ(1, measured) - << "Plane 1 glyphs should have a length of 1 char16_t"; -} - -TEST_F(UnicodeTest, UTF8toUTF16SurrogateLength) { - ssize_t measured; - - // U+10000 - const uint8_t str[] = { 0xF0, 0x90, 0x80, 0x80 }; - - measured = utf8_to_utf16_length(str, sizeof(str)); - EXPECT_EQ(2, measured) - << "Surrogate pairs should have a length of 2 char16_t"; -} - -TEST_F(UnicodeTest, UTF8toUTF16TruncatedUTF8) { - ssize_t measured; - - // Truncated U+2323 SMILE - // U+2323 SMILE - const uint8_t str[] = { 0xE2, 0x8C }; - - measured = utf8_to_utf16_length(str, sizeof(str)); - EXPECT_EQ(-1, measured) - << "Truncated UTF-8 should return -1 to indicate invalid"; -} - -TEST_F(UnicodeTest, UTF8toUTF16Normal) { - const uint8_t str[] = { - 0x30, // U+0030, 1 UTF-16 character - 0xC4, 0x80, // U+0100, 1 UTF-16 character - 0xE2, 0x8C, 0xA3, // U+2323, 1 UTF-16 character - 0xF0, 0x90, 0x80, 0x80, // U+10000, 2 UTF-16 character - }; - - char16_t output[1 + 1 + 1 + 2 + 1]; // Room for NULL - - utf8_to_utf16(str, sizeof(str), output); - - EXPECT_EQ(0x0030, output[0]) - << "should be U+0030"; - EXPECT_EQ(0x0100, output[1]) - << "should be U+0100"; - EXPECT_EQ(0x2323, output[2]) - << "should be U+2323"; - EXPECT_EQ(0xD800, output[3]) - << "should be first half of surrogate U+10000"; - EXPECT_EQ(0xDC00, output[4]) - << "should be second half of surrogate U+10000"; - EXPECT_EQ(NULL, output[5]) - << "should be NULL terminated"; -} - -} |