egl_cache.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /*
  2. ** Copyright 2011, The Android Open Source Project
  3. **
  4. ** Licensed under the Apache License, Version 2.0 (the "License");
  5. ** you may not use this file except in compliance with the License.
  6. ** You may obtain a copy of the License at
  7. **
  8. ** http://www.apache.org/licenses/LICENSE-2.0
  9. **
  10. ** Unless required by applicable law or agreed to in writing, software
  11. ** distributed under the License is distributed on an "AS IS" BASIS,
  12. ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. ** See the License for the specific language governing permissions and
  14. ** limitations under the License.
  15. */
  16. #include "../egl_impl.h"
  17. #include "egl_cache.h"
  18. #include "egl_display.h"
  19. #include "egldefs.h"
  20. #include <fcntl.h>
  21. #include <sys/mman.h>
  22. #include <sys/stat.h>
  23. #include <sys/types.h>
  24. #include <unistd.h>
  25. #ifndef MAX_EGL_CACHE_ENTRY_SIZE
  26. #define MAX_EGL_CACHE_ENTRY_SIZE (16 * 1024);
  27. #endif
  28. #ifndef MAX_EGL_CACHE_KEY_SIZE
  29. #define MAX_EGL_CACHE_KEY_SIZE (1024);
  30. #endif
  31. #ifndef MAX_EGL_CACHE_SIZE
  32. #define MAX_EGL_CACHE_SIZE (64 * 1024);
  33. #endif
  34. // Cache size limits.
  35. static const size_t maxKeySize = MAX_EGL_CACHE_KEY_SIZE;
  36. static const size_t maxValueSize = MAX_EGL_CACHE_ENTRY_SIZE;
  37. static const size_t maxTotalSize = MAX_EGL_CACHE_SIZE;
  38. // Cache file header
  39. static const char* cacheFileMagic = "EGL$";
  40. static const size_t cacheFileHeaderSize = 8;
  41. // The time in seconds to wait before saving newly inserted cache entries.
  42. static const unsigned int deferredSaveDelay = 4;
  43. // ----------------------------------------------------------------------------
  44. namespace android {
  45. // ----------------------------------------------------------------------------
  46. #define BC_EXT_STR "EGL_ANDROID_blob_cache"
  47. //
  48. // Callback functions passed to EGL.
  49. //
  50. static void setBlob(const void* key, EGLsizeiANDROID keySize,
  51. const void* value, EGLsizeiANDROID valueSize) {
  52. egl_cache_t::get()->setBlob(key, keySize, value, valueSize);
  53. }
  54. static EGLsizeiANDROID getBlob(const void* key, EGLsizeiANDROID keySize,
  55. void* value, EGLsizeiANDROID valueSize) {
  56. return egl_cache_t::get()->getBlob(key, keySize, value, valueSize);
  57. }
  58. //
  59. // egl_cache_t definition
  60. //
  61. egl_cache_t::egl_cache_t() :
  62. mInitialized(false),
  63. mBlobCache(NULL) {
  64. }
  65. egl_cache_t::~egl_cache_t() {
  66. }
  67. egl_cache_t egl_cache_t::sCache;
  68. egl_cache_t* egl_cache_t::get() {
  69. return &sCache;
  70. }
  71. void egl_cache_t::initialize(egl_display_t *display) {
  72. Mutex::Autolock lock(mMutex);
  73. egl_connection_t* const cnx = &gEGLImpl;
  74. if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
  75. const char* exts = display->disp.queryString.extensions;
  76. size_t bcExtLen = strlen(BC_EXT_STR);
  77. size_t extsLen = strlen(exts);
  78. bool equal = !strcmp(BC_EXT_STR, exts);
  79. bool atStart = !strncmp(BC_EXT_STR " ", exts, bcExtLen+1);
  80. bool atEnd = (bcExtLen+1) < extsLen &&
  81. !strcmp(" " BC_EXT_STR, exts + extsLen - (bcExtLen+1));
  82. bool inMiddle = strstr(exts, " " BC_EXT_STR " ");
  83. if (equal || atStart || atEnd || inMiddle) {
  84. PFNEGLSETBLOBCACHEFUNCSANDROIDPROC eglSetBlobCacheFuncsANDROID;
  85. eglSetBlobCacheFuncsANDROID =
  86. reinterpret_cast<PFNEGLSETBLOBCACHEFUNCSANDROIDPROC>(
  87. cnx->egl.eglGetProcAddress(
  88. "eglSetBlobCacheFuncsANDROID"));
  89. if (eglSetBlobCacheFuncsANDROID == NULL) {
  90. ALOGE("EGL_ANDROID_blob_cache advertised, "
  91. "but unable to get eglSetBlobCacheFuncsANDROID");
  92. return;
  93. }
  94. eglSetBlobCacheFuncsANDROID(display->disp.dpy,
  95. android::setBlob, android::getBlob);
  96. EGLint err = cnx->egl.eglGetError();
  97. if (err != EGL_SUCCESS) {
  98. ALOGE("eglSetBlobCacheFuncsANDROID resulted in an error: "
  99. "%#x", err);
  100. }
  101. }
  102. }
  103. mInitialized = true;
  104. }
  105. void egl_cache_t::terminate() {
  106. Mutex::Autolock lock(mMutex);
  107. saveBlobCacheLocked();
  108. mBlobCache = NULL;
  109. }
  110. void egl_cache_t::setBlob(const void* key, EGLsizeiANDROID keySize,
  111. const void* value, EGLsizeiANDROID valueSize) {
  112. Mutex::Autolock lock(mMutex);
  113. if (keySize < 0 || valueSize < 0) {
  114. ALOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed");
  115. return;
  116. }
  117. if (mInitialized) {
  118. sp<BlobCache> bc = getBlobCacheLocked();
  119. bc->set(key, keySize, value, valueSize);
  120. if (!mSavePending) {
  121. class DeferredSaveThread : public Thread {
  122. public:
  123. DeferredSaveThread() : Thread(false) {}
  124. virtual bool threadLoop() {
  125. sleep(deferredSaveDelay);
  126. egl_cache_t* c = egl_cache_t::get();
  127. Mutex::Autolock lock(c->mMutex);
  128. if (c->mInitialized) {
  129. c->saveBlobCacheLocked();
  130. }
  131. c->mSavePending = false;
  132. return false;
  133. }
  134. };
  135. // The thread will hold a strong ref to itself until it has finished
  136. // running, so there's no need to keep a ref around.
  137. sp<Thread> deferredSaveThread(new DeferredSaveThread());
  138. mSavePending = true;
  139. deferredSaveThread->run();
  140. }
  141. }
  142. }
  143. EGLsizeiANDROID egl_cache_t::getBlob(const void* key, EGLsizeiANDROID keySize,
  144. void* value, EGLsizeiANDROID valueSize) {
  145. Mutex::Autolock lock(mMutex);
  146. if (keySize < 0 || valueSize < 0) {
  147. ALOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed");
  148. return 0;
  149. }
  150. if (mInitialized) {
  151. sp<BlobCache> bc = getBlobCacheLocked();
  152. return bc->get(key, keySize, value, valueSize);
  153. }
  154. return 0;
  155. }
  156. void egl_cache_t::setCacheFilename(const char* filename) {
  157. Mutex::Autolock lock(mMutex);
  158. mFilename = filename;
  159. }
  160. sp<BlobCache> egl_cache_t::getBlobCacheLocked() {
  161. if (mBlobCache == NULL) {
  162. mBlobCache = new BlobCache(maxKeySize, maxValueSize, maxTotalSize);
  163. loadBlobCacheLocked();
  164. }
  165. return mBlobCache;
  166. }
  167. static uint32_t crc32c(const uint8_t* buf, size_t len) {
  168. const uint32_t polyBits = 0x82F63B78;
  169. uint32_t r = 0;
  170. for (size_t i = 0; i < len; i++) {
  171. r ^= buf[i];
  172. for (int j = 0; j < 8; j++) {
  173. if (r & 1) {
  174. r = (r >> 1) ^ polyBits;
  175. } else {
  176. r >>= 1;
  177. }
  178. }
  179. }
  180. return r;
  181. }
  182. void egl_cache_t::saveBlobCacheLocked() {
  183. if (mFilename.length() > 0 && mBlobCache != NULL) {
  184. size_t cacheSize = mBlobCache->getFlattenedSize();
  185. size_t headerSize = cacheFileHeaderSize;
  186. const char* fname = mFilename.string();
  187. // Try to create the file with no permissions so we can write it
  188. // without anyone trying to read it.
  189. int fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0);
  190. if (fd == -1) {
  191. if (errno == EEXIST) {
  192. // The file exists, delete it and try again.
  193. if (unlink(fname) == -1) {
  194. // No point in retrying if the unlink failed.
  195. ALOGE("error unlinking cache file %s: %s (%d)", fname,
  196. strerror(errno), errno);
  197. return;
  198. }
  199. // Retry now that we've unlinked the file.
  200. fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0);
  201. }
  202. if (fd == -1) {
  203. ALOGE("error creating cache file %s: %s (%d)", fname,
  204. strerror(errno), errno);
  205. return;
  206. }
  207. }
  208. size_t fileSize = headerSize + cacheSize;
  209. uint8_t* buf = new uint8_t [fileSize];
  210. if (!buf) {
  211. ALOGE("error allocating buffer for cache contents: %s (%d)",
  212. strerror(errno), errno);
  213. close(fd);
  214. unlink(fname);
  215. return;
  216. }
  217. status_t err = mBlobCache->flatten(buf + headerSize, cacheSize);
  218. if (err != OK) {
  219. ALOGE("error writing cache contents: %s (%d)", strerror(-err),
  220. -err);
  221. delete [] buf;
  222. close(fd);
  223. unlink(fname);
  224. return;
  225. }
  226. // Write the file magic and CRC
  227. memcpy(buf, cacheFileMagic, 4);
  228. uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4);
  229. *crc = crc32c(buf + headerSize, cacheSize);
  230. if (write(fd, buf, fileSize) == -1) {
  231. ALOGE("error writing cache file: %s (%d)", strerror(errno),
  232. errno);
  233. delete [] buf;
  234. close(fd);
  235. unlink(fname);
  236. return;
  237. }
  238. delete [] buf;
  239. fchmod(fd, S_IRUSR);
  240. close(fd);
  241. }
  242. }
  243. void egl_cache_t::loadBlobCacheLocked() {
  244. if (mFilename.length() > 0) {
  245. size_t headerSize = cacheFileHeaderSize;
  246. int fd = open(mFilename.string(), O_RDONLY, 0);
  247. if (fd == -1) {
  248. if (errno != ENOENT) {
  249. ALOGE("error opening cache file %s: %s (%d)", mFilename.string(),
  250. strerror(errno), errno);
  251. }
  252. return;
  253. }
  254. struct stat statBuf;
  255. if (fstat(fd, &statBuf) == -1) {
  256. ALOGE("error stat'ing cache file: %s (%d)", strerror(errno), errno);
  257. close(fd);
  258. return;
  259. }
  260. // Sanity check the size before trying to mmap it.
  261. size_t fileSize = statBuf.st_size;
  262. if (fileSize > maxTotalSize * 2) {
  263. ALOGE("cache file is too large: %#llx", statBuf.st_size);
  264. close(fd);
  265. return;
  266. }
  267. uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(NULL, fileSize,
  268. PROT_READ, MAP_PRIVATE, fd, 0));
  269. if (buf == MAP_FAILED) {
  270. ALOGE("error mmaping cache file: %s (%d)", strerror(errno),
  271. errno);
  272. close(fd);
  273. return;
  274. }
  275. // Check the file magic and CRC
  276. size_t cacheSize = fileSize - headerSize;
  277. if (memcmp(buf, cacheFileMagic, 4) != 0) {
  278. ALOGE("cache file has bad mojo");
  279. close(fd);
  280. return;
  281. }
  282. uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4);
  283. if (crc32c(buf + headerSize, cacheSize) != *crc) {
  284. ALOGE("cache file failed CRC check");
  285. close(fd);
  286. return;
  287. }
  288. status_t err = mBlobCache->unflatten(buf + headerSize, cacheSize);
  289. if (err != OK) {
  290. ALOGE("error reading cache contents: %s (%d)", strerror(-err),
  291. -err);
  292. munmap(buf, fileSize);
  293. close(fd);
  294. return;
  295. }
  296. munmap(buf, fileSize);
  297. close(fd);
  298. }
  299. }
  300. // ----------------------------------------------------------------------------
  301. }; // namespace android
  302. // ----------------------------------------------------------------------------