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> 24eacd31f41ef1851bb420c65552b1aed6b74abe29Dan Albert#include <inttypes.h> 2598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis#include <sys/mman.h> 2698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis#include <sys/stat.h> 2798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis#include <sys/types.h> 2898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis#include <unistd.h> 2998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 3089c1d61c16c786ecfd258a43fed24bcf8f8456edJamie Gennis#ifndef MAX_EGL_CACHE_ENTRY_SIZE 3189c1d61c16c786ecfd258a43fed24bcf8f8456edJamie Gennis#define MAX_EGL_CACHE_ENTRY_SIZE (16 * 1024); 3289c1d61c16c786ecfd258a43fed24bcf8f8456edJamie Gennis#endif 3389c1d61c16c786ecfd258a43fed24bcf8f8456edJamie Gennis 34f478e6d18cb9eba1ded1f124ce16a899d271689eJamie Gennis#ifndef MAX_EGL_CACHE_KEY_SIZE 35f478e6d18cb9eba1ded1f124ce16a899d271689eJamie Gennis#define MAX_EGL_CACHE_KEY_SIZE (1024); 36f478e6d18cb9eba1ded1f124ce16a899d271689eJamie Gennis#endif 37f478e6d18cb9eba1ded1f124ce16a899d271689eJamie Gennis 3889c1d61c16c786ecfd258a43fed24bcf8f8456edJamie Gennis#ifndef MAX_EGL_CACHE_SIZE 3989c1d61c16c786ecfd258a43fed24bcf8f8456edJamie Gennis#define MAX_EGL_CACHE_SIZE (64 * 1024); 4089c1d61c16c786ecfd258a43fed24bcf8f8456edJamie Gennis#endif 4189c1d61c16c786ecfd258a43fed24bcf8f8456edJamie Gennis 42766010858ea7696d64f1b559413670bdd8627595Jamie Gennis// Cache size limits. 43f478e6d18cb9eba1ded1f124ce16a899d271689eJamie Gennisstatic const size_t maxKeySize = MAX_EGL_CACHE_KEY_SIZE; 4489c1d61c16c786ecfd258a43fed24bcf8f8456edJamie Gennisstatic const size_t maxValueSize = MAX_EGL_CACHE_ENTRY_SIZE; 4589c1d61c16c786ecfd258a43fed24bcf8f8456edJamie Gennisstatic const size_t maxTotalSize = MAX_EGL_CACHE_SIZE; 46766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 4798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis// Cache file header 4898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennisstatic const char* cacheFileMagic = "EGL$"; 4998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennisstatic const size_t cacheFileHeaderSize = 8; 5098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 5199c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis// The time in seconds to wait before saving newly inserted cache entries. 5299c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennisstatic const unsigned int deferredSaveDelay = 4; 5399c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis 54aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// ---------------------------------------------------------------------------- 55aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennisnamespace android { 56aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// ---------------------------------------------------------------------------- 57aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 58aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis#define BC_EXT_STR "EGL_ANDROID_blob_cache" 59aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 60aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// 61766010858ea7696d64f1b559413670bdd8627595Jamie Gennis// Callback functions passed to EGL. 62aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// 63c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennisstatic void setBlob(const void* key, EGLsizeiANDROID keySize, 64c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennis const void* value, EGLsizeiANDROID valueSize) { 65766010858ea7696d64f1b559413670bdd8627595Jamie Gennis egl_cache_t::get()->setBlob(key, keySize, value, valueSize); 66766010858ea7696d64f1b559413670bdd8627595Jamie Gennis} 67aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 68c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennisstatic EGLsizeiANDROID getBlob(const void* key, EGLsizeiANDROID keySize, 69c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennis void* value, EGLsizeiANDROID valueSize) { 70766010858ea7696d64f1b559413670bdd8627595Jamie Gennis return egl_cache_t::get()->getBlob(key, keySize, value, valueSize); 71766010858ea7696d64f1b559413670bdd8627595Jamie Gennis} 72aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 73aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// 74aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// egl_cache_t definition 75aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// 76766010858ea7696d64f1b559413670bdd8627595Jamie Gennisegl_cache_t::egl_cache_t() : 77766010858ea7696d64f1b559413670bdd8627595Jamie Gennis mInitialized(false), 78766010858ea7696d64f1b559413670bdd8627595Jamie Gennis mBlobCache(NULL) { 79aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis} 80aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 81766010858ea7696d64f1b559413670bdd8627595Jamie Gennisegl_cache_t::~egl_cache_t() { 82aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis} 83aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 8498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennisegl_cache_t egl_cache_t::sCache; 8598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 86aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennisegl_cache_t* egl_cache_t::get() { 8798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return &sCache; 88aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis} 89aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 90aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennisvoid egl_cache_t::initialize(egl_display_t *display) { 91766010858ea7696d64f1b559413670bdd8627595Jamie Gennis Mutex::Autolock lock(mMutex); 92ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian 93ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian egl_connection_t* const cnx = &gEGLImpl; 94ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) { 95ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian const char* exts = display->disp.queryString.extensions; 96ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian size_t bcExtLen = strlen(BC_EXT_STR); 97ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian size_t extsLen = strlen(exts); 98ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian bool equal = !strcmp(BC_EXT_STR, exts); 99ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian bool atStart = !strncmp(BC_EXT_STR " ", exts, bcExtLen+1); 100ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian bool atEnd = (bcExtLen+1) < extsLen && 101ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian !strcmp(" " BC_EXT_STR, exts + extsLen - (bcExtLen+1)); 102ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian bool inMiddle = strstr(exts, " " BC_EXT_STR " "); 103ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian if (equal || atStart || atEnd || inMiddle) { 104ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian PFNEGLSETBLOBCACHEFUNCSANDROIDPROC eglSetBlobCacheFuncsANDROID; 105ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian eglSetBlobCacheFuncsANDROID = 106ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian reinterpret_cast<PFNEGLSETBLOBCACHEFUNCSANDROIDPROC>( 107c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennis cnx->egl.eglGetProcAddress( 108c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennis "eglSetBlobCacheFuncsANDROID")); 109ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian if (eglSetBlobCacheFuncsANDROID == NULL) { 110ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian ALOGE("EGL_ANDROID_blob_cache advertised, " 111ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian "but unable to get eglSetBlobCacheFuncsANDROID"); 112ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian return; 113ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian } 114ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian 115ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian eglSetBlobCacheFuncsANDROID(display->disp.dpy, 116ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian android::setBlob, android::getBlob); 117ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian EGLint err = cnx->egl.eglGetError(); 118ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian if (err != EGL_SUCCESS) { 119ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian ALOGE("eglSetBlobCacheFuncsANDROID resulted in an error: " 120ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian "%#x", err); 121aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis } 122aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis } 123aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis } 124ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian 125766010858ea7696d64f1b559413670bdd8627595Jamie Gennis mInitialized = true; 126766010858ea7696d64f1b559413670bdd8627595Jamie Gennis} 127766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 128766010858ea7696d64f1b559413670bdd8627595Jamie Gennisvoid egl_cache_t::terminate() { 129766010858ea7696d64f1b559413670bdd8627595Jamie Gennis Mutex::Autolock lock(mMutex); 1305539e219de5ffa93e9f22b30dacf7c28e7f7a0beJamie Gennis saveBlobCacheLocked(); 1315539e219de5ffa93e9f22b30dacf7c28e7f7a0beJamie Gennis mBlobCache = NULL; 132766010858ea7696d64f1b559413670bdd8627595Jamie Gennis} 133766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 134c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennisvoid egl_cache_t::setBlob(const void* key, EGLsizeiANDROID keySize, 135c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennis const void* value, EGLsizeiANDROID valueSize) { 136766010858ea7696d64f1b559413670bdd8627595Jamie Gennis Mutex::Autolock lock(mMutex); 137766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 138766010858ea7696d64f1b559413670bdd8627595Jamie Gennis if (keySize < 0 || valueSize < 0) { 13932397c1cd3327905173b36baa6fd1c579bc328ffSteve Block ALOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed"); 140766010858ea7696d64f1b559413670bdd8627595Jamie Gennis return; 141766010858ea7696d64f1b559413670bdd8627595Jamie Gennis } 142766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 143766010858ea7696d64f1b559413670bdd8627595Jamie Gennis if (mInitialized) { 144766010858ea7696d64f1b559413670bdd8627595Jamie Gennis sp<BlobCache> bc = getBlobCacheLocked(); 145766010858ea7696d64f1b559413670bdd8627595Jamie Gennis bc->set(key, keySize, value, valueSize); 14699c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis 14799c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis if (!mSavePending) { 14899c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis class DeferredSaveThread : public Thread { 14999c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis public: 15099c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis DeferredSaveThread() : Thread(false) {} 15199c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis 15299c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis virtual bool threadLoop() { 15399c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis sleep(deferredSaveDelay); 15499c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis egl_cache_t* c = egl_cache_t::get(); 15599c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis Mutex::Autolock lock(c->mMutex); 15699c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis if (c->mInitialized) { 15799c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis c->saveBlobCacheLocked(); 15899c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis } 15999c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis c->mSavePending = false; 16099c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis return false; 16199c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis } 16299c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis }; 16399c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis 16499c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis // The thread will hold a strong ref to itself until it has finished 16599c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis // running, so there's no need to keep a ref around. 16699c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis sp<Thread> deferredSaveThread(new DeferredSaveThread()); 16799c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis mSavePending = true; 16883b1e685d252e589fa4a2e7e54c1f416aca63043Brian Carlstrom deferredSaveThread->run("DeferredSaveThread"); 16999c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis } 170766010858ea7696d64f1b559413670bdd8627595Jamie Gennis } 171766010858ea7696d64f1b559413670bdd8627595Jamie Gennis} 172766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 173c42fcf05ce253d5342993b28c412be16e61efffbJamie GennisEGLsizeiANDROID egl_cache_t::getBlob(const void* key, EGLsizeiANDROID keySize, 174c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennis void* value, EGLsizeiANDROID valueSize) { 175766010858ea7696d64f1b559413670bdd8627595Jamie Gennis Mutex::Autolock lock(mMutex); 176766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 177766010858ea7696d64f1b559413670bdd8627595Jamie Gennis if (keySize < 0 || valueSize < 0) { 17832397c1cd3327905173b36baa6fd1c579bc328ffSteve Block ALOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed"); 179766010858ea7696d64f1b559413670bdd8627595Jamie Gennis return 0; 180766010858ea7696d64f1b559413670bdd8627595Jamie Gennis } 181766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 182766010858ea7696d64f1b559413670bdd8627595Jamie Gennis if (mInitialized) { 183766010858ea7696d64f1b559413670bdd8627595Jamie Gennis sp<BlobCache> bc = getBlobCacheLocked(); 184766010858ea7696d64f1b559413670bdd8627595Jamie Gennis return bc->get(key, keySize, value, valueSize); 185766010858ea7696d64f1b559413670bdd8627595Jamie Gennis } 186766010858ea7696d64f1b559413670bdd8627595Jamie Gennis return 0; 187766010858ea7696d64f1b559413670bdd8627595Jamie Gennis} 188766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 18998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennisvoid egl_cache_t::setCacheFilename(const char* filename) { 19098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis Mutex::Autolock lock(mMutex); 19198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis mFilename = filename; 19298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis} 19398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 194766010858ea7696d64f1b559413670bdd8627595Jamie Gennissp<BlobCache> egl_cache_t::getBlobCacheLocked() { 195766010858ea7696d64f1b559413670bdd8627595Jamie Gennis if (mBlobCache == NULL) { 196766010858ea7696d64f1b559413670bdd8627595Jamie Gennis mBlobCache = new BlobCache(maxKeySize, maxValueSize, maxTotalSize); 197766010858ea7696d64f1b559413670bdd8627595Jamie Gennis loadBlobCacheLocked(); 198766010858ea7696d64f1b559413670bdd8627595Jamie Gennis } 199766010858ea7696d64f1b559413670bdd8627595Jamie Gennis return mBlobCache; 200766010858ea7696d64f1b559413670bdd8627595Jamie Gennis} 201766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 20298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennisstatic uint32_t crc32c(const uint8_t* buf, size_t len) { 20398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis const uint32_t polyBits = 0x82F63B78; 20498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis uint32_t r = 0; 20598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis for (size_t i = 0; i < len; i++) { 20698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis r ^= buf[i]; 20798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis for (int j = 0; j < 8; j++) { 20898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (r & 1) { 20998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis r = (r >> 1) ^ polyBits; 21098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } else { 21198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis r >>= 1; 21298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 21398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 21498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 21598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return r; 21698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis} 21798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 218766010858ea7696d64f1b559413670bdd8627595Jamie Gennisvoid egl_cache_t::saveBlobCacheLocked() { 2195539e219de5ffa93e9f22b30dacf7c28e7f7a0beJamie Gennis if (mFilename.length() > 0 && mBlobCache != NULL) { 22098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis size_t cacheSize = mBlobCache->getFlattenedSize(); 22198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis size_t headerSize = cacheFileHeaderSize; 22298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis const char* fname = mFilename.string(); 22398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 22498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis // Try to create the file with no permissions so we can write it 22598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis // without anyone trying to read it. 22698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis int fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0); 22798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (fd == -1) { 22898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (errno == EEXIST) { 22998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis // The file exists, delete it and try again. 23098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (unlink(fname) == -1) { 23198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis // No point in retrying if the unlink failed. 232e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("error unlinking cache file %s: %s (%d)", fname, 23398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis strerror(errno), errno); 23498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 23598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 23698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis // Retry now that we've unlinked the file. 23798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0); 23898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 23998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (fd == -1) { 240e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("error creating cache file %s: %s (%d)", fname, 24198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis strerror(errno), errno); 24298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 24398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 24498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 24598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 24698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis size_t fileSize = headerSize + cacheSize; 24798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 248a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta uint8_t* buf = new uint8_t [fileSize]; 249a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta if (!buf) { 250a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta ALOGE("error allocating buffer for cache contents: %s (%d)", 251a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta strerror(errno), errno); 25298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 25398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis unlink(fname); 25498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 25598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 25698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 257e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian status_t err = mBlobCache->flatten(buf + headerSize, cacheSize); 25898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (err != OK) { 259e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("error writing cache contents: %s (%d)", strerror(-err), 26098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis -err); 261a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta delete [] buf; 26298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 26398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis unlink(fname); 26498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 26598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 26698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 26798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis // Write the file magic and CRC 26898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis memcpy(buf, cacheFileMagic, 4); 26998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4); 27098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis *crc = crc32c(buf + headerSize, cacheSize); 27198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 272a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta if (write(fd, buf, fileSize) == -1) { 273a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta ALOGE("error writing cache file: %s (%d)", strerror(errno), 274a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta errno); 275a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta delete [] buf; 276a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta close(fd); 277a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta unlink(fname); 278a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta return; 279a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta } 280a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta 281a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta delete [] buf; 28298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis fchmod(fd, S_IRUSR); 28398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 28498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 285766010858ea7696d64f1b559413670bdd8627595Jamie Gennis} 286766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 287766010858ea7696d64f1b559413670bdd8627595Jamie Gennisvoid egl_cache_t::loadBlobCacheLocked() { 28898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (mFilename.length() > 0) { 28998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis size_t headerSize = cacheFileHeaderSize; 29098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 29198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis int fd = open(mFilename.string(), O_RDONLY, 0); 29298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (fd == -1) { 29398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (errno != ENOENT) { 294e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("error opening cache file %s: %s (%d)", mFilename.string(), 29598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis strerror(errno), errno); 29698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 29798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 29898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 29998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 30098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis struct stat statBuf; 30198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (fstat(fd, &statBuf) == -1) { 302e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("error stat'ing cache file: %s (%d)", strerror(errno), errno); 30398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 30498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 30598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 30698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 30798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis // Sanity check the size before trying to mmap it. 30898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis size_t fileSize = statBuf.st_size; 30998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (fileSize > maxTotalSize * 2) { 310eacd31f41ef1851bb420c65552b1aed6b74abe29Dan Albert ALOGE("cache file is too large: %#" PRIx64, 311eacd31f41ef1851bb420c65552b1aed6b74abe29Dan Albert static_cast<off64_t>(statBuf.st_size)); 31298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 31398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 31498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 31598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 31698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(NULL, fileSize, 31798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis PROT_READ, MAP_PRIVATE, fd, 0)); 31898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (buf == MAP_FAILED) { 319e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("error mmaping cache file: %s (%d)", strerror(errno), 32098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis errno); 32198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 32298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 32398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 32498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 32598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis // Check the file magic and CRC 32698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis size_t cacheSize = fileSize - headerSize; 32798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (memcmp(buf, cacheFileMagic, 4) != 0) { 328e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("cache file has bad mojo"); 32998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 33098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 33198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 33298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4); 33398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (crc32c(buf + headerSize, cacheSize) != *crc) { 334e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("cache file failed CRC check"); 33598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 33698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 33798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 33898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 339e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian status_t err = mBlobCache->unflatten(buf + headerSize, cacheSize); 34098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (err != OK) { 341e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("error reading cache contents: %s (%d)", strerror(-err), 34298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis -err); 34398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis munmap(buf, fileSize); 34498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 34598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 34698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 34798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 34898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis munmap(buf, fileSize); 34998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 35098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 351aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis} 352aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 353aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// ---------------------------------------------------------------------------- 354aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis}; // namespace android 355aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// ---------------------------------------------------------------------------- 356