1aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis/* 2aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis ** Copyright 2011, The Android Open Source Project 3aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis ** 4aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis ** Licensed under the Apache License, Version 2.0 (the "License"); 5aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis ** you may not use this file except in compliance with the License. 6aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis ** You may obtain a copy of the License at 7aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis ** 8aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis ** http://www.apache.org/licenses/LICENSE-2.0 9aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis ** 10aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis ** Unless required by applicable law or agreed to in writing, software 11aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis ** distributed under the License is distributed on an "AS IS" BASIS, 12aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis ** See the License for the specific language governing permissions and 14aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis ** limitations under the License. 15aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis */ 16aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 1739c24a20bbc697630d2b92c251b70c04d6f9d00cMathias Agopian#include "../egl_impl.h" 1839c24a20bbc697630d2b92c251b70c04d6f9d00cMathias Agopian 19aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis#include "egl_cache.h" 20aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis#include "egl_display.h" 21aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis#include "egldefs.h" 22aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 2398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis#include <fcntl.h> 2498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis#include <sys/mman.h> 2598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis#include <sys/stat.h> 2698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis#include <sys/types.h> 2798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis#include <unistd.h> 2898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 2989c1d61c16c786ecfd258a43fed24bcf8f8456edJamie Gennis#ifndef MAX_EGL_CACHE_ENTRY_SIZE 3089c1d61c16c786ecfd258a43fed24bcf8f8456edJamie Gennis#define MAX_EGL_CACHE_ENTRY_SIZE (16 * 1024); 3189c1d61c16c786ecfd258a43fed24bcf8f8456edJamie Gennis#endif 3289c1d61c16c786ecfd258a43fed24bcf8f8456edJamie Gennis 33f478e6d18cb9eba1ded1f124ce16a899d271689eJamie Gennis#ifndef MAX_EGL_CACHE_KEY_SIZE 34f478e6d18cb9eba1ded1f124ce16a899d271689eJamie Gennis#define MAX_EGL_CACHE_KEY_SIZE (1024); 35f478e6d18cb9eba1ded1f124ce16a899d271689eJamie Gennis#endif 36f478e6d18cb9eba1ded1f124ce16a899d271689eJamie Gennis 3789c1d61c16c786ecfd258a43fed24bcf8f8456edJamie Gennis#ifndef MAX_EGL_CACHE_SIZE 3889c1d61c16c786ecfd258a43fed24bcf8f8456edJamie Gennis#define MAX_EGL_CACHE_SIZE (64 * 1024); 3989c1d61c16c786ecfd258a43fed24bcf8f8456edJamie Gennis#endif 4089c1d61c16c786ecfd258a43fed24bcf8f8456edJamie Gennis 41766010858ea7696d64f1b559413670bdd8627595Jamie Gennis// Cache size limits. 42f478e6d18cb9eba1ded1f124ce16a899d271689eJamie Gennisstatic const size_t maxKeySize = MAX_EGL_CACHE_KEY_SIZE; 4389c1d61c16c786ecfd258a43fed24bcf8f8456edJamie Gennisstatic const size_t maxValueSize = MAX_EGL_CACHE_ENTRY_SIZE; 4489c1d61c16c786ecfd258a43fed24bcf8f8456edJamie Gennisstatic const size_t maxTotalSize = MAX_EGL_CACHE_SIZE; 45766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 4698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis// Cache file header 4798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennisstatic const char* cacheFileMagic = "EGL$"; 4898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennisstatic const size_t cacheFileHeaderSize = 8; 4998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 5099c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis// The time in seconds to wait before saving newly inserted cache entries. 5199c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennisstatic const unsigned int deferredSaveDelay = 4; 5299c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis 53aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// ---------------------------------------------------------------------------- 54aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennisnamespace android { 55aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// ---------------------------------------------------------------------------- 56aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 57aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis#define BC_EXT_STR "EGL_ANDROID_blob_cache" 58aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 59aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// 60766010858ea7696d64f1b559413670bdd8627595Jamie Gennis// Callback functions passed to EGL. 61aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// 62c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennisstatic void setBlob(const void* key, EGLsizeiANDROID keySize, 63c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennis const void* value, EGLsizeiANDROID valueSize) { 64766010858ea7696d64f1b559413670bdd8627595Jamie Gennis egl_cache_t::get()->setBlob(key, keySize, value, valueSize); 65766010858ea7696d64f1b559413670bdd8627595Jamie Gennis} 66aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 67c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennisstatic EGLsizeiANDROID getBlob(const void* key, EGLsizeiANDROID keySize, 68c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennis void* value, EGLsizeiANDROID valueSize) { 69766010858ea7696d64f1b559413670bdd8627595Jamie Gennis return egl_cache_t::get()->getBlob(key, keySize, value, valueSize); 70766010858ea7696d64f1b559413670bdd8627595Jamie Gennis} 71aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 72aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// 73aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// egl_cache_t definition 74aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// 75766010858ea7696d64f1b559413670bdd8627595Jamie Gennisegl_cache_t::egl_cache_t() : 76766010858ea7696d64f1b559413670bdd8627595Jamie Gennis mInitialized(false), 77766010858ea7696d64f1b559413670bdd8627595Jamie Gennis mBlobCache(NULL) { 78aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis} 79aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 80766010858ea7696d64f1b559413670bdd8627595Jamie Gennisegl_cache_t::~egl_cache_t() { 81aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis} 82aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 8398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennisegl_cache_t egl_cache_t::sCache; 8498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 85aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennisegl_cache_t* egl_cache_t::get() { 8698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return &sCache; 87aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis} 88aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 89aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennisvoid egl_cache_t::initialize(egl_display_t *display) { 90766010858ea7696d64f1b559413670bdd8627595Jamie Gennis Mutex::Autolock lock(mMutex); 91ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian 92ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian egl_connection_t* const cnx = &gEGLImpl; 93ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) { 94ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian const char* exts = display->disp.queryString.extensions; 95ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian size_t bcExtLen = strlen(BC_EXT_STR); 96ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian size_t extsLen = strlen(exts); 97ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian bool equal = !strcmp(BC_EXT_STR, exts); 98ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian bool atStart = !strncmp(BC_EXT_STR " ", exts, bcExtLen+1); 99ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian bool atEnd = (bcExtLen+1) < extsLen && 100ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian !strcmp(" " BC_EXT_STR, exts + extsLen - (bcExtLen+1)); 101ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian bool inMiddle = strstr(exts, " " BC_EXT_STR " "); 102ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian if (equal || atStart || atEnd || inMiddle) { 103ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian PFNEGLSETBLOBCACHEFUNCSANDROIDPROC eglSetBlobCacheFuncsANDROID; 104ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian eglSetBlobCacheFuncsANDROID = 105ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian reinterpret_cast<PFNEGLSETBLOBCACHEFUNCSANDROIDPROC>( 106c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennis cnx->egl.eglGetProcAddress( 107c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennis "eglSetBlobCacheFuncsANDROID")); 108ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian if (eglSetBlobCacheFuncsANDROID == NULL) { 109ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian ALOGE("EGL_ANDROID_blob_cache advertised, " 110ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian "but unable to get eglSetBlobCacheFuncsANDROID"); 111ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian return; 112ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian } 113ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian 114ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian eglSetBlobCacheFuncsANDROID(display->disp.dpy, 115ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian android::setBlob, android::getBlob); 116ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian EGLint err = cnx->egl.eglGetError(); 117ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian if (err != EGL_SUCCESS) { 118ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian ALOGE("eglSetBlobCacheFuncsANDROID resulted in an error: " 119ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian "%#x", err); 120aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis } 121aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis } 122aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis } 123ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian 124766010858ea7696d64f1b559413670bdd8627595Jamie Gennis mInitialized = true; 125766010858ea7696d64f1b559413670bdd8627595Jamie Gennis} 126766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 127766010858ea7696d64f1b559413670bdd8627595Jamie Gennisvoid egl_cache_t::terminate() { 128766010858ea7696d64f1b559413670bdd8627595Jamie Gennis Mutex::Autolock lock(mMutex); 1295539e219de5ffa93e9f22b30dacf7c28e7f7a0beJamie Gennis saveBlobCacheLocked(); 1305539e219de5ffa93e9f22b30dacf7c28e7f7a0beJamie Gennis mBlobCache = NULL; 131766010858ea7696d64f1b559413670bdd8627595Jamie Gennis} 132766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 133c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennisvoid egl_cache_t::setBlob(const void* key, EGLsizeiANDROID keySize, 134c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennis const void* value, EGLsizeiANDROID valueSize) { 135766010858ea7696d64f1b559413670bdd8627595Jamie Gennis Mutex::Autolock lock(mMutex); 136766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 137766010858ea7696d64f1b559413670bdd8627595Jamie Gennis if (keySize < 0 || valueSize < 0) { 13832397c1cd3327905173b36baa6fd1c579bc328ffSteve Block ALOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed"); 139766010858ea7696d64f1b559413670bdd8627595Jamie Gennis return; 140766010858ea7696d64f1b559413670bdd8627595Jamie Gennis } 141766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 142766010858ea7696d64f1b559413670bdd8627595Jamie Gennis if (mInitialized) { 143766010858ea7696d64f1b559413670bdd8627595Jamie Gennis sp<BlobCache> bc = getBlobCacheLocked(); 144766010858ea7696d64f1b559413670bdd8627595Jamie Gennis bc->set(key, keySize, value, valueSize); 14599c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis 14699c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis if (!mSavePending) { 14799c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis class DeferredSaveThread : public Thread { 14899c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis public: 14999c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis DeferredSaveThread() : Thread(false) {} 15099c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis 15199c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis virtual bool threadLoop() { 15299c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis sleep(deferredSaveDelay); 15399c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis egl_cache_t* c = egl_cache_t::get(); 15499c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis Mutex::Autolock lock(c->mMutex); 15599c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis if (c->mInitialized) { 15699c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis c->saveBlobCacheLocked(); 15799c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis } 15899c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis c->mSavePending = false; 15999c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis return false; 16099c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis } 16199c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis }; 16299c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis 16399c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis // The thread will hold a strong ref to itself until it has finished 16499c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis // running, so there's no need to keep a ref around. 16599c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis sp<Thread> deferredSaveThread(new DeferredSaveThread()); 16699c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis mSavePending = true; 16799c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis deferredSaveThread->run(); 16899c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis } 169766010858ea7696d64f1b559413670bdd8627595Jamie Gennis } 170766010858ea7696d64f1b559413670bdd8627595Jamie Gennis} 171766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 172c42fcf05ce253d5342993b28c412be16e61efffbJamie GennisEGLsizeiANDROID egl_cache_t::getBlob(const void* key, EGLsizeiANDROID keySize, 173c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennis void* value, EGLsizeiANDROID valueSize) { 174766010858ea7696d64f1b559413670bdd8627595Jamie Gennis Mutex::Autolock lock(mMutex); 175766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 176766010858ea7696d64f1b559413670bdd8627595Jamie Gennis if (keySize < 0 || valueSize < 0) { 17732397c1cd3327905173b36baa6fd1c579bc328ffSteve Block ALOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed"); 178766010858ea7696d64f1b559413670bdd8627595Jamie Gennis return 0; 179766010858ea7696d64f1b559413670bdd8627595Jamie Gennis } 180766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 181766010858ea7696d64f1b559413670bdd8627595Jamie Gennis if (mInitialized) { 182766010858ea7696d64f1b559413670bdd8627595Jamie Gennis sp<BlobCache> bc = getBlobCacheLocked(); 183766010858ea7696d64f1b559413670bdd8627595Jamie Gennis return bc->get(key, keySize, value, valueSize); 184766010858ea7696d64f1b559413670bdd8627595Jamie Gennis } 185766010858ea7696d64f1b559413670bdd8627595Jamie Gennis return 0; 186766010858ea7696d64f1b559413670bdd8627595Jamie Gennis} 187766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 18898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennisvoid egl_cache_t::setCacheFilename(const char* filename) { 18998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis Mutex::Autolock lock(mMutex); 19098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis mFilename = filename; 19198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis} 19298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 193766010858ea7696d64f1b559413670bdd8627595Jamie Gennissp<BlobCache> egl_cache_t::getBlobCacheLocked() { 194766010858ea7696d64f1b559413670bdd8627595Jamie Gennis if (mBlobCache == NULL) { 195766010858ea7696d64f1b559413670bdd8627595Jamie Gennis mBlobCache = new BlobCache(maxKeySize, maxValueSize, maxTotalSize); 196766010858ea7696d64f1b559413670bdd8627595Jamie Gennis loadBlobCacheLocked(); 197766010858ea7696d64f1b559413670bdd8627595Jamie Gennis } 198766010858ea7696d64f1b559413670bdd8627595Jamie Gennis return mBlobCache; 199766010858ea7696d64f1b559413670bdd8627595Jamie Gennis} 200766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 20198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennisstatic uint32_t crc32c(const uint8_t* buf, size_t len) { 20298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis const uint32_t polyBits = 0x82F63B78; 20398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis uint32_t r = 0; 20498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis for (size_t i = 0; i < len; i++) { 20598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis r ^= buf[i]; 20698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis for (int j = 0; j < 8; j++) { 20798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (r & 1) { 20898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis r = (r >> 1) ^ polyBits; 20998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } else { 21098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis r >>= 1; 21198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 21298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 21398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 21498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return r; 21598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis} 21698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 217766010858ea7696d64f1b559413670bdd8627595Jamie Gennisvoid egl_cache_t::saveBlobCacheLocked() { 2185539e219de5ffa93e9f22b30dacf7c28e7f7a0beJamie Gennis if (mFilename.length() > 0 && mBlobCache != NULL) { 21998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis size_t cacheSize = mBlobCache->getFlattenedSize(); 22098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis size_t headerSize = cacheFileHeaderSize; 22198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis const char* fname = mFilename.string(); 22298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 22398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis // Try to create the file with no permissions so we can write it 22498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis // without anyone trying to read it. 22598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis int fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0); 22698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (fd == -1) { 22798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (errno == EEXIST) { 22898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis // The file exists, delete it and try again. 22998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (unlink(fname) == -1) { 23098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis // No point in retrying if the unlink failed. 231e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("error unlinking cache file %s: %s (%d)", fname, 23298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis strerror(errno), errno); 23398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 23498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 23598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis // Retry now that we've unlinked the file. 23698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0); 23798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 23898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (fd == -1) { 239e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("error creating cache file %s: %s (%d)", fname, 24098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis strerror(errno), errno); 24198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 24298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 24398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 24498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 24598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis size_t fileSize = headerSize + cacheSize; 24698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 247a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta uint8_t* buf = new uint8_t [fileSize]; 248a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta if (!buf) { 249a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta ALOGE("error allocating buffer for cache contents: %s (%d)", 250a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta strerror(errno), errno); 25198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 25298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis unlink(fname); 25398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 25498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 25598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 256e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian status_t err = mBlobCache->flatten(buf + headerSize, cacheSize); 25798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (err != OK) { 258e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("error writing cache contents: %s (%d)", strerror(-err), 25998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis -err); 260a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta delete [] buf; 26198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 26298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis unlink(fname); 26398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 26498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 26598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 26698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis // Write the file magic and CRC 26798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis memcpy(buf, cacheFileMagic, 4); 26898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4); 26998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis *crc = crc32c(buf + headerSize, cacheSize); 27098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 271a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta if (write(fd, buf, fileSize) == -1) { 272a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta ALOGE("error writing cache file: %s (%d)", strerror(errno), 273a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta errno); 274a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta delete [] buf; 275a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta close(fd); 276a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta unlink(fname); 277a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta return; 278a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta } 279a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta 280a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta delete [] buf; 28198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis fchmod(fd, S_IRUSR); 28298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 28398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 284766010858ea7696d64f1b559413670bdd8627595Jamie Gennis} 285766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 286766010858ea7696d64f1b559413670bdd8627595Jamie Gennisvoid egl_cache_t::loadBlobCacheLocked() { 28798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (mFilename.length() > 0) { 28898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis size_t headerSize = cacheFileHeaderSize; 28998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 29098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis int fd = open(mFilename.string(), O_RDONLY, 0); 29198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (fd == -1) { 29298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (errno != ENOENT) { 293e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("error opening cache file %s: %s (%d)", mFilename.string(), 29498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis strerror(errno), errno); 29598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 29698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 29798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 29898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 29998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis struct stat statBuf; 30098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (fstat(fd, &statBuf) == -1) { 301e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("error stat'ing cache file: %s (%d)", strerror(errno), errno); 30298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 30398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 30498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 30598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 30698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis // Sanity check the size before trying to mmap it. 30798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis size_t fileSize = statBuf.st_size; 30898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (fileSize > maxTotalSize * 2) { 309e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("cache file is too large: %#llx", statBuf.st_size); 31098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 31198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 31298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 31398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 31498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(NULL, fileSize, 31598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis PROT_READ, MAP_PRIVATE, fd, 0)); 31698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (buf == MAP_FAILED) { 317e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("error mmaping cache file: %s (%d)", strerror(errno), 31898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis errno); 31998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 32098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 32198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 32298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 32398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis // Check the file magic and CRC 32498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis size_t cacheSize = fileSize - headerSize; 32598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (memcmp(buf, cacheFileMagic, 4) != 0) { 326e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("cache file has bad mojo"); 32798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 32898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 32998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 33098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4); 33198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (crc32c(buf + headerSize, cacheSize) != *crc) { 332e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("cache file failed CRC check"); 33398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 33498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 33598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 33698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 337e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian status_t err = mBlobCache->unflatten(buf + headerSize, cacheSize); 33898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (err != OK) { 339e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("error reading cache contents: %s (%d)", strerror(-err), 34098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis -err); 34198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis munmap(buf, fileSize); 34298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 34398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 34498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 34598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 34698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis munmap(buf, fileSize); 34798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 34898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 349aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis} 350aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 351aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// ---------------------------------------------------------------------------- 352aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis}; // namespace android 353aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// ---------------------------------------------------------------------------- 354