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