EGL Multifile Blobcache: Handle lost cache
During execution, if the app's cache is cleared from outside
our control, two issues occur:
* New entries won't persist to disk because the multifile directory
is missing.
* applyLRU will abort eviction, allowing entries beyond the limits.
To address this, this CL:
* Adds missing directory detection to our deferred write thread
which then attempts to recreate it and continue.
* Updates eviction to issue a warning rather than abort so it can
update tracking and continue.
For missing entries, the app will get hits from hotcache, but
anything beyond that will become a miss.
Additional tests:
* RecoverFromLostCache
* EvictAfterLostCache
Based on work by: Igor Nazarov <i.nazarov@samsung.com>
Test: libEGL_test, EGL_test, ANGLE trace tests, apps
Bug: b/351867582, b/380483358
Flag: com.android.graphics.egl.flags.multifile_blobcache_advanced_usage
Change-Id: I13c8cdf58c957163eed4498c0d4be180574bf03e
diff --git a/opengl/libs/EGL/MultifileBlobCache.cpp b/opengl/libs/EGL/MultifileBlobCache.cpp
index 53a08bb..1f6d4d0 100644
--- a/opengl/libs/EGL/MultifileBlobCache.cpp
+++ b/opengl/libs/EGL/MultifileBlobCache.cpp
@@ -137,7 +137,7 @@
// Check that our cacheVersion and buildId match
struct stat st;
if (stat(mMultifileDirName.c_str(), &st) == 0) {
- if (checkStatus(mMultifileDirName.c_str())) {
+ if (checkStatus(mMultifileDirName)) {
statusGood = true;
} else {
ALOGV("INIT: Cache status has changed, clearing the cache");
@@ -851,8 +851,8 @@
// Remove it from the system
std::string entryPath = mMultifileDirName + "/" + std::to_string(entryHash);
if (remove(entryPath.c_str()) != 0) {
- ALOGE("LRU: Error removing %s: %s", entryPath.c_str(), std::strerror(errno));
- return false;
+ // Continue evicting invalid item (app's cache might be cleared)
+ ALOGW("LRU: Error removing %s: %s", entryPath.c_str(), std::strerror(errno));
}
// Increment the iterator before clearing the entry
@@ -945,9 +945,36 @@
// Create the file or reset it if already present, read+write for user only
int fd = open(fullPath.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (fd == -1) {
- ALOGE("Cache error in SET - failed to open fullPath: %s, error: %s",
- fullPath.c_str(), std::strerror(errno));
- return;
+ if (flags::multifile_blobcache_advanced_usage()) {
+ struct stat st;
+ if (stat(mMultifileDirName.c_str(), &st) == -1) {
+ ALOGW("Cache directory missing (app's cache cleared?). Recreating...");
+
+ // Restore the multifile directory
+ if (mkdir(mMultifileDirName.c_str(), 0755) != 0 && (errno != EEXIST)) {
+ ALOGE("Cache error in SET - Unable to create directory (%s), errno "
+ "(%i)",
+ mMultifileDirName.c_str(), errno);
+ return;
+ }
+
+ // Create new status file
+ if (!createStatus(mMultifileDirName.c_str())) {
+ ALOGE("Cache error in SET - Failed to create status file!");
+ return;
+ }
+
+ // Try to open the file again
+ fd = open(fullPath.c_str(), O_WRONLY | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR);
+ }
+ }
+
+ if (fd == -1) {
+ ALOGE("Cache error in SET - failed to open fullPath: %s, error: %s",
+ fullPath.c_str(), std::strerror(errno));
+ return;
+ }
}
ALOGV("DEFERRED: Opened fd %i from %s", fd, fullPath.c_str());