diff options
Diffstat (limited to 'include/utils')
-rw-r--r-- | include/utils/BasicHashtable.h | 393 | ||||
-rw-r--r-- | include/utils/CallStack.h | 8 | ||||
-rw-r--r-- | include/utils/GenerationCache.h | 114 | ||||
-rw-r--r-- | include/utils/ResourceTypes.h | 606 | ||||
-rw-r--r-- | include/utils/TypeHelpers.h | 48 | ||||
-rw-r--r-- | include/utils/threads.h | 12 |
6 files changed, 538 insertions, 643 deletions
diff --git a/include/utils/BasicHashtable.h b/include/utils/BasicHashtable.h new file mode 100644 index 0000000..fdf9738 --- /dev/null +++ b/include/utils/BasicHashtable.h @@ -0,0 +1,393 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_BASIC_HASHTABLE_H +#define ANDROID_BASIC_HASHTABLE_H + +#include <stdint.h> +#include <sys/types.h> +#include <utils/SharedBuffer.h> +#include <utils/TypeHelpers.h> + +namespace android { + +/* Implementation type. Nothing to see here. */ +class BasicHashtableImpl { +protected: + struct Bucket { + // The collision flag indicates that the bucket is part of a collision chain + // such that at least two entries both hash to this bucket. When true, we + // may need to seek further along the chain to find the entry. + static const uint32_t COLLISION = 0x80000000UL; + + // The present flag indicates that the bucket contains an initialized entry value. + static const uint32_t PRESENT = 0x40000000UL; + + // Mask for 30 bits worth of the hash code that are stored within the bucket to + // speed up lookups and rehashing by eliminating the need to recalculate the + // hash code of the entry's key. + static const uint32_t HASH_MASK = 0x3fffffffUL; + + // Combined value that stores the collision and present flags as well as + // a 30 bit hash code. + uint32_t cookie; + + // Storage for the entry begins here. + char entry[0]; + }; + + BasicHashtableImpl(size_t entrySize, bool hasTrivialDestructor, + size_t minimumInitialCapacity, float loadFactor); + BasicHashtableImpl(const BasicHashtableImpl& other); + + void dispose(); + + inline void edit() { + if (mBuckets && !SharedBuffer::bufferFromData(mBuckets)->onlyOwner()) { + clone(); + } + } + + void setTo(const BasicHashtableImpl& other); + void clear(); + + ssize_t next(ssize_t index) const; + ssize_t find(ssize_t index, hash_t hash, const void* __restrict__ key) const; + size_t add(hash_t hash, const void* __restrict__ entry); + void removeAt(size_t index); + void rehash(size_t minimumCapacity, float loadFactor); + + const size_t mBucketSize; // number of bytes per bucket including the entry + const bool mHasTrivialDestructor; // true if the entry type does not require destruction + size_t mCapacity; // number of buckets that can be filled before exceeding load factor + float mLoadFactor; // load factor + size_t mSize; // number of elements actually in the table + size_t mFilledBuckets; // number of buckets for which collision or present is true + size_t mBucketCount; // number of slots in the mBuckets array + void* mBuckets; // array of buckets, as a SharedBuffer + + inline const Bucket& bucketAt(const void* __restrict__ buckets, size_t index) const { + return *reinterpret_cast<const Bucket*>( + static_cast<const uint8_t*>(buckets) + index * mBucketSize); + } + + inline Bucket& bucketAt(void* __restrict__ buckets, size_t index) const { + return *reinterpret_cast<Bucket*>(static_cast<uint8_t*>(buckets) + index * mBucketSize); + } + + virtual bool compareBucketKey(const Bucket& bucket, const void* __restrict__ key) const = 0; + virtual void initializeBucketEntry(Bucket& bucket, const void* __restrict__ entry) const = 0; + virtual void destroyBucketEntry(Bucket& bucket) const = 0; + +private: + void clone(); + + // Allocates a bucket array as a SharedBuffer. + void* allocateBuckets(size_t count) const; + + // Releases a bucket array's associated SharedBuffer. + void releaseBuckets(void* __restrict__ buckets, size_t count) const; + + // Destroys the contents of buckets (invokes destroyBucketEntry for each + // populated bucket if needed). + void destroyBuckets(void* __restrict__ buckets, size_t count) const; + + // Copies the content of buckets (copies the cookie and invokes copyBucketEntry + // for each populated bucket if needed). + void copyBuckets(const void* __restrict__ fromBuckets, + void* __restrict__ toBuckets, size_t count) const; + + // Determines the appropriate size of a bucket array to store a certain minimum + // number of entries and returns its effective capacity. + static void determineCapacity(size_t minimumCapacity, float loadFactor, + size_t* __restrict__ outBucketCount, size_t* __restrict__ outCapacity); + + // Trim a hash code to 30 bits to match what we store in the bucket's cookie. + inline static hash_t trimHash(hash_t hash) { + return (hash & Bucket::HASH_MASK) ^ (hash >> 30); + } + + // Returns the index of the first bucket that is in the collision chain + // for the specified hash code, given the total number of buckets. + // (Primary hash) + inline static size_t chainStart(hash_t hash, size_t count) { + return hash % count; + } + + // Returns the increment to add to a bucket index to seek to the next bucket + // in the collision chain for the specified hash code, given the total number of buckets. + // (Secondary hash) + inline static size_t chainIncrement(hash_t hash, size_t count) { + return ((hash >> 7) | (hash << 25)) % (count - 1) + 1; + } + + // Returns the index of the next bucket that is in the collision chain + // that is defined by the specified increment, given the total number of buckets. + inline static size_t chainSeek(size_t index, size_t increment, size_t count) { + return (index + increment) % count; + } +}; + +/* + * A BasicHashtable stores entries that are indexed by hash code in place + * within an array. The basic operations are finding entries by key, + * adding new entries and removing existing entries. + * + * This class provides a very limited set of operations with simple semantics. + * It is intended to be used as a building block to construct more complex + * and interesting data structures such as HashMap. Think very hard before + * adding anything extra to BasicHashtable, it probably belongs at a + * higher level of abstraction. + * + * TKey: The key type. + * TEntry: The entry type which is what is actually stored in the array. + * + * TKey must support the following contract: + * bool operator==(const TKey& other) const; // return true if equal + * bool operator!=(const TKey& other) const; // return true if unequal + * + * TEntry must support the following contract: + * const TKey& getKey() const; // get the key from the entry + * + * This class supports storing entries with duplicate keys. Of course, it can't + * tell them apart during removal so only the first entry will be removed. + * We do this because it means that operations like add() can't fail. + */ +template <typename TKey, typename TEntry> +class BasicHashtable : private BasicHashtableImpl { +public: + /* Creates a hashtable with the specified minimum initial capacity. + * The underlying array will be created when the first entry is added. + * + * minimumInitialCapacity: The minimum initial capacity for the hashtable. + * Default is 0. + * loadFactor: The desired load factor for the hashtable, between 0 and 1. + * Default is 0.75. + */ + BasicHashtable(size_t minimumInitialCapacity = 0, float loadFactor = 0.75f); + + /* Copies a hashtable. + * The underlying storage is shared copy-on-write. + */ + BasicHashtable(const BasicHashtable& other); + + /* Clears and destroys the hashtable. + */ + virtual ~BasicHashtable(); + + /* Making this hashtable a copy of the other hashtable. + * The underlying storage is shared copy-on-write. + * + * other: The hashtable to copy. + */ + inline BasicHashtable<TKey, TEntry>& operator =(const BasicHashtable<TKey, TEntry> & other) { + setTo(other); + return *this; + } + + /* Returns the number of entries in the hashtable. + */ + inline size_t size() const { + return mSize; + } + + /* Returns the capacity of the hashtable, which is the number of elements that can + * added to the hashtable without requiring it to be grown. + */ + inline size_t capacity() const { + return mCapacity; + } + + /* Returns the number of buckets that the hashtable has, which is the size of its + * underlying array. + */ + inline size_t bucketCount() const { + return mBucketCount; + } + + /* Returns the load factor of the hashtable. */ + inline float loadFactor() const { + return mLoadFactor; + }; + + /* Returns a const reference to the entry at the specified index. + * + * index: The index of the entry to retrieve. Must be a valid index within + * the bounds of the hashtable. + */ + inline const TEntry& entryAt(size_t index) const { + return entryFor(bucketAt(mBuckets, index)); + } + + /* Returns a non-const reference to the entry at the specified index. + * + * index: The index of the entry to edit. Must be a valid index within + * the bounds of the hashtable. + */ + inline TEntry& editEntryAt(size_t index) { + edit(); + return entryFor(bucketAt(mBuckets, index)); + } + + /* Clears the hashtable. + * All entries in the hashtable are destroyed immediately. + * If you need to do something special with the entries in the hashtable then iterate + * over them and do what you need before clearing the hashtable. + */ + inline void clear() { + BasicHashtableImpl::clear(); + } + + /* Returns the index of the next entry in the hashtable given the index of a previous entry. + * If the given index is -1, then returns the index of the first entry in the hashtable, + * if there is one, or -1 otherwise. + * If the given index is not -1, then returns the index of the next entry in the hashtable, + * in strictly increasing order, or -1 if there are none left. + * + * index: The index of the previous entry that was iterated, or -1 to begin + * iteration at the beginning of the hashtable. + */ + inline ssize_t next(ssize_t index) const { + return BasicHashtableImpl::next(index); + } + + /* Finds the index of an entry with the specified key. + * If the given index is -1, then returns the index of the first matching entry, + * otherwise returns the index of the next matching entry. + * If the hashtable contains multiple entries with keys that match the requested + * key, then the sequence of entries returned is arbitrary. + * Returns -1 if no entry was found. + * + * index: The index of the previous entry with the specified key, or -1 to + * find the first matching entry. + * hash: The hashcode of the key. + * key: The key. + */ + inline ssize_t find(ssize_t index, hash_t hash, const TKey& key) const { + return BasicHashtableImpl::find(index, hash, &key); + } + + /* Adds the entry to the hashtable. + * Returns the index of the newly added entry. + * If an entry with the same key already exists, then a duplicate entry is added. + * If the entry will not fit, then the hashtable's capacity is increased and + * its contents are rehashed. See rehash(). + * + * hash: The hashcode of the key. + * entry: The entry to add. + */ + inline size_t add(hash_t hash, const TEntry& entry) { + return BasicHashtableImpl::add(hash, &entry); + } + + /* Removes the entry with the specified index from the hashtable. + * The entry is destroyed immediately. + * The index must be valid. + * + * The hashtable is not compacted after an item is removed, so it is legal + * to continue iterating over the hashtable using next() or find(). + * + * index: The index of the entry to remove. Must be a valid index within the + * bounds of the hashtable, and it must refer to an existing entry. + */ + inline void removeAt(size_t index) { + BasicHashtableImpl::removeAt(index); + } + + /* Rehashes the contents of the hashtable. + * Grows the hashtable to at least the specified minimum capacity or the + * current number of elements, whichever is larger. + * + * Rehashing causes all entries to be copied and the entry indices may change. + * Although the hash codes are cached by the hashtable, rehashing can be an + * expensive operation and should be avoided unless the hashtable's size + * needs to be changed. + * + * Rehashing is the only way to change the capacity or load factor of the + * hashtable once it has been created. It can be used to compact the + * hashtable by choosing a minimum capacity that is smaller than the current + * capacity (such as 0). + * + * minimumCapacity: The desired minimum capacity after rehashing. + * loadFactor: The desired load factor after rehashing. + */ + inline void rehash(size_t minimumCapacity, float loadFactor) { + BasicHashtableImpl::rehash(minimumCapacity, loadFactor); + } + +protected: + static inline const TEntry& entryFor(const Bucket& bucket) { + return reinterpret_cast<const TEntry&>(bucket.entry); + } + + static inline TEntry& entryFor(Bucket& bucket) { + return reinterpret_cast<TEntry&>(bucket.entry); + } + + virtual bool compareBucketKey(const Bucket& bucket, const void* __restrict__ key) const; + virtual void initializeBucketEntry(Bucket& bucket, const void* __restrict__ entry) const; + virtual void destroyBucketEntry(Bucket& bucket) const; + +private: + // For dumping the raw contents of a hashtable during testing. + friend class BasicHashtableTest; + inline uint32_t cookieAt(size_t index) const { + return bucketAt(mBuckets, index).cookie; + } +}; + +template <typename TKey, typename TEntry> +BasicHashtable<TKey, TEntry>::BasicHashtable(size_t minimumInitialCapacity, float loadFactor) : + BasicHashtableImpl(sizeof(TEntry), traits<TEntry>::has_trivial_dtor, + minimumInitialCapacity, loadFactor) { +} + +template <typename TKey, typename TEntry> +BasicHashtable<TKey, TEntry>::BasicHashtable(const BasicHashtable<TKey, TEntry>& other) : + BasicHashtableImpl(other) { +} + +template <typename TKey, typename TEntry> +BasicHashtable<TKey, TEntry>::~BasicHashtable() { + dispose(); +} + +template <typename TKey, typename TEntry> +bool BasicHashtable<TKey, TEntry>::compareBucketKey(const Bucket& bucket, + const void* __restrict__ key) const { + return entryFor(bucket).getKey() == *static_cast<const TKey*>(key); +} + +template <typename TKey, typename TEntry> +void BasicHashtable<TKey, TEntry>::initializeBucketEntry(Bucket& bucket, + const void* __restrict__ entry) const { + if (!traits<TEntry>::has_trivial_copy) { + new (&entryFor(bucket)) TEntry(*(static_cast<const TEntry*>(entry))); + } else { + memcpy(&entryFor(bucket), entry, sizeof(TEntry)); + } +} + +template <typename TKey, typename TEntry> +void BasicHashtable<TKey, TEntry>::destroyBucketEntry(Bucket& bucket) const { + if (!traits<TEntry>::has_trivial_dtor) { + entryFor(bucket).~TEntry(); + } +} + +}; // namespace android + +#endif // ANDROID_BASIC_HASHTABLE_H diff --git a/include/utils/CallStack.h b/include/utils/CallStack.h index 8817120..079e20c 100644 --- a/include/utils/CallStack.h +++ b/include/utils/CallStack.h @@ -21,6 +21,7 @@ #include <sys/types.h> #include <utils/String8.h> +#include <corkscrew/backtrace.h> // --------------------------------------------------------------------------- @@ -61,11 +62,8 @@ public: size_t size() const { return mCount; } private: - // Internal helper function - String8 toStringSingleLevel(const char* prefix, int32_t level) const; - - size_t mCount; - const void* mStack[MAX_DEPTH]; + size_t mCount; + backtrace_frame_t mStack[MAX_DEPTH]; }; }; // namespace android diff --git a/include/utils/GenerationCache.h b/include/utils/GenerationCache.h index bb9ddd6..40722d1 100644 --- a/include/utils/GenerationCache.h +++ b/include/utils/GenerationCache.h @@ -34,17 +34,17 @@ public: template<typename EntryKey, typename EntryValue> struct Entry: public LightRefBase<Entry<EntryKey, EntryValue> > { - Entry() { } - Entry(const Entry<EntryKey, EntryValue>& e): - key(e.key), value(e.value), parent(e.parent), child(e.child) { } - Entry(sp<Entry<EntryKey, EntryValue> > e): - key(e->key), value(e->value), parent(e->parent), child(e->child) { } + Entry(const Entry<EntryKey, EntryValue>& e) : + key(e.key), value(e.value), + parent(e.parent), child(e.child) { } + Entry(const EntryKey& key, const EntryValue& value) : + key(key), value(value) { } EntryKey key; EntryValue value; - sp<Entry<EntryKey, EntryValue> > parent; - sp<Entry<EntryKey, EntryValue> > child; + sp<Entry<EntryKey, EntryValue> > parent; // next older entry + sp<Entry<EntryKey, EntryValue> > child; // next younger entry }; // struct Entry /** @@ -62,23 +62,20 @@ public: void setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener); - void clear(); + size_t size() const; - bool contains(K key) const; - V get(K key); - K getKeyAt(uint32_t index) const; - bool put(K key, V value); - V remove(K key); - V removeOldest(); - V getValueAt(uint32_t index) const; + void clear(); - uint32_t size() const; + bool contains(const K& key) const; + const K& getKeyAt(size_t index) const; + const V& getValueAt(size_t index) const; - void addToCache(sp<Entry<K, V> > entry, K key, V value); - void attachToCache(sp<Entry<K, V> > entry); - void detachFromCache(sp<Entry<K, V> > entry); + const V& get(const K& key); + bool put(const K& key, const V& value); - V removeAt(ssize_t index); + void removeAt(ssize_t index); + bool remove(const K& key); + bool removeOldest(); private: KeyedVector<K, sp<Entry<K, V> > > mCache; @@ -88,11 +85,16 @@ private: sp<Entry<K, V> > mOldest; sp<Entry<K, V> > mYoungest; + + void attachToCache(const sp<Entry<K, V> >& entry); + void detachFromCache(const sp<Entry<K, V> >& entry); + + const V mNullValue; }; // class GenerationCache template<typename K, typename V> GenerationCache<K, V>::GenerationCache(uint32_t maxCapacity): mMaxCapacity(maxCapacity), - mListener(NULL) { + mListener(NULL), mNullValue(NULL) { }; template<typename K, typename V> @@ -130,45 +132,44 @@ void GenerationCache<K, V>::clear() { } template<typename K, typename V> -bool GenerationCache<K, V>::contains(K key) const { +bool GenerationCache<K, V>::contains(const K& key) const { return mCache.indexOfKey(key) >= 0; } template<typename K, typename V> -K GenerationCache<K, V>::getKeyAt(uint32_t index) const { +const K& GenerationCache<K, V>::getKeyAt(size_t index) const { return mCache.keyAt(index); } template<typename K, typename V> -V GenerationCache<K, V>::getValueAt(uint32_t index) const { +const V& GenerationCache<K, V>::getValueAt(size_t index) const { return mCache.valueAt(index)->value; } template<typename K, typename V> -V GenerationCache<K, V>::get(K key) { +const V& GenerationCache<K, V>::get(const K& key) { ssize_t index = mCache.indexOfKey(key); if (index >= 0) { - sp<Entry<K, V> > entry = mCache.valueAt(index); - if (entry.get()) { - detachFromCache(entry); - attachToCache(entry); - return entry->value; - } + const sp<Entry<K, V> >& entry = mCache.valueAt(index); + detachFromCache(entry); + attachToCache(entry); + return entry->value; } - return NULL; + return mNullValue; } template<typename K, typename V> -bool GenerationCache<K, V>::put(K key, V value) { +bool GenerationCache<K, V>::put(const K& key, const V& value) { if (mMaxCapacity != kUnlimitedCapacity && mCache.size() >= mMaxCapacity) { removeOldest(); } ssize_t index = mCache.indexOfKey(key); if (index < 0) { - sp<Entry<K, V> > entry = new Entry<K, V>; - addToCache(entry, key, value); + sp<Entry<K, V> > entry = new Entry<K, V>(key, value); + mCache.add(key, entry); + attachToCache(entry); return true; } @@ -176,49 +177,44 @@ bool GenerationCache<K, V>::put(K key, V value) { } template<typename K, typename V> -void GenerationCache<K, V>::addToCache(sp<Entry<K, V> > entry, K key, V value) { - entry->key = key; - entry->value = value; - mCache.add(key, entry); - attachToCache(entry); -} - -template<typename K, typename V> -V GenerationCache<K, V>::remove(K key) { +bool GenerationCache<K, V>::remove(const K& key) { ssize_t index = mCache.indexOfKey(key); if (index >= 0) { - return removeAt(index); + removeAt(index); + return true; } - return NULL; + return false; } template<typename K, typename V> -V GenerationCache<K, V>::removeAt(ssize_t index) { +void GenerationCache<K, V>::removeAt(ssize_t index) { sp<Entry<K, V> > entry = mCache.valueAt(index); if (mListener) { (*mListener)(entry->key, entry->value); } mCache.removeItemsAt(index, 1); detachFromCache(entry); - - return entry->value; } template<typename K, typename V> -V GenerationCache<K, V>::removeOldest() { +bool GenerationCache<K, V>::removeOldest() { if (mOldest.get()) { ssize_t index = mCache.indexOfKey(mOldest->key); if (index >= 0) { - return removeAt(index); + removeAt(index); + return true; } + ALOGE("GenerationCache: removeOldest failed to find the item in the cache " + "with the given key, but we know it must be in there. " + "Is the key comparator kaput?"); } - return NULL; + return false; } template<typename K, typename V> -void GenerationCache<K, V>::attachToCache(sp<Entry<K, V> > entry) { +void GenerationCache<K, V>::attachToCache(const sp<Entry<K, V> >& entry) { if (!mYoungest.get()) { mYoungest = mOldest = entry; } else { @@ -229,20 +225,16 @@ void GenerationCache<K, V>::attachToCache(sp<Entry<K, V> > entry) { } template<typename K, typename V> -void GenerationCache<K, V>::detachFromCache(sp<Entry<K, V> > entry) { +void GenerationCache<K, V>::detachFromCache(const sp<Entry<K, V> >& entry) { if (entry->parent.get()) { entry->parent->child = entry->child; + } else { + mOldest = entry->child; } if (entry->child.get()) { entry->child->parent = entry->parent; - } - - if (mOldest == entry) { - mOldest = entry->child; - } - - if (mYoungest == entry) { + } else { mYoungest = entry->parent; } diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h index 71e5324..c496da6 100644 --- a/include/utils/ResourceTypes.h +++ b/include/utils/ResourceTypes.h @@ -444,23 +444,31 @@ public: void uninit(); + // Return string entry as UTF16; if the pool is UTF8, the string will + // be converted before returning. inline const char16_t* stringAt(const ResStringPool_ref& ref, size_t* outLen) const { return stringAt(ref.index, outLen); } const char16_t* stringAt(size_t idx, size_t* outLen) const; + // Note: returns null if the string pool is not UTF8. const char* string8At(size_t idx, size_t* outLen) const; + // Return string whether the pool is UTF8 or UTF16. Does not allow you + // to distinguish null. + const String8 string8ObjectAt(size_t idx) const; + const ResStringPool_span* styleAt(const ResStringPool_ref& ref) const; const ResStringPool_span* styleAt(size_t idx) const; ssize_t indexOfString(const char16_t* str, size_t strLen) const; size_t size() const; + size_t styleCount() const; + size_t bytes() const; -#ifndef HAVE_ANDROID_OS + bool isSorted() const; bool isUTF8() const; -#endif private: status_t mError; @@ -746,7 +754,9 @@ private: /** * Header for a resource table. Its data contains a series of * additional chunks: - * * A ResStringPool_header containing all table values. + * * A ResStringPool_header containing all table values. This string pool + * contains all of the string values in the entire resource table (not + * the names of entries or type identifiers however). * * One or more ResTable_package chunks. * * Specific entries within a resource table can be uniquely identified @@ -843,6 +853,8 @@ struct ResTable_config DENSITY_MEDIUM = ACONFIGURATION_DENSITY_MEDIUM, DENSITY_TV = ACONFIGURATION_DENSITY_TV, DENSITY_HIGH = ACONFIGURATION_DENSITY_HIGH, + DENSITY_XHIGH = ACONFIGURATION_DENSITY_XHIGH, + DENSITY_XXHIGH = ACONFIGURATION_DENSITY_XXHIGH, DENSITY_NONE = ACONFIGURATION_DENSITY_NONE }; @@ -955,6 +967,7 @@ struct ResTable_config UI_MODE_TYPE_DESK = ACONFIGURATION_UI_MODE_TYPE_DESK, UI_MODE_TYPE_CAR = ACONFIGURATION_UI_MODE_TYPE_CAR, UI_MODE_TYPE_TELEVISION = ACONFIGURATION_UI_MODE_TYPE_TELEVISION, + UI_MODE_TYPE_APPLIANCE = ACONFIGURATION_UI_MODE_TYPE_APPLIANCE, // uiMode bits for the night switch. MASK_UI_MODE_NIGHT = 0x30, @@ -981,68 +994,15 @@ struct ResTable_config uint32_t screenSizeDp; }; - inline void copyFromDeviceNoSwap(const ResTable_config& o) { - const size_t size = dtohl(o.size); - if (size >= sizeof(ResTable_config)) { - *this = o; - } else { - memcpy(this, &o, size); - memset(((uint8_t*)this)+size, 0, sizeof(ResTable_config)-size); - } - } + void copyFromDeviceNoSwap(const ResTable_config& o); - inline void copyFromDtoH(const ResTable_config& o) { - copyFromDeviceNoSwap(o); - size = sizeof(ResTable_config); - mcc = dtohs(mcc); - mnc = dtohs(mnc); - density = dtohs(density); - screenWidth = dtohs(screenWidth); - screenHeight = dtohs(screenHeight); - sdkVersion = dtohs(sdkVersion); - minorVersion = dtohs(minorVersion); - smallestScreenWidthDp = dtohs(smallestScreenWidthDp); - screenWidthDp = dtohs(screenWidthDp); - screenHeightDp = dtohs(screenHeightDp); - } - - inline void swapHtoD() { - size = htodl(size); - mcc = htods(mcc); - mnc = htods(mnc); - density = htods(density); - screenWidth = htods(screenWidth); - screenHeight = htods(screenHeight); - sdkVersion = htods(sdkVersion); - minorVersion = htods(minorVersion); - smallestScreenWidthDp = htods(smallestScreenWidthDp); - screenWidthDp = htods(screenWidthDp); - screenHeightDp = htods(screenHeightDp); - } - - inline int compare(const ResTable_config& o) const { - int32_t diff = (int32_t)(imsi - o.imsi); - if (diff != 0) return diff; - diff = (int32_t)(locale - o.locale); - if (diff != 0) return diff; - diff = (int32_t)(screenType - o.screenType); - if (diff != 0) return diff; - diff = (int32_t)(input - o.input); - if (diff != 0) return diff; - diff = (int32_t)(screenSize - o.screenSize); - if (diff != 0) return diff; - diff = (int32_t)(version - o.version); - if (diff != 0) return diff; - diff = (int32_t)(screenLayout - o.screenLayout); - if (diff != 0) return diff; - diff = (int32_t)(uiMode - o.uiMode); - if (diff != 0) return diff; - diff = (int32_t)(smallestScreenWidthDp - o.smallestScreenWidthDp); - if (diff != 0) return diff; - diff = (int32_t)(screenSizeDp - o.screenSizeDp); - return (int)diff; - } + void copyFromDtoH(const ResTable_config& o); + void swapHtoD(); + + int compare(const ResTable_config& o) const; + int compareLogical(const ResTable_config& o) const; + // Flags indicating a set of config values. These flag constants must // match the corresponding ones in android.content.pm.ActivityInfo and // attrs_manifest.xml. @@ -1065,158 +1025,10 @@ struct ResTable_config // Compare two configuration, returning CONFIG_* flags set for each value // that is different. - inline int diff(const ResTable_config& o) const { - int diffs = 0; - if (mcc != o.mcc) diffs |= CONFIG_MCC; - if (mnc != o.mnc) diffs |= CONFIG_MNC; - if (locale != o.locale) diffs |= CONFIG_LOCALE; - if (orientation != o.orientation) diffs |= CONFIG_ORIENTATION; - if (density != o.density) diffs |= CONFIG_DENSITY; - if (touchscreen != o.touchscreen) diffs |= CONFIG_TOUCHSCREEN; - if (((inputFlags^o.inputFlags)&(MASK_KEYSHIDDEN|MASK_NAVHIDDEN)) != 0) - diffs |= CONFIG_KEYBOARD_HIDDEN; - if (keyboard != o.keyboard) diffs |= CONFIG_KEYBOARD; - if (navigation != o.navigation) diffs |= CONFIG_NAVIGATION; - if (screenSize != o.screenSize) diffs |= CONFIG_SCREEN_SIZE; - if (version != o.version) diffs |= CONFIG_VERSION; - if (screenLayout != o.screenLayout) diffs |= CONFIG_SCREEN_LAYOUT; - if (uiMode != o.uiMode) diffs |= CONFIG_UI_MODE; - if (smallestScreenWidthDp != o.smallestScreenWidthDp) diffs |= CONFIG_SMALLEST_SCREEN_SIZE; - if (screenSizeDp != o.screenSizeDp) diffs |= CONFIG_SCREEN_SIZE; - return diffs; - } + int diff(const ResTable_config& o) const; // Return true if 'this' is more specific than 'o'. - inline bool - isMoreSpecificThan(const ResTable_config& o) const { - // The order of the following tests defines the importance of one - // configuration parameter over another. Those tests first are more - // important, trumping any values in those following them. - if (imsi || o.imsi) { - if (mcc != o.mcc) { - if (!mcc) return false; - if (!o.mcc) return true; - } - - if (mnc != o.mnc) { - if (!mnc) return false; - if (!o.mnc) return true; - } - } - - if (locale || o.locale) { - if (language[0] != o.language[0]) { - if (!language[0]) return false; - if (!o.language[0]) return true; - } - - if (country[0] != o.country[0]) { - if (!country[0]) return false; - if (!o.country[0]) return true; - } - } - - if (smallestScreenWidthDp || o.smallestScreenWidthDp) { - if (smallestScreenWidthDp != o.smallestScreenWidthDp) { - if (!smallestScreenWidthDp) return false; - if (!o.smallestScreenWidthDp) return true; - } - } - - if (screenSizeDp || o.screenSizeDp) { - if (screenWidthDp != o.screenWidthDp) { - if (!screenWidthDp) return false; - if (!o.screenWidthDp) return true; - } - - if (screenHeightDp != o.screenHeightDp) { - if (!screenHeightDp) return false; - if (!o.screenHeightDp) return true; - } - } - - if (screenLayout || o.screenLayout) { - if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0) { - if (!(screenLayout & MASK_SCREENSIZE)) return false; - if (!(o.screenLayout & MASK_SCREENSIZE)) return true; - } - if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0) { - if (!(screenLayout & MASK_SCREENLONG)) return false; - if (!(o.screenLayout & MASK_SCREENLONG)) return true; - } - } - - if (orientation != o.orientation) { - if (!orientation) return false; - if (!o.orientation) return true; - } - - if (uiMode || o.uiMode) { - if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0) { - if (!(uiMode & MASK_UI_MODE_TYPE)) return false; - if (!(o.uiMode & MASK_UI_MODE_TYPE)) return true; - } - if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0) { - if (!(uiMode & MASK_UI_MODE_NIGHT)) return false; - if (!(o.uiMode & MASK_UI_MODE_NIGHT)) return true; - } - } - - // density is never 'more specific' - // as the default just equals 160 - - if (touchscreen != o.touchscreen) { - if (!touchscreen) return false; - if (!o.touchscreen) return true; - } - - if (input || o.input) { - if (((inputFlags^o.inputFlags) & MASK_KEYSHIDDEN) != 0) { - if (!(inputFlags & MASK_KEYSHIDDEN)) return false; - if (!(o.inputFlags & MASK_KEYSHIDDEN)) return true; - } - - if (((inputFlags^o.inputFlags) & MASK_NAVHIDDEN) != 0) { - if (!(inputFlags & MASK_NAVHIDDEN)) return false; - if (!(o.inputFlags & MASK_NAVHIDDEN)) return true; - } - - if (keyboard != o.keyboard) { - if (!keyboard) return false; - if (!o.keyboard) return true; - } - - if (navigation != o.navigation) { - if (!navigation) return false; - if (!o.navigation) return true; - } - } - - if (screenSize || o.screenSize) { - if (screenWidth != o.screenWidth) { - if (!screenWidth) return false; - if (!o.screenWidth) return true; - } - - if (screenHeight != o.screenHeight) { - if (!screenHeight) return false; - if (!o.screenHeight) return true; - } - } - - if (version || o.version) { - if (sdkVersion != o.sdkVersion) { - if (!sdkVersion) return false; - if (!o.sdkVersion) return true; - } - - if (minorVersion != o.minorVersion) { - if (!minorVersion) return false; - if (!o.minorVersion) return true; - } - } - return false; - } + bool isMoreSpecificThan(const ResTable_config& o) const; // Return true if 'this' is a better match than 'o' for the 'requested' // configuration. This assumes that match() has already been used to @@ -1228,222 +1040,7 @@ struct ResTable_config // they are not equal then one must be generic because only generic and // '==requested' will pass the match() call. So if this is not generic, // it wins. If this IS generic, o wins (return false). - inline bool - isBetterThan(const ResTable_config& o, - const ResTable_config* requested) const { - if (requested) { - if (imsi || o.imsi) { - if ((mcc != o.mcc) && requested->mcc) { - return (mcc); - } - - if ((mnc != o.mnc) && requested->mnc) { - return (mnc); - } - } - - if (locale || o.locale) { - if ((language[0] != o.language[0]) && requested->language[0]) { - return (language[0]); - } - - if ((country[0] != o.country[0]) && requested->country[0]) { - return (country[0]); - } - } - - if (smallestScreenWidthDp || o.smallestScreenWidthDp) { - // The configuration closest to the actual size is best. - // We assume that larger configs have already been filtered - // out at this point. That means we just want the largest one. - return smallestScreenWidthDp >= o.smallestScreenWidthDp; - } - - if (screenSizeDp || o.screenSizeDp) { - // "Better" is based on the sum of the difference between both - // width and height from the requested dimensions. We are - // assuming the invalid configs (with smaller dimens) have - // already been filtered. Note that if a particular dimension - // is unspecified, we will end up with a large value (the - // difference between 0 and the requested dimension), which is - // good since we will prefer a config that has specified a - // dimension value. - int myDelta = 0, otherDelta = 0; - if (requested->screenWidthDp) { - myDelta += requested->screenWidthDp - screenWidthDp; - otherDelta += requested->screenWidthDp - o.screenWidthDp; - } - if (requested->screenHeightDp) { - myDelta += requested->screenHeightDp - screenHeightDp; - otherDelta += requested->screenHeightDp - o.screenHeightDp; - } - //ALOGI("Comparing this %dx%d to other %dx%d in %dx%d: myDelta=%d otherDelta=%d", - // screenWidthDp, screenHeightDp, o.screenWidthDp, o.screenHeightDp, - // requested->screenWidthDp, requested->screenHeightDp, myDelta, otherDelta); - return (myDelta <= otherDelta); - } - - if (screenLayout || o.screenLayout) { - if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0 - && (requested->screenLayout & MASK_SCREENSIZE)) { - // A little backwards compatibility here: undefined is - // considered equivalent to normal. But only if the - // requested size is at least normal; otherwise, small - // is better than the default. - int mySL = (screenLayout & MASK_SCREENSIZE); - int oSL = (o.screenLayout & MASK_SCREENSIZE); - int fixedMySL = mySL; - int fixedOSL = oSL; - if ((requested->screenLayout & MASK_SCREENSIZE) >= SCREENSIZE_NORMAL) { - if (fixedMySL == 0) fixedMySL = SCREENSIZE_NORMAL; - if (fixedOSL == 0) fixedOSL = SCREENSIZE_NORMAL; - } - // For screen size, the best match is the one that is - // closest to the requested screen size, but not over - // (the not over part is dealt with in match() below). - if (fixedMySL == fixedOSL) { - // If the two are the same, but 'this' is actually - // undefined, then the other is really a better match. - if (mySL == 0) return false; - return true; - } - return fixedMySL >= fixedOSL; - } - if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0 - && (requested->screenLayout & MASK_SCREENLONG)) { - return (screenLayout & MASK_SCREENLONG); - } - } - - if ((orientation != o.orientation) && requested->orientation) { - return (orientation); - } - - if (uiMode || o.uiMode) { - if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0 - && (requested->uiMode & MASK_UI_MODE_TYPE)) { - return (uiMode & MASK_UI_MODE_TYPE); - } - if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0 - && (requested->uiMode & MASK_UI_MODE_NIGHT)) { - return (uiMode & MASK_UI_MODE_NIGHT); - } - } - - if (screenType || o.screenType) { - if (density != o.density) { - // density is tough. Any density is potentially useful - // because the system will scale it. Scaling down - // is generally better than scaling up. - // Default density counts as 160dpi (the system default) - // TODO - remove 160 constants - int h = (density?density:160); - int l = (o.density?o.density:160); - bool bImBigger = true; - if (l > h) { - int t = h; - h = l; - l = t; - bImBigger = false; - } - - int reqValue = (requested->density?requested->density:160); - if (reqValue >= h) { - // requested value higher than both l and h, give h - return bImBigger; - } - if (l >= reqValue) { - // requested value lower than both l and h, give l - return !bImBigger; - } - // saying that scaling down is 2x better than up - if (((2 * l) - reqValue) * h > reqValue * reqValue) { - return !bImBigger; - } else { - return bImBigger; - } - } - - if ((touchscreen != o.touchscreen) && requested->touchscreen) { - return (touchscreen); - } - } - - if (input || o.input) { - const int keysHidden = inputFlags & MASK_KEYSHIDDEN; - const int oKeysHidden = o.inputFlags & MASK_KEYSHIDDEN; - if (keysHidden != oKeysHidden) { - const int reqKeysHidden = - requested->inputFlags & MASK_KEYSHIDDEN; - if (reqKeysHidden) { - - if (!keysHidden) return false; - if (!oKeysHidden) return true; - // For compatibility, we count KEYSHIDDEN_NO as being - // the same as KEYSHIDDEN_SOFT. Here we disambiguate - // these by making an exact match more specific. - if (reqKeysHidden == keysHidden) return true; - if (reqKeysHidden == oKeysHidden) return false; - } - } - - const int navHidden = inputFlags & MASK_NAVHIDDEN; - const int oNavHidden = o.inputFlags & MASK_NAVHIDDEN; - if (navHidden != oNavHidden) { - const int reqNavHidden = - requested->inputFlags & MASK_NAVHIDDEN; - if (reqNavHidden) { - - if (!navHidden) return false; - if (!oNavHidden) return true; - } - } - - if ((keyboard != o.keyboard) && requested->keyboard) { - return (keyboard); - } - - if ((navigation != o.navigation) && requested->navigation) { - return (navigation); - } - } - - if (screenSize || o.screenSize) { - // "Better" is based on the sum of the difference between both - // width and height from the requested dimensions. We are - // assuming the invalid configs (with smaller sizes) have - // already been filtered. Note that if a particular dimension - // is unspecified, we will end up with a large value (the - // difference between 0 and the requested dimension), which is - // good since we will prefer a config that has specified a - // size value. - int myDelta = 0, otherDelta = 0; - if (requested->screenWidth) { - myDelta += requested->screenWidth - screenWidth; - otherDelta += requested->screenWidth - o.screenWidth; - } - if (requested->screenHeight) { - myDelta += requested->screenHeight - screenHeight; - otherDelta += requested->screenHeight - o.screenHeight; - } - return (myDelta <= otherDelta); - } - - if (version || o.version) { - if ((sdkVersion != o.sdkVersion) && requested->sdkVersion) { - return (sdkVersion > o.sdkVersion); - } - - if ((minorVersion != o.minorVersion) && - requested->minorVersion) { - return (minorVersion); - } - } - - return false; - } - return isMoreSpecificThan(o); - } + bool isBetterThan(const ResTable_config& o, const ResTable_config* requested) const; // Return true if 'this' can be considered a match for the parameters in // 'settings'. @@ -1451,150 +1048,11 @@ struct ResTable_config // but a request for the default should not match odd specifics // (ie, request with no mcc should not match a particular mcc's data) // settings is the requested settings - inline bool match(const ResTable_config& settings) const { - if (imsi != 0) { - if (mcc != 0 && mcc != settings.mcc) { - return false; - } - if (mnc != 0 && mnc != settings.mnc) { - return false; - } - } - if (locale != 0) { - if (language[0] != 0 - && (language[0] != settings.language[0] - || language[1] != settings.language[1])) { - return false; - } - if (country[0] != 0 - && (country[0] != settings.country[0] - || country[1] != settings.country[1])) { - return false; - } - } - if (screenConfig != 0) { - const int screenSize = screenLayout&MASK_SCREENSIZE; - const int setScreenSize = settings.screenLayout&MASK_SCREENSIZE; - // Any screen sizes for larger screens than the setting do not - // match. - if (screenSize != 0 && screenSize > setScreenSize) { - return false; - } - - const int screenLong = screenLayout&MASK_SCREENLONG; - const int setScreenLong = settings.screenLayout&MASK_SCREENLONG; - if (screenLong != 0 && screenLong != setScreenLong) { - return false; - } - - const int uiModeType = uiMode&MASK_UI_MODE_TYPE; - const int setUiModeType = settings.uiMode&MASK_UI_MODE_TYPE; - if (uiModeType != 0 && uiModeType != setUiModeType) { - return false; - } - - const int uiModeNight = uiMode&MASK_UI_MODE_NIGHT; - const int setUiModeNight = settings.uiMode&MASK_UI_MODE_NIGHT; - if (uiModeNight != 0 && uiModeNight != setUiModeNight) { - return false; - } - - if (smallestScreenWidthDp != 0 - && smallestScreenWidthDp > settings.smallestScreenWidthDp) { - return false; - } - } - if (screenSizeDp != 0) { - if (screenWidthDp != 0 && screenWidthDp > settings.screenWidthDp) { - //ALOGI("Filtering out width %d in requested %d", screenWidthDp, settings.screenWidthDp); - return false; - } - if (screenHeightDp != 0 && screenHeightDp > settings.screenHeightDp) { - //ALOGI("Filtering out height %d in requested %d", screenHeightDp, settings.screenHeightDp); - return false; - } - } - if (screenType != 0) { - if (orientation != 0 && orientation != settings.orientation) { - return false; - } - // density always matches - we can scale it. See isBetterThan - if (touchscreen != 0 && touchscreen != settings.touchscreen) { - return false; - } - } - if (input != 0) { - const int keysHidden = inputFlags&MASK_KEYSHIDDEN; - const int setKeysHidden = settings.inputFlags&MASK_KEYSHIDDEN; - if (keysHidden != 0 && keysHidden != setKeysHidden) { - // For compatibility, we count a request for KEYSHIDDEN_NO as also - // matching the more recent KEYSHIDDEN_SOFT. Basically - // KEYSHIDDEN_NO means there is some kind of keyboard available. - //ALOGI("Matching keysHidden: have=%d, config=%d\n", keysHidden, setKeysHidden); - if (keysHidden != KEYSHIDDEN_NO || setKeysHidden != KEYSHIDDEN_SOFT) { - //ALOGI("No match!"); - return false; - } - } - const int navHidden = inputFlags&MASK_NAVHIDDEN; - const int setNavHidden = settings.inputFlags&MASK_NAVHIDDEN; - if (navHidden != 0 && navHidden != setNavHidden) { - return false; - } - if (keyboard != 0 && keyboard != settings.keyboard) { - return false; - } - if (navigation != 0 && navigation != settings.navigation) { - return false; - } - } - if (screenSize != 0) { - if (screenWidth != 0 && screenWidth > settings.screenWidth) { - return false; - } - if (screenHeight != 0 && screenHeight > settings.screenHeight) { - return false; - } - } - if (version != 0) { - if (sdkVersion != 0 && sdkVersion > settings.sdkVersion) { - return false; - } - if (minorVersion != 0 && minorVersion != settings.minorVersion) { - return false; - } - } - return true; - } + bool match(const ResTable_config& settings) const; - void getLocale(char str[6]) const { - memset(str, 0, 6); - if (language[0]) { - str[0] = language[0]; - str[1] = language[1]; - if (country[0]) { - str[2] = '_'; - str[3] = country[0]; - str[4] = country[1]; - } - } - } + void getLocale(char str[6]) const; - String8 toString() const { - char buf[200]; - sprintf(buf, "imsi=%d/%d lang=%c%c reg=%c%c orient=%d touch=%d dens=%d " - "kbd=%d nav=%d input=%d ssz=%dx%d sw%ddp w%ddp h%ddp sz=%d long=%d " - "ui=%d night=%d vers=%d.%d", - mcc, mnc, - language[0] ? language[0] : '-', language[1] ? language[1] : '-', - country[0] ? country[0] : '-', country[1] ? country[1] : '-', - orientation, touchscreen, density, keyboard, navigation, inputFlags, - screenWidth, screenHeight, smallestScreenWidthDp, screenWidthDp, screenHeightDp, - screenLayout&MASK_SCREENSIZE, screenLayout&MASK_SCREENLONG, - uiMode&MASK_UI_MODE_TYPE, uiMode&MASK_UI_MODE_NIGHT, - sdkVersion, minorVersion); - return String8(buf); - } + String8 toString() const; }; /** @@ -2053,8 +1511,14 @@ public: const char16_t* getBasePackageName(size_t idx) const; uint32_t getBasePackageId(size_t idx) const; + // Return the number of resource tables that the object contains. size_t getTableCount() const; + // Return the values string pool for the resource table at the given + // index. This string pool contains all of the strings for values + // contained in the resource table -- that is the item values themselves, + // but not the names their entries or types. const ResStringPool* getTableStringBlock(size_t index) const; + // Return unique cookie identifier for the given resource table. void* getTableCookie(size_t index) const; // Return the configurations (ResTable_config) that we know about diff --git a/include/utils/TypeHelpers.h b/include/utils/TypeHelpers.h index a1663f3..1f2c2d5 100644 --- a/include/utils/TypeHelpers.h +++ b/include/utils/TypeHelpers.h @@ -213,6 +213,9 @@ void move_backward_type(TYPE* d, const TYPE* s, size_t n = 1) { template <typename KEY, typename VALUE> struct key_value_pair_t { + typedef KEY key_t; + typedef VALUE value_t; + KEY key; VALUE value; key_value_pair_t() { } @@ -222,27 +225,64 @@ struct key_value_pair_t { inline bool operator < (const key_value_pair_t& o) const { return strictly_order_type(key, o.key); } + inline const KEY& getKey() const { + return key; + } + inline const VALUE& getValue() const { + return value; + } }; -template<> template <typename K, typename V> struct trait_trivial_ctor< key_value_pair_t<K, V> > { enum { value = aggregate_traits<K,V>::has_trivial_ctor }; }; -template<> template <typename K, typename V> struct trait_trivial_dtor< key_value_pair_t<K, V> > { enum { value = aggregate_traits<K,V>::has_trivial_dtor }; }; -template<> template <typename K, typename V> struct trait_trivial_copy< key_value_pair_t<K, V> > { enum { value = aggregate_traits<K,V>::has_trivial_copy }; }; -template<> template <typename K, typename V> struct trait_trivial_move< key_value_pair_t<K, V> > { enum { value = aggregate_traits<K,V>::has_trivial_move }; }; // --------------------------------------------------------------------------- +/* + * Hash codes. + */ +typedef uint32_t hash_t; + +template <typename TKey> +hash_t hash_type(const TKey& key); + +/* Built-in hash code specializations. + * Assumes pointers are 32bit. */ +#define ANDROID_INT32_HASH(T) \ + template <> inline hash_t hash_type(const T& value) { return hash_t(value); } +#define ANDROID_INT64_HASH(T) \ + template <> inline hash_t hash_type(const T& value) { \ + return hash_t((value >> 32) ^ value); } +#define ANDROID_REINTERPRET_HASH(T, R) \ + template <> inline hash_t hash_type(const T& value) { \ + return hash_type(*reinterpret_cast<const R*>(&value)); } + +ANDROID_INT32_HASH(bool) +ANDROID_INT32_HASH(int8_t) +ANDROID_INT32_HASH(uint8_t) +ANDROID_INT32_HASH(int16_t) +ANDROID_INT32_HASH(uint16_t) +ANDROID_INT32_HASH(int32_t) +ANDROID_INT32_HASH(uint32_t) +ANDROID_INT64_HASH(int64_t) +ANDROID_INT64_HASH(uint64_t) +ANDROID_REINTERPRET_HASH(float, uint32_t) +ANDROID_REINTERPRET_HASH(double, uint64_t) + +template <typename T> inline hash_t hash_type(const T*& value) { + return hash_type(uintptr_t(value)); +} + }; // namespace android // --------------------------------------------------------------------------- diff --git a/include/utils/threads.h b/include/utils/threads.h index ab3e8cd..b4a8b7c 100644 --- a/include/utils/threads.h +++ b/include/utils/threads.h @@ -526,6 +526,12 @@ public: // Do not call from this object's thread; will return WOULD_BLOCK in that case. status_t join(); +#ifdef HAVE_ANDROID_OS + // Return the thread's kernel ID, same as the thread itself calling gettid() or + // androidGetTid(), or -1 if the thread is not running. + pid_t getTid() const; +#endif + protected: // exitPending() returns true if requestExit() has been called. bool exitPending() const; @@ -551,8 +557,10 @@ private: volatile bool mExitPending; volatile bool mRunning; sp<Thread> mHoldSelf; -#if HAVE_ANDROID_OS - int mTid; +#ifdef HAVE_ANDROID_OS + // legacy for debugging, not used by getTid() as it is set by the child thread + // and so is not initialized until the child reaches that point + pid_t mTid; #endif }; |