summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Ray2013-08-02 16:40:08 -0500
committerAlex Ray2013-08-02 16:40:08 -0500
commitd98e07fdf9c338589f263c47ce5c844ed43efad5 (patch)
treed4ff9849df225df1e4c46386fdabe30407ba5513 /libutils
parentbe06210c508d5878dcc7d185e5613f4c7e38dfe8 (diff)
downloadplatform-system-core-d98e07fdf9c338589f263c47ce5c844ed43efad5.tar.gz
platform-system-core-d98e07fdf9c338589f263c47ce5c844ed43efad5.tar.xz
platform-system-core-d98e07fdf9c338589f263c47ce5c844ed43efad5.zip
move libs/utils to libutils
Change-Id: I6cf4268599460791414882f91eeb88a992fbd29d
Diffstat (limited to 'libutils')
-rw-r--r--libutils/Android.mk144
-rw-r--r--libutils/BasicHashtable.cpp342
-rw-r--r--libutils/BlobCache.cpp362
-rw-r--r--libutils/CallStack.cpp138
-rw-r--r--libutils/CleanSpec.mk51
-rw-r--r--libutils/FileMap.cpp225
-rw-r--r--libutils/JenkinsHash.cpp64
-rw-r--r--libutils/LinearAllocator.cpp227
-rw-r--r--libutils/LinearTransform.cpp265
-rw-r--r--libutils/Log.cpp37
-rw-r--r--libutils/Looper.cpp573
-rw-r--r--libutils/MODULE_LICENSE_APACHE20
-rw-r--r--libutils/NOTICE190
-rw-r--r--libutils/PropertyMap.cpp218
-rw-r--r--libutils/README289
-rw-r--r--libutils/RefBase.cpp650
-rw-r--r--libutils/SharedBuffer.cpp113
-rw-r--r--libutils/Static.cpp49
-rw-r--r--libutils/StopWatch.cpp88
-rw-r--r--libutils/String16.cpp422
-rw-r--r--libutils/String8.cpp640
-rw-r--r--libutils/SystemClock.cpp155
-rw-r--r--libutils/Threads.cpp878
-rw-r--r--libutils/Timers.cpp72
-rw-r--r--libutils/Tokenizer.cpp175
-rw-r--r--libutils/Trace.cpp25
-rw-r--r--libutils/Unicode.cpp606
-rw-r--r--libutils/VectorImpl.cpp625
-rw-r--r--libutils/misc.cpp90
-rwxr-xr-xlibutils/primes.py47
-rw-r--r--libutils/tests/Android.mk34
-rw-r--r--libutils/tests/BasicHashtable_test.cpp577
-rw-r--r--libutils/tests/BitSet_test.cpp87
-rw-r--r--libutils/tests/BlobCache_test.cpp421
-rw-r--r--libutils/tests/Looper_test.cpp693
-rw-r--r--libutils/tests/LruCache_test.cpp291
-rw-r--r--libutils/tests/String8_test.cpp75
-rw-r--r--libutils/tests/TestHelpers.h79
-rw-r--r--libutils/tests/Unicode_test.cpp115
-rw-r--r--libutils/tests/Vector_test.cpp75
40 files changed, 10207 insertions, 0 deletions
diff --git a/libutils/Android.mk b/libutils/Android.mk
new file mode 100644
index 000000000..7e6b1be42
--- /dev/null
+++ b/libutils/Android.mk
@@ -0,0 +1,144 @@
1# Copyright (C) 2008 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15LOCAL_PATH:= $(call my-dir)
16
17# libutils is a little unique: It's built twice, once for the host
18# and once for the device.
19
20commonSources:= \
21 BasicHashtable.cpp \
22 BlobCache.cpp \
23 CallStack.cpp \
24 FileMap.cpp \
25 JenkinsHash.cpp \
26 LinearAllocator.cpp \
27 LinearTransform.cpp \
28 Log.cpp \
29 PropertyMap.cpp \
30 RefBase.cpp \
31 SharedBuffer.cpp \
32 Static.cpp \
33 StopWatch.cpp \
34 String8.cpp \
35 String16.cpp \
36 SystemClock.cpp \
37 Threads.cpp \
38 Timers.cpp \
39 Tokenizer.cpp \
40 Unicode.cpp \
41 VectorImpl.cpp \
42 misc.cpp
43
44host_commonCflags := -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS)
45
46ifeq ($(HOST_OS),windows)
47ifeq ($(strip $(USE_CYGWIN),),)
48# Under MinGW, ctype.h doesn't need multi-byte support
49host_commonCflags += -DMB_CUR_MAX=1
50endif
51endif
52
53host_commonLdlibs :=
54
55ifeq ($(TARGET_OS),linux)
56host_commonLdlibs += -lrt -ldl
57endif
58
59
60# For the host
61# =====================================================
62include $(CLEAR_VARS)
63LOCAL_SRC_FILES:= $(commonSources)
64ifeq ($(HOST_OS), linux)
65LOCAL_SRC_FILES += Looper.cpp
66endif
67LOCAL_MODULE:= libutils
68LOCAL_STATIC_LIBRARIES := liblog
69LOCAL_CFLAGS += $(host_commonCflags)
70LOCAL_LDLIBS += $(host_commonLdlibs)
71include $(BUILD_HOST_STATIC_LIBRARY)
72
73
74# For the host, 64-bit
75# =====================================================
76include $(CLEAR_VARS)
77LOCAL_SRC_FILES:= $(commonSources)
78ifeq ($(HOST_OS), linux)
79LOCAL_SRC_FILES += Looper.cpp
80endif
81LOCAL_MODULE:= lib64utils
82LOCAL_STATIC_LIBRARIES := liblog
83LOCAL_CFLAGS += $(host_commonCflags) -m64
84LOCAL_LDLIBS += $(host_commonLdlibs)
85include $(BUILD_HOST_STATIC_LIBRARY)
86
87
88# For the device, static
89# =====================================================
90include $(CLEAR_VARS)
91
92
93# we have the common sources, plus some device-specific stuff
94LOCAL_SRC_FILES:= \
95 $(commonSources) \
96 Looper.cpp \
97 Trace.cpp
98
99ifeq ($(TARGET_OS),linux)
100LOCAL_LDLIBS += -lrt -ldl
101endif
102
103ifeq ($(TARGET_ARCH),mips)
104LOCAL_CFLAGS += -DALIGN_DOUBLE
105endif
106
107LOCAL_C_INCLUDES += \
108 bionic/libc/private \
109 external/zlib
110
111LOCAL_LDLIBS += -lpthread
112
113LOCAL_STATIC_LIBRARIES := \
114 libcutils
115
116LOCAL_SHARED_LIBRARIES := \
117 libcorkscrew \
118 liblog \
119 libdl
120
121LOCAL_MODULE:= libutils
122include $(BUILD_STATIC_LIBRARY)
123
124# For the device, shared
125# =====================================================
126include $(CLEAR_VARS)
127LOCAL_MODULE:= libutils
128LOCAL_WHOLE_STATIC_LIBRARIES := libutils
129LOCAL_SHARED_LIBRARIES := \
130 liblog \
131 libcutils \
132 libdl \
133 libcorkscrew
134
135include $(BUILD_SHARED_LIBRARY)
136
137# Include subdirectory makefiles
138# ============================================================
139
140# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
141# team really wants is to build the stuff defined by this makefile.
142ifeq (,$(ONE_SHOT_MAKEFILE))
143include $(call first-makefiles-under,$(LOCAL_PATH))
144endif
diff --git a/libutils/BasicHashtable.cpp b/libutils/BasicHashtable.cpp
new file mode 100644
index 000000000..491d9e98b
--- /dev/null
+++ b/libutils/BasicHashtable.cpp
@@ -0,0 +1,342 @@
1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "BasicHashtable"
18
19#include <math.h>
20
21#include <utils/Log.h>
22#include <utils/BasicHashtable.h>
23#include <utils/misc.h>
24
25namespace android {
26
27BasicHashtableImpl::BasicHashtableImpl(size_t entrySize, bool hasTrivialDestructor,
28 size_t minimumInitialCapacity, float loadFactor) :
29 mBucketSize(entrySize + sizeof(Bucket)), mHasTrivialDestructor(hasTrivialDestructor),
30 mLoadFactor(loadFactor), mSize(0),
31 mFilledBuckets(0), mBuckets(NULL) {
32 determineCapacity(minimumInitialCapacity, mLoadFactor, &mBucketCount, &mCapacity);
33}
34
35BasicHashtableImpl::BasicHashtableImpl(const BasicHashtableImpl& other) :
36 mBucketSize(other.mBucketSize), mHasTrivialDestructor(other.mHasTrivialDestructor),
37 mCapacity(other.mCapacity), mLoadFactor(other.mLoadFactor),
38 mSize(other.mSize), mFilledBuckets(other.mFilledBuckets),
39 mBucketCount(other.mBucketCount), mBuckets(other.mBuckets) {
40 if (mBuckets) {
41 SharedBuffer::bufferFromData(mBuckets)->acquire();
42 }
43}
44
45BasicHashtableImpl::~BasicHashtableImpl()
46{
47}
48
49void BasicHashtableImpl::dispose() {
50 if (mBuckets) {
51 releaseBuckets(mBuckets, mBucketCount);
52 }
53}
54
55void BasicHashtableImpl::clone() {
56 if (mBuckets) {
57 void* newBuckets = allocateBuckets(mBucketCount);
58 copyBuckets(mBuckets, newBuckets, mBucketCount);
59 releaseBuckets(mBuckets, mBucketCount);
60 mBuckets = newBuckets;
61 }
62}
63
64void BasicHashtableImpl::setTo(const BasicHashtableImpl& other) {
65 if (mBuckets) {
66 releaseBuckets(mBuckets, mBucketCount);
67 }
68
69 mCapacity = other.mCapacity;
70 mLoadFactor = other.mLoadFactor;
71 mSize = other.mSize;
72 mFilledBuckets = other.mFilledBuckets;
73 mBucketCount = other.mBucketCount;
74 mBuckets = other.mBuckets;
75
76 if (mBuckets) {
77 SharedBuffer::bufferFromData(mBuckets)->acquire();
78 }
79}
80
81void BasicHashtableImpl::clear() {
82 if (mBuckets) {
83 if (mFilledBuckets) {
84 SharedBuffer* sb = SharedBuffer::bufferFromData(mBuckets);
85 if (sb->onlyOwner()) {
86 destroyBuckets(mBuckets, mBucketCount);
87 for (size_t i = 0; i < mBucketCount; i++) {
88 Bucket& bucket = bucketAt(mBuckets, i);
89 bucket.cookie = 0;
90 }
91 } else {
92 releaseBuckets(mBuckets, mBucketCount);
93 mBuckets = NULL;
94 }
95 mFilledBuckets = 0;
96 }
97 mSize = 0;
98 }
99}
100
101ssize_t BasicHashtableImpl::next(ssize_t index) const {
102 if (mSize) {
103 while (size_t(++index) < mBucketCount) {
104 const Bucket& bucket = bucketAt(mBuckets, index);
105 if (bucket.cookie & Bucket::PRESENT) {
106 return index;
107 }
108 }
109 }
110 return -1;
111}
112
113ssize_t BasicHashtableImpl::find(ssize_t index, hash_t hash,
114 const void* __restrict__ key) const {
115 if (!mSize) {
116 return -1;
117 }
118
119 hash = trimHash(hash);
120 if (index < 0) {
121 index = chainStart(hash, mBucketCount);
122
123 const Bucket& bucket = bucketAt(mBuckets, size_t(index));
124 if (bucket.cookie & Bucket::PRESENT) {
125 if (compareBucketKey(bucket, key)) {
126 return index;
127 }
128 } else {
129 if (!(bucket.cookie & Bucket::COLLISION)) {
130 return -1;
131 }
132 }
133 }
134
135 size_t inc = chainIncrement(hash, mBucketCount);
136 for (;;) {
137 index = chainSeek(index, inc, mBucketCount);
138
139 const Bucket& bucket = bucketAt(mBuckets, size_t(index));
140 if (bucket.cookie & Bucket::PRESENT) {
141 if ((bucket.cookie & Bucket::HASH_MASK) == hash
142 && compareBucketKey(bucket, key)) {
143 return index;
144 }
145 }
146 if (!(bucket.cookie & Bucket::COLLISION)) {
147 return -1;
148 }
149 }
150}
151
152size_t BasicHashtableImpl::add(hash_t hash, const void* entry) {
153 if (!mBuckets) {
154 mBuckets = allocateBuckets(mBucketCount);
155 } else {
156 edit();
157 }
158
159 hash = trimHash(hash);
160 for (;;) {
161 size_t index = chainStart(hash, mBucketCount);
162 Bucket* bucket = &bucketAt(mBuckets, size_t(index));
163 if (bucket->cookie & Bucket::PRESENT) {
164 size_t inc = chainIncrement(hash, mBucketCount);
165 do {
166 bucket->cookie |= Bucket::COLLISION;
167 index = chainSeek(index, inc, mBucketCount);
168 bucket = &bucketAt(mBuckets, size_t(index));
169 } while (bucket->cookie & Bucket::PRESENT);
170 }
171
172 uint32_t collision = bucket->cookie & Bucket::COLLISION;
173 if (!collision) {
174 if (mFilledBuckets >= mCapacity) {
175 rehash(mCapacity * 2, mLoadFactor);
176 continue;
177 }
178 mFilledBuckets += 1;
179 }
180
181 bucket->cookie = collision | Bucket::PRESENT | hash;
182 mSize += 1;
183 initializeBucketEntry(*bucket, entry);
184 return index;
185 }
186}
187
188void BasicHashtableImpl::removeAt(size_t index) {
189 edit();
190
191 Bucket& bucket = bucketAt(mBuckets, index);
192 bucket.cookie &= ~Bucket::PRESENT;
193 if (!(bucket.cookie & Bucket::COLLISION)) {
194 mFilledBuckets -= 1;
195 }
196 mSize -= 1;
197 if (!mHasTrivialDestructor) {
198 destroyBucketEntry(bucket);
199 }
200}
201
202void BasicHashtableImpl::rehash(size_t minimumCapacity, float loadFactor) {
203 if (minimumCapacity < mSize) {
204 minimumCapacity = mSize;
205 }
206 size_t newBucketCount, newCapacity;
207 determineCapacity(minimumCapacity, loadFactor, &newBucketCount, &newCapacity);
208
209 if (newBucketCount != mBucketCount || newCapacity != mCapacity) {
210 if (mBuckets) {
211 void* newBuckets;
212 if (mSize) {
213 newBuckets = allocateBuckets(newBucketCount);
214 for (size_t i = 0; i < mBucketCount; i++) {
215 const Bucket& fromBucket = bucketAt(mBuckets, i);
216 if (fromBucket.cookie & Bucket::PRESENT) {
217 hash_t hash = fromBucket.cookie & Bucket::HASH_MASK;
218 size_t index = chainStart(hash, newBucketCount);
219 Bucket* toBucket = &bucketAt(newBuckets, size_t(index));
220 if (toBucket->cookie & Bucket::PRESENT) {
221 size_t inc = chainIncrement(hash, newBucketCount);
222 do {
223 toBucket->cookie |= Bucket::COLLISION;
224 index = chainSeek(index, inc, newBucketCount);
225 toBucket = &bucketAt(newBuckets, size_t(index));
226 } while (toBucket->cookie & Bucket::PRESENT);
227 }
228 toBucket->cookie = Bucket::PRESENT | hash;
229 initializeBucketEntry(*toBucket, fromBucket.entry);
230 }
231 }
232 } else {
233 newBuckets = NULL;
234 }
235 releaseBuckets(mBuckets, mBucketCount);
236 mBuckets = newBuckets;
237 mFilledBuckets = mSize;
238 }
239 mBucketCount = newBucketCount;
240 mCapacity = newCapacity;
241 }
242 mLoadFactor = loadFactor;
243}
244
245void* BasicHashtableImpl::allocateBuckets(size_t count) const {
246 size_t bytes = count * mBucketSize;
247 SharedBuffer* sb = SharedBuffer::alloc(bytes);
248 LOG_ALWAYS_FATAL_IF(!sb, "Could not allocate %u bytes for hashtable with %u buckets.",
249 uint32_t(bytes), uint32_t(count));
250 void* buckets = sb->data();
251 for (size_t i = 0; i < count; i++) {
252 Bucket& bucket = bucketAt(buckets, i);
253 bucket.cookie = 0;
254 }
255 return buckets;
256}
257
258void BasicHashtableImpl::releaseBuckets(void* __restrict__ buckets, size_t count) const {
259 SharedBuffer* sb = SharedBuffer::bufferFromData(buckets);
260 if (sb->release(SharedBuffer::eKeepStorage) == 1) {
261 destroyBuckets(buckets, count);
262 SharedBuffer::dealloc(sb);
263 }
264}
265
266void BasicHashtableImpl::destroyBuckets(void* __restrict__ buckets, size_t count) const {
267 if (!mHasTrivialDestructor) {
268 for (size_t i = 0; i < count; i++) {
269 Bucket& bucket = bucketAt(buckets, i);
270 if (bucket.cookie & Bucket::PRESENT) {
271 destroyBucketEntry(bucket);
272 }
273 }
274 }
275}
276
277void BasicHashtableImpl::copyBuckets(const void* __restrict__ fromBuckets,
278 void* __restrict__ toBuckets, size_t count) const {
279 for (size_t i = 0; i < count; i++) {
280 const Bucket& fromBucket = bucketAt(fromBuckets, i);
281 Bucket& toBucket = bucketAt(toBuckets, i);
282 toBucket.cookie = fromBucket.cookie;
283 if (fromBucket.cookie & Bucket::PRESENT) {
284 initializeBucketEntry(toBucket, fromBucket.entry);
285 }
286 }
287}
288
289// Table of 31-bit primes where each prime is no less than twice as large
290// as the previous one. Generated by "primes.py".
291static size_t PRIMES[] = {
292 5,
293 11,
294 23,
295 47,
296 97,
297 197,
298 397,
299 797,
300 1597,
301 3203,
302 6421,
303 12853,
304 25717,
305 51437,
306 102877,
307 205759,
308 411527,
309 823117,
310 1646237,
311 3292489,
312 6584983,
313 13169977,
314 26339969,
315 52679969,
316 105359939,
317 210719881,
318 421439783,
319 842879579,
320 1685759167,
321 0,
322};
323
324void BasicHashtableImpl::determineCapacity(size_t minimumCapacity, float loadFactor,
325 size_t* __restrict__ outBucketCount, size_t* __restrict__ outCapacity) {
326 LOG_ALWAYS_FATAL_IF(loadFactor <= 0.0f || loadFactor > 1.0f,
327 "Invalid load factor %0.3f. Must be in the range (0, 1].", loadFactor);
328
329 size_t count = ceilf(minimumCapacity / loadFactor) + 1;
330 size_t i = 0;
331 while (count > PRIMES[i] && i < NELEM(PRIMES)) {
332 i++;
333 }
334 count = PRIMES[i];
335 LOG_ALWAYS_FATAL_IF(!count, "Could not determine required number of buckets for "
336 "hashtable with minimum capacity %u and load factor %0.3f.",
337 uint32_t(minimumCapacity), loadFactor);
338 *outBucketCount = count;
339 *outCapacity = ceilf((count - 1) * loadFactor);
340}
341
342}; // namespace android
diff --git a/libutils/BlobCache.cpp b/libutils/BlobCache.cpp
new file mode 100644
index 000000000..0fb1d8e99
--- /dev/null
+++ b/libutils/BlobCache.cpp
@@ -0,0 +1,362 @@
1/*
2 ** Copyright 2011, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17#define LOG_TAG "BlobCache"
18//#define LOG_NDEBUG 0
19
20#include <stdlib.h>
21#include <string.h>
22
23#include <utils/BlobCache.h>
24#include <utils/Errors.h>
25#include <utils/Log.h>
26
27namespace android {
28
29// BlobCache::Header::mMagicNumber value
30static const uint32_t blobCacheMagic = '_Bb$';
31
32// BlobCache::Header::mBlobCacheVersion value
33static const uint32_t blobCacheVersion = 1;
34
35// BlobCache::Header::mDeviceVersion value
36static const uint32_t blobCacheDeviceVersion = 1;
37
38BlobCache::BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize):
39 mMaxKeySize(maxKeySize),
40 mMaxValueSize(maxValueSize),
41 mMaxTotalSize(maxTotalSize),
42 mTotalSize(0) {
43 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
44#ifdef _WIN32
45 srand(now);
46#else
47 mRandState[0] = (now >> 0) & 0xFFFF;
48 mRandState[1] = (now >> 16) & 0xFFFF;
49 mRandState[2] = (now >> 32) & 0xFFFF;
50#endif
51 ALOGV("initializing random seed using %lld", now);
52}
53
54void BlobCache::set(const void* key, size_t keySize, const void* value,
55 size_t valueSize) {
56 if (mMaxKeySize < keySize) {
57 ALOGV("set: not caching because the key is too large: %d (limit: %d)",
58 keySize, mMaxKeySize);
59 return;
60 }
61 if (mMaxValueSize < valueSize) {
62 ALOGV("set: not caching because the value is too large: %d (limit: %d)",
63 valueSize, mMaxValueSize);
64 return;
65 }
66 if (mMaxTotalSize < keySize + valueSize) {
67 ALOGV("set: not caching because the combined key/value size is too "
68 "large: %d (limit: %d)", keySize + valueSize, mMaxTotalSize);
69 return;
70 }
71 if (keySize == 0) {
72 ALOGW("set: not caching because keySize is 0");
73 return;
74 }
75 if (valueSize <= 0) {
76 ALOGW("set: not caching because valueSize is 0");
77 return;
78 }
79
80 sp<Blob> dummyKey(new Blob(key, keySize, false));
81 CacheEntry dummyEntry(dummyKey, NULL);
82
83 while (true) {
84 ssize_t index = mCacheEntries.indexOf(dummyEntry);
85 if (index < 0) {
86 // Create a new cache entry.
87 sp<Blob> keyBlob(new Blob(key, keySize, true));
88 sp<Blob> valueBlob(new Blob(value, valueSize, true));
89 size_t newTotalSize = mTotalSize + keySize + valueSize;
90 if (mMaxTotalSize < newTotalSize) {
91 if (isCleanable()) {
92 // Clean the cache and try again.
93 clean();
94 continue;
95 } else {
96 ALOGV("set: not caching new key/value pair because the "
97 "total cache size limit would be exceeded: %d "
98 "(limit: %d)",
99 keySize + valueSize, mMaxTotalSize);
100 break;
101 }
102 }
103 mCacheEntries.add(CacheEntry(keyBlob, valueBlob));
104 mTotalSize = newTotalSize;
105 ALOGV("set: created new cache entry with %d byte key and %d byte value",
106 keySize, valueSize);
107 } else {
108 // Update the existing cache entry.
109 sp<Blob> valueBlob(new Blob(value, valueSize, true));
110 sp<Blob> oldValueBlob(mCacheEntries[index].getValue());
111 size_t newTotalSize = mTotalSize + valueSize - oldValueBlob->getSize();
112 if (mMaxTotalSize < newTotalSize) {
113 if (isCleanable()) {
114 // Clean the cache and try again.
115 clean();
116 continue;
117 } else {
118 ALOGV("set: not caching new value because the total cache "
119 "size limit would be exceeded: %d (limit: %d)",
120 keySize + valueSize, mMaxTotalSize);
121 break;
122 }
123 }
124 mCacheEntries.editItemAt(index).setValue(valueBlob);
125 mTotalSize = newTotalSize;
126 ALOGV("set: updated existing cache entry with %d byte key and %d byte "
127 "value", keySize, valueSize);
128 }
129 break;
130 }
131}
132
133size_t BlobCache::get(const void* key, size_t keySize, void* value,
134 size_t valueSize) {
135 if (mMaxKeySize < keySize) {
136 ALOGV("get: not searching because the key is too large: %d (limit %d)",
137 keySize, mMaxKeySize);
138 return 0;
139 }
140 sp<Blob> dummyKey(new Blob(key, keySize, false));
141 CacheEntry dummyEntry(dummyKey, NULL);
142 ssize_t index = mCacheEntries.indexOf(dummyEntry);
143 if (index < 0) {
144 ALOGV("get: no cache entry found for key of size %d", keySize);
145 return 0;
146 }
147
148 // The key was found. Return the value if the caller's buffer is large
149 // enough.
150 sp<Blob> valueBlob(mCacheEntries[index].getValue());
151 size_t valueBlobSize = valueBlob->getSize();
152 if (valueBlobSize <= valueSize) {
153 ALOGV("get: copying %d bytes to caller's buffer", valueBlobSize);
154 memcpy(value, valueBlob->getData(), valueBlobSize);
155 } else {
156 ALOGV("get: caller's buffer is too small for value: %d (needs %d)",
157 valueSize, valueBlobSize);
158 }
159 return valueBlobSize;
160}
161
162static inline size_t align4(size_t size) {
163 return (size + 3) & ~3;
164}
165
166size_t BlobCache::getFlattenedSize() const {
167 size_t size = sizeof(Header);
168 for (size_t i = 0; i < mCacheEntries.size(); i++) {
169 const CacheEntry& e(mCacheEntries[i]);
170 sp<Blob> keyBlob = e.getKey();
171 sp<Blob> valueBlob = e.getValue();
172 size = align4(size);
173 size += sizeof(EntryHeader) + keyBlob->getSize() +
174 valueBlob->getSize();
175 }
176 return size;
177}
178
179status_t BlobCache::flatten(void* buffer, size_t size) const {
180 // Write the cache header
181 if (size < sizeof(Header)) {
182 ALOGE("flatten: not enough room for cache header");
183 return BAD_VALUE;
184 }
185 Header* header = reinterpret_cast<Header*>(buffer);
186 header->mMagicNumber = blobCacheMagic;
187 header->mBlobCacheVersion = blobCacheVersion;
188 header->mDeviceVersion = blobCacheDeviceVersion;
189 header->mNumEntries = mCacheEntries.size();
190
191 // Write cache entries
192 uint8_t* byteBuffer = reinterpret_cast<uint8_t*>(buffer);
193 off_t byteOffset = align4(sizeof(Header));
194 for (size_t i = 0; i < mCacheEntries.size(); i++) {
195 const CacheEntry& e(mCacheEntries[i]);
196 sp<Blob> keyBlob = e.getKey();
197 sp<Blob> valueBlob = e.getValue();
198 size_t keySize = keyBlob->getSize();
199 size_t valueSize = valueBlob->getSize();
200
201 size_t entrySize = sizeof(EntryHeader) + keySize + valueSize;
202 if (byteOffset + entrySize > size) {
203 ALOGE("flatten: not enough room for cache entries");
204 return BAD_VALUE;
205 }
206
207 EntryHeader* eheader = reinterpret_cast<EntryHeader*>(
208 &byteBuffer[byteOffset]);
209 eheader->mKeySize = keySize;
210 eheader->mValueSize = valueSize;
211
212 memcpy(eheader->mData, keyBlob->getData(), keySize);
213 memcpy(eheader->mData + keySize, valueBlob->getData(), valueSize);
214
215 byteOffset += align4(entrySize);
216 }
217
218 return OK;
219}
220
221status_t BlobCache::unflatten(void const* buffer, size_t size) {
222 // All errors should result in the BlobCache being in an empty state.
223 mCacheEntries.clear();
224
225 // Read the cache header
226 if (size < sizeof(Header)) {
227 ALOGE("unflatten: not enough room for cache header");
228 return BAD_VALUE;
229 }
230 const Header* header = reinterpret_cast<const Header*>(buffer);
231 if (header->mMagicNumber != blobCacheMagic) {
232 ALOGE("unflatten: bad magic number: %d", header->mMagicNumber);
233 return BAD_VALUE;
234 }
235 if (header->mBlobCacheVersion != blobCacheVersion ||
236 header->mDeviceVersion != blobCacheDeviceVersion) {
237 // We treat version mismatches as an empty cache.
238 return OK;
239 }
240
241 // Read cache entries
242 const uint8_t* byteBuffer = reinterpret_cast<const uint8_t*>(buffer);
243 off_t byteOffset = align4(sizeof(Header));
244 size_t numEntries = header->mNumEntries;
245 for (size_t i = 0; i < numEntries; i++) {
246 if (byteOffset + sizeof(EntryHeader) > size) {
247 mCacheEntries.clear();
248 ALOGE("unflatten: not enough room for cache entry headers");
249 return BAD_VALUE;
250 }
251
252 const EntryHeader* eheader = reinterpret_cast<const EntryHeader*>(
253 &byteBuffer[byteOffset]);
254 size_t keySize = eheader->mKeySize;
255 size_t valueSize = eheader->mValueSize;
256 size_t entrySize = sizeof(EntryHeader) + keySize + valueSize;
257
258 if (byteOffset + entrySize > size) {
259 mCacheEntries.clear();
260 ALOGE("unflatten: not enough room for cache entry headers");
261 return BAD_VALUE;
262 }
263
264 const uint8_t* data = eheader->mData;
265 set(data, keySize, data + keySize, valueSize);
266
267 byteOffset += align4(entrySize);
268 }
269
270 return OK;
271}
272
273long int BlobCache::blob_random() {
274#ifdef _WIN32
275 return rand();
276#else
277 return nrand48(mRandState);
278#endif
279}
280
281void BlobCache::clean() {
282 // Remove a random cache entry until the total cache size gets below half
283 // the maximum total cache size.
284 while (mTotalSize > mMaxTotalSize / 2) {
285 size_t i = size_t(blob_random() % (mCacheEntries.size()));
286 const CacheEntry& entry(mCacheEntries[i]);
287 mTotalSize -= entry.getKey()->getSize() + entry.getValue()->getSize();
288 mCacheEntries.removeAt(i);
289 }
290}
291
292bool BlobCache::isCleanable() const {
293 return mTotalSize > mMaxTotalSize / 2;
294}
295
296BlobCache::Blob::Blob(const void* data, size_t size, bool copyData):
297 mData(copyData ? malloc(size) : data),
298 mSize(size),
299 mOwnsData(copyData) {
300 if (data != NULL && copyData) {
301 memcpy(const_cast<void*>(mData), data, size);
302 }
303}
304
305BlobCache::Blob::~Blob() {
306 if (mOwnsData) {
307 free(const_cast<void*>(mData));
308 }
309}
310
311bool BlobCache::Blob::operator<(const Blob& rhs) const {
312 if (mSize == rhs.mSize) {
313 return memcmp(mData, rhs.mData, mSize) < 0;
314 } else {
315 return mSize < rhs.mSize;
316 }
317}
318
319const void* BlobCache::Blob::getData() const {
320 return mData;
321}
322
323size_t BlobCache::Blob::getSize() const {
324 return mSize;
325}
326
327BlobCache::CacheEntry::CacheEntry() {
328}
329
330BlobCache::CacheEntry::CacheEntry(const sp<Blob>& key, const sp<Blob>& value):
331 mKey(key),
332 mValue(value) {
333}
334
335BlobCache::CacheEntry::CacheEntry(const CacheEntry& ce):
336 mKey(ce.mKey),
337 mValue(ce.mValue) {
338}
339
340bool BlobCache::CacheEntry::operator<(const CacheEntry& rhs) const {
341 return *mKey < *rhs.mKey;
342}
343
344const BlobCache::CacheEntry& BlobCache::CacheEntry::operator=(const CacheEntry& rhs) {
345 mKey = rhs.mKey;
346 mValue = rhs.mValue;
347 return *this;
348}
349
350sp<BlobCache::Blob> BlobCache::CacheEntry::getKey() const {
351 return mKey;
352}
353
354sp<BlobCache::Blob> BlobCache::CacheEntry::getValue() const {
355 return mValue;
356}
357
358void BlobCache::CacheEntry::setValue(const sp<Blob>& value) {
359 mValue = value;
360}
361
362} // namespace android
diff --git a/libutils/CallStack.cpp b/libutils/CallStack.cpp
new file mode 100644
index 000000000..e60f5d8e7
--- /dev/null
+++ b/libutils/CallStack.cpp
@@ -0,0 +1,138 @@
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "CallStack"
18
19#include <string.h>
20
21#include <utils/Log.h>
22#include <utils/Errors.h>
23#include <utils/CallStack.h>
24#include <corkscrew/backtrace.h>
25
26/*****************************************************************************/
27namespace android {
28
29CallStack::CallStack() :
30 mCount(0) {
31}
32
33CallStack::CallStack(const char* logtag, int32_t ignoreDepth, int32_t maxDepth) {
34 this->update(ignoreDepth+1, maxDepth);
35 this->dump(logtag);
36}
37
38CallStack::CallStack(const CallStack& rhs) :
39 mCount(rhs.mCount) {
40 if (mCount) {
41 memcpy(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t));
42 }
43}
44
45CallStack::~CallStack() {
46}
47
48CallStack& CallStack::operator = (const CallStack& rhs) {
49 mCount = rhs.mCount;
50 if (mCount) {
51 memcpy(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t));
52 }
53 return *this;
54}
55
56bool CallStack::operator == (const CallStack& rhs) const {
57 if (mCount != rhs.mCount)
58 return false;
59 return !mCount || memcmp(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t)) == 0;
60}
61
62bool CallStack::operator != (const CallStack& rhs) const {
63 return !operator == (rhs);
64}
65
66bool CallStack::operator < (const CallStack& rhs) const {
67 if (mCount != rhs.mCount)
68 return mCount < rhs.mCount;
69 return memcmp(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t)) < 0;
70}
71
72bool CallStack::operator >= (const CallStack& rhs) const {
73 return !operator < (rhs);
74}
75
76bool CallStack::operator > (const CallStack& rhs) const {
77 if (mCount != rhs.mCount)
78 return mCount > rhs.mCount;
79 return memcmp(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t)) > 0;
80}
81
82bool CallStack::operator <= (const CallStack& rhs) const {
83 return !operator > (rhs);
84}
85
86const void* CallStack::operator [] (int index) const {
87 if (index >= int(mCount))
88 return 0;
89 return reinterpret_cast<const void*>(mStack[index].absolute_pc);
90}
91
92void CallStack::clear() {
93 mCount = 0;
94}
95
96void CallStack::update(int32_t ignoreDepth, int32_t maxDepth) {
97 if (maxDepth > MAX_DEPTH) {
98 maxDepth = MAX_DEPTH;
99 }
100 ssize_t count = unwind_backtrace(mStack, ignoreDepth + 1, maxDepth);
101 mCount = count > 0 ? count : 0;
102}
103
104void CallStack::dump(const char* logtag, const char* prefix) const {
105 backtrace_symbol_t symbols[mCount];
106
107 get_backtrace_symbols(mStack, mCount, symbols);
108 for (size_t i = 0; i < mCount; i++) {
109 char line[MAX_BACKTRACE_LINE_LENGTH];
110 format_backtrace_line(i, &mStack[i], &symbols[i],
111 line, MAX_BACKTRACE_LINE_LENGTH);
112 ALOG(LOG_DEBUG, logtag, "%s%s",
113 prefix ? prefix : "",
114 line);
115 }
116 free_backtrace_symbols(symbols, mCount);
117}
118
119String8 CallStack::toString(const char* prefix) const {
120 String8 str;
121 backtrace_symbol_t symbols[mCount];
122
123 get_backtrace_symbols(mStack, mCount, symbols);
124 for (size_t i = 0; i < mCount; i++) {
125 char line[MAX_BACKTRACE_LINE_LENGTH];
126 format_backtrace_line(i, &mStack[i], &symbols[i],
127 line, MAX_BACKTRACE_LINE_LENGTH);
128 if (prefix) {
129 str.append(prefix);
130 }
131 str.append(line);
132 str.append("\n");
133 }
134 free_backtrace_symbols(symbols, mCount);
135 return str;
136}
137
138}; // namespace android
diff --git a/libutils/CleanSpec.mk b/libutils/CleanSpec.mk
new file mode 100644
index 000000000..c3c5651b2
--- /dev/null
+++ b/libutils/CleanSpec.mk
@@ -0,0 +1,51 @@
1# Copyright (C) 2012 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14#
15
16# If you don't need to do a full clean build but would like to touch
17# a file or delete some intermediate files, add a clean step to the end
18# of the list. These steps will only be run once, if they haven't been
19# run before.
20#
21# E.g.:
22# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
23# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
24#
25# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
26# files that are missing or have been moved.
27#
28# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
29# Use $(OUT_DIR) to refer to the "out" directory.
30#
31# If you need to re-do something that's already mentioned, just copy
32# the command and add it to the bottom of the list. E.g., if a change
33# that you made last week required touching a file and a change you
34# made today requires touching the same file, just copy the old
35# touch step and add it to the end of the list.
36#
37# ************************************************
38# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
39# ************************************************
40
41# For example:
42#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
43#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
44#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
45#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
46
47# ************************************************
48# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
49# ************************************************
50$(call add-clean-step, rm -rf $(HOST_OUT)/obj/STATIC_LIBRARIES/libutils_intermediates/import_includes)
51$(call add-clean-step, rm -rf $(HOST_OUT)/obj/STATIC_LIBRARIES/lib64utils_intermediates/import_includes)
diff --git a/libutils/FileMap.cpp b/libutils/FileMap.cpp
new file mode 100644
index 000000000..9ce370e0e
--- /dev/null
+++ b/libutils/FileMap.cpp
@@ -0,0 +1,225 @@
1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//
18// Shared file mapping class.
19//
20
21#define LOG_TAG "filemap"
22
23#include <utils/FileMap.h>
24#include <utils/Log.h>
25
26#include <stdio.h>
27#include <stdlib.h>
28
29#ifdef HAVE_POSIX_FILEMAP
30#include <sys/mman.h>
31#endif
32
33#include <string.h>
34#include <memory.h>
35#include <errno.h>
36#include <assert.h>
37
38using namespace android;
39
40/*static*/ long FileMap::mPageSize = -1;
41
42
43/*
44 * Constructor. Create an empty object.
45 */
46FileMap::FileMap(void)
47 : mRefCount(1), mFileName(NULL), mBasePtr(NULL), mBaseLength(0),
48 mDataPtr(NULL), mDataLength(0)
49{
50}
51
52/*
53 * Destructor.
54 */
55FileMap::~FileMap(void)
56{
57 assert(mRefCount == 0);
58
59 //printf("+++ removing FileMap %p %u\n", mDataPtr, mDataLength);
60
61 mRefCount = -100; // help catch double-free
62 if (mFileName != NULL) {
63 free(mFileName);
64 }
65#ifdef HAVE_POSIX_FILEMAP
66 if (mBasePtr && munmap(mBasePtr, mBaseLength) != 0) {
67 ALOGD("munmap(%p, %d) failed\n", mBasePtr, (int) mBaseLength);
68 }
69#endif
70#ifdef HAVE_WIN32_FILEMAP
71 if (mBasePtr && UnmapViewOfFile(mBasePtr) == 0) {
72 ALOGD("UnmapViewOfFile(%p) failed, error = %ld\n", mBasePtr,
73 GetLastError() );
74 }
75 if (mFileMapping != INVALID_HANDLE_VALUE) {
76 CloseHandle(mFileMapping);
77 }
78 CloseHandle(mFileHandle);
79#endif
80}
81
82
83/*
84 * Create a new mapping on an open file.
85 *
86 * Closing the file descriptor does not unmap the pages, so we don't
87 * claim ownership of the fd.
88 *
89 * Returns "false" on failure.
90 */
91bool FileMap::create(const char* origFileName, int fd, off64_t offset, size_t length,
92 bool readOnly)
93{
94#ifdef HAVE_WIN32_FILEMAP
95 int adjust;
96 off64_t adjOffset;
97 size_t adjLength;
98
99 if (mPageSize == -1) {
100 SYSTEM_INFO si;
101
102 GetSystemInfo( &si );
103 mPageSize = si.dwAllocationGranularity;
104 }
105
106 DWORD protect = readOnly ? PAGE_READONLY : PAGE_READWRITE;
107
108 mFileHandle = (HANDLE) _get_osfhandle(fd);
109 mFileMapping = CreateFileMapping( mFileHandle, NULL, protect, 0, 0, NULL);
110 if (mFileMapping == NULL) {
111 ALOGE("CreateFileMapping(%p, %lx) failed with error %ld\n",
112 mFileHandle, protect, GetLastError() );
113 return false;
114 }
115
116 adjust = offset % mPageSize;
117 adjOffset = offset - adjust;
118 adjLength = length + adjust;
119
120 mBasePtr = MapViewOfFile( mFileMapping,
121 readOnly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS,
122 0,
123 (DWORD)(adjOffset),
124 adjLength );
125 if (mBasePtr == NULL) {
126 ALOGE("MapViewOfFile(%ld, %ld) failed with error %ld\n",
127 adjOffset, adjLength, GetLastError() );
128 CloseHandle(mFileMapping);
129 mFileMapping = INVALID_HANDLE_VALUE;
130 return false;
131 }
132#endif
133#ifdef HAVE_POSIX_FILEMAP
134 int prot, flags, adjust;
135 off64_t adjOffset;
136 size_t adjLength;
137
138 void* ptr;
139
140 assert(mRefCount == 1);
141 assert(fd >= 0);
142 assert(offset >= 0);
143 assert(length > 0);
144
145 /* init on first use */
146 if (mPageSize == -1) {
147#if NOT_USING_KLIBC
148 mPageSize = sysconf(_SC_PAGESIZE);
149 if (mPageSize == -1) {
150 ALOGE("could not get _SC_PAGESIZE\n");
151 return false;
152 }
153#else
154 /* this holds for Linux, Darwin, Cygwin, and doesn't pain the ARM */
155 mPageSize = 4096;
156#endif
157 }
158
159 adjust = offset % mPageSize;
160try_again:
161 adjOffset = offset - adjust;
162 adjLength = length + adjust;
163
164 flags = MAP_SHARED;
165 prot = PROT_READ;
166 if (!readOnly)
167 prot |= PROT_WRITE;
168
169 ptr = mmap(NULL, adjLength, prot, flags, fd, adjOffset);
170 if (ptr == MAP_FAILED) {
171 // Cygwin does not seem to like file mapping files from an offset.
172 // So if we fail, try again with offset zero
173 if (adjOffset > 0) {
174 adjust = offset;
175 goto try_again;
176 }
177
178 ALOGE("mmap(%ld,%ld) failed: %s\n",
179 (long) adjOffset, (long) adjLength, strerror(errno));
180 return false;
181 }
182 mBasePtr = ptr;
183#endif /* HAVE_POSIX_FILEMAP */
184
185 mFileName = origFileName != NULL ? strdup(origFileName) : NULL;
186 mBaseLength = adjLength;
187 mDataOffset = offset;
188 mDataPtr = (char*) mBasePtr + adjust;
189 mDataLength = length;
190
191 assert(mBasePtr != NULL);
192
193 ALOGV("MAP: base %p/%d data %p/%d\n",
194 mBasePtr, (int) mBaseLength, mDataPtr, (int) mDataLength);
195
196 return true;
197}
198
199/*
200 * Provide guidance to the system.
201 */
202int FileMap::advise(MapAdvice advice)
203{
204#if HAVE_MADVISE
205 int cc, sysAdvice;
206
207 switch (advice) {
208 case NORMAL: sysAdvice = MADV_NORMAL; break;
209 case RANDOM: sysAdvice = MADV_RANDOM; break;
210 case SEQUENTIAL: sysAdvice = MADV_SEQUENTIAL; break;
211 case WILLNEED: sysAdvice = MADV_WILLNEED; break;
212 case DONTNEED: sysAdvice = MADV_DONTNEED; break;
213 default:
214 assert(false);
215 return -1;
216 }
217
218 cc = madvise(mBasePtr, mBaseLength, sysAdvice);
219 if (cc != 0)
220 ALOGW("madvise(%d) failed: %s\n", sysAdvice, strerror(errno));
221 return cc;
222#else
223 return -1;
224#endif // HAVE_MADVISE
225}
diff --git a/libutils/JenkinsHash.cpp b/libutils/JenkinsHash.cpp
new file mode 100644
index 000000000..52c9bb7df
--- /dev/null
+++ b/libutils/JenkinsHash.cpp
@@ -0,0 +1,64 @@
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/* Implementation of Jenkins one-at-a-time hash function. These choices are
18 * optimized for code size and portability, rather than raw speed. But speed
19 * should still be quite good.
20 **/
21
22#include <utils/JenkinsHash.h>
23
24namespace android {
25
26hash_t JenkinsHashWhiten(uint32_t hash) {
27 hash += (hash << 3);
28 hash ^= (hash >> 11);
29 hash += (hash << 15);
30 return hash;
31}
32
33uint32_t JenkinsHashMixBytes(uint32_t hash, const uint8_t* bytes, size_t size) {
34 hash = JenkinsHashMix(hash, (uint32_t)size);
35 size_t i;
36 for (i = 0; i < (size & -4); i += 4) {
37 uint32_t data = bytes[i] | (bytes[i+1] << 8) | (bytes[i+2] << 16) | (bytes[i+3] << 24);
38 hash = JenkinsHashMix(hash, data);
39 }
40 if (size & 3) {
41 uint32_t data = bytes[i];
42 data |= ((size & 3) > 1) ? (bytes[i+1] << 8) : 0;
43 data |= ((size & 3) > 2) ? (bytes[i+2] << 16) : 0;
44 hash = JenkinsHashMix(hash, data);
45 }
46 return hash;
47}
48
49uint32_t JenkinsHashMixShorts(uint32_t hash, const uint16_t* shorts, size_t size) {
50 hash = JenkinsHashMix(hash, (uint32_t)size);
51 size_t i;
52 for (i = 0; i < (size & -2); i += 2) {
53 uint32_t data = shorts[i] | (shorts[i+1] << 16);
54 hash = JenkinsHashMix(hash, data);
55 }
56 if (size & 1) {
57 uint32_t data = shorts[i];
58 hash = JenkinsHashMix(hash, data);
59 }
60 return hash;
61}
62
63}
64
diff --git a/libutils/LinearAllocator.cpp b/libutils/LinearAllocator.cpp
new file mode 100644
index 000000000..a07a2916e
--- /dev/null
+++ b/libutils/LinearAllocator.cpp
@@ -0,0 +1,227 @@
1/*
2 * Copyright 2012, The Android Open Source Project
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#define LOG_TAG "LinearAllocator"
27#define LOG_NDEBUG 1
28
29#include <stdlib.h>
30#include <utils/LinearAllocator.h>
31#include <utils/Log.h>
32
33
34// The ideal size of a page allocation (these need to be multiples of 8)
35#define INITIAL_PAGE_SIZE ((size_t)4096) // 4kb
36#define MAX_PAGE_SIZE ((size_t)131072) // 128kb
37
38// The maximum amount of wasted space we can have per page
39// Allocations exceeding this will have their own dedicated page
40// If this is too low, we will malloc too much
41// Too high, and we may waste too much space
42// Must be smaller than INITIAL_PAGE_SIZE
43#define MAX_WASTE_SIZE ((size_t)1024)
44
45#if ALIGN_DOUBLE
46#define ALIGN_SZ (sizeof(double))
47#else
48#define ALIGN_SZ (sizeof(int))
49#endif
50
51#define ALIGN(x) ((x + ALIGN_SZ - 1 ) & ~(ALIGN_SZ - 1))
52#define ALIGN_PTR(p) ((void*)(ALIGN((size_t)p)))
53
54#if LOG_NDEBUG
55#define ADD_ALLOCATION(size)
56#define RM_ALLOCATION(size)
57#else
58#include <utils/Thread.h>
59#include <utils/Timers.h>
60static size_t s_totalAllocations = 0;
61static nsecs_t s_nextLog = 0;
62static android::Mutex s_mutex;
63
64static void _logUsageLocked() {
65 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
66 if (now > s_nextLog) {
67 s_nextLog = now + milliseconds_to_nanoseconds(10);
68 ALOGV("Total memory usage: %zu kb", s_totalAllocations / 1024);
69 }
70}
71
72static void _addAllocation(size_t size) {
73 android::AutoMutex lock(s_mutex);
74 s_totalAllocations += size;
75 _logUsageLocked();
76}
77
78#define ADD_ALLOCATION(size) _addAllocation(size);
79#define RM_ALLOCATION(size) _addAllocation(-size);
80#endif
81
82#define min(x,y) (((x) < (y)) ? (x) : (y))
83
84namespace android {
85
86class LinearAllocator::Page {
87public:
88 Page* next() { return mNextPage; }
89 void setNext(Page* next) { mNextPage = next; }
90
91 Page()
92 : mNextPage(0)
93 {}
94
95 void* operator new(size_t size, void* buf) { return buf; }
96
97 void* start() {
98 return (void*) (((size_t)this) + sizeof(Page));
99 }
100
101 void* end(int pageSize) {
102 return (void*) (((size_t)start()) + pageSize);
103 }
104
105private:
106 Page(const Page& other) {}
107 Page* mNextPage;
108};
109
110LinearAllocator::LinearAllocator()
111 : mPageSize(INITIAL_PAGE_SIZE)
112 , mMaxAllocSize(MAX_WASTE_SIZE)
113 , mNext(0)
114 , mCurrentPage(0)
115 , mPages(0)
116 , mTotalAllocated(0)
117 , mWastedSpace(0)
118 , mPageCount(0)
119 , mDedicatedPageCount(0) {}
120
121LinearAllocator::~LinearAllocator(void) {
122 Page* p = mPages;
123 while (p) {
124 Page* next = p->next();
125 p->~Page();
126 free(p);
127 RM_ALLOCATION(mPageSize);
128 p = next;
129 }
130}
131
132void* LinearAllocator::start(Page* p) {
133 return ALIGN_PTR(((size_t*)p) + sizeof(Page));
134}
135
136void* LinearAllocator::end(Page* p) {
137 return ((char*)p) + mPageSize;
138}
139
140bool LinearAllocator::fitsInCurrentPage(size_t size) {
141 return mNext && ((char*)mNext + size) <= end(mCurrentPage);
142}
143
144void LinearAllocator::ensureNext(size_t size) {
145 if (fitsInCurrentPage(size)) return;
146
147 if (mCurrentPage && mPageSize < MAX_PAGE_SIZE) {
148 mPageSize = min(MAX_PAGE_SIZE, mPageSize * 2);
149 mPageSize = ALIGN(mPageSize);
150 }
151 mWastedSpace += mPageSize;
152 Page* p = newPage(mPageSize);
153 if (mCurrentPage) {
154 mCurrentPage->setNext(p);
155 }
156 mCurrentPage = p;
157 if (!mPages) {
158 mPages = mCurrentPage;
159 }
160 mNext = start(mCurrentPage);
161}
162
163void* LinearAllocator::alloc(size_t size) {
164 size = ALIGN(size);
165 if (size > mMaxAllocSize && !fitsInCurrentPage(size)) {
166 ALOGV("Exceeded max size %zu > %zu", size, mMaxAllocSize);
167 // Allocation is too large, create a dedicated page for the allocation
168 Page* page = newPage(size);
169 mDedicatedPageCount++;
170 page->setNext(mPages);
171 mPages = page;
172 if (!mCurrentPage)
173 mCurrentPage = mPages;
174 return start(page);
175 }
176 ensureNext(size);
177 void* ptr = mNext;
178 mNext = ((char*)mNext) + size;
179 mWastedSpace -= size;
180 return ptr;
181}
182
183void LinearAllocator::rewindIfLastAlloc(void* ptr, size_t allocSize) {
184 // Don't bother rewinding across pages
185 allocSize = ALIGN(allocSize);
186 if (ptr >= start(mCurrentPage) && ptr < end(mCurrentPage)
187 && ptr == ((char*)mNext - allocSize)) {
188 mTotalAllocated -= allocSize;
189 mWastedSpace += allocSize;
190 mNext = ptr;
191 }
192}
193
194LinearAllocator::Page* LinearAllocator::newPage(size_t pageSize) {
195 pageSize = ALIGN(pageSize + sizeof(LinearAllocator::Page));
196 ADD_ALLOCATION(pageSize);
197 mTotalAllocated += pageSize;
198 mPageCount++;
199 void* buf = malloc(pageSize);
200 return new (buf) Page();
201}
202
203static const char* toSize(size_t value, float& result) {
204 if (value < 2000) {
205 result = value;
206 return "B";
207 }
208 if (value < 2000000) {
209 result = value / 1024.0f;
210 return "KB";
211 }
212 result = value / 1048576.0f;
213 return "MB";
214}
215
216void LinearAllocator::dumpMemoryStats(const char* prefix) {
217 float prettySize;
218 const char* prettySuffix;
219 prettySuffix = toSize(mTotalAllocated, prettySize);
220 ALOGD("%sTotal allocated: %.2f%s", prefix, prettySize, prettySuffix);
221 prettySuffix = toSize(mWastedSpace, prettySize);
222 ALOGD("%sWasted space: %.2f%s (%.1f%%)", prefix, prettySize, prettySuffix,
223 (float) mWastedSpace / (float) mTotalAllocated * 100.0f);
224 ALOGD("%sPages %zu (dedicated %zu)", prefix, mPageCount, mDedicatedPageCount);
225}
226
227}; // namespace android
diff --git a/libutils/LinearTransform.cpp b/libutils/LinearTransform.cpp
new file mode 100644
index 000000000..b7d28d4b3
--- /dev/null
+++ b/libutils/LinearTransform.cpp
@@ -0,0 +1,265 @@
1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define __STDC_LIMIT_MACROS
18
19#include <assert.h>
20#include <stdint.h>
21
22#include <utils/LinearTransform.h>
23
24namespace android {
25
26template<class T> static inline T ABS(T x) { return (x < 0) ? -x : x; }
27
28// Static math methods involving linear transformations
29static bool scale_u64_to_u64(
30 uint64_t val,
31 uint32_t N,
32 uint32_t D,
33 uint64_t* res,
34 bool round_up_not_down) {
35 uint64_t tmp1, tmp2;
36 uint32_t r;
37
38 assert(res);
39 assert(D);
40
41 // Let U32(X) denote a uint32_t containing the upper 32 bits of a 64 bit
42 // integer X.
43 // Let L32(X) denote a uint32_t containing the lower 32 bits of a 64 bit
44 // integer X.
45 // Let X[A, B] with A <= B denote bits A through B of the integer X.
46 // Let (A | B) denote the concatination of two 32 bit ints, A and B.
47 // IOW X = (A | B) => U32(X) == A && L32(X) == B
48 //
49 // compute M = val * N (a 96 bit int)
50 // ---------------------------------
51 // tmp2 = U32(val) * N (a 64 bit int)
52 // tmp1 = L32(val) * N (a 64 bit int)
53 // which means
54 // M = val * N = (tmp2 << 32) + tmp1
55 tmp2 = (val >> 32) * N;
56 tmp1 = (val & UINT32_MAX) * N;
57
58 // compute M[32, 95]
59 // tmp2 = tmp2 + U32(tmp1)
60 // = (U32(val) * N) + U32(L32(val) * N)
61 // = M[32, 95]
62 tmp2 += tmp1 >> 32;
63
64 // if M[64, 95] >= D, then M/D has bits > 63 set and we have
65 // an overflow.
66 if ((tmp2 >> 32) >= D) {
67 *res = UINT64_MAX;
68 return false;
69 }
70
71 // Divide. Going in we know
72 // tmp2 = M[32, 95]
73 // U32(tmp2) < D
74 r = tmp2 % D;
75 tmp2 /= D;
76
77 // At this point
78 // tmp1 = L32(val) * N
79 // tmp2 = M[32, 95] / D
80 // = (M / D)[32, 95]
81 // r = M[32, 95] % D
82 // U32(tmp2) = 0
83 //
84 // compute tmp1 = (r | M[0, 31])
85 tmp1 = (tmp1 & UINT32_MAX) | ((uint64_t)r << 32);
86
87 // Divide again. Keep the remainder around in order to round properly.
88 r = tmp1 % D;
89 tmp1 /= D;
90
91 // At this point
92 // tmp2 = (M / D)[32, 95]
93 // tmp1 = (M / D)[ 0, 31]
94 // r = M % D
95 // U32(tmp1) = 0
96 // U32(tmp2) = 0
97
98 // Pack the result and deal with the round-up case (As well as the
99 // remote possiblility over overflow in such a case).
100 *res = (tmp2 << 32) | tmp1;
101 if (r && round_up_not_down) {
102 ++(*res);
103 if (!(*res)) {
104 *res = UINT64_MAX;
105 return false;
106 }
107 }
108
109 return true;
110}
111
112static bool linear_transform_s64_to_s64(
113 int64_t val,
114 int64_t basis1,
115 int32_t N,
116 uint32_t D,
117 bool invert_frac,
118 int64_t basis2,
119 int64_t* out) {
120 uint64_t scaled, res;
121 uint64_t abs_val;
122 bool is_neg;
123
124 if (!out)
125 return false;
126
127 // Compute abs(val - basis_64). Keep track of whether or not this delta
128 // will be negative after the scale opertaion.
129 if (val < basis1) {
130 is_neg = true;
131 abs_val = basis1 - val;
132 } else {
133 is_neg = false;
134 abs_val = val - basis1;
135 }
136
137 if (N < 0)
138 is_neg = !is_neg;
139
140 if (!scale_u64_to_u64(abs_val,
141 invert_frac ? D : ABS(N),
142 invert_frac ? ABS(N) : D,
143 &scaled,
144 is_neg))
145 return false; // overflow/undeflow
146
147 // if scaled is >= 0x8000<etc>, then we are going to overflow or
148 // underflow unless ABS(basis2) is large enough to pull us back into the
149 // non-overflow/underflow region.
150 if (scaled & INT64_MIN) {
151 if (is_neg && (basis2 < 0))
152 return false; // certain underflow
153
154 if (!is_neg && (basis2 >= 0))
155 return false; // certain overflow
156
157 if (ABS(basis2) <= static_cast<int64_t>(scaled & INT64_MAX))
158 return false; // not enough
159
160 // Looks like we are OK
161 *out = (is_neg ? (-scaled) : scaled) + basis2;
162 } else {
163 // Scaled fits within signed bounds, so we just need to check for
164 // over/underflow for two signed integers. Basically, if both scaled
165 // and basis2 have the same sign bit, and the result has a different
166 // sign bit, then we have under/overflow. An easy way to compute this
167 // is
168 // (scaled_signbit XNOR basis_signbit) &&
169 // (scaled_signbit XOR res_signbit)
170 // ==
171 // (scaled_signbit XOR basis_signbit XOR 1) &&
172 // (scaled_signbit XOR res_signbit)
173
174 if (is_neg)
175 scaled = -scaled;
176 res = scaled + basis2;
177
178 if ((scaled ^ basis2 ^ INT64_MIN) & (scaled ^ res) & INT64_MIN)
179 return false;
180
181 *out = res;
182 }
183
184 return true;
185}
186
187bool LinearTransform::doForwardTransform(int64_t a_in, int64_t* b_out) const {
188 if (0 == a_to_b_denom)
189 return false;
190
191 return linear_transform_s64_to_s64(a_in,
192 a_zero,
193 a_to_b_numer,
194 a_to_b_denom,
195 false,
196 b_zero,
197 b_out);
198}
199
200bool LinearTransform::doReverseTransform(int64_t b_in, int64_t* a_out) const {
201 if (0 == a_to_b_numer)
202 return false;
203
204 return linear_transform_s64_to_s64(b_in,
205 b_zero,
206 a_to_b_numer,
207 a_to_b_denom,
208 true,
209 a_zero,
210 a_out);
211}
212
213template <class T> void LinearTransform::reduce(T* N, T* D) {
214 T a, b;
215 if (!N || !D || !(*D)) {
216 assert(false);
217 return;
218 }
219
220 a = *N;
221 b = *D;
222
223 if (a == 0) {
224 *D = 1;
225 return;
226 }
227
228 // This implements Euclid's method to find GCD.
229 if (a < b) {
230 T tmp = a;
231 a = b;
232 b = tmp;
233 }
234
235 while (1) {
236 // a is now the greater of the two.
237 const T remainder = a % b;
238 if (remainder == 0) {
239 *N /= b;
240 *D /= b;
241 return;
242 }
243 // by swapping remainder and b, we are guaranteeing that a is
244 // still the greater of the two upon entrance to the loop.
245 a = b;
246 b = remainder;
247 }
248};
249
250template void LinearTransform::reduce<uint64_t>(uint64_t* N, uint64_t* D);
251template void LinearTransform::reduce<uint32_t>(uint32_t* N, uint32_t* D);
252
253void LinearTransform::reduce(int32_t* N, uint32_t* D) {
254 if (N && D && *D) {
255 if (*N < 0) {
256 *N = -(*N);
257 reduce(reinterpret_cast<uint32_t*>(N), D);
258 *N = -(*N);
259 } else {
260 reduce(reinterpret_cast<uint32_t*>(N), D);
261 }
262 }
263}
264
265} // namespace android
diff --git a/libutils/Log.cpp b/libutils/Log.cpp
new file mode 100644
index 000000000..bffb56eda
--- /dev/null
+++ b/libutils/Log.cpp
@@ -0,0 +1,37 @@
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "Log"
18
19#include <utils/Log.h>
20#include <utils/Timers.h>
21
22namespace android {
23
24LogIfSlow::LogIfSlow(const char* tag, android_LogPriority priority,
25 int timeoutMillis, const char* message) :
26 mTag(tag), mPriority(priority), mTimeoutMillis(timeoutMillis), mMessage(message),
27 mStart(systemTime(SYSTEM_TIME_BOOTTIME)) {
28}
29
30LogIfSlow::~LogIfSlow() {
31 int durationMillis = nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_BOOTTIME) - mStart);
32 if (durationMillis > mTimeoutMillis) {
33 LOG_PRI(mPriority, mTag, "%s: %dms", mMessage, durationMillis);
34 }
35}
36
37} // namespace android
diff --git a/libutils/Looper.cpp b/libutils/Looper.cpp
new file mode 100644
index 000000000..c51df2d1a
--- /dev/null
+++ b/libutils/Looper.cpp
@@ -0,0 +1,573 @@
1//
2// Copyright 2010 The Android Open Source Project
3//
4// A looper implementation based on epoll().
5//
6#define LOG_TAG "Looper"
7
8//#define LOG_NDEBUG 0
9
10// Debugs poll and wake interactions.
11#define DEBUG_POLL_AND_WAKE 0
12
13// Debugs callback registration and invocation.
14#define DEBUG_CALLBACKS 0
15
16#include <cutils/log.h>
17#include <utils/Looper.h>
18#include <utils/Timers.h>
19
20#include <unistd.h>
21#include <fcntl.h>
22#include <limits.h>
23
24
25namespace android {
26
27// --- WeakMessageHandler ---
28
29WeakMessageHandler::WeakMessageHandler(const wp<MessageHandler>& handler) :
30 mHandler(handler) {
31}
32
33WeakMessageHandler::~WeakMessageHandler() {
34}
35
36void WeakMessageHandler::handleMessage(const Message& message) {
37 sp<MessageHandler> handler = mHandler.promote();
38 if (handler != NULL) {
39 handler->handleMessage(message);
40 }
41}
42
43
44// --- SimpleLooperCallback ---
45
46SimpleLooperCallback::SimpleLooperCallback(ALooper_callbackFunc callback) :
47 mCallback(callback) {
48}
49
50SimpleLooperCallback::~SimpleLooperCallback() {
51}
52
53int SimpleLooperCallback::handleEvent(int fd, int events, void* data) {
54 return mCallback(fd, events, data);
55}
56
57
58// --- Looper ---
59
60// Hint for number of file descriptors to be associated with the epoll instance.
61static const int EPOLL_SIZE_HINT = 8;
62
63// Maximum number of file descriptors for which to retrieve poll events each iteration.
64static const int EPOLL_MAX_EVENTS = 16;
65
66static pthread_once_t gTLSOnce = PTHREAD_ONCE_INIT;
67static pthread_key_t gTLSKey = 0;
68
69Looper::Looper(bool allowNonCallbacks) :
70 mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
71 mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
72 int wakeFds[2];
73 int result = pipe(wakeFds);
74 LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
75
76 mWakeReadPipeFd = wakeFds[0];
77 mWakeWritePipeFd = wakeFds[1];
78
79 result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
80 LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",
81 errno);
82
83 result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
84 LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
85 errno);
86
87 mIdling = false;
88
89 // Allocate the epoll instance and register the wake pipe.
90 mEpollFd = epoll_create(EPOLL_SIZE_HINT);
91 LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno);
92
93 struct epoll_event eventItem;
94 memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
95 eventItem.events = EPOLLIN;
96 eventItem.data.fd = mWakeReadPipeFd;
97 result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
98 LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d",
99 errno);
100}
101
102Looper::~Looper() {
103 close(mWakeReadPipeFd);
104 close(mWakeWritePipeFd);
105 close(mEpollFd);
106}
107
108void Looper::initTLSKey() {
109 int result = pthread_key_create(& gTLSKey, threadDestructor);
110 LOG_ALWAYS_FATAL_IF(result != 0, "Could not allocate TLS key.");
111}
112
113void Looper::threadDestructor(void *st) {
114 Looper* const self = static_cast<Looper*>(st);
115 if (self != NULL) {
116 self->decStrong((void*)threadDestructor);
117 }
118}
119
120void Looper::setForThread(const sp<Looper>& looper) {
121 sp<Looper> old = getForThread(); // also has side-effect of initializing TLS
122
123 if (looper != NULL) {
124 looper->incStrong((void*)threadDestructor);
125 }
126
127 pthread_setspecific(gTLSKey, looper.get());
128
129 if (old != NULL) {
130 old->decStrong((void*)threadDestructor);
131 }
132}
133
134sp<Looper> Looper::getForThread() {
135 int result = pthread_once(& gTLSOnce, initTLSKey);
136 LOG_ALWAYS_FATAL_IF(result != 0, "pthread_once failed");
137
138 return (Looper*)pthread_getspecific(gTLSKey);
139}
140
141sp<Looper> Looper::prepare(int opts) {
142 bool allowNonCallbacks = opts & ALOOPER_PREPARE_ALLOW_NON_CALLBACKS;
143 sp<Looper> looper = Looper::getForThread();
144 if (looper == NULL) {
145 looper = new Looper(allowNonCallbacks);
146 Looper::setForThread(looper);
147 }
148 if (looper->getAllowNonCallbacks() != allowNonCallbacks) {
149 ALOGW("Looper already prepared for this thread with a different value for the "
150 "ALOOPER_PREPARE_ALLOW_NON_CALLBACKS option.");
151 }
152 return looper;
153}
154
155bool Looper::getAllowNonCallbacks() const {
156 return mAllowNonCallbacks;
157}
158
159int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
160 int result = 0;
161 for (;;) {
162 while (mResponseIndex < mResponses.size()) {
163 const Response& response = mResponses.itemAt(mResponseIndex++);
164 int ident = response.request.ident;
165 if (ident >= 0) {
166 int fd = response.request.fd;
167 int events = response.events;
168 void* data = response.request.data;
169#if DEBUG_POLL_AND_WAKE
170 ALOGD("%p ~ pollOnce - returning signalled identifier %d: "
171 "fd=%d, events=0x%x, data=%p",
172 this, ident, fd, events, data);
173#endif
174 if (outFd != NULL) *outFd = fd;
175 if (outEvents != NULL) *outEvents = events;
176 if (outData != NULL) *outData = data;
177 return ident;
178 }
179 }
180
181 if (result != 0) {
182#if DEBUG_POLL_AND_WAKE
183 ALOGD("%p ~ pollOnce - returning result %d", this, result);
184#endif
185 if (outFd != NULL) *outFd = 0;
186 if (outEvents != NULL) *outEvents = 0;
187 if (outData != NULL) *outData = NULL;
188 return result;
189 }
190
191 result = pollInner(timeoutMillis);
192 }
193}
194
195int Looper::pollInner(int timeoutMillis) {
196#if DEBUG_POLL_AND_WAKE
197 ALOGD("%p ~ pollOnce - waiting: timeoutMillis=%d", this, timeoutMillis);
198#endif
199
200 // Adjust the timeout based on when the next message is due.
201 if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {
202 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
203 int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime);
204 if (messageTimeoutMillis >= 0
205 && (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) {
206 timeoutMillis = messageTimeoutMillis;
207 }
208#if DEBUG_POLL_AND_WAKE
209 ALOGD("%p ~ pollOnce - next message in %lldns, adjusted timeout: timeoutMillis=%d",
210 this, mNextMessageUptime - now, timeoutMillis);
211#endif
212 }
213
214 // Poll.
215 int result = ALOOPER_POLL_WAKE;
216 mResponses.clear();
217 mResponseIndex = 0;
218
219 // We are about to idle.
220 mIdling = true;
221
222 struct epoll_event eventItems[EPOLL_MAX_EVENTS];
223 int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
224
225 // No longer idling.
226 mIdling = false;
227
228 // Acquire lock.
229 mLock.lock();
230
231 // Check for poll error.
232 if (eventCount < 0) {
233 if (errno == EINTR) {
234 goto Done;
235 }
236 ALOGW("Poll failed with an unexpected error, errno=%d", errno);
237 result = ALOOPER_POLL_ERROR;
238 goto Done;
239 }
240
241 // Check for poll timeout.
242 if (eventCount == 0) {
243#if DEBUG_POLL_AND_WAKE
244 ALOGD("%p ~ pollOnce - timeout", this);
245#endif
246 result = ALOOPER_POLL_TIMEOUT;
247 goto Done;
248 }
249
250 // Handle all events.
251#if DEBUG_POLL_AND_WAKE
252 ALOGD("%p ~ pollOnce - handling events from %d fds", this, eventCount);
253#endif
254
255 for (int i = 0; i < eventCount; i++) {
256 int fd = eventItems[i].data.fd;
257 uint32_t epollEvents = eventItems[i].events;
258 if (fd == mWakeReadPipeFd) {
259 if (epollEvents & EPOLLIN) {
260 awoken();
261 } else {
262 ALOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents);
263 }
264 } else {
265 ssize_t requestIndex = mRequests.indexOfKey(fd);
266 if (requestIndex >= 0) {
267 int events = 0;
268 if (epollEvents & EPOLLIN) events |= ALOOPER_EVENT_INPUT;
269 if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT;
270 if (epollEvents & EPOLLERR) events |= ALOOPER_EVENT_ERROR;
271 if (epollEvents & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP;
272 pushResponse(events, mRequests.valueAt(requestIndex));
273 } else {
274 ALOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
275 "no longer registered.", epollEvents, fd);
276 }
277 }
278 }
279Done: ;
280
281 // Invoke pending message callbacks.
282 mNextMessageUptime = LLONG_MAX;
283 while (mMessageEnvelopes.size() != 0) {
284 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
285 const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0);
286 if (messageEnvelope.uptime <= now) {
287 // Remove the envelope from the list.
288 // We keep a strong reference to the handler until the call to handleMessage
289 // finishes. Then we drop it so that the handler can be deleted *before*
290 // we reacquire our lock.
291 { // obtain handler
292 sp<MessageHandler> handler = messageEnvelope.handler;
293 Message message = messageEnvelope.message;
294 mMessageEnvelopes.removeAt(0);
295 mSendingMessage = true;
296 mLock.unlock();
297
298#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
299 ALOGD("%p ~ pollOnce - sending message: handler=%p, what=%d",
300 this, handler.get(), message.what);
301#endif
302 handler->handleMessage(message);
303 } // release handler
304
305 mLock.lock();
306 mSendingMessage = false;
307 result = ALOOPER_POLL_CALLBACK;
308 } else {
309 // The last message left at the head of the queue determines the next wakeup time.
310 mNextMessageUptime = messageEnvelope.uptime;
311 break;
312 }
313 }
314
315 // Release lock.
316 mLock.unlock();
317
318 // Invoke all response callbacks.
319 for (size_t i = 0; i < mResponses.size(); i++) {
320 Response& response = mResponses.editItemAt(i);
321 if (response.request.ident == ALOOPER_POLL_CALLBACK) {
322 int fd = response.request.fd;
323 int events = response.events;
324 void* data = response.request.data;
325#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
326 ALOGD("%p ~ pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p",
327 this, response.request.callback.get(), fd, events, data);
328#endif
329 int callbackResult = response.request.callback->handleEvent(fd, events, data);
330 if (callbackResult == 0) {
331 removeFd(fd);
332 }
333 // Clear the callback reference in the response structure promptly because we
334 // will not clear the response vector itself until the next poll.
335 response.request.callback.clear();
336 result = ALOOPER_POLL_CALLBACK;
337 }
338 }
339 return result;
340}
341
342int Looper::pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
343 if (timeoutMillis <= 0) {
344 int result;
345 do {
346 result = pollOnce(timeoutMillis, outFd, outEvents, outData);
347 } while (result == ALOOPER_POLL_CALLBACK);
348 return result;
349 } else {
350 nsecs_t endTime = systemTime(SYSTEM_TIME_MONOTONIC)
351 + milliseconds_to_nanoseconds(timeoutMillis);
352
353 for (;;) {
354 int result = pollOnce(timeoutMillis, outFd, outEvents, outData);
355 if (result != ALOOPER_POLL_CALLBACK) {
356 return result;
357 }
358
359 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
360 timeoutMillis = toMillisecondTimeoutDelay(now, endTime);
361 if (timeoutMillis == 0) {
362 return ALOOPER_POLL_TIMEOUT;
363 }
364 }
365 }
366}
367
368void Looper::wake() {
369#if DEBUG_POLL_AND_WAKE
370 ALOGD("%p ~ wake", this);
371#endif
372
373 ssize_t nWrite;
374 do {
375 nWrite = write(mWakeWritePipeFd, "W", 1);
376 } while (nWrite == -1 && errno == EINTR);
377
378 if (nWrite != 1) {
379 if (errno != EAGAIN) {
380 ALOGW("Could not write wake signal, errno=%d", errno);
381 }
382 }
383}
384
385void Looper::awoken() {
386#if DEBUG_POLL_AND_WAKE
387 ALOGD("%p ~ awoken", this);
388#endif
389
390 char buffer[16];
391 ssize_t nRead;
392 do {
393 nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
394 } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
395}
396
397void Looper::pushResponse(int events, const Request& request) {
398 Response response;
399 response.events = events;
400 response.request = request;
401 mResponses.push(response);
402}
403
404int Looper::addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void* data) {
405 return addFd(fd, ident, events, callback ? new SimpleLooperCallback(callback) : NULL, data);
406}
407
408int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {
409#if DEBUG_CALLBACKS
410 ALOGD("%p ~ addFd - fd=%d, ident=%d, events=0x%x, callback=%p, data=%p", this, fd, ident,
411 events, callback.get(), data);
412#endif
413
414 if (!callback.get()) {
415 if (! mAllowNonCallbacks) {
416 ALOGE("Invalid attempt to set NULL callback but not allowed for this looper.");
417 return -1;
418 }
419
420 if (ident < 0) {
421 ALOGE("Invalid attempt to set NULL callback with ident < 0.");
422 return -1;
423 }
424 } else {
425 ident = ALOOPER_POLL_CALLBACK;
426 }
427
428 int epollEvents = 0;
429 if (events & ALOOPER_EVENT_INPUT) epollEvents |= EPOLLIN;
430 if (events & ALOOPER_EVENT_OUTPUT) epollEvents |= EPOLLOUT;
431
432 { // acquire lock
433 AutoMutex _l(mLock);
434
435 Request request;
436 request.fd = fd;
437 request.ident = ident;
438 request.callback = callback;
439 request.data = data;
440
441 struct epoll_event eventItem;
442 memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
443 eventItem.events = epollEvents;
444 eventItem.data.fd = fd;
445
446 ssize_t requestIndex = mRequests.indexOfKey(fd);
447 if (requestIndex < 0) {
448 int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
449 if (epollResult < 0) {
450 ALOGE("Error adding epoll events for fd %d, errno=%d", fd, errno);
451 return -1;
452 }
453 mRequests.add(fd, request);
454 } else {
455 int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
456 if (epollResult < 0) {
457 ALOGE("Error modifying epoll events for fd %d, errno=%d", fd, errno);
458 return -1;
459 }
460 mRequests.replaceValueAt(requestIndex, request);
461 }
462 } // release lock
463 return 1;
464}
465
466int Looper::removeFd(int fd) {
467#if DEBUG_CALLBACKS
468 ALOGD("%p ~ removeFd - fd=%d", this, fd);
469#endif
470
471 { // acquire lock
472 AutoMutex _l(mLock);
473 ssize_t requestIndex = mRequests.indexOfKey(fd);
474 if (requestIndex < 0) {
475 return 0;
476 }
477
478 int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, NULL);
479 if (epollResult < 0) {
480 ALOGE("Error removing epoll events for fd %d, errno=%d", fd, errno);
481 return -1;
482 }
483
484 mRequests.removeItemsAt(requestIndex);
485 } // release lock
486 return 1;
487}
488
489void Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message) {
490 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
491 sendMessageAtTime(now, handler, message);
492}
493
494void Looper::sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler,
495 const Message& message) {
496 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
497 sendMessageAtTime(now + uptimeDelay, handler, message);
498}
499
500void Looper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
501 const Message& message) {
502#if DEBUG_CALLBACKS
503 ALOGD("%p ~ sendMessageAtTime - uptime=%lld, handler=%p, what=%d",
504 this, uptime, handler.get(), message.what);
505#endif
506
507 size_t i = 0;
508 { // acquire lock
509 AutoMutex _l(mLock);
510
511 size_t messageCount = mMessageEnvelopes.size();
512 while (i < messageCount && uptime >= mMessageEnvelopes.itemAt(i).uptime) {
513 i += 1;
514 }
515
516 MessageEnvelope messageEnvelope(uptime, handler, message);
517 mMessageEnvelopes.insertAt(messageEnvelope, i, 1);
518
519 // Optimization: If the Looper is currently sending a message, then we can skip
520 // the call to wake() because the next thing the Looper will do after processing
521 // messages is to decide when the next wakeup time should be. In fact, it does
522 // not even matter whether this code is running on the Looper thread.
523 if (mSendingMessage) {
524 return;
525 }
526 } // release lock
527
528 // Wake the poll loop only when we enqueue a new message at the head.
529 if (i == 0) {
530 wake();
531 }
532}
533
534void Looper::removeMessages(const sp<MessageHandler>& handler) {
535#if DEBUG_CALLBACKS
536 ALOGD("%p ~ removeMessages - handler=%p", this, handler.get());
537#endif
538
539 { // acquire lock
540 AutoMutex _l(mLock);
541
542 for (size_t i = mMessageEnvelopes.size(); i != 0; ) {
543 const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(--i);
544 if (messageEnvelope.handler == handler) {
545 mMessageEnvelopes.removeAt(i);
546 }
547 }
548 } // release lock
549}
550
551void Looper::removeMessages(const sp<MessageHandler>& handler, int what) {
552#if DEBUG_CALLBACKS
553 ALOGD("%p ~ removeMessages - handler=%p, what=%d", this, handler.get(), what);
554#endif
555
556 { // acquire lock
557 AutoMutex _l(mLock);
558
559 for (size_t i = mMessageEnvelopes.size(); i != 0; ) {
560 const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(--i);
561 if (messageEnvelope.handler == handler
562 && messageEnvelope.message.what == what) {
563 mMessageEnvelopes.removeAt(i);
564 }
565 }
566 } // release lock
567}
568
569bool Looper::isIdling() const {
570 return mIdling;
571}
572
573} // namespace android
diff --git a/libutils/MODULE_LICENSE_APACHE2 b/libutils/MODULE_LICENSE_APACHE2
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/libutils/MODULE_LICENSE_APACHE2
diff --git a/libutils/NOTICE b/libutils/NOTICE
new file mode 100644
index 000000000..c5b1efa7a
--- /dev/null
+++ b/libutils/NOTICE
@@ -0,0 +1,190 @@
1
2 Copyright (c) 2005-2008, The Android Open Source Project
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6
7 Unless required by applicable law or agreed to in writing, software
8 distributed under the License is distributed on an "AS IS" BASIS,
9 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 See the License for the specific language governing permissions and
11 limitations under the License.
12
13
14 Apache License
15 Version 2.0, January 2004
16 http://www.apache.org/licenses/
17
18 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
19
20 1. Definitions.
21
22 "License" shall mean the terms and conditions for use, reproduction,
23 and distribution as defined by Sections 1 through 9 of this document.
24
25 "Licensor" shall mean the copyright owner or entity authorized by
26 the copyright owner that is granting the License.
27
28 "Legal Entity" shall mean the union of the acting entity and all
29 other entities that control, are controlled by, or are under common
30 control with that entity. For the purposes of this definition,
31 "control" means (i) the power, direct or indirect, to cause the
32 direction or management of such entity, whether by contract or
33 otherwise, or (ii) ownership of fifty percent (50%) or more of the
34 outstanding shares, or (iii) beneficial ownership of such entity.
35
36 "You" (or "Your") shall mean an individual or Legal Entity
37 exercising permissions granted by this License.
38
39 "Source" form shall mean the preferred form for making modifications,
40 including but not limited to software source code, documentation
41 source, and configuration files.
42
43 "Object" form shall mean any form resulting from mechanical
44 transformation or translation of a Source form, including but
45 not limited to compiled object code, generated documentation,
46 and conversions to other media types.
47
48 "Work" shall mean the work of authorship, whether in Source or
49 Object form, made available under the License, as indicated by a
50 copyright notice that is included in or attached to the work
51 (an example is provided in the Appendix below).
52
53 "Derivative Works" shall mean any work, whether in Source or Object
54 form, that is based on (or derived from) the Work and for which the
55 editorial revisions, annotations, elaborations, or other modifications
56 represent, as a whole, an original work of authorship. For the purposes
57 of this License, Derivative Works shall not include works that remain
58 separable from, or merely link (or bind by name) to the interfaces of,
59 the Work and Derivative Works thereof.
60
61 "Contribution" shall mean any work of authorship, including
62 the original version of the Work and any modifications or additions
63 to that Work or Derivative Works thereof, that is intentionally
64 submitted to Licensor for inclusion in the Work by the copyright owner
65 or by an individual or Legal Entity authorized to submit on behalf of
66 the copyright owner. For the purposes of this definition, "submitted"
67 means any form of electronic, verbal, or written communication sent
68 to the Licensor or its representatives, including but not limited to
69 communication on electronic mailing lists, source code control systems,
70 and issue tracking systems that are managed by, or on behalf of, the
71 Licensor for the purpose of discussing and improving the Work, but
72 excluding communication that is conspicuously marked or otherwise
73 designated in writing by the copyright owner as "Not a Contribution."
74
75 "Contributor" shall mean Licensor and any individual or Legal Entity
76 on behalf of whom a Contribution has been received by Licensor and
77 subsequently incorporated within the Work.
78
79 2. Grant of Copyright License. Subject to the terms and conditions of
80 this License, each Contributor hereby grants to You a perpetual,
81 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
82 copyright license to reproduce, prepare Derivative Works of,
83 publicly display, publicly perform, sublicense, and distribute the
84 Work and such Derivative Works in Source or Object form.
85
86 3. Grant of Patent License. Subject to the terms and conditions of
87 this License, each Contributor hereby grants to You a perpetual,
88 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
89 (except as stated in this section) patent license to make, have made,
90 use, offer to sell, sell, import, and otherwise transfer the Work,
91 where such license applies only to those patent claims licensable
92 by such Contributor that are necessarily infringed by their
93 Contribution(s) alone or by combination of their Contribution(s)
94 with the Work to which such Contribution(s) was submitted. If You
95 institute patent litigation against any entity (including a
96 cross-claim or counterclaim in a lawsuit) alleging that the Work
97 or a Contribution incorporated within the Work constitutes direct
98 or contributory patent infringement, then any patent licenses
99 granted to You under this License for that Work shall terminate
100 as of the date such litigation is filed.
101
102 4. Redistribution. You may reproduce and distribute copies of the
103 Work or Derivative Works thereof in any medium, with or without
104 modifications, and in Source or Object form, provided that You
105 meet the following conditions:
106
107 (a) You must give any other recipients of the Work or
108 Derivative Works a copy of this License; and
109
110 (b) You must cause any modified files to carry prominent notices
111 stating that You changed the files; and
112
113 (c) You must retain, in the Source form of any Derivative Works
114 that You distribute, all copyright, patent, trademark, and
115 attribution notices from the Source form of the Work,
116 excluding those notices that do not pertain to any part of
117 the Derivative Works; and
118
119 (d) If the Work includes a "NOTICE" text file as part of its
120 distribution, then any Derivative Works that You distribute must
121 include a readable copy of the attribution notices contained
122 within such NOTICE file, excluding those notices that do not
123 pertain to any part of the Derivative Works, in at least one
124 of the following places: within a NOTICE text file distributed
125 as part of the Derivative Works; within the Source form or
126 documentation, if provided along with the Derivative Works; or,
127 within a display generated by the Derivative Works, if and
128 wherever such third-party notices normally appear. The contents
129 of the NOTICE file are for informational purposes only and
130 do not modify the License. You may add Your own attribution
131 notices within Derivative Works that You distribute, alongside
132 or as an addendum to the NOTICE text from the Work, provided
133 that such additional attribution notices cannot be construed
134 as modifying the License.
135
136 You may add Your own copyright statement to Your modifications and
137 may provide additional or different license terms and conditions
138 for use, reproduction, or distribution of Your modifications, or
139 for any such Derivative Works as a whole, provided Your use,
140 reproduction, and distribution of the Work otherwise complies with
141 the conditions stated in this License.
142
143 5. Submission of Contributions. Unless You explicitly state otherwise,
144 any Contribution intentionally submitted for inclusion in the Work
145 by You to the Licensor shall be under the terms and conditions of
146 this License, without any additional terms or conditions.
147 Notwithstanding the above, nothing herein shall supersede or modify
148 the terms of any separate license agreement you may have executed
149 with Licensor regarding such Contributions.
150
151 6. Trademarks. This License does not grant permission to use the trade
152 names, trademarks, service marks, or product names of the Licensor,
153 except as required for reasonable and customary use in describing the
154 origin of the Work and reproducing the content of the NOTICE file.
155
156 7. Disclaimer of Warranty. Unless required by applicable law or
157 agreed to in writing, Licensor provides the Work (and each
158 Contributor provides its Contributions) on an "AS IS" BASIS,
159 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
160 implied, including, without limitation, any warranties or conditions
161 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
162 PARTICULAR PURPOSE. You are solely responsible for determining the
163 appropriateness of using or redistributing the Work and assume any
164 risks associated with Your exercise of permissions under this License.
165
166 8. Limitation of Liability. In no event and under no legal theory,
167 whether in tort (including negligence), contract, or otherwise,
168 unless required by applicable law (such as deliberate and grossly
169 negligent acts) or agreed to in writing, shall any Contributor be
170 liable to You for damages, including any direct, indirect, special,
171 incidental, or consequential damages of any character arising as a
172 result of this License or out of the use or inability to use the
173 Work (including but not limited to damages for loss of goodwill,
174 work stoppage, computer failure or malfunction, or any and all
175 other commercial damages or losses), even if such Contributor
176 has been advised of the possibility of such damages.
177
178 9. Accepting Warranty or Additional Liability. While redistributing
179 the Work or Derivative Works thereof, You may choose to offer,
180 and charge a fee for, acceptance of support, warranty, indemnity,
181 or other liability obligations and/or rights consistent with this
182 License. However, in accepting such obligations, You may act only
183 on Your own behalf and on Your sole responsibility, not on behalf
184 of any other Contributor, and only if You agree to indemnify,
185 defend, and hold each Contributor harmless for any liability
186 incurred by, or claims asserted against, such Contributor by reason
187 of your accepting any such warranty or additional liability.
188
189 END OF TERMS AND CONDITIONS
190
diff --git a/libutils/PropertyMap.cpp b/libutils/PropertyMap.cpp
new file mode 100644
index 000000000..55207027b
--- /dev/null
+++ b/libutils/PropertyMap.cpp
@@ -0,0 +1,218 @@
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "PropertyMap"
18
19#include <stdlib.h>
20#include <string.h>
21
22#include <utils/PropertyMap.h>
23#include <utils/Log.h>
24
25// Enables debug output for the parser.
26#define DEBUG_PARSER 0
27
28// Enables debug output for parser performance.
29#define DEBUG_PARSER_PERFORMANCE 0
30
31
32namespace android {
33
34static const char* WHITESPACE = " \t\r";
35static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r=";
36
37
38// --- PropertyMap ---
39
40PropertyMap::PropertyMap() {
41}
42
43PropertyMap::~PropertyMap() {
44}
45
46void PropertyMap::clear() {
47 mProperties.clear();
48}
49
50void PropertyMap::addProperty(const String8& key, const String8& value) {
51 mProperties.add(key, value);
52}
53
54bool PropertyMap::hasProperty(const String8& key) const {
55 return mProperties.indexOfKey(key) >= 0;
56}
57
58bool PropertyMap::tryGetProperty(const String8& key, String8& outValue) const {
59 ssize_t index = mProperties.indexOfKey(key);
60 if (index < 0) {
61 return false;
62 }
63
64 outValue = mProperties.valueAt(index);
65 return true;
66}
67
68bool PropertyMap::tryGetProperty(const String8& key, bool& outValue) const {
69 int32_t intValue;
70 if (!tryGetProperty(key, intValue)) {
71 return false;
72 }
73
74 outValue = intValue;
75 return true;
76}
77
78bool PropertyMap::tryGetProperty(const String8& key, int32_t& outValue) const {
79 String8 stringValue;
80 if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) {
81 return false;
82 }
83
84 char* end;
85 int value = strtol(stringValue.string(), & end, 10);
86 if (*end != '\0') {
87 ALOGW("Property key '%s' has invalid value '%s'. Expected an integer.",
88 key.string(), stringValue.string());
89 return false;
90 }
91 outValue = value;
92 return true;
93}
94
95bool PropertyMap::tryGetProperty(const String8& key, float& outValue) const {
96 String8 stringValue;
97 if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) {
98 return false;
99 }
100
101 char* end;
102 float value = strtof(stringValue.string(), & end);
103 if (*end != '\0') {
104 ALOGW("Property key '%s' has invalid value '%s'. Expected a float.",
105 key.string(), stringValue.string());
106 return false;
107 }
108 outValue = value;
109 return true;
110}
111
112void PropertyMap::addAll(const PropertyMap* map) {
113 for (size_t i = 0; i < map->mProperties.size(); i++) {
114 mProperties.add(map->mProperties.keyAt(i), map->mProperties.valueAt(i));
115 }
116}
117
118status_t PropertyMap::load(const String8& filename, PropertyMap** outMap) {
119 *outMap = NULL;
120
121 Tokenizer* tokenizer;
122 status_t status = Tokenizer::open(filename, &tokenizer);
123 if (status) {
124 ALOGE("Error %d opening property file %s.", status, filename.string());
125 } else {
126 PropertyMap* map = new PropertyMap();
127 if (!map) {
128 ALOGE("Error allocating property map.");
129 status = NO_MEMORY;
130 } else {
131#if DEBUG_PARSER_PERFORMANCE
132 nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
133#endif
134 Parser parser(map, tokenizer);
135 status = parser.parse();
136#if DEBUG_PARSER_PERFORMANCE
137 nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
138 ALOGD("Parsed property file '%s' %d lines in %0.3fms.",
139 tokenizer->getFilename().string(), tokenizer->getLineNumber(),
140 elapsedTime / 1000000.0);
141#endif
142 if (status) {
143 delete map;
144 } else {
145 *outMap = map;
146 }
147 }
148 delete tokenizer;
149 }
150 return status;
151}
152
153
154// --- PropertyMap::Parser ---
155
156PropertyMap::Parser::Parser(PropertyMap* map, Tokenizer* tokenizer) :
157 mMap(map), mTokenizer(tokenizer) {
158}
159
160PropertyMap::Parser::~Parser() {
161}
162
163status_t PropertyMap::Parser::parse() {
164 while (!mTokenizer->isEof()) {
165#if DEBUG_PARSER
166 ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
167 mTokenizer->peekRemainderOfLine().string());
168#endif
169
170 mTokenizer->skipDelimiters(WHITESPACE);
171
172 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
173 String8 keyToken = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
174 if (keyToken.isEmpty()) {
175 ALOGE("%s: Expected non-empty property key.", mTokenizer->getLocation().string());
176 return BAD_VALUE;
177 }
178
179 mTokenizer->skipDelimiters(WHITESPACE);
180
181 if (mTokenizer->nextChar() != '=') {
182 ALOGE("%s: Expected '=' between property key and value.",
183 mTokenizer->getLocation().string());
184 return BAD_VALUE;
185 }
186
187 mTokenizer->skipDelimiters(WHITESPACE);
188
189 String8 valueToken = mTokenizer->nextToken(WHITESPACE);
190 if (valueToken.find("\\", 0) >= 0 || valueToken.find("\"", 0) >= 0) {
191 ALOGE("%s: Found reserved character '\\' or '\"' in property value.",
192 mTokenizer->getLocation().string());
193 return BAD_VALUE;
194 }
195
196 mTokenizer->skipDelimiters(WHITESPACE);
197 if (!mTokenizer->isEol()) {
198 ALOGE("%s: Expected end of line, got '%s'.",
199 mTokenizer->getLocation().string(),
200 mTokenizer->peekRemainderOfLine().string());
201 return BAD_VALUE;
202 }
203
204 if (mMap->hasProperty(keyToken)) {
205 ALOGE("%s: Duplicate property value for key '%s'.",
206 mTokenizer->getLocation().string(), keyToken.string());
207 return BAD_VALUE;
208 }
209
210 mMap->addProperty(keyToken, valueToken);
211 }
212
213 mTokenizer->nextLine();
214 }
215 return NO_ERROR;
216}
217
218} // namespace android
diff --git a/libutils/README b/libutils/README
new file mode 100644
index 000000000..01741e093
--- /dev/null
+++ b/libutils/README
@@ -0,0 +1,289 @@
1Android Utility Function Library
2================================
3
4
5If you need a feature that is native to Linux but not present on other
6platforms, construct a platform-dependent implementation that shares
7the Linux interface. That way the actual device runs as "light" as
8possible.
9
10If that isn't feasible, create a system-independent interface and hide
11the details.
12
13The ultimate goal is *not* to create a super-duper platform abstraction
14layer. The goal is to provide an optimized solution for Linux with
15reasonable implementations for other platforms.
16
17
18
19Resource overlay
20================
21
22
23Introduction
24------------
25
26Overlay packages are special .apk files which provide no code but
27additional resource values (and possibly new configurations) for
28resources in other packages. When an application requests resources,
29the system will return values from either the application's original
30package or any associated overlay package. Any redirection is completely
31transparent to the calling application.
32
33Resource values have the following precedence table, listed in
34descending precedence.
35
36 * overlay package, matching config (eg res/values-en-land)
37
38 * original package, matching config
39
40 * overlay package, no config (eg res/values)
41
42 * original package, no config
43
44During compilation, overlay packages are differentiated from regular
45packages by passing the -o flag to aapt.
46
47
48Background
49----------
50
51This section provides generic background material on resources in
52Android.
53
54
55How resources are bundled in .apk files
56~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
57Android .apk files are .zip files, usually housing .dex code,
58certificates and resources, though packages containing resources but
59no code are possible. Resources can be divided into the following
60categories; a `configuration' indicates a set of phone language, display
61density, network operator, etc.
62
63 * assets: uncompressed, raw files packaged as part of an .apk and
64 explicitly referenced by filename. These files are
65 independent of configuration.
66
67 * res/drawable: bitmap or xml graphics. Each file may have different
68 values depending on configuration.
69
70 * res/values: integers, strings, etc. Each resource may have different
71 values depending on configuration.
72
73Resource meta information and information proper is stored in a binary
74format in a named file resources.arsc, bundled as part of the .apk.
75
76Resource IDs and lookup
77~~~~~~~~~~~~~~~~~~~~~~~
78During compilation, the aapt tool gathers application resources and
79generates a resources.arsc file. Each resource name is assigned an
80integer ID 0xppttiii (translated to a symbolic name via R.java), where
81
82 * pp: corresponds to the package namespace (details below).
83
84 * tt: corresponds to the resource type (string, int, etc). Every
85 resource of the same type within the same package has the same
86 tt value, but depending on available types, the actual numerical
87 value may be different between packages.
88
89 * iiii: sequential number, assigned in the order resources are found.
90
91Resource values are specified paired with a set of configuration
92constraints (the default being the empty set), eg res/values-sv-port
93which imposes restrictions on language (Swedish) and display orientation
94(portrait). During lookup, every constraint set is matched against the
95current configuration, and the value corresponding to the best matching
96constraint set is returned (ResourceTypes.{h,cpp}).
97
98Parsing of resources.arsc is handled by ResourceTypes.cpp; this utility
99is governed by AssetManager.cpp, which tracks loaded resources per
100process.
101
102Assets are looked up by path and filename in AssetManager.cpp. The path
103to resources in res/drawable are located by ResourceTypes.cpp and then
104handled like assets by AssetManager.cpp. Other resources are handled
105solely by ResourceTypes.cpp.
106
107Package ID as namespace
108~~~~~~~~~~~~~~~~~~~~~~~
109The pp part of a resource ID defines a namespace. Android currently
110defines two namespaces:
111
112 * 0x01: system resources (pre-installed in framework-res.apk)
113
114 * 0x7f: application resources (bundled in the application .apk)
115
116ResourceTypes.cpp supports package IDs between 0x01 and 0x7f
117(inclusive); values outside this range are invalid.
118
119Each running (Dalvik) process is assigned a unique instance of
120AssetManager, which in turn keeps a forest structure of loaded
121resource.arsc files. Normally, this forest is structured as follows,
122where mPackageMap is the internal vector employed in ResourceTypes.cpp.
123
124mPackageMap[0x00] -> system package
125mPackageMap[0x01] -> NULL
126mPackageMap[0x02] -> NULL
127...
128mPackageMap[0x7f - 2] -> NULL
129mPackageMap[0x7f - 1] -> application package
130
131
132
133The resource overlay extension
134------------------------------
135
136The resource overlay mechanism aims to (partly) shadow and extend
137existing resources with new values for defined and new configurations.
138Technically, this is achieved by adding resource-only packages (called
139overlay packages) to existing resource namespaces, like so:
140
141mPackageMap[0x00] -> system package -> system overlay package
142mPackageMap[0x01] -> NULL
143mPackageMap[0x02] -> NULL
144...
145mPackageMap[0x7f - 2] -> NULL
146mPackageMap[0x7f - 1] -> application package -> overlay 1 -> overlay 2
147
148The use of overlay resources is completely transparent to
149applications; no additional resource identifiers are introduced, only
150configuration/value pairs. Any number of overlay packages may be loaded
151at a time; overlay packages are agnostic to what they target -- both
152system and application resources are fair game.
153
154The package targeted by an overlay package is called the target or
155original package.
156
157Resource overlay operates on symbolic resources names. Hence, to
158override the string/str1 resources in a package, the overlay package
159would include a resource also named string/str1. The end user does not
160have to worry about the numeric resources IDs assigned by aapt, as this
161is resolved automatically by the system.
162
163As of this writing, the use of resource overlay has not been fully
164explored. Until it has, only OEMs are trusted to use resource overlay.
165For this reason, overlay packages must reside in /system/overlay.
166
167
168Resource ID mapping
169~~~~~~~~~~~~~~~~~~~
170Resource identifiers must be coherent within the same namespace (ie
171PackageGroup in ResourceTypes.cpp). Calling applications will refer to
172resources using the IDs defined in the original package, but there is no
173guarantee aapt has assigned the same ID to the corresponding resource in
174an overlay package. To translate between the two, a resource ID mapping
175{original ID -> overlay ID} is created during package installation
176(PackageManagerService.java) and used during resource lookup. The
177mapping is stored in /data/resource-cache, with a @idmap file name
178suffix.
179
180The idmap file format is documented in a separate section, below.
181
182
183Package management
184~~~~~~~~~~~~~~~~~~
185Packages are managed by the PackageManagerService. Addition and removal
186of packages are monitored via the inotify framework, exposed via
187android.os.FileObserver.
188
189During initialization of a Dalvik process, ActivityThread.java requests
190the process' AssetManager (by proxy, via AssetManager.java and JNI)
191to load a list of packages. This list includes overlay packages, if
192present.
193
194When a target package or a corresponding overlay package is installed,
195the target package's process is stopped and a new idmap is generated.
196This is similar to how applications are stopped when their packages are
197upgraded.
198
199
200Creating overlay packages
201-------------------------
202
203Overlay packages should contain no code, define (some) resources with
204the same type and name as in the original package, and be compiled with
205the -o flag passed to aapt.
206
207The aapt -o flag instructs aapt to create an overlay package.
208Technically, this means the package will be assigned package id 0x00.
209
210There are no restrictions on overlay packages names, though the naming
211convention <original.package.name>.overlay.<name> is recommended.
212
213
214Example overlay package
215~~~~~~~~~~~~~~~~~~~~~~~
216
217To overlay the resource bool/b in package com.foo.bar, to be applied
218when the display is in landscape mode, create a new package with
219no source code and a single .xml file under res/values-land, with
220an entry for bool/b. Compile with aapt -o and place the results in
221/system/overlay by adding the following to Android.mk:
222
223LOCAL_AAPT_FLAGS := -o com.foo.bar
224LOCAL_MODULE_PATH := $(TARGET_OUT)/overlay
225
226
227The ID map (idmap) file format
228------------------------------
229
230The idmap format is designed for lookup performance. However, leading
231and trailing undefined overlay values are discarded to reduce the memory
232footprint.
233
234
235idmap grammar
236~~~~~~~~~~~~~
237All atoms (names in square brackets) are uint32_t integers. The
238idmap-magic constant spells "idmp" in ASCII. Offsets are given relative
239to the data_header, not to the beginning of the file.
240
241map := header data
242header := idmap-magic <crc32-original-pkg> <crc32-overlay-pkg>
243idmap-magic := <0x706d6469>
244data := data_header type_block+
245data_header := <m> header_block{m}
246header_block := <0> | <type_block_offset>
247type_block := <n> <id_offset> entry{n}
248entry := <resource_id_in_target_package>
249
250
251idmap example
252~~~~~~~~~~~~~
253Given a pair of target and overlay packages with CRC sums 0x216a8fe2
254and 0x6b9beaec, each defining the following resources
255
256Name Target package Overlay package
257string/str0 0x7f010000 -
258string/str1 0x7f010001 0x7f010000
259string/str2 0x7f010002 -
260string/str3 0x7f010003 0x7f010001
261string/str4 0x7f010004 -
262bool/bool0 0x7f020000 -
263integer/int0 0x7f030000 0x7f020000
264integer/int1 0x7f030001 -
265
266the corresponding resource map is
267
2680x706d6469 0x216a8fe2 0x6b9beaec 0x00000003 \
2690x00000004 0x00000000 0x00000009 0x00000003 \
2700x00000001 0x7f010000 0x00000000 0x7f010001 \
2710x00000001 0x00000000 0x7f020000
272
273or, formatted differently
274
2750x706d6469 # magic: all idmap files begin with this constant
2760x216a8fe2 # CRC32 of the resources.arsc file in the original package
2770x6b9beaec # CRC32 of the resources.arsc file in the overlay package
2780x00000003 # header; three types (string, bool, integer) in the target package
2790x00000004 # header_block for type 0 (string) is located at offset 4
2800x00000000 # no bool type exists in overlay package -> no header_block
2810x00000009 # header_block for type 2 (integer) is located at offset 9
2820x00000003 # header_block for string; overlay IDs span 3 elements
2830x00000001 # the first string in target package is entry 1 == offset
2840x7f010000 # target 0x7f01001 -> overlay 0x7f010000
2850x00000000 # str2 not defined in overlay package
2860x7f010001 # target 0x7f010003 -> overlay 0x7f010001
2870x00000001 # header_block for integer; overlay IDs span 1 element
2880x00000000 # offset == 0
2890x7f020000 # target 0x7f030000 -> overlay 0x7f020000
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
new file mode 100644
index 000000000..f398a82ce
--- /dev/null
+++ b/libutils/RefBase.cpp
@@ -0,0 +1,650 @@
1/*
2 * Copyright (C) 2005 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "RefBase"
18// #define LOG_NDEBUG 0
19
20#include <utils/RefBase.h>
21
22#include <utils/Atomic.h>
23#include <utils/CallStack.h>
24#include <utils/Log.h>
25#include <utils/threads.h>
26
27#include <stdlib.h>
28#include <stdio.h>
29#include <typeinfo>
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <fcntl.h>
33#include <unistd.h>
34
35// compile with refcounting debugging enabled
36#define DEBUG_REFS 0
37
38// whether ref-tracking is enabled by default, if not, trackMe(true, false)
39// needs to be called explicitly
40#define DEBUG_REFS_ENABLED_BY_DEFAULT 0
41
42// whether callstack are collected (significantly slows things down)
43#define DEBUG_REFS_CALLSTACK_ENABLED 1
44
45// folder where stack traces are saved when DEBUG_REFS is enabled
46// this folder needs to exist and be writable
47#define DEBUG_REFS_CALLSTACK_PATH "/data/debug"
48
49// log all reference counting operations
50#define PRINT_REFS 0
51
52// ---------------------------------------------------------------------------
53
54namespace android {
55
56#define INITIAL_STRONG_VALUE (1<<28)
57
58// ---------------------------------------------------------------------------
59
60class RefBase::weakref_impl : public RefBase::weakref_type
61{
62public:
63 volatile int32_t mStrong;
64 volatile int32_t mWeak;
65 RefBase* const mBase;
66 volatile int32_t mFlags;
67
68#if !DEBUG_REFS
69
70 weakref_impl(RefBase* base)
71 : mStrong(INITIAL_STRONG_VALUE)
72 , mWeak(0)
73 , mBase(base)
74 , mFlags(0)
75 {
76 }
77
78 void addStrongRef(const void* /*id*/) { }
79 void removeStrongRef(const void* /*id*/) { }
80 void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { }
81 void addWeakRef(const void* /*id*/) { }
82 void removeWeakRef(const void* /*id*/) { }
83 void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { }
84 void printRefs() const { }
85 void trackMe(bool, bool) { }
86
87#else
88
89 weakref_impl(RefBase* base)
90 : mStrong(INITIAL_STRONG_VALUE)
91 , mWeak(0)
92 , mBase(base)
93 , mFlags(0)
94 , mStrongRefs(NULL)
95 , mWeakRefs(NULL)
96 , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
97 , mRetain(false)
98 {
99 }
100
101 ~weakref_impl()
102 {
103 bool dumpStack = false;
104 if (!mRetain && mStrongRefs != NULL) {
105 dumpStack = true;
106 ALOGE("Strong references remain:");
107 ref_entry* refs = mStrongRefs;
108 while (refs) {
109 char inc = refs->ref >= 0 ? '+' : '-';
110 ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
111#if DEBUG_REFS_CALLSTACK_ENABLED
112 refs->stack.dump(LOG_TAG);
113#endif
114 refs = refs->next;
115 }
116 }
117
118 if (!mRetain && mWeakRefs != NULL) {
119 dumpStack = true;
120 ALOGE("Weak references remain!");
121 ref_entry* refs = mWeakRefs;
122 while (refs) {
123 char inc = refs->ref >= 0 ? '+' : '-';
124 ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
125#if DEBUG_REFS_CALLSTACK_ENABLED
126 refs->stack.dump(LOG_TAG);
127#endif
128 refs = refs->next;
129 }
130 }
131 if (dumpStack) {
132 ALOGE("above errors at:");
133 CallStack stack(LOG_TAG);
134 }
135 }
136
137 void addStrongRef(const void* id) {
138 //ALOGD_IF(mTrackEnabled,
139 // "addStrongRef: RefBase=%p, id=%p", mBase, id);
140 addRef(&mStrongRefs, id, mStrong);
141 }
142
143 void removeStrongRef(const void* id) {
144 //ALOGD_IF(mTrackEnabled,
145 // "removeStrongRef: RefBase=%p, id=%p", mBase, id);
146 if (!mRetain) {
147 removeRef(&mStrongRefs, id);
148 } else {
149 addRef(&mStrongRefs, id, -mStrong);
150 }
151 }
152
153 void renameStrongRefId(const void* old_id, const void* new_id) {
154 //ALOGD_IF(mTrackEnabled,
155 // "renameStrongRefId: RefBase=%p, oid=%p, nid=%p",
156 // mBase, old_id, new_id);
157 renameRefsId(mStrongRefs, old_id, new_id);
158 }
159
160 void addWeakRef(const void* id) {
161 addRef(&mWeakRefs, id, mWeak);
162 }
163
164 void removeWeakRef(const void* id) {
165 if (!mRetain) {
166 removeRef(&mWeakRefs, id);
167 } else {
168 addRef(&mWeakRefs, id, -mWeak);
169 }
170 }
171
172 void renameWeakRefId(const void* old_id, const void* new_id) {
173 renameRefsId(mWeakRefs, old_id, new_id);
174 }
175
176 void trackMe(bool track, bool retain)
177 {
178 mTrackEnabled = track;
179 mRetain = retain;
180 }
181
182 void printRefs() const
183 {
184 String8 text;
185
186 {
187 Mutex::Autolock _l(mMutex);
188 char buf[128];
189 sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
190 text.append(buf);
191 printRefsLocked(&text, mStrongRefs);
192 sprintf(buf, "Weak references on RefBase %p (weakref_type %p):\n", mBase, this);
193 text.append(buf);
194 printRefsLocked(&text, mWeakRefs);
195 }
196
197 {
198 char name[100];
199 snprintf(name, 100, DEBUG_REFS_CALLSTACK_PATH "/%p.stack", this);
200 int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 644);
201 if (rc >= 0) {
202 write(rc, text.string(), text.length());
203 close(rc);
204 ALOGD("STACK TRACE for %p saved in %s", this, name);
205 }
206 else ALOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this,
207 name, strerror(errno));
208 }
209 }
210
211private:
212 struct ref_entry
213 {
214 ref_entry* next;
215 const void* id;
216#if DEBUG_REFS_CALLSTACK_ENABLED
217 CallStack stack;
218#endif
219 int32_t ref;
220 };
221
222 void addRef(ref_entry** refs, const void* id, int32_t mRef)
223 {
224 if (mTrackEnabled) {
225 AutoMutex _l(mMutex);
226
227 ref_entry* ref = new ref_entry;
228 // Reference count at the time of the snapshot, but before the
229 // update. Positive value means we increment, negative--we
230 // decrement the reference count.
231 ref->ref = mRef;
232 ref->id = id;
233#if DEBUG_REFS_CALLSTACK_ENABLED
234 ref->stack.update(2);
235#endif
236 ref->next = *refs;
237 *refs = ref;
238 }
239 }
240
241 void removeRef(ref_entry** refs, const void* id)
242 {
243 if (mTrackEnabled) {
244 AutoMutex _l(mMutex);
245
246 ref_entry* const head = *refs;
247 ref_entry* ref = head;
248 while (ref != NULL) {
249 if (ref->id == id) {
250 *refs = ref->next;
251 delete ref;
252 return;
253 }
254 refs = &ref->next;
255 ref = *refs;
256 }
257
258 ALOGE("RefBase: removing id %p on RefBase %p"
259 "(weakref_type %p) that doesn't exist!",
260 id, mBase, this);
261
262 ref = head;
263 while (ref) {
264 char inc = ref->ref >= 0 ? '+' : '-';
265 ALOGD("\t%c ID %p (ref %d):", inc, ref->id, ref->ref);
266 ref = ref->next;
267 }
268
269 CallStack stack(LOG_TAG);
270 }
271 }
272
273 void renameRefsId(ref_entry* r, const void* old_id, const void* new_id)
274 {
275 if (mTrackEnabled) {
276 AutoMutex _l(mMutex);
277 ref_entry* ref = r;
278 while (ref != NULL) {
279 if (ref->id == old_id) {
280 ref->id = new_id;
281 }
282 ref = ref->next;
283 }
284 }
285 }
286
287 void printRefsLocked(String8* out, const ref_entry* refs) const
288 {
289 char buf[128];
290 while (refs) {
291 char inc = refs->ref >= 0 ? '+' : '-';
292 sprintf(buf, "\t%c ID %p (ref %d):\n",
293 inc, refs->id, refs->ref);
294 out->append(buf);
295#if DEBUG_REFS_CALLSTACK_ENABLED
296 out->append(refs->stack.toString("\t\t"));
297#else
298 out->append("\t\t(call stacks disabled)");
299#endif
300 refs = refs->next;
301 }
302 }
303
304 mutable Mutex mMutex;
305 ref_entry* mStrongRefs;
306 ref_entry* mWeakRefs;
307
308 bool mTrackEnabled;
309 // Collect stack traces on addref and removeref, instead of deleting the stack references
310 // on removeref that match the address ones.
311 bool mRetain;
312
313#endif
314};
315
316// ---------------------------------------------------------------------------
317
318void RefBase::incStrong(const void* id) const
319{
320 weakref_impl* const refs = mRefs;
321 refs->incWeak(id);
322
323 refs->addStrongRef(id);
324 const int32_t c = android_atomic_inc(&refs->mStrong);
325 ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
326#if PRINT_REFS
327 ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
328#endif
329 if (c != INITIAL_STRONG_VALUE) {
330 return;
331 }
332
333 android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
334 refs->mBase->onFirstRef();
335}
336
337void RefBase::decStrong(const void* id) const
338{
339 weakref_impl* const refs = mRefs;
340 refs->removeStrongRef(id);
341 const int32_t c = android_atomic_dec(&refs->mStrong);
342#if PRINT_REFS
343 ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
344#endif
345 ALOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
346 if (c == 1) {
347 refs->mBase->onLastStrongRef(id);
348 if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
349 delete this;
350 }
351 }
352 refs->decWeak(id);
353}
354
355void RefBase::forceIncStrong(const void* id) const
356{
357 weakref_impl* const refs = mRefs;
358 refs->incWeak(id);
359
360 refs->addStrongRef(id);
361 const int32_t c = android_atomic_inc(&refs->mStrong);
362 ALOG_ASSERT(c >= 0, "forceIncStrong called on %p after ref count underflow",
363 refs);
364#if PRINT_REFS
365 ALOGD("forceIncStrong of %p from %p: cnt=%d\n", this, id, c);
366#endif
367
368 switch (c) {
369 case INITIAL_STRONG_VALUE:
370 android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
371 // fall through...
372 case 0:
373 refs->mBase->onFirstRef();
374 }
375}
376
377int32_t RefBase::getStrongCount() const
378{
379 return mRefs->mStrong;
380}
381
382RefBase* RefBase::weakref_type::refBase() const
383{
384 return static_cast<const weakref_impl*>(this)->mBase;
385}
386
387void RefBase::weakref_type::incWeak(const void* id)
388{
389 weakref_impl* const impl = static_cast<weakref_impl*>(this);
390 impl->addWeakRef(id);
391 const int32_t c = android_atomic_inc(&impl->mWeak);
392 ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
393}
394
395
396void RefBase::weakref_type::decWeak(const void* id)
397{
398 weakref_impl* const impl = static_cast<weakref_impl*>(this);
399 impl->removeWeakRef(id);
400 const int32_t c = android_atomic_dec(&impl->mWeak);
401 ALOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
402 if (c != 1) return;
403
404 if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
405 // This is the regular lifetime case. The object is destroyed
406 // when the last strong reference goes away. Since weakref_impl
407 // outlive the object, it is not destroyed in the dtor, and
408 // we'll have to do it here.
409 if (impl->mStrong == INITIAL_STRONG_VALUE) {
410 // Special case: we never had a strong reference, so we need to
411 // destroy the object now.
412 delete impl->mBase;
413 } else {
414 // ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
415 delete impl;
416 }
417 } else {
418 // less common case: lifetime is OBJECT_LIFETIME_{WEAK|FOREVER}
419 impl->mBase->onLastWeakRef(id);
420 if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
421 // this is the OBJECT_LIFETIME_WEAK case. The last weak-reference
422 // is gone, we can destroy the object.
423 delete impl->mBase;
424 }
425 }
426}
427
428bool RefBase::weakref_type::attemptIncStrong(const void* id)
429{
430 incWeak(id);
431
432 weakref_impl* const impl = static_cast<weakref_impl*>(this);
433 int32_t curCount = impl->mStrong;
434
435 ALOG_ASSERT(curCount >= 0,
436 "attemptIncStrong called on %p after underflow", this);
437
438 while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
439 // we're in the easy/common case of promoting a weak-reference
440 // from an existing strong reference.
441 if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
442 break;
443 }
444 // the strong count has changed on us, we need to re-assert our
445 // situation.
446 curCount = impl->mStrong;
447 }
448
449 if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
450 // we're now in the harder case of either:
451 // - there never was a strong reference on us
452 // - or, all strong references have been released
453 if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
454 // this object has a "normal" life-time, i.e.: it gets destroyed
455 // when the last strong reference goes away
456 if (curCount <= 0) {
457 // the last strong-reference got released, the object cannot
458 // be revived.
459 decWeak(id);
460 return false;
461 }
462
463 // here, curCount == INITIAL_STRONG_VALUE, which means
464 // there never was a strong-reference, so we can try to
465 // promote this object; we need to do that atomically.
466 while (curCount > 0) {
467 if (android_atomic_cmpxchg(curCount, curCount + 1,
468 &impl->mStrong) == 0) {
469 break;
470 }
471 // the strong count has changed on us, we need to re-assert our
472 // situation (e.g.: another thread has inc/decStrong'ed us)
473 curCount = impl->mStrong;
474 }
475
476 if (curCount <= 0) {
477 // promote() failed, some other thread destroyed us in the
478 // meantime (i.e.: strong count reached zero).
479 decWeak(id);
480 return false;
481 }
482 } else {
483 // this object has an "extended" life-time, i.e.: it can be
484 // revived from a weak-reference only.
485 // Ask the object's implementation if it agrees to be revived
486 if (!impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)) {
487 // it didn't so give-up.
488 decWeak(id);
489 return false;
490 }
491 // grab a strong-reference, which is always safe due to the
492 // extended life-time.
493 curCount = android_atomic_inc(&impl->mStrong);
494 }
495
496 // If the strong reference count has already been incremented by
497 // someone else, the implementor of onIncStrongAttempted() is holding
498 // an unneeded reference. So call onLastStrongRef() here to remove it.
499 // (No, this is not pretty.) Note that we MUST NOT do this if we
500 // are in fact acquiring the first reference.
501 if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
502 impl->mBase->onLastStrongRef(id);
503 }
504 }
505
506 impl->addStrongRef(id);
507
508#if PRINT_REFS
509 ALOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
510#endif
511
512 // now we need to fix-up the count if it was INITIAL_STRONG_VALUE
513 // this must be done safely, i.e.: handle the case where several threads
514 // were here in attemptIncStrong().
515 curCount = impl->mStrong;
516 while (curCount >= INITIAL_STRONG_VALUE) {
517 ALOG_ASSERT(curCount > INITIAL_STRONG_VALUE,
518 "attemptIncStrong in %p underflowed to INITIAL_STRONG_VALUE",
519 this);
520 if (android_atomic_cmpxchg(curCount, curCount-INITIAL_STRONG_VALUE,
521 &impl->mStrong) == 0) {
522 break;
523 }
524 // the strong-count changed on us, we need to re-assert the situation,
525 // for e.g.: it's possible the fix-up happened in another thread.
526 curCount = impl->mStrong;
527 }
528
529 return true;
530}
531
532bool RefBase::weakref_type::attemptIncWeak(const void* id)
533{
534 weakref_impl* const impl = static_cast<weakref_impl*>(this);
535
536 int32_t curCount = impl->mWeak;
537 ALOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow",
538 this);
539 while (curCount > 0) {
540 if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mWeak) == 0) {
541 break;
542 }
543 curCount = impl->mWeak;
544 }
545
546 if (curCount > 0) {
547 impl->addWeakRef(id);
548 }
549
550 return curCount > 0;
551}
552
553int32_t RefBase::weakref_type::getWeakCount() const
554{
555 return static_cast<const weakref_impl*>(this)->mWeak;
556}
557
558void RefBase::weakref_type::printRefs() const
559{
560 static_cast<const weakref_impl*>(this)->printRefs();
561}
562
563void RefBase::weakref_type::trackMe(bool enable, bool retain)
564{
565 static_cast<weakref_impl*>(this)->trackMe(enable, retain);
566}
567
568RefBase::weakref_type* RefBase::createWeak(const void* id) const
569{
570 mRefs->incWeak(id);
571 return mRefs;
572}
573
574RefBase::weakref_type* RefBase::getWeakRefs() const
575{
576 return mRefs;
577}
578
579RefBase::RefBase()
580 : mRefs(new weakref_impl(this))
581{
582}
583
584RefBase::~RefBase()
585{
586 if (mRefs->mStrong == INITIAL_STRONG_VALUE) {
587 // we never acquired a strong (and/or weak) reference on this object.
588 delete mRefs;
589 } else {
590 // life-time of this object is extended to WEAK or FOREVER, in
591 // which case weakref_impl doesn't out-live the object and we
592 // can free it now.
593 if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
594 // It's possible that the weak count is not 0 if the object
595 // re-acquired a weak reference in its destructor
596 if (mRefs->mWeak == 0) {
597 delete mRefs;
598 }
599 }
600 }
601 // for debugging purposes, clear this.
602 const_cast<weakref_impl*&>(mRefs) = NULL;
603}
604
605void RefBase::extendObjectLifetime(int32_t mode)
606{
607 android_atomic_or(mode, &mRefs->mFlags);
608}
609
610void RefBase::onFirstRef()
611{
612}
613
614void RefBase::onLastStrongRef(const void* /*id*/)
615{
616}
617
618bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id)
619{
620 return (flags&FIRST_INC_STRONG) ? true : false;
621}
622
623void RefBase::onLastWeakRef(const void* /*id*/)
624{
625}
626
627// ---------------------------------------------------------------------------
628
629void RefBase::renameRefs(size_t n, const ReferenceRenamer& renamer) {
630#if DEBUG_REFS
631 for (size_t i=0 ; i<n ; i++) {
632 renamer(i);
633 }
634#endif
635}
636
637void RefBase::renameRefId(weakref_type* ref,
638 const void* old_id, const void* new_id) {
639 weakref_impl* const impl = static_cast<weakref_impl*>(ref);
640 impl->renameStrongRefId(old_id, new_id);
641 impl->renameWeakRefId(old_id, new_id);
642}
643
644void RefBase::renameRefId(RefBase* ref,
645 const void* old_id, const void* new_id) {
646 ref->mRefs->renameStrongRefId(old_id, new_id);
647 ref->mRefs->renameWeakRefId(old_id, new_id);
648}
649
650}; // namespace android
diff --git a/libutils/SharedBuffer.cpp b/libutils/SharedBuffer.cpp
new file mode 100644
index 000000000..3555fb712
--- /dev/null
+++ b/libutils/SharedBuffer.cpp
@@ -0,0 +1,113 @@
1/*
2 * Copyright (C) 2005 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdlib.h>
18#include <string.h>
19
20#include <utils/SharedBuffer.h>
21#include <utils/Atomic.h>
22
23// ---------------------------------------------------------------------------
24
25namespace android {
26
27SharedBuffer* SharedBuffer::alloc(size_t size)
28{
29 SharedBuffer* sb = static_cast<SharedBuffer *>(malloc(sizeof(SharedBuffer) + size));
30 if (sb) {
31 sb->mRefs = 1;
32 sb->mSize = size;
33 }
34 return sb;
35}
36
37
38ssize_t SharedBuffer::dealloc(const SharedBuffer* released)
39{
40 if (released->mRefs != 0) return -1; // XXX: invalid operation
41 free(const_cast<SharedBuffer*>(released));
42 return 0;