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