158c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis/* 258c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis ** Copyright 2011, The Android Open Source Project 358c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis ** 458c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis ** Licensed under the Apache License, Version 2.0 (the "License"); 558c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis ** you may not use this file except in compliance with the License. 658c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis ** You may obtain a copy of the License at 758c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis ** 858c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis ** http://www.apache.org/licenses/LICENSE-2.0 958c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis ** 1058c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis ** Unless required by applicable law or agreed to in writing, software 1158c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis ** distributed under the License is distributed on an "AS IS" BASIS, 1258c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1358c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis ** See the License for the specific language governing permissions and 1458c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis ** limitations under the License. 1558c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis */ 1658c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 1758c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis#define LOG_TAG "BlobCache" 1858c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis//#define LOG_NDEBUG 0 1958c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 2058c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis#include <stdlib.h> 2158c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis#include <string.h> 2258c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 2358c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis#include <utils/BlobCache.h> 240e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis#include <utils/Errors.h> 2558c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis#include <utils/Log.h> 2658c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 2758c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennisnamespace android { 2858c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 290e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis// BlobCache::Header::mMagicNumber value 300e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennisstatic const uint32_t blobCacheMagic = '_Bb$'; 310e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis 320e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis// BlobCache::Header::mBlobCacheVersion value 330e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennisstatic const uint32_t blobCacheVersion = 1; 340e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis 350e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis// BlobCache::Header::mDeviceVersion value 360e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennisstatic const uint32_t blobCacheDeviceVersion = 1; 370e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis 3858c8dd2aa9a8931a53923054679fb31fecc696c9Jamie GennisBlobCache::BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize): 3958c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis mMaxKeySize(maxKeySize), 4058c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis mMaxValueSize(maxValueSize), 4158c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis mMaxTotalSize(maxTotalSize), 4258c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis mTotalSize(0) { 4358c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); 44111280a8de1700f718744f48d163789473b9da30Kenny Root#ifdef _WIN32 45111280a8de1700f718744f48d163789473b9da30Kenny Root srand(now); 46111280a8de1700f718744f48d163789473b9da30Kenny Root#else 4758c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis mRandState[0] = (now >> 0) & 0xFFFF; 4858c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis mRandState[1] = (now >> 16) & 0xFFFF; 4958c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis mRandState[2] = (now >> 32) & 0xFFFF; 50111280a8de1700f718744f48d163789473b9da30Kenny Root#endif 516807e59e0ff943cc6225d46e3c33a8a7eae9b3d7Steve Block ALOGV("initializing random seed using %lld", now); 5258c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis} 5358c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 5458c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennisvoid BlobCache::set(const void* key, size_t keySize, const void* value, 5558c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis size_t valueSize) { 5658c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis if (mMaxKeySize < keySize) { 576807e59e0ff943cc6225d46e3c33a8a7eae9b3d7Steve Block ALOGV("set: not caching because the key is too large: %d (limit: %d)", 5858c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis keySize, mMaxKeySize); 5958c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis return; 6058c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis } 6158c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis if (mMaxValueSize < valueSize) { 626807e59e0ff943cc6225d46e3c33a8a7eae9b3d7Steve Block ALOGV("set: not caching because the value is too large: %d (limit: %d)", 6358c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis valueSize, mMaxValueSize); 6458c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis return; 6558c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis } 6658c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis if (mMaxTotalSize < keySize + valueSize) { 676807e59e0ff943cc6225d46e3c33a8a7eae9b3d7Steve Block ALOGV("set: not caching because the combined key/value size is too " 6858c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis "large: %d (limit: %d)", keySize + valueSize, mMaxTotalSize); 6958c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis return; 7058c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis } 7158c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis if (keySize == 0) { 7232397c1cd3327905173b36baa6fd1c579bc328ffSteve Block ALOGW("set: not caching because keySize is 0"); 7358c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis return; 7458c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis } 7558c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis if (valueSize <= 0) { 7632397c1cd3327905173b36baa6fd1c579bc328ffSteve Block ALOGW("set: not caching because valueSize is 0"); 7758c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis return; 7858c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis } 7958c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 8058c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis sp<Blob> dummyKey(new Blob(key, keySize, false)); 8158c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis CacheEntry dummyEntry(dummyKey, NULL); 8258c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 8358c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis while (true) { 8458c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis ssize_t index = mCacheEntries.indexOf(dummyEntry); 8558c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis if (index < 0) { 8658c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis // Create a new cache entry. 8758c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis sp<Blob> keyBlob(new Blob(key, keySize, true)); 8858c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis sp<Blob> valueBlob(new Blob(value, valueSize, true)); 8958c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis size_t newTotalSize = mTotalSize + keySize + valueSize; 9058c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis if (mMaxTotalSize < newTotalSize) { 9158c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis if (isCleanable()) { 9258c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis // Clean the cache and try again. 9358c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis clean(); 9458c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis continue; 9558c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis } else { 966807e59e0ff943cc6225d46e3c33a8a7eae9b3d7Steve Block ALOGV("set: not caching new key/value pair because the " 9758c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis "total cache size limit would be exceeded: %d " 9858c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis "(limit: %d)", 9958c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis keySize + valueSize, mMaxTotalSize); 10058c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis break; 10158c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis } 10258c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis } 10358c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis mCacheEntries.add(CacheEntry(keyBlob, valueBlob)); 10458c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis mTotalSize = newTotalSize; 1056807e59e0ff943cc6225d46e3c33a8a7eae9b3d7Steve Block ALOGV("set: created new cache entry with %d byte key and %d byte value", 10658c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis keySize, valueSize); 10758c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis } else { 10858c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis // Update the existing cache entry. 10958c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis sp<Blob> valueBlob(new Blob(value, valueSize, true)); 11058c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis sp<Blob> oldValueBlob(mCacheEntries[index].getValue()); 11158c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis size_t newTotalSize = mTotalSize + valueSize - oldValueBlob->getSize(); 11258c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis if (mMaxTotalSize < newTotalSize) { 11358c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis if (isCleanable()) { 11458c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis // Clean the cache and try again. 11558c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis clean(); 11658c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis continue; 11758c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis } else { 1186807e59e0ff943cc6225d46e3c33a8a7eae9b3d7Steve Block ALOGV("set: not caching new value because the total cache " 11958c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis "size limit would be exceeded: %d (limit: %d)", 12058c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis keySize + valueSize, mMaxTotalSize); 12158c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis break; 12258c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis } 12358c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis } 12458c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis mCacheEntries.editItemAt(index).setValue(valueBlob); 12558c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis mTotalSize = newTotalSize; 1266807e59e0ff943cc6225d46e3c33a8a7eae9b3d7Steve Block ALOGV("set: updated existing cache entry with %d byte key and %d byte " 12758c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis "value", keySize, valueSize); 12858c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis } 12958c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis break; 13058c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis } 13158c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis} 13258c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 13358c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennissize_t BlobCache::get(const void* key, size_t keySize, void* value, 13458c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis size_t valueSize) { 13558c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis if (mMaxKeySize < keySize) { 1366807e59e0ff943cc6225d46e3c33a8a7eae9b3d7Steve Block ALOGV("get: not searching because the key is too large: %d (limit %d)", 13758c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis keySize, mMaxKeySize); 13858c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis return 0; 13958c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis } 14058c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis sp<Blob> dummyKey(new Blob(key, keySize, false)); 14158c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis CacheEntry dummyEntry(dummyKey, NULL); 14258c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis ssize_t index = mCacheEntries.indexOf(dummyEntry); 14358c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis if (index < 0) { 1446807e59e0ff943cc6225d46e3c33a8a7eae9b3d7Steve Block ALOGV("get: no cache entry found for key of size %d", keySize); 14558c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis return 0; 14658c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis } 14758c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 14858c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis // The key was found. Return the value if the caller's buffer is large 14958c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis // enough. 15058c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis sp<Blob> valueBlob(mCacheEntries[index].getValue()); 15158c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis size_t valueBlobSize = valueBlob->getSize(); 15258c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis if (valueBlobSize <= valueSize) { 1536807e59e0ff943cc6225d46e3c33a8a7eae9b3d7Steve Block ALOGV("get: copying %d bytes to caller's buffer", valueBlobSize); 15458c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis memcpy(value, valueBlob->getData(), valueBlobSize); 15558c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis } else { 1566807e59e0ff943cc6225d46e3c33a8a7eae9b3d7Steve Block ALOGV("get: caller's buffer is too small for value: %d (needs %d)", 15758c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis valueSize, valueBlobSize); 15858c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis } 15958c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis return valueBlobSize; 16058c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis} 16158c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 1620e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennisstatic inline size_t align4(size_t size) { 1630e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis return (size + 3) & ~3; 1640e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis} 1650e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis 1660e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennissize_t BlobCache::getFlattenedSize() const { 1670e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis size_t size = sizeof(Header); 1680e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis for (size_t i = 0; i < mCacheEntries.size(); i++) { 1690e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis const CacheEntry& e(mCacheEntries[i]); 1700e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis sp<Blob> keyBlob = e.getKey(); 1710e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis sp<Blob> valueBlob = e.getValue(); 1720e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis size = align4(size); 1730e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis size += sizeof(EntryHeader) + keyBlob->getSize() + 1740e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis valueBlob->getSize(); 1750e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis } 1760e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis return size; 1770e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis} 1780e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis 1790e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennissize_t BlobCache::getFdCount() const { 1800e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis return 0; 1810e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis} 1820e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis 1830e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennisstatus_t BlobCache::flatten(void* buffer, size_t size, int fds[], size_t count) 1840e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis const { 1850e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis if (count != 0) { 1860ae8c14b4b915b318250484eff9a18700cd934c3Andrew Hsieh ALOGE("flatten: nonzero fd count: %zu", count); 1870e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis return BAD_VALUE; 1880e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis } 1890e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis 1900e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis // Write the cache header 1910e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis if (size < sizeof(Header)) { 192e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("flatten: not enough room for cache header"); 1930e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis return BAD_VALUE; 1940e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis } 1950e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis Header* header = reinterpret_cast<Header*>(buffer); 1960e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis header->mMagicNumber = blobCacheMagic; 1970e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis header->mBlobCacheVersion = blobCacheVersion; 1980e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis header->mDeviceVersion = blobCacheDeviceVersion; 1990e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis header->mNumEntries = mCacheEntries.size(); 2000e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis 2010e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis // Write cache entries 2020e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis uint8_t* byteBuffer = reinterpret_cast<uint8_t*>(buffer); 2030e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis off_t byteOffset = align4(sizeof(Header)); 2040e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis for (size_t i = 0; i < mCacheEntries.size(); i++) { 2050e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis const CacheEntry& e(mCacheEntries[i]); 2060e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis sp<Blob> keyBlob = e.getKey(); 2070e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis sp<Blob> valueBlob = e.getValue(); 2080e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis size_t keySize = keyBlob->getSize(); 2090e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis size_t valueSize = valueBlob->getSize(); 2100e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis 2110e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis size_t entrySize = sizeof(EntryHeader) + keySize + valueSize; 2120e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis if (byteOffset + entrySize > size) { 213e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("flatten: not enough room for cache entries"); 2140e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis return BAD_VALUE; 2150e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis } 2160e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis 2170e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis EntryHeader* eheader = reinterpret_cast<EntryHeader*>( 2180e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis &byteBuffer[byteOffset]); 2190e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis eheader->mKeySize = keySize; 2200e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis eheader->mValueSize = valueSize; 2210e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis 2220e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis memcpy(eheader->mData, keyBlob->getData(), keySize); 2230e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis memcpy(eheader->mData + keySize, valueBlob->getData(), valueSize); 2240e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis 2250e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis byteOffset += align4(entrySize); 2260e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis } 2270e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis 2280e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis return OK; 2290e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis} 2300e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis 2310e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennisstatus_t BlobCache::unflatten(void const* buffer, size_t size, int fds[], 2320e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis size_t count) { 2330e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis // All errors should result in the BlobCache being in an empty state. 2340e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis mCacheEntries.clear(); 2350e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis 2360e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis if (count != 0) { 2370ae8c14b4b915b318250484eff9a18700cd934c3Andrew Hsieh ALOGE("unflatten: nonzero fd count: %zu", count); 2380e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis return BAD_VALUE; 2390e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis } 2400e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis 2410e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis // Read the cache header 2420e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis if (size < sizeof(Header)) { 243e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("unflatten: not enough room for cache header"); 2440e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis return BAD_VALUE; 2450e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis } 2460e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis const Header* header = reinterpret_cast<const Header*>(buffer); 2470e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis if (header->mMagicNumber != blobCacheMagic) { 248e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("unflatten: bad magic number: %d", header->mMagicNumber); 2490e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis return BAD_VALUE; 2500e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis } 2510e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis if (header->mBlobCacheVersion != blobCacheVersion || 2520e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis header->mDeviceVersion != blobCacheDeviceVersion) { 2530e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis // We treat version mismatches as an empty cache. 2540e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis return OK; 2550e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis } 2560e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis 2570e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis // Read cache entries 2580e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis const uint8_t* byteBuffer = reinterpret_cast<const uint8_t*>(buffer); 2590e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis off_t byteOffset = align4(sizeof(Header)); 2600e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis size_t numEntries = header->mNumEntries; 2610e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis for (size_t i = 0; i < numEntries; i++) { 2620e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis if (byteOffset + sizeof(EntryHeader) > size) { 2630e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis mCacheEntries.clear(); 264e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("unflatten: not enough room for cache entry headers"); 2650e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis return BAD_VALUE; 2660e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis } 2670e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis 2680e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis const EntryHeader* eheader = reinterpret_cast<const EntryHeader*>( 2690e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis &byteBuffer[byteOffset]); 2700e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis size_t keySize = eheader->mKeySize; 2710e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis size_t valueSize = eheader->mValueSize; 2720e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis size_t entrySize = sizeof(EntryHeader) + keySize + valueSize; 2730e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis 2740e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis if (byteOffset + entrySize > size) { 2750e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis mCacheEntries.clear(); 276e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("unflatten: not enough room for cache entry headers"); 2770e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis return BAD_VALUE; 2780e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis } 2790e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis 2800e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis const uint8_t* data = eheader->mData; 2810e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis set(data, keySize, data + keySize, valueSize); 2820e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis 2830e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis byteOffset += align4(entrySize); 2840e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis } 2850e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis 2860e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis return OK; 2870e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis} 2880e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis 289111280a8de1700f718744f48d163789473b9da30Kenny Rootlong int BlobCache::blob_random() { 290111280a8de1700f718744f48d163789473b9da30Kenny Root#ifdef _WIN32 291111280a8de1700f718744f48d163789473b9da30Kenny Root return rand(); 292111280a8de1700f718744f48d163789473b9da30Kenny Root#else 293111280a8de1700f718744f48d163789473b9da30Kenny Root return nrand48(mRandState); 294111280a8de1700f718744f48d163789473b9da30Kenny Root#endif 295111280a8de1700f718744f48d163789473b9da30Kenny Root} 296111280a8de1700f718744f48d163789473b9da30Kenny Root 29758c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennisvoid BlobCache::clean() { 29858c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis // Remove a random cache entry until the total cache size gets below half 29958c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis // the maximum total cache size. 30058c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis while (mTotalSize > mMaxTotalSize / 2) { 301111280a8de1700f718744f48d163789473b9da30Kenny Root size_t i = size_t(blob_random() % (mCacheEntries.size())); 30258c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis const CacheEntry& entry(mCacheEntries[i]); 30358c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis mTotalSize -= entry.getKey()->getSize() + entry.getValue()->getSize(); 30458c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis mCacheEntries.removeAt(i); 30558c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis } 30658c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis} 30758c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 30858c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennisbool BlobCache::isCleanable() const { 30958c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis return mTotalSize > mMaxTotalSize / 2; 31058c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis} 31158c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 31258c8dd2aa9a8931a53923054679fb31fecc696c9Jamie GennisBlobCache::Blob::Blob(const void* data, size_t size, bool copyData): 31358c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis mData(copyData ? malloc(size) : data), 31458c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis mSize(size), 31558c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis mOwnsData(copyData) { 3160e1bc174293d4802f06641187dc5bf632f4e938aJamie Gennis if (data != NULL && copyData) { 31758c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis memcpy(const_cast<void*>(mData), data, size); 31858c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis } 31958c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis} 32058c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 32158c8dd2aa9a8931a53923054679fb31fecc696c9Jamie GennisBlobCache::Blob::~Blob() { 32258c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis if (mOwnsData) { 32358c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis free(const_cast<void*>(mData)); 32458c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis } 32558c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis} 32658c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 32758c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennisbool BlobCache::Blob::operator<(const Blob& rhs) const { 32858c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis if (mSize == rhs.mSize) { 32958c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis return memcmp(mData, rhs.mData, mSize) < 0; 33058c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis } else { 33158c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis return mSize < rhs.mSize; 33258c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis } 33358c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis} 33458c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 33558c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennisconst void* BlobCache::Blob::getData() const { 33658c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis return mData; 33758c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis} 33858c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 33958c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennissize_t BlobCache::Blob::getSize() const { 34058c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis return mSize; 34158c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis} 34258c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 34358c8dd2aa9a8931a53923054679fb31fecc696c9Jamie GennisBlobCache::CacheEntry::CacheEntry() { 34458c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis} 34558c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 34658c8dd2aa9a8931a53923054679fb31fecc696c9Jamie GennisBlobCache::CacheEntry::CacheEntry(const sp<Blob>& key, const sp<Blob>& value): 34758c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis mKey(key), 34858c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis mValue(value) { 34958c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis} 35058c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 35158c8dd2aa9a8931a53923054679fb31fecc696c9Jamie GennisBlobCache::CacheEntry::CacheEntry(const CacheEntry& ce): 35258c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis mKey(ce.mKey), 35358c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis mValue(ce.mValue) { 35458c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis} 35558c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 35658c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennisbool BlobCache::CacheEntry::operator<(const CacheEntry& rhs) const { 35758c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis return *mKey < *rhs.mKey; 35858c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis} 35958c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 36058c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennisconst BlobCache::CacheEntry& BlobCache::CacheEntry::operator=(const CacheEntry& rhs) { 36158c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis mKey = rhs.mKey; 36258c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis mValue = rhs.mValue; 36358c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis return *this; 36458c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis} 36558c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 36658c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennissp<BlobCache::Blob> BlobCache::CacheEntry::getKey() const { 36758c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis return mKey; 36858c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis} 36958c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 37058c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennissp<BlobCache::Blob> BlobCache::CacheEntry::getValue() const { 37158c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis return mValue; 37258c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis} 37358c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 37458c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennisvoid BlobCache::CacheEntry::setValue(const sp<Blob>& value) { 37558c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis mValue = value; 37658c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis} 37758c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis 37858c8dd2aa9a8931a53923054679fb31fecc696c9Jamie Gennis} // namespace android 379