xref: /aosp_15_r20/frameworks/native/opengl/libs/EGL/BlobCache.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  ** Copyright 2011, The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  **
4*38e8c45fSAndroid Build Coastguard Worker  ** Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  ** you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  ** You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  **
8*38e8c45fSAndroid Build Coastguard Worker  **     http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  **
10*38e8c45fSAndroid Build Coastguard Worker  ** Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  ** distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  ** See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  ** limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker 
17*38e8c45fSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
18*38e8c45fSAndroid Build Coastguard Worker #define ATRACE_TAG ATRACE_TAG_GRAPHICS
19*38e8c45fSAndroid Build Coastguard Worker 
20*38e8c45fSAndroid Build Coastguard Worker #include "BlobCache.h"
21*38e8c45fSAndroid Build Coastguard Worker 
22*38e8c45fSAndroid Build Coastguard Worker #include <android-base/properties.h>
23*38e8c45fSAndroid Build Coastguard Worker #include <errno.h>
24*38e8c45fSAndroid Build Coastguard Worker #include <inttypes.h>
25*38e8c45fSAndroid Build Coastguard Worker #include <log/log.h>
26*38e8c45fSAndroid Build Coastguard Worker #include <utils/Trace.h>
27*38e8c45fSAndroid Build Coastguard Worker 
28*38e8c45fSAndroid Build Coastguard Worker #include <chrono>
29*38e8c45fSAndroid Build Coastguard Worker 
30*38e8c45fSAndroid Build Coastguard Worker namespace android {
31*38e8c45fSAndroid Build Coastguard Worker 
32*38e8c45fSAndroid Build Coastguard Worker // BlobCache::Header::mMagicNumber value
33*38e8c45fSAndroid Build Coastguard Worker static const uint32_t blobCacheMagic = ('_' << 24) + ('B' << 16) + ('b' << 8) + '$';
34*38e8c45fSAndroid Build Coastguard Worker 
35*38e8c45fSAndroid Build Coastguard Worker // BlobCache::Header::mBlobCacheVersion value
36*38e8c45fSAndroid Build Coastguard Worker static const uint32_t blobCacheVersion = 3;
37*38e8c45fSAndroid Build Coastguard Worker 
38*38e8c45fSAndroid Build Coastguard Worker // BlobCache::Header::mDeviceVersion value
39*38e8c45fSAndroid Build Coastguard Worker static const uint32_t blobCacheDeviceVersion = 1;
40*38e8c45fSAndroid Build Coastguard Worker 
BlobCache(size_t maxKeySize,size_t maxValueSize,size_t maxTotalSize)41*38e8c45fSAndroid Build Coastguard Worker BlobCache::BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize)
42*38e8c45fSAndroid Build Coastguard Worker       : mMaxTotalSize(maxTotalSize),
43*38e8c45fSAndroid Build Coastguard Worker         mMaxKeySize(maxKeySize),
44*38e8c45fSAndroid Build Coastguard Worker         mMaxValueSize(maxValueSize),
45*38e8c45fSAndroid Build Coastguard Worker         mTotalSize(0) {
46*38e8c45fSAndroid Build Coastguard Worker     int64_t now = std::chrono::steady_clock::now().time_since_epoch().count();
47*38e8c45fSAndroid Build Coastguard Worker #ifdef _WIN32
48*38e8c45fSAndroid Build Coastguard Worker     srand(now);
49*38e8c45fSAndroid Build Coastguard Worker #else
50*38e8c45fSAndroid Build Coastguard Worker     mRandState[0] = (now >> 0) & 0xFFFF;
51*38e8c45fSAndroid Build Coastguard Worker     mRandState[1] = (now >> 16) & 0xFFFF;
52*38e8c45fSAndroid Build Coastguard Worker     mRandState[2] = (now >> 32) & 0xFFFF;
53*38e8c45fSAndroid Build Coastguard Worker #endif
54*38e8c45fSAndroid Build Coastguard Worker     ALOGV("initializing random seed using %lld", (unsigned long long)now);
55*38e8c45fSAndroid Build Coastguard Worker }
56*38e8c45fSAndroid Build Coastguard Worker 
set(const void * key,size_t keySize,const void * value,size_t valueSize)57*38e8c45fSAndroid Build Coastguard Worker BlobCache::InsertResult BlobCache::set(const void* key, size_t keySize, const void* value,
58*38e8c45fSAndroid Build Coastguard Worker                                        size_t valueSize) {
59*38e8c45fSAndroid Build Coastguard Worker     if (mMaxKeySize < keySize) {
60*38e8c45fSAndroid Build Coastguard Worker         ALOGV("set: not caching because the key is too large: %zu (limit: %zu)", keySize,
61*38e8c45fSAndroid Build Coastguard Worker               mMaxKeySize);
62*38e8c45fSAndroid Build Coastguard Worker         return InsertResult::kKeyTooBig;
63*38e8c45fSAndroid Build Coastguard Worker     }
64*38e8c45fSAndroid Build Coastguard Worker     if (mMaxValueSize < valueSize) {
65*38e8c45fSAndroid Build Coastguard Worker         ALOGV("set: not caching because the value is too large: %zu (limit: %zu)", valueSize,
66*38e8c45fSAndroid Build Coastguard Worker               mMaxValueSize);
67*38e8c45fSAndroid Build Coastguard Worker         return InsertResult::kValueTooBig;
68*38e8c45fSAndroid Build Coastguard Worker     }
69*38e8c45fSAndroid Build Coastguard Worker     if (mMaxTotalSize < keySize + valueSize) {
70*38e8c45fSAndroid Build Coastguard Worker         ALOGV("set: not caching because the combined key/value size is too "
71*38e8c45fSAndroid Build Coastguard Worker               "large: %zu (limit: %zu)",
72*38e8c45fSAndroid Build Coastguard Worker               keySize + valueSize, mMaxTotalSize);
73*38e8c45fSAndroid Build Coastguard Worker         return InsertResult::kCombinedTooBig;
74*38e8c45fSAndroid Build Coastguard Worker     }
75*38e8c45fSAndroid Build Coastguard Worker     if (keySize == 0) {
76*38e8c45fSAndroid Build Coastguard Worker         ALOGW("set: not caching because keySize is 0");
77*38e8c45fSAndroid Build Coastguard Worker         return InsertResult::kInvalidKeySize;
78*38e8c45fSAndroid Build Coastguard Worker     }
79*38e8c45fSAndroid Build Coastguard Worker     if (valueSize == 0) {
80*38e8c45fSAndroid Build Coastguard Worker         ALOGW("set: not caching because valueSize is 0");
81*38e8c45fSAndroid Build Coastguard Worker         return InsertResult::kInvalidValueSize;
82*38e8c45fSAndroid Build Coastguard Worker     }
83*38e8c45fSAndroid Build Coastguard Worker 
84*38e8c45fSAndroid Build Coastguard Worker     std::shared_ptr<Blob> cacheKey(new Blob(key, keySize, false));
85*38e8c45fSAndroid Build Coastguard Worker     CacheEntry cacheEntry(cacheKey, nullptr);
86*38e8c45fSAndroid Build Coastguard Worker 
87*38e8c45fSAndroid Build Coastguard Worker     bool didClean = false;
88*38e8c45fSAndroid Build Coastguard Worker     while (true) {
89*38e8c45fSAndroid Build Coastguard Worker         auto index = std::lower_bound(mCacheEntries.begin(), mCacheEntries.end(), cacheEntry);
90*38e8c45fSAndroid Build Coastguard Worker         if (index == mCacheEntries.end() || cacheEntry < *index) {
91*38e8c45fSAndroid Build Coastguard Worker             // Create a new cache entry.
92*38e8c45fSAndroid Build Coastguard Worker             std::shared_ptr<Blob> keyBlob(new Blob(key, keySize, true));
93*38e8c45fSAndroid Build Coastguard Worker             std::shared_ptr<Blob> valueBlob(new Blob(value, valueSize, true));
94*38e8c45fSAndroid Build Coastguard Worker             size_t newTotalSize = mTotalSize + keySize + valueSize;
95*38e8c45fSAndroid Build Coastguard Worker             if (mMaxTotalSize < newTotalSize) {
96*38e8c45fSAndroid Build Coastguard Worker                 if (isCleanable()) {
97*38e8c45fSAndroid Build Coastguard Worker                     // Clean the cache and try again.
98*38e8c45fSAndroid Build Coastguard Worker                     clean();
99*38e8c45fSAndroid Build Coastguard Worker                     didClean = true;
100*38e8c45fSAndroid Build Coastguard Worker                     continue;
101*38e8c45fSAndroid Build Coastguard Worker                 } else {
102*38e8c45fSAndroid Build Coastguard Worker                     ALOGV("set: not caching new key/value pair because the "
103*38e8c45fSAndroid Build Coastguard Worker                           "total cache size limit would be exceeded: %zu "
104*38e8c45fSAndroid Build Coastguard Worker                           "(limit: %zu)",
105*38e8c45fSAndroid Build Coastguard Worker                           keySize + valueSize, mMaxTotalSize);
106*38e8c45fSAndroid Build Coastguard Worker                     return InsertResult::kNotEnoughSpace;
107*38e8c45fSAndroid Build Coastguard Worker                 }
108*38e8c45fSAndroid Build Coastguard Worker             }
109*38e8c45fSAndroid Build Coastguard Worker             mCacheEntries.insert(index, CacheEntry(keyBlob, valueBlob));
110*38e8c45fSAndroid Build Coastguard Worker             mTotalSize = newTotalSize;
111*38e8c45fSAndroid Build Coastguard Worker             ALOGV("set: created new cache entry with %zu byte key and %zu byte value", keySize,
112*38e8c45fSAndroid Build Coastguard Worker                   valueSize);
113*38e8c45fSAndroid Build Coastguard Worker         } else {
114*38e8c45fSAndroid Build Coastguard Worker             // Update the existing cache entry.
115*38e8c45fSAndroid Build Coastguard Worker             std::shared_ptr<Blob> valueBlob(new Blob(value, valueSize, true));
116*38e8c45fSAndroid Build Coastguard Worker             std::shared_ptr<Blob> oldValueBlob(index->getValue());
117*38e8c45fSAndroid Build Coastguard Worker             size_t newTotalSize = mTotalSize + valueSize - oldValueBlob->getSize();
118*38e8c45fSAndroid Build Coastguard Worker             if (mMaxTotalSize < newTotalSize) {
119*38e8c45fSAndroid Build Coastguard Worker                 if (isCleanable()) {
120*38e8c45fSAndroid Build Coastguard Worker                     // Clean the cache and try again.
121*38e8c45fSAndroid Build Coastguard Worker                     clean();
122*38e8c45fSAndroid Build Coastguard Worker                     didClean = true;
123*38e8c45fSAndroid Build Coastguard Worker                     continue;
124*38e8c45fSAndroid Build Coastguard Worker                 } else {
125*38e8c45fSAndroid Build Coastguard Worker                     ALOGV("set: not caching new value because the total cache "
126*38e8c45fSAndroid Build Coastguard Worker                           "size limit would be exceeded: %zu (limit: %zu)",
127*38e8c45fSAndroid Build Coastguard Worker                           keySize + valueSize, mMaxTotalSize);
128*38e8c45fSAndroid Build Coastguard Worker                     return InsertResult::kNotEnoughSpace;
129*38e8c45fSAndroid Build Coastguard Worker                 }
130*38e8c45fSAndroid Build Coastguard Worker             }
131*38e8c45fSAndroid Build Coastguard Worker             index->setValue(valueBlob);
132*38e8c45fSAndroid Build Coastguard Worker             mTotalSize = newTotalSize;
133*38e8c45fSAndroid Build Coastguard Worker             ALOGV("set: updated existing cache entry with %zu byte key and %zu byte "
134*38e8c45fSAndroid Build Coastguard Worker                   "value",
135*38e8c45fSAndroid Build Coastguard Worker                   keySize, valueSize);
136*38e8c45fSAndroid Build Coastguard Worker         }
137*38e8c45fSAndroid Build Coastguard Worker         return didClean ? InsertResult::kDidClean : InsertResult::kInserted;
138*38e8c45fSAndroid Build Coastguard Worker     }
139*38e8c45fSAndroid Build Coastguard Worker }
140*38e8c45fSAndroid Build Coastguard Worker 
get(const void * key,size_t keySize,void * value,size_t valueSize)141*38e8c45fSAndroid Build Coastguard Worker size_t BlobCache::get(const void* key, size_t keySize, void* value, size_t valueSize) {
142*38e8c45fSAndroid Build Coastguard Worker     if (mMaxKeySize < keySize) {
143*38e8c45fSAndroid Build Coastguard Worker         ALOGV("get: not searching because the key is too large: %zu (limit %zu)", keySize,
144*38e8c45fSAndroid Build Coastguard Worker               mMaxKeySize);
145*38e8c45fSAndroid Build Coastguard Worker         return 0;
146*38e8c45fSAndroid Build Coastguard Worker     }
147*38e8c45fSAndroid Build Coastguard Worker     std::shared_ptr<Blob> cacheKey(new Blob(key, keySize, false));
148*38e8c45fSAndroid Build Coastguard Worker     CacheEntry cacheEntry(cacheKey, nullptr);
149*38e8c45fSAndroid Build Coastguard Worker     auto index = std::lower_bound(mCacheEntries.begin(), mCacheEntries.end(), cacheEntry);
150*38e8c45fSAndroid Build Coastguard Worker     if (index == mCacheEntries.end() || cacheEntry < *index) {
151*38e8c45fSAndroid Build Coastguard Worker         ALOGV("get: no cache entry found for key of size %zu", keySize);
152*38e8c45fSAndroid Build Coastguard Worker         return 0;
153*38e8c45fSAndroid Build Coastguard Worker     }
154*38e8c45fSAndroid Build Coastguard Worker 
155*38e8c45fSAndroid Build Coastguard Worker     // The key was found. Return the value if the caller's buffer is large
156*38e8c45fSAndroid Build Coastguard Worker     // enough.
157*38e8c45fSAndroid Build Coastguard Worker     std::shared_ptr<Blob> valueBlob(index->getValue());
158*38e8c45fSAndroid Build Coastguard Worker     size_t valueBlobSize = valueBlob->getSize();
159*38e8c45fSAndroid Build Coastguard Worker     if (valueBlobSize <= valueSize) {
160*38e8c45fSAndroid Build Coastguard Worker         ALOGV("get: copying %zu bytes to caller's buffer", valueBlobSize);
161*38e8c45fSAndroid Build Coastguard Worker         memcpy(value, valueBlob->getData(), valueBlobSize);
162*38e8c45fSAndroid Build Coastguard Worker     } else {
163*38e8c45fSAndroid Build Coastguard Worker         ALOGV("get: caller's buffer is too small for value: %zu (needs %zu)", valueSize,
164*38e8c45fSAndroid Build Coastguard Worker               valueBlobSize);
165*38e8c45fSAndroid Build Coastguard Worker     }
166*38e8c45fSAndroid Build Coastguard Worker     return valueBlobSize;
167*38e8c45fSAndroid Build Coastguard Worker }
168*38e8c45fSAndroid Build Coastguard Worker 
align4(size_t size)169*38e8c45fSAndroid Build Coastguard Worker static inline size_t align4(size_t size) {
170*38e8c45fSAndroid Build Coastguard Worker     return (size + 3) & ~3;
171*38e8c45fSAndroid Build Coastguard Worker }
172*38e8c45fSAndroid Build Coastguard Worker 
getFlattenedSize() const173*38e8c45fSAndroid Build Coastguard Worker size_t BlobCache::getFlattenedSize() const {
174*38e8c45fSAndroid Build Coastguard Worker     auto buildId = base::GetProperty("ro.build.id", "");
175*38e8c45fSAndroid Build Coastguard Worker     size_t size = align4(sizeof(Header) + buildId.size());
176*38e8c45fSAndroid Build Coastguard Worker     for (const CacheEntry& e : mCacheEntries) {
177*38e8c45fSAndroid Build Coastguard Worker         std::shared_ptr<Blob> const& keyBlob = e.getKey();
178*38e8c45fSAndroid Build Coastguard Worker         std::shared_ptr<Blob> const& valueBlob = e.getValue();
179*38e8c45fSAndroid Build Coastguard Worker         size += align4(sizeof(EntryHeader) + keyBlob->getSize() + valueBlob->getSize());
180*38e8c45fSAndroid Build Coastguard Worker     }
181*38e8c45fSAndroid Build Coastguard Worker     return size;
182*38e8c45fSAndroid Build Coastguard Worker }
183*38e8c45fSAndroid Build Coastguard Worker 
flatten(void * buffer,size_t size) const184*38e8c45fSAndroid Build Coastguard Worker int BlobCache::flatten(void* buffer, size_t size) const {
185*38e8c45fSAndroid Build Coastguard Worker     // Write the cache header
186*38e8c45fSAndroid Build Coastguard Worker     if (size < sizeof(Header)) {
187*38e8c45fSAndroid Build Coastguard Worker         ALOGE("flatten: not enough room for cache header");
188*38e8c45fSAndroid Build Coastguard Worker         return 0;
189*38e8c45fSAndroid Build Coastguard Worker     }
190*38e8c45fSAndroid Build Coastguard Worker     Header* header = reinterpret_cast<Header*>(buffer);
191*38e8c45fSAndroid Build Coastguard Worker     header->mMagicNumber = blobCacheMagic;
192*38e8c45fSAndroid Build Coastguard Worker     header->mBlobCacheVersion = blobCacheVersion;
193*38e8c45fSAndroid Build Coastguard Worker     header->mDeviceVersion = blobCacheDeviceVersion;
194*38e8c45fSAndroid Build Coastguard Worker     header->mNumEntries = mCacheEntries.size();
195*38e8c45fSAndroid Build Coastguard Worker     auto buildId = base::GetProperty("ro.build.id", "");
196*38e8c45fSAndroid Build Coastguard Worker     header->mBuildIdLength = buildId.size();
197*38e8c45fSAndroid Build Coastguard Worker     memcpy(header->mBuildId, buildId.c_str(), header->mBuildIdLength);
198*38e8c45fSAndroid Build Coastguard Worker 
199*38e8c45fSAndroid Build Coastguard Worker     // Write cache entries
200*38e8c45fSAndroid Build Coastguard Worker     uint8_t* byteBuffer = reinterpret_cast<uint8_t*>(buffer);
201*38e8c45fSAndroid Build Coastguard Worker     off_t byteOffset = align4(sizeof(Header) + header->mBuildIdLength);
202*38e8c45fSAndroid Build Coastguard Worker     for (const CacheEntry& e : mCacheEntries) {
203*38e8c45fSAndroid Build Coastguard Worker         std::shared_ptr<Blob> const& keyBlob = e.getKey();
204*38e8c45fSAndroid Build Coastguard Worker         std::shared_ptr<Blob> const& valueBlob = e.getValue();
205*38e8c45fSAndroid Build Coastguard Worker         size_t keySize = keyBlob->getSize();
206*38e8c45fSAndroid Build Coastguard Worker         size_t valueSize = valueBlob->getSize();
207*38e8c45fSAndroid Build Coastguard Worker 
208*38e8c45fSAndroid Build Coastguard Worker         size_t entrySize = sizeof(EntryHeader) + keySize + valueSize;
209*38e8c45fSAndroid Build Coastguard Worker         size_t totalSize = align4(entrySize);
210*38e8c45fSAndroid Build Coastguard Worker         if (byteOffset + totalSize > size) {
211*38e8c45fSAndroid Build Coastguard Worker             ALOGE("flatten: not enough room for cache entries");
212*38e8c45fSAndroid Build Coastguard Worker             return -EINVAL;
213*38e8c45fSAndroid Build Coastguard Worker         }
214*38e8c45fSAndroid Build Coastguard Worker 
215*38e8c45fSAndroid Build Coastguard Worker         EntryHeader* eheader = reinterpret_cast<EntryHeader*>(&byteBuffer[byteOffset]);
216*38e8c45fSAndroid Build Coastguard Worker         eheader->mKeySize = keySize;
217*38e8c45fSAndroid Build Coastguard Worker         eheader->mValueSize = valueSize;
218*38e8c45fSAndroid Build Coastguard Worker 
219*38e8c45fSAndroid Build Coastguard Worker         memcpy(eheader->mData, keyBlob->getData(), keySize);
220*38e8c45fSAndroid Build Coastguard Worker         memcpy(eheader->mData + keySize, valueBlob->getData(), valueSize);
221*38e8c45fSAndroid Build Coastguard Worker 
222*38e8c45fSAndroid Build Coastguard Worker         if (totalSize > entrySize) {
223*38e8c45fSAndroid Build Coastguard Worker             // We have padding bytes. Those will get written to storage, and contribute to the CRC,
224*38e8c45fSAndroid Build Coastguard Worker             // so make sure we zero-them to have reproducible results.
225*38e8c45fSAndroid Build Coastguard Worker             memset(eheader->mData + keySize + valueSize, 0, totalSize - entrySize);
226*38e8c45fSAndroid Build Coastguard Worker         }
227*38e8c45fSAndroid Build Coastguard Worker 
228*38e8c45fSAndroid Build Coastguard Worker         byteOffset += totalSize;
229*38e8c45fSAndroid Build Coastguard Worker     }
230*38e8c45fSAndroid Build Coastguard Worker 
231*38e8c45fSAndroid Build Coastguard Worker     return 0;
232*38e8c45fSAndroid Build Coastguard Worker }
233*38e8c45fSAndroid Build Coastguard Worker 
unflatten(void const * buffer,size_t size)234*38e8c45fSAndroid Build Coastguard Worker int BlobCache::unflatten(void const* buffer, size_t size) {
235*38e8c45fSAndroid Build Coastguard Worker     ATRACE_NAME("BlobCache::unflatten");
236*38e8c45fSAndroid Build Coastguard Worker 
237*38e8c45fSAndroid Build Coastguard Worker     // All errors should result in the BlobCache being in an empty state.
238*38e8c45fSAndroid Build Coastguard Worker     clear();
239*38e8c45fSAndroid Build Coastguard Worker 
240*38e8c45fSAndroid Build Coastguard Worker     // Read the cache header
241*38e8c45fSAndroid Build Coastguard Worker     if (size < sizeof(Header)) {
242*38e8c45fSAndroid Build Coastguard Worker         ALOGE("unflatten: not enough room for cache header");
243*38e8c45fSAndroid Build Coastguard Worker         return -EINVAL;
244*38e8c45fSAndroid Build Coastguard Worker     }
245*38e8c45fSAndroid Build Coastguard Worker     const Header* header = reinterpret_cast<const Header*>(buffer);
246*38e8c45fSAndroid Build Coastguard Worker     if (header->mMagicNumber != blobCacheMagic) {
247*38e8c45fSAndroid Build Coastguard Worker         ALOGE("unflatten: bad magic number: %" PRIu32, header->mMagicNumber);
248*38e8c45fSAndroid Build Coastguard Worker         return -EINVAL;
249*38e8c45fSAndroid Build Coastguard Worker     }
250*38e8c45fSAndroid Build Coastguard Worker     auto buildId = base::GetProperty("ro.build.id", "");
251*38e8c45fSAndroid Build Coastguard Worker     if (header->mBlobCacheVersion != blobCacheVersion ||
252*38e8c45fSAndroid Build Coastguard Worker         header->mDeviceVersion != blobCacheDeviceVersion ||
253*38e8c45fSAndroid Build Coastguard Worker         buildId.size() != header->mBuildIdLength ||
254*38e8c45fSAndroid Build Coastguard Worker         strncmp(buildId.c_str(), header->mBuildId, buildId.size())) {
255*38e8c45fSAndroid Build Coastguard Worker         // We treat version mismatches as an empty cache.
256*38e8c45fSAndroid Build Coastguard Worker         return 0;
257*38e8c45fSAndroid Build Coastguard Worker     }
258*38e8c45fSAndroid Build Coastguard Worker 
259*38e8c45fSAndroid Build Coastguard Worker     // Read cache entries
260*38e8c45fSAndroid Build Coastguard Worker     const uint8_t* byteBuffer = reinterpret_cast<const uint8_t*>(buffer);
261*38e8c45fSAndroid Build Coastguard Worker     off_t byteOffset = align4(sizeof(Header) + header->mBuildIdLength);
262*38e8c45fSAndroid Build Coastguard Worker     size_t numEntries = header->mNumEntries;
263*38e8c45fSAndroid Build Coastguard Worker     for (size_t i = 0; i < numEntries; i++) {
264*38e8c45fSAndroid Build Coastguard Worker         if (byteOffset + sizeof(EntryHeader) > size) {
265*38e8c45fSAndroid Build Coastguard Worker             clear();
266*38e8c45fSAndroid Build Coastguard Worker             ALOGE("unflatten: not enough room for cache entry headers");
267*38e8c45fSAndroid Build Coastguard Worker             return -EINVAL;
268*38e8c45fSAndroid Build Coastguard Worker         }
269*38e8c45fSAndroid Build Coastguard Worker 
270*38e8c45fSAndroid Build Coastguard Worker         const EntryHeader* eheader = reinterpret_cast<const EntryHeader*>(&byteBuffer[byteOffset]);
271*38e8c45fSAndroid Build Coastguard Worker         size_t keySize = eheader->mKeySize;
272*38e8c45fSAndroid Build Coastguard Worker         size_t valueSize = eheader->mValueSize;
273*38e8c45fSAndroid Build Coastguard Worker         size_t entrySize = sizeof(EntryHeader) + keySize + valueSize;
274*38e8c45fSAndroid Build Coastguard Worker 
275*38e8c45fSAndroid Build Coastguard Worker         size_t totalSize = align4(entrySize);
276*38e8c45fSAndroid Build Coastguard Worker         if (byteOffset + totalSize > size) {
277*38e8c45fSAndroid Build Coastguard Worker             clear();
278*38e8c45fSAndroid Build Coastguard Worker             ALOGE("unflatten: not enough room for cache entry headers");
279*38e8c45fSAndroid Build Coastguard Worker             return -EINVAL;
280*38e8c45fSAndroid Build Coastguard Worker         }
281*38e8c45fSAndroid Build Coastguard Worker 
282*38e8c45fSAndroid Build Coastguard Worker         const uint8_t* data = eheader->mData;
283*38e8c45fSAndroid Build Coastguard Worker         set(data, keySize, data + keySize, valueSize);
284*38e8c45fSAndroid Build Coastguard Worker 
285*38e8c45fSAndroid Build Coastguard Worker         byteOffset += totalSize;
286*38e8c45fSAndroid Build Coastguard Worker     }
287*38e8c45fSAndroid Build Coastguard Worker 
288*38e8c45fSAndroid Build Coastguard Worker     return 0;
289*38e8c45fSAndroid Build Coastguard Worker }
290*38e8c45fSAndroid Build Coastguard Worker 
blob_random()291*38e8c45fSAndroid Build Coastguard Worker long int BlobCache::blob_random() {
292*38e8c45fSAndroid Build Coastguard Worker #ifdef _WIN32
293*38e8c45fSAndroid Build Coastguard Worker     return rand();
294*38e8c45fSAndroid Build Coastguard Worker #else
295*38e8c45fSAndroid Build Coastguard Worker     return nrand48(mRandState);
296*38e8c45fSAndroid Build Coastguard Worker #endif
297*38e8c45fSAndroid Build Coastguard Worker }
298*38e8c45fSAndroid Build Coastguard Worker 
clean()299*38e8c45fSAndroid Build Coastguard Worker void BlobCache::clean() {
300*38e8c45fSAndroid Build Coastguard Worker     ATRACE_NAME("BlobCache::clean");
301*38e8c45fSAndroid Build Coastguard Worker 
302*38e8c45fSAndroid Build Coastguard Worker     // Remove a random cache entry until the total cache size gets below half
303*38e8c45fSAndroid Build Coastguard Worker     // the maximum total cache size.
304*38e8c45fSAndroid Build Coastguard Worker     while (mTotalSize > mMaxTotalSize / 2) {
305*38e8c45fSAndroid Build Coastguard Worker         size_t i = size_t(blob_random() % (mCacheEntries.size()));
306*38e8c45fSAndroid Build Coastguard Worker         const CacheEntry& entry(mCacheEntries[i]);
307*38e8c45fSAndroid Build Coastguard Worker         mTotalSize -= entry.getKey()->getSize() + entry.getValue()->getSize();
308*38e8c45fSAndroid Build Coastguard Worker         mCacheEntries.erase(mCacheEntries.begin() + i);
309*38e8c45fSAndroid Build Coastguard Worker     }
310*38e8c45fSAndroid Build Coastguard Worker }
311*38e8c45fSAndroid Build Coastguard Worker 
isCleanable() const312*38e8c45fSAndroid Build Coastguard Worker bool BlobCache::isCleanable() const {
313*38e8c45fSAndroid Build Coastguard Worker     return mTotalSize > mMaxTotalSize / 2;
314*38e8c45fSAndroid Build Coastguard Worker }
315*38e8c45fSAndroid Build Coastguard Worker 
Blob(const void * data,size_t size,bool copyData)316*38e8c45fSAndroid Build Coastguard Worker BlobCache::Blob::Blob(const void* data, size_t size, bool copyData)
317*38e8c45fSAndroid Build Coastguard Worker       : mData(copyData ? malloc(size) : data), mSize(size), mOwnsData(copyData) {
318*38e8c45fSAndroid Build Coastguard Worker     if (data != nullptr && copyData) {
319*38e8c45fSAndroid Build Coastguard Worker         memcpy(const_cast<void*>(mData), data, size);
320*38e8c45fSAndroid Build Coastguard Worker     }
321*38e8c45fSAndroid Build Coastguard Worker }
322*38e8c45fSAndroid Build Coastguard Worker 
~Blob()323*38e8c45fSAndroid Build Coastguard Worker BlobCache::Blob::~Blob() {
324*38e8c45fSAndroid Build Coastguard Worker     if (mOwnsData) {
325*38e8c45fSAndroid Build Coastguard Worker         free(const_cast<void*>(mData));
326*38e8c45fSAndroid Build Coastguard Worker     }
327*38e8c45fSAndroid Build Coastguard Worker }
328*38e8c45fSAndroid Build Coastguard Worker 
operator <(const Blob & rhs) const329*38e8c45fSAndroid Build Coastguard Worker bool BlobCache::Blob::operator<(const Blob& rhs) const {
330*38e8c45fSAndroid Build Coastguard Worker     if (mSize == rhs.mSize) {
331*38e8c45fSAndroid Build Coastguard Worker         return memcmp(mData, rhs.mData, mSize) < 0;
332*38e8c45fSAndroid Build Coastguard Worker     } else {
333*38e8c45fSAndroid Build Coastguard Worker         return mSize < rhs.mSize;
334*38e8c45fSAndroid Build Coastguard Worker     }
335*38e8c45fSAndroid Build Coastguard Worker }
336*38e8c45fSAndroid Build Coastguard Worker 
getData() const337*38e8c45fSAndroid Build Coastguard Worker const void* BlobCache::Blob::getData() const {
338*38e8c45fSAndroid Build Coastguard Worker     return mData;
339*38e8c45fSAndroid Build Coastguard Worker }
340*38e8c45fSAndroid Build Coastguard Worker 
getSize() const341*38e8c45fSAndroid Build Coastguard Worker size_t BlobCache::Blob::getSize() const {
342*38e8c45fSAndroid Build Coastguard Worker     return mSize;
343*38e8c45fSAndroid Build Coastguard Worker }
344*38e8c45fSAndroid Build Coastguard Worker 
CacheEntry()345*38e8c45fSAndroid Build Coastguard Worker BlobCache::CacheEntry::CacheEntry() {}
346*38e8c45fSAndroid Build Coastguard Worker 
CacheEntry(const std::shared_ptr<Blob> & key,const std::shared_ptr<Blob> & value)347*38e8c45fSAndroid Build Coastguard Worker BlobCache::CacheEntry::CacheEntry(const std::shared_ptr<Blob>& key,
348*38e8c45fSAndroid Build Coastguard Worker                                   const std::shared_ptr<Blob>& value)
349*38e8c45fSAndroid Build Coastguard Worker       : mKey(key), mValue(value) {}
350*38e8c45fSAndroid Build Coastguard Worker 
CacheEntry(const CacheEntry & ce)351*38e8c45fSAndroid Build Coastguard Worker BlobCache::CacheEntry::CacheEntry(const CacheEntry& ce) : mKey(ce.mKey), mValue(ce.mValue) {}
352*38e8c45fSAndroid Build Coastguard Worker 
operator <(const CacheEntry & rhs) const353*38e8c45fSAndroid Build Coastguard Worker bool BlobCache::CacheEntry::operator<(const CacheEntry& rhs) const {
354*38e8c45fSAndroid Build Coastguard Worker     return *mKey < *rhs.mKey;
355*38e8c45fSAndroid Build Coastguard Worker }
356*38e8c45fSAndroid Build Coastguard Worker 
operator =(const CacheEntry & rhs)357*38e8c45fSAndroid Build Coastguard Worker const BlobCache::CacheEntry& BlobCache::CacheEntry::operator=(const CacheEntry& rhs) {
358*38e8c45fSAndroid Build Coastguard Worker     mKey = rhs.mKey;
359*38e8c45fSAndroid Build Coastguard Worker     mValue = rhs.mValue;
360*38e8c45fSAndroid Build Coastguard Worker     return *this;
361*38e8c45fSAndroid Build Coastguard Worker }
362*38e8c45fSAndroid Build Coastguard Worker 
getKey() const363*38e8c45fSAndroid Build Coastguard Worker std::shared_ptr<BlobCache::Blob> BlobCache::CacheEntry::getKey() const {
364*38e8c45fSAndroid Build Coastguard Worker     return mKey;
365*38e8c45fSAndroid Build Coastguard Worker }
366*38e8c45fSAndroid Build Coastguard Worker 
getValue() const367*38e8c45fSAndroid Build Coastguard Worker std::shared_ptr<BlobCache::Blob> BlobCache::CacheEntry::getValue() const {
368*38e8c45fSAndroid Build Coastguard Worker     return mValue;
369*38e8c45fSAndroid Build Coastguard Worker }
370*38e8c45fSAndroid Build Coastguard Worker 
setValue(const std::shared_ptr<Blob> & value)371*38e8c45fSAndroid Build Coastguard Worker void BlobCache::CacheEntry::setValue(const std::shared_ptr<Blob>& value) {
372*38e8c45fSAndroid Build Coastguard Worker     mValue = value;
373*38e8c45fSAndroid Build Coastguard Worker }
374*38e8c45fSAndroid Build Coastguard Worker 
375*38e8c45fSAndroid Build Coastguard Worker } // namespace android
376