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 17311b479d7f50bc9e487cf9b4859843d0f4778382Mathias Agopian#include "egl_cache.h" 18311b479d7f50bc9e487cf9b4859843d0f4778382Mathias Agopian 1939c24a20bbc697630d2b92c251b70c04d6f9d00cMathias Agopian#include "../egl_impl.h" 2039c24a20bbc697630d2b92c251b70c04d6f9d00cMathias Agopian 21aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis#include "egl_display.h" 22aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 23b7f9a2400aaa2e0d29ffefd91576e90036d4cf83Mathias Agopian 24b7f9a2400aaa2e0d29ffefd91576e90036d4cf83Mathias Agopian#include <private/EGL/cache.h> 25b7f9a2400aaa2e0d29ffefd91576e90036d4cf83Mathias Agopian 26eacd31f41ef1851bb420c65552b1aed6b74abe29Dan Albert#include <inttypes.h> 2798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis#include <sys/mman.h> 2898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis#include <sys/stat.h> 29a243e5dc36b5c75fb963d51064b132ea5367372eJiyong Park#include <unistd.h> 30311b479d7f50bc9e487cf9b4859843d0f4778382Mathias Agopian 3165421435a67b881dad79e7008e9dee7fb425f180Mathias Agopian#include <thread> 3265421435a67b881dad79e7008e9dee7fb425f180Mathias Agopian 3365421435a67b881dad79e7008e9dee7fb425f180Mathias Agopian#include <log/log.h> 3498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 35766010858ea7696d64f1b559413670bdd8627595Jamie Gennis// Cache size limits. 36bace39e1dd7dbe6c74a926e980699c442f957f89Dan Willemsenstatic const size_t maxKeySize = 12 * 1024; 37bace39e1dd7dbe6c74a926e980699c442f957f89Dan Willemsenstatic const size_t maxValueSize = 64 * 1024; 38bace39e1dd7dbe6c74a926e980699c442f957f89Dan Willemsenstatic const size_t maxTotalSize = 2 * 1024 * 1024; 39766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 4098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis// Cache file header 4198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennisstatic const char* cacheFileMagic = "EGL$"; 4298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennisstatic const size_t cacheFileHeaderSize = 8; 4398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 4499c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis// The time in seconds to wait before saving newly inserted cache entries. 4599c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennisstatic const unsigned int deferredSaveDelay = 4; 4699c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis 47aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// ---------------------------------------------------------------------------- 48aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennisnamespace android { 49aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// ---------------------------------------------------------------------------- 50aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 51aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis#define BC_EXT_STR "EGL_ANDROID_blob_cache" 52aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 53b7f9a2400aaa2e0d29ffefd91576e90036d4cf83Mathias Agopian// called from android_view_ThreadedRenderer.cpp 54b7f9a2400aaa2e0d29ffefd91576e90036d4cf83Mathias Agopianvoid egl_set_cache_filename(const char* filename) { 55b7f9a2400aaa2e0d29ffefd91576e90036d4cf83Mathias Agopian egl_cache_t::get()->setCacheFilename(filename); 56b7f9a2400aaa2e0d29ffefd91576e90036d4cf83Mathias Agopian} 57b7f9a2400aaa2e0d29ffefd91576e90036d4cf83Mathias Agopian 58aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// 59766010858ea7696d64f1b559413670bdd8627595Jamie Gennis// Callback functions passed to EGL. 60aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// 61c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennisstatic void setBlob(const void* key, EGLsizeiANDROID keySize, 62c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennis const void* value, EGLsizeiANDROID valueSize) { 63766010858ea7696d64f1b559413670bdd8627595Jamie Gennis egl_cache_t::get()->setBlob(key, keySize, value, valueSize); 64766010858ea7696d64f1b559413670bdd8627595Jamie Gennis} 65aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 66c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennisstatic EGLsizeiANDROID getBlob(const void* key, EGLsizeiANDROID keySize, 67c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennis void* value, EGLsizeiANDROID valueSize) { 68766010858ea7696d64f1b559413670bdd8627595Jamie Gennis return egl_cache_t::get()->getBlob(key, keySize, value, valueSize); 69766010858ea7696d64f1b559413670bdd8627595Jamie Gennis} 70aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 71aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// 72aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// egl_cache_t definition 73aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// 74766010858ea7696d64f1b559413670bdd8627595Jamie Gennisegl_cache_t::egl_cache_t() : 75b7f9a2400aaa2e0d29ffefd91576e90036d4cf83Mathias Agopian mInitialized(false) { 76aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis} 77aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 78766010858ea7696d64f1b559413670bdd8627595Jamie Gennisegl_cache_t::~egl_cache_t() { 79aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis} 80aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 8198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennisegl_cache_t egl_cache_t::sCache; 8298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 83aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennisegl_cache_t* egl_cache_t::get() { 8498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return &sCache; 85aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis} 86aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 87aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennisvoid egl_cache_t::initialize(egl_display_t *display) { 8865421435a67b881dad79e7008e9dee7fb425f180Mathias Agopian std::lock_guard<std::mutex> lock(mMutex); 89ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian 90ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian egl_connection_t* const cnx = &gEGLImpl; 91ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) { 92ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian const char* exts = display->disp.queryString.extensions; 93ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian size_t bcExtLen = strlen(BC_EXT_STR); 94ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian size_t extsLen = strlen(exts); 95ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian bool equal = !strcmp(BC_EXT_STR, exts); 96ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian bool atStart = !strncmp(BC_EXT_STR " ", exts, bcExtLen+1); 97ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian bool atEnd = (bcExtLen+1) < extsLen && 98ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian !strcmp(" " BC_EXT_STR, exts + extsLen - (bcExtLen+1)); 99311b479d7f50bc9e487cf9b4859843d0f4778382Mathias Agopian bool inMiddle = strstr(exts, " " BC_EXT_STR " ") != nullptr; 100ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian if (equal || atStart || atEnd || inMiddle) { 101ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian PFNEGLSETBLOBCACHEFUNCSANDROIDPROC eglSetBlobCacheFuncsANDROID; 102ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian eglSetBlobCacheFuncsANDROID = 103ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian reinterpret_cast<PFNEGLSETBLOBCACHEFUNCSANDROIDPROC>( 104c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennis cnx->egl.eglGetProcAddress( 105c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennis "eglSetBlobCacheFuncsANDROID")); 106ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian if (eglSetBlobCacheFuncsANDROID == NULL) { 107ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian ALOGE("EGL_ANDROID_blob_cache advertised, " 108ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian "but unable to get eglSetBlobCacheFuncsANDROID"); 109ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian return; 110ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian } 111ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian 112ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian eglSetBlobCacheFuncsANDROID(display->disp.dpy, 113ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian android::setBlob, android::getBlob); 114ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian EGLint err = cnx->egl.eglGetError(); 115ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian if (err != EGL_SUCCESS) { 116ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian ALOGE("eglSetBlobCacheFuncsANDROID resulted in an error: " 117ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian "%#x", err); 118aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis } 119aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis } 120aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis } 121ada798b7ca7cabc255aa159964b64975e7fdb2dfMathias Agopian 122766010858ea7696d64f1b559413670bdd8627595Jamie Gennis mInitialized = true; 123766010858ea7696d64f1b559413670bdd8627595Jamie Gennis} 124766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 125766010858ea7696d64f1b559413670bdd8627595Jamie Gennisvoid egl_cache_t::terminate() { 12665421435a67b881dad79e7008e9dee7fb425f180Mathias Agopian std::lock_guard<std::mutex> lock(mMutex); 1275539e219de5ffa93e9f22b30dacf7c28e7f7a0beJamie Gennis saveBlobCacheLocked(); 1285539e219de5ffa93e9f22b30dacf7c28e7f7a0beJamie Gennis mBlobCache = NULL; 129766010858ea7696d64f1b559413670bdd8627595Jamie Gennis} 130766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 131c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennisvoid egl_cache_t::setBlob(const void* key, EGLsizeiANDROID keySize, 132c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennis const void* value, EGLsizeiANDROID valueSize) { 13365421435a67b881dad79e7008e9dee7fb425f180Mathias Agopian std::lock_guard<std::mutex> lock(mMutex); 134766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 135766010858ea7696d64f1b559413670bdd8627595Jamie Gennis if (keySize < 0 || valueSize < 0) { 13632397c1cd3327905173b36baa6fd1c579bc328ffSteve Block ALOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed"); 137766010858ea7696d64f1b559413670bdd8627595Jamie Gennis return; 138766010858ea7696d64f1b559413670bdd8627595Jamie Gennis } 139766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 140766010858ea7696d64f1b559413670bdd8627595Jamie Gennis if (mInitialized) { 141b7f9a2400aaa2e0d29ffefd91576e90036d4cf83Mathias Agopian BlobCache* bc = getBlobCacheLocked(); 142766010858ea7696d64f1b559413670bdd8627595Jamie Gennis bc->set(key, keySize, value, valueSize); 14399c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis 14499c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis if (!mSavePending) { 14599c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis mSavePending = true; 14665421435a67b881dad79e7008e9dee7fb425f180Mathias Agopian std::thread deferredSaveThread([this]() { 14765421435a67b881dad79e7008e9dee7fb425f180Mathias Agopian sleep(deferredSaveDelay); 14865421435a67b881dad79e7008e9dee7fb425f180Mathias Agopian std::lock_guard<std::mutex> lock(mMutex); 14965421435a67b881dad79e7008e9dee7fb425f180Mathias Agopian if (mInitialized) { 15065421435a67b881dad79e7008e9dee7fb425f180Mathias Agopian saveBlobCacheLocked(); 15165421435a67b881dad79e7008e9dee7fb425f180Mathias Agopian } 15265421435a67b881dad79e7008e9dee7fb425f180Mathias Agopian mSavePending = false; 15365421435a67b881dad79e7008e9dee7fb425f180Mathias Agopian }); 15465421435a67b881dad79e7008e9dee7fb425f180Mathias Agopian deferredSaveThread.detach(); 15599c3d700d2d0886fe27fa961c89dae7c6c3b8195Jamie Gennis } 156766010858ea7696d64f1b559413670bdd8627595Jamie Gennis } 157766010858ea7696d64f1b559413670bdd8627595Jamie Gennis} 158766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 159c42fcf05ce253d5342993b28c412be16e61efffbJamie GennisEGLsizeiANDROID egl_cache_t::getBlob(const void* key, EGLsizeiANDROID keySize, 160c42fcf05ce253d5342993b28c412be16e61efffbJamie Gennis void* value, EGLsizeiANDROID valueSize) { 16165421435a67b881dad79e7008e9dee7fb425f180Mathias Agopian std::lock_guard<std::mutex> lock(mMutex); 162766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 163766010858ea7696d64f1b559413670bdd8627595Jamie Gennis if (keySize < 0 || valueSize < 0) { 16432397c1cd3327905173b36baa6fd1c579bc328ffSteve Block ALOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed"); 165766010858ea7696d64f1b559413670bdd8627595Jamie Gennis return 0; 166766010858ea7696d64f1b559413670bdd8627595Jamie Gennis } 167766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 168766010858ea7696d64f1b559413670bdd8627595Jamie Gennis if (mInitialized) { 169b7f9a2400aaa2e0d29ffefd91576e90036d4cf83Mathias Agopian BlobCache* bc = getBlobCacheLocked(); 170766010858ea7696d64f1b559413670bdd8627595Jamie Gennis return bc->get(key, keySize, value, valueSize); 171766010858ea7696d64f1b559413670bdd8627595Jamie Gennis } 172766010858ea7696d64f1b559413670bdd8627595Jamie Gennis return 0; 173766010858ea7696d64f1b559413670bdd8627595Jamie Gennis} 174766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 17598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennisvoid egl_cache_t::setCacheFilename(const char* filename) { 17665421435a67b881dad79e7008e9dee7fb425f180Mathias Agopian std::lock_guard<std::mutex> lock(mMutex); 17798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis mFilename = filename; 17898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis} 17998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 180b7f9a2400aaa2e0d29ffefd91576e90036d4cf83Mathias AgopianBlobCache* egl_cache_t::getBlobCacheLocked() { 181b7f9a2400aaa2e0d29ffefd91576e90036d4cf83Mathias Agopian if (mBlobCache == nullptr) { 182b7f9a2400aaa2e0d29ffefd91576e90036d4cf83Mathias Agopian mBlobCache.reset(new BlobCache(maxKeySize, maxValueSize, maxTotalSize)); 183766010858ea7696d64f1b559413670bdd8627595Jamie Gennis loadBlobCacheLocked(); 184766010858ea7696d64f1b559413670bdd8627595Jamie Gennis } 185b7f9a2400aaa2e0d29ffefd91576e90036d4cf83Mathias Agopian return mBlobCache.get(); 186766010858ea7696d64f1b559413670bdd8627595Jamie Gennis} 187766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 18898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennisstatic uint32_t crc32c(const uint8_t* buf, size_t len) { 18998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis const uint32_t polyBits = 0x82F63B78; 19098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis uint32_t r = 0; 19198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis for (size_t i = 0; i < len; i++) { 19298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis r ^= buf[i]; 19398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis for (int j = 0; j < 8; j++) { 19498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (r & 1) { 19598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis r = (r >> 1) ^ polyBits; 19698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } else { 19798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis r >>= 1; 19898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 19998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 20098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 20198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return r; 20298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis} 20398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 204766010858ea7696d64f1b559413670bdd8627595Jamie Gennisvoid egl_cache_t::saveBlobCacheLocked() { 2055539e219de5ffa93e9f22b30dacf7c28e7f7a0beJamie Gennis if (mFilename.length() > 0 && mBlobCache != NULL) { 20698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis size_t cacheSize = mBlobCache->getFlattenedSize(); 20798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis size_t headerSize = cacheFileHeaderSize; 20865421435a67b881dad79e7008e9dee7fb425f180Mathias Agopian const char* fname = mFilename.c_str(); 20998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 21098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis // Try to create the file with no permissions so we can write it 21198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis // without anyone trying to read it. 21298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis int fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0); 21398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (fd == -1) { 21498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (errno == EEXIST) { 21598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis // The file exists, delete it and try again. 21698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (unlink(fname) == -1) { 21798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis // No point in retrying if the unlink failed. 218e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("error unlinking cache file %s: %s (%d)", fname, 21998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis strerror(errno), errno); 22098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 22198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 22298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis // Retry now that we've unlinked the file. 22398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0); 22498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 22598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (fd == -1) { 226e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("error creating cache file %s: %s (%d)", fname, 22798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis strerror(errno), errno); 22898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 22998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 23098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 23198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 23298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis size_t fileSize = headerSize + cacheSize; 23398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 234a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta uint8_t* buf = new uint8_t [fileSize]; 235a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta if (!buf) { 236a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta ALOGE("error allocating buffer for cache contents: %s (%d)", 237a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta strerror(errno), errno); 23898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 23998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis unlink(fname); 24098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 24198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 24298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 24365421435a67b881dad79e7008e9dee7fb425f180Mathias Agopian int err = mBlobCache->flatten(buf + headerSize, cacheSize); 24465421435a67b881dad79e7008e9dee7fb425f180Mathias Agopian if (err < 0) { 245e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("error writing cache contents: %s (%d)", strerror(-err), 24698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis -err); 247a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta delete [] buf; 24898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 24998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis unlink(fname); 25098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 25198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 25298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 25398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis // Write the file magic and CRC 25498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis memcpy(buf, cacheFileMagic, 4); 25598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4); 25698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis *crc = crc32c(buf + headerSize, cacheSize); 25798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 258a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta if (write(fd, buf, fileSize) == -1) { 259a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta ALOGE("error writing cache file: %s (%d)", strerror(errno), 260a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta errno); 261a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta delete [] buf; 262a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta close(fd); 263a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta unlink(fname); 264a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta return; 265a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta } 266a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta 267a30cc7db8dba9f028333a8e1865006bf6d4f410dvijay gupta delete [] buf; 26898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis fchmod(fd, S_IRUSR); 26998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 27098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 271766010858ea7696d64f1b559413670bdd8627595Jamie Gennis} 272766010858ea7696d64f1b559413670bdd8627595Jamie Gennis 273766010858ea7696d64f1b559413670bdd8627595Jamie Gennisvoid egl_cache_t::loadBlobCacheLocked() { 27498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (mFilename.length() > 0) { 27598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis size_t headerSize = cacheFileHeaderSize; 27698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 27765421435a67b881dad79e7008e9dee7fb425f180Mathias Agopian int fd = open(mFilename.c_str(), O_RDONLY, 0); 27898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (fd == -1) { 27998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (errno != ENOENT) { 28065421435a67b881dad79e7008e9dee7fb425f180Mathias Agopian ALOGE("error opening cache file %s: %s (%d)", mFilename.c_str(), 28198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis strerror(errno), errno); 28298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 28398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 28498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 28598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 28698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis struct stat statBuf; 28798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (fstat(fd, &statBuf) == -1) { 288e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("error stat'ing cache file: %s (%d)", strerror(errno), errno); 28998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 29098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 29198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 29298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 29398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis // Sanity check the size before trying to mmap it. 29498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis size_t fileSize = statBuf.st_size; 29598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (fileSize > maxTotalSize * 2) { 296eacd31f41ef1851bb420c65552b1aed6b74abe29Dan Albert ALOGE("cache file is too large: %#" PRIx64, 297eacd31f41ef1851bb420c65552b1aed6b74abe29Dan Albert static_cast<off64_t>(statBuf.st_size)); 29898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 29998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 30098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 30198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 30298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(NULL, fileSize, 30398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis PROT_READ, MAP_PRIVATE, fd, 0)); 30498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (buf == MAP_FAILED) { 305e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("error mmaping cache file: %s (%d)", strerror(errno), 30698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis errno); 30798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 30898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 30998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 31098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 31198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis // Check the file magic and CRC 31298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis size_t cacheSize = fileSize - headerSize; 31398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (memcmp(buf, cacheFileMagic, 4) != 0) { 314e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("cache file has bad mojo"); 31598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 31698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 31798c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 31898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4); 31998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis if (crc32c(buf + headerSize, cacheSize) != *crc) { 320e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("cache file failed CRC check"); 32198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 32298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 32398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 32498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 32565421435a67b881dad79e7008e9dee7fb425f180Mathias Agopian int err = mBlobCache->unflatten(buf + headerSize, cacheSize); 32665421435a67b881dad79e7008e9dee7fb425f180Mathias Agopian if (err < 0) { 327e6f43ddce78d6846af12550ff9193c5c6fe5844bSteve Block ALOGE("error reading cache contents: %s (%d)", strerror(-err), 32898c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis -err); 32998c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis munmap(buf, fileSize); 33098c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 33198c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis return; 33298c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 33398c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis 33498c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis munmap(buf, fileSize); 33598c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis close(fd); 33698c6383580f94bb7ff9cc9a7cc24d8b8519e484aJamie Gennis } 337aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis} 338aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis 339aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// ---------------------------------------------------------------------------- 340aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis}; // namespace android 341aca51c06f38155f1435fbc6944d7fc0a9bf1e4e9Jamie Gennis// ---------------------------------------------------------------------------- 342