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