EGL Multifile Blobcache: Add status file
Add a status file that contains the cache version and
platform build ID. On future startups, if those values
don't match, clear the cache.
This alleviates a problem on driver updates, which cause
all new queries to miss, creating new entires, filling the
cache. For apps with many small entries, the start up
time has become a problem.
Test: libEGL_test, EGL_test, ANGLE trace tests, apps
Bug: b/295051628
Bug: b/310535559
Change-Id: I17b91fb6c994237fb5c2a220db4f23050d45742b
diff --git a/opengl/libs/EGL/MultifileBlobCache.cpp b/opengl/libs/EGL/MultifileBlobCache.cpp
index 13a5e7b..9905210 100644
--- a/opengl/libs/EGL/MultifileBlobCache.cpp
+++ b/opengl/libs/EGL/MultifileBlobCache.cpp
@@ -18,6 +18,7 @@
#include "MultifileBlobCache.h"
+#include <android-base/properties.h>
#include <dirent.h>
#include <fcntl.h>
#include <inttypes.h>
@@ -64,6 +65,7 @@
MultifileBlobCache::MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize,
size_t maxTotalEntries, const std::string& baseDir)
: mInitialized(false),
+ mCacheVersion(0),
mMaxKeySize(maxKeySize),
mMaxValueSize(maxValueSize),
mMaxTotalSize(maxTotalSize),
@@ -78,6 +80,26 @@
return;
}
+ // Set the cache version, override if debug value set
+ mCacheVersion = kMultifileBlobCacheVersion;
+ int debugCacheVersion = base::GetIntProperty("debug.egl.blobcache.cache_version", -1);
+ if (debugCacheVersion >= 0) {
+ ALOGV("INIT: Using %u as cacheVersion instead of %u", debugCacheVersion, mCacheVersion);
+ mCacheVersion = debugCacheVersion;
+ }
+
+ // Set the platform build ID, override if debug value set
+ mBuildId = base::GetProperty("ro.build.id", "");
+ std::string debugBuildId = base::GetProperty("debug.egl.blobcache.build_id", "");
+ if (!debugBuildId.empty()) {
+ ALOGV("INIT: Using %s as buildId instead of %s", debugBuildId.c_str(), mBuildId.c_str());
+ if (debugBuildId.length() > PROP_VALUE_MAX) {
+ ALOGV("INIT: debugBuildId is too long (%zu), reduce it to %u", debugBuildId.length(),
+ PROP_VALUE_MAX);
+ }
+ mBuildId = debugBuildId;
+ }
+
// Establish the name of our multifile directory
mMultifileDirName = baseDir + ".multifile";
@@ -95,14 +117,30 @@
mTaskThread = std::thread(&MultifileBlobCache::processTasks, this);
// See if the dir exists, and initialize using its contents
+ bool statusGood = false;
+
+ // Check that our cacheVersion and buildId match
struct stat st;
if (stat(mMultifileDirName.c_str(), &st) == 0) {
+ if (checkStatus(mMultifileDirName.c_str())) {
+ statusGood = true;
+ } else {
+ ALOGV("INIT: Cache status has changed, clearing the cache");
+ if (!clearCache()) {
+ ALOGE("INIT: Unable to clear cache");
+ return;
+ }
+ }
+ }
+
+ if (statusGood) {
// Read all the files and gather details, then preload their contents
DIR* dir;
struct dirent* entry;
if ((dir = opendir(mMultifileDirName.c_str())) != nullptr) {
while ((entry = readdir(dir)) != nullptr) {
- if (entry->d_name == "."s || entry->d_name == ".."s) {
+ if (entry->d_name == "."s || entry->d_name == ".."s ||
+ strcmp(entry->d_name, kMultifileBlobCacheStatusFile) == 0) {
continue;
}
@@ -125,7 +163,8 @@
if (st.st_size <= 0 || st.st_atime <= 0) {
ALOGE("INIT: Entry %u has invalid stats! Removing.", entryHash);
if (remove(fullPath.c_str()) != 0) {
- ALOGE("Error removing %s: %s", fullPath.c_str(), std::strerror(errno));
+ ALOGE("INIT: Error removing %s: %s", fullPath.c_str(),
+ std::strerror(errno));
}
continue;
}
@@ -142,7 +181,7 @@
MultifileHeader header;
size_t result = read(fd, static_cast<void*>(&header), sizeof(MultifileHeader));
if (result != sizeof(MultifileHeader)) {
- ALOGE("Error reading MultifileHeader from cache entry (%s): %s",
+ ALOGE("INIT: Error reading MultifileHeader from cache entry (%s): %s",
fullPath.c_str(), std::strerror(errno));
close(fd);
return;
@@ -152,7 +191,8 @@
if (header.magic != kMultifileMagic) {
ALOGE("INIT: Entry %u has bad magic (%u)! Removing.", entryHash, header.magic);
if (remove(fullPath.c_str()) != 0) {
- ALOGE("Error removing %s: %s", fullPath.c_str(), std::strerror(errno));
+ ALOGE("INIT: Error removing %s: %s", fullPath.c_str(),
+ std::strerror(errno));
}
close(fd);
continue;
@@ -177,7 +217,7 @@
if (header.crc !=
crc32c(mappedEntry + sizeof(MultifileHeader),
fileSize - sizeof(MultifileHeader))) {
- ALOGE("INIT: Entry %u failed CRC check! Removing.", entryHash);
+ ALOGV("INIT: Entry %u failed CRC check! Removing.", entryHash);
if (remove(fullPath.c_str()) != 0) {
ALOGE("Error removing %s: %s", fullPath.c_str(), std::strerror(errno));
}
@@ -186,11 +226,12 @@
// If the cache entry is damaged or no good, remove it
if (header.keySize <= 0 || header.valueSize <= 0) {
- ALOGE("INIT: Entry %u has a bad header keySize (%lu) or valueSize (%lu), "
+ ALOGV("INIT: Entry %u has a bad header keySize (%lu) or valueSize (%lu), "
"removing.",
entryHash, header.keySize, header.valueSize);
if (remove(fullPath.c_str()) != 0) {
- ALOGE("Error removing %s: %s", fullPath.c_str(), std::strerror(errno));
+ ALOGE("INIT: Error removing %s: %s", fullPath.c_str(),
+ std::strerror(errno));
}
continue;
}
@@ -228,9 +269,17 @@
// If the multifile directory does not exist, create it and start from scratch
if (mkdir(mMultifileDirName.c_str(), 0755) != 0 && (errno != EEXIST)) {
ALOGE("Unable to create directory (%s), errno (%i)", mMultifileDirName.c_str(), errno);
+ return;
+ }
+
+ // Create new status file
+ if (!createStatus(mMultifileDirName.c_str())) {
+ ALOGE("INIT: Failed to create status file!");
+ return;
}
}
+ ALOGV("INIT: Multifile BlobCache initialization succeeded");
mInitialized = true;
}
@@ -471,6 +520,112 @@
}
}
+bool MultifileBlobCache::createStatus(const std::string& baseDir) {
+ // Populate the status struct
+ struct MultifileStatus status;
+ memset(&status, 0, sizeof(status));
+ status.magic = kMultifileMagic;
+ status.cacheVersion = mCacheVersion;
+
+ // Copy the buildId string in, up to our allocated space
+ strncpy(status.buildId, mBuildId.c_str(),
+ mBuildId.length() > PROP_VALUE_MAX ? PROP_VALUE_MAX : mBuildId.length());
+
+ // Finally update the crc, using cacheVersion and everything the follows
+ status.crc =
+ crc32c(reinterpret_cast<uint8_t*>(&status) + offsetof(MultifileStatus, cacheVersion),
+ sizeof(status) - offsetof(MultifileStatus, cacheVersion));
+
+ // Create the status file
+ std::string cacheStatus = baseDir + "/" + kMultifileBlobCacheStatusFile;
+ int fd = open(cacheStatus.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+ if (fd == -1) {
+ ALOGE("STATUS(CREATE): Unable to create status file: %s, error: %s", cacheStatus.c_str(),
+ std::strerror(errno));
+ return false;
+ }
+
+ // Write the buffer contents to disk
+ ssize_t result = write(fd, &status, sizeof(status));
+ close(fd);
+ if (result != sizeof(status)) {
+ ALOGE("STATUS(CREATE): Error writing cache status file: %s, error %s", cacheStatus.c_str(),
+ std::strerror(errno));
+ return false;
+ }
+
+ ALOGV("STATUS(CREATE): Created status file: %s", cacheStatus.c_str());
+ return true;
+}
+
+bool MultifileBlobCache::checkStatus(const std::string& baseDir) {
+ std::string cacheStatus = baseDir + "/" + kMultifileBlobCacheStatusFile;
+
+ // Does status exist
+ struct stat st;
+ if (stat(cacheStatus.c_str(), &st) != 0) {
+ ALOGV("STATUS(CHECK): Status file (%s) missing", cacheStatus.c_str());
+ return false;
+ }
+
+ // If the status entry is damaged or no good, remove it
+ if (st.st_size <= 0 || st.st_atime <= 0) {
+ ALOGE("STATUS(CHECK): Cache status has invalid stats!");
+ return false;
+ }
+
+ // Open the file so we can read its header
+ int fd = open(cacheStatus.c_str(), O_RDONLY);
+ if (fd == -1) {
+ ALOGE("STATUS(CHECK): Cache error - failed to open cacheStatus: %s, error: %s",
+ cacheStatus.c_str(), std::strerror(errno));
+ return false;
+ }
+
+ // Read in the status header
+ MultifileStatus status;
+ size_t result = read(fd, static_cast<void*>(&status), sizeof(MultifileStatus));
+ close(fd);
+ if (result != sizeof(MultifileStatus)) {
+ ALOGE("STATUS(CHECK): Error reading cache status (%s): %s", cacheStatus.c_str(),
+ std::strerror(errno));
+ return false;
+ }
+
+ // Verify header magic
+ if (status.magic != kMultifileMagic) {
+ ALOGE("STATUS(CHECK): Cache status has bad magic (%u)!", status.magic);
+ return false;
+ }
+
+ // Ensure we have a good CRC
+ if (status.crc !=
+ crc32c(reinterpret_cast<uint8_t*>(&status) + offsetof(MultifileStatus, cacheVersion),
+ sizeof(status) - offsetof(MultifileStatus, cacheVersion))) {
+ ALOGE("STATUS(CHECK): Cache status failed CRC check!");
+ return false;
+ }
+
+ // Check cacheVersion
+ if (status.cacheVersion != mCacheVersion) {
+ ALOGV("STATUS(CHECK): Cache version has changed! old(%u) new(%u)", status.cacheVersion,
+ mCacheVersion);
+ return false;
+ }
+
+ // Check buildId
+ if (strcmp(status.buildId, mBuildId.c_str()) != 0) {
+ ALOGV("STATUS(CHECK): BuildId has changed! old(%s) new(%s)", status.buildId,
+ mBuildId.c_str());
+ return false;
+ }
+
+ // All checks passed!
+ ALOGV("STATUS(CHECK): Status file is good! cacheVersion(%u), buildId(%s) file(%s)",
+ status.cacheVersion, status.buildId, cacheStatus.c_str());
+ return true;
+}
+
void MultifileBlobCache::trackEntry(uint32_t entryHash, EGLsizeiANDROID valueSize, size_t fileSize,
time_t accessTime) {
mEntries.insert(entryHash);
@@ -606,6 +761,40 @@
return false;
}
+// Clear the cache by removing all entries and deleting the directory
+bool MultifileBlobCache::clearCache() {
+ DIR* dir;
+ struct dirent* entry;
+ dir = opendir(mMultifileDirName.c_str());
+ if (dir == nullptr) {
+ ALOGE("CLEAR: Unable to open multifile dir: %s", mMultifileDirName.c_str());
+ return false;
+ }
+
+ // Delete all entries and the status file
+ while ((entry = readdir(dir)) != nullptr) {
+ if (entry->d_name == "."s || entry->d_name == ".."s) {
+ continue;
+ }
+
+ std::string entryName = entry->d_name;
+ std::string fullPath = mMultifileDirName + "/" + entryName;
+ if (remove(fullPath.c_str()) != 0) {
+ ALOGE("CLEAR: Error removing %s: %s", fullPath.c_str(), std::strerror(errno));
+ return false;
+ }
+ }
+
+ // Delete the directory
+ if (remove(mMultifileDirName.c_str()) != 0) {
+ ALOGE("CLEAR: Error removing %s: %s", mMultifileDirName.c_str(), std::strerror(errno));
+ return false;
+ }
+
+ ALOGV("CLEAR: Cleared the multifile blobcache");
+ return true;
+}
+
// When removing files, what fraction of the overall limit should be reached when removing files
// A divisor of two will decrease the cache to 50%, four to 25% and so on
// We use the same limit to manage size and entry count
diff --git a/opengl/libs/EGL/MultifileBlobCache.h b/opengl/libs/EGL/MultifileBlobCache.h
index 9a396f0..18566c2 100644
--- a/opengl/libs/EGL/MultifileBlobCache.h
+++ b/opengl/libs/EGL/MultifileBlobCache.h
@@ -21,6 +21,7 @@
#include <EGL/eglext.h>
#include <android-base/thread_annotations.h>
+#include <cutils/properties.h>
#include <future>
#include <map>
#include <queue>
@@ -33,6 +34,9 @@
namespace android {
+constexpr uint32_t kMultifileBlobCacheVersion = 1;
+constexpr char kMultifileBlobCacheStatusFile[] = "cache.status";
+
struct MultifileHeader {
uint32_t magic;
uint32_t crc;
@@ -46,6 +50,13 @@
time_t accessTime;
};
+struct MultifileStatus {
+ uint32_t magic;
+ uint32_t crc;
+ uint32_t cacheVersion;
+ char buildId[PROP_VALUE_MAX];
+};
+
struct MultifileHotCache {
int entryFd;
uint8_t* entryBuffer;
@@ -105,6 +116,12 @@
size_t getTotalSize() const { return mTotalCacheSize; }
size_t getTotalEntries() const { return mTotalCacheEntries; }
+ const std::string& getCurrentBuildId() const { return mBuildId; }
+ void setCurrentBuildId(const std::string& buildId) { mBuildId = buildId; }
+
+ uint32_t getCurrentCacheVersion() const { return mCacheVersion; }
+ void setCurrentCacheVersion(uint32_t cacheVersion) { mCacheVersion = cacheVersion; }
+
private:
void trackEntry(uint32_t entryHash, EGLsizeiANDROID valueSize, size_t fileSize,
time_t accessTime);
@@ -112,6 +129,9 @@
bool removeEntry(uint32_t entryHash);
MultifileEntryStats getEntryStats(uint32_t entryHash);
+ bool createStatus(const std::string& baseDir);
+ bool checkStatus(const std::string& baseDir);
+
size_t getFileSize(uint32_t entryHash);
size_t getValueSize(uint32_t entryHash);
@@ -121,12 +141,16 @@
bool addToHotCache(uint32_t entryHash, int fd, uint8_t* entryBufer, size_t entrySize);
bool removeFromHotCache(uint32_t entryHash);
+ bool clearCache();
void trimCache();
bool applyLRU(size_t cacheSizeLimit, size_t cacheEntryLimit);
bool mInitialized;
std::string mMultifileDirName;
+ std::string mBuildId;
+ uint32_t mCacheVersion;
+
std::unordered_set<uint32_t> mEntries;
std::unordered_map<uint32_t, MultifileEntryStats> mEntryStats;
std::unordered_map<uint32_t, MultifileHotCache> mHotCache;
diff --git a/opengl/libs/EGL/MultifileBlobCache_test.cpp b/opengl/libs/EGL/MultifileBlobCache_test.cpp
index 8e27f5a..90a0f1e 100644
--- a/opengl/libs/EGL/MultifileBlobCache_test.cpp
+++ b/opengl/libs/EGL/MultifileBlobCache_test.cpp
@@ -16,13 +16,17 @@
#include "MultifileBlobCache.h"
+#include <android-base/properties.h>
#include <android-base/test_utils.h>
#include <fcntl.h>
#include <gtest/gtest.h>
#include <stdio.h>
+#include <fstream>
#include <memory>
+using namespace std::literals;
+
namespace android {
template <typename T>
@@ -36,19 +40,35 @@
class MultifileBlobCacheTest : public ::testing::Test {
protected:
virtual void SetUp() {
+ clearProperties();
mTempFile.reset(new TemporaryFile());
mMBC.reset(new MultifileBlobCache(kMaxKeySize, kMaxValueSize, kMaxTotalSize,
kMaxTotalEntries, &mTempFile->path[0]));
}
- virtual void TearDown() { mMBC.reset(); }
+ virtual void TearDown() {
+ clearProperties();
+ mMBC.reset();
+ }
int getFileDescriptorCount();
+ std::vector<std::string> getCacheEntries();
+
+ void clearProperties();
std::unique_ptr<TemporaryFile> mTempFile;
std::unique_ptr<MultifileBlobCache> mMBC;
};
+void MultifileBlobCacheTest::clearProperties() {
+ // Clear any debug properties used in the tests
+ base::SetProperty("debug.egl.blobcache.cache_version", "");
+ base::WaitForProperty("debug.egl.blobcache.cache_version", "");
+
+ base::SetProperty("debug.egl.blobcache.build_id", "");
+ base::WaitForProperty("debug.egl.blobcache.build_id", "");
+}
+
TEST_F(MultifileBlobCacheTest, CacheSingleValueSucceeds) {
unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
mMBC->set("abcd", 4, "efgh", 4);
@@ -287,4 +307,200 @@
ASSERT_LT(getFileDescriptorCount(), kMaxTotalEntries / 2);
}
+std::vector<std::string> MultifileBlobCacheTest::getCacheEntries() {
+ std::string cachePath = &mTempFile->path[0];
+ std::string multifileDirName = cachePath + ".multifile";
+ std::vector<std::string> cacheEntries;
+
+ struct stat info;
+ if (stat(multifileDirName.c_str(), &info) == 0) {
+ // We have a multifile dir. Skip the status file and return the only entry.
+ DIR* dir;
+ struct dirent* entry;
+ if ((dir = opendir(multifileDirName.c_str())) != nullptr) {
+ while ((entry = readdir(dir)) != nullptr) {
+ if (entry->d_name == "."s || entry->d_name == ".."s) {
+ continue;
+ }
+ if (strcmp(entry->d_name, kMultifileBlobCacheStatusFile) == 0) {
+ continue;
+ }
+ cacheEntries.push_back(multifileDirName + "/" + entry->d_name);
+ }
+ } else {
+ printf("Unable to open %s, error: %s\n", multifileDirName.c_str(),
+ std::strerror(errno));
+ }
+ } else {
+ printf("Unable to stat %s, error: %s\n", multifileDirName.c_str(), std::strerror(errno));
+ }
+
+ return cacheEntries;
+}
+
+TEST_F(MultifileBlobCacheTest, CacheContainsStatus) {
+ struct stat info;
+ std::stringstream statusFile;
+ statusFile << &mTempFile->path[0] << ".multifile/" << kMultifileBlobCacheStatusFile;
+
+ // After INIT, cache should have a status
+ ASSERT_TRUE(stat(statusFile.str().c_str(), &info) == 0);
+
+ // Set one entry
+ mMBC->set("abcd", 4, "efgh", 4);
+
+ // Close the cache so everything writes out
+ mMBC->finish();
+ mMBC.reset();
+
+ // Ensure status lives after closing the cache
+ ASSERT_TRUE(stat(statusFile.str().c_str(), &info) == 0);
+
+ // Open the cache again
+ mMBC.reset(new MultifileBlobCache(kMaxKeySize, kMaxValueSize, kMaxTotalSize, kMaxTotalEntries,
+ &mTempFile->path[0]));
+
+ // Ensure we still have a status
+ ASSERT_TRUE(stat(statusFile.str().c_str(), &info) == 0);
+}
+
+// Verify missing cache status file causes cache the be cleared
+TEST_F(MultifileBlobCacheTest, MissingCacheStatusClears) {
+ // Set one entry
+ mMBC->set("abcd", 4, "efgh", 4);
+
+ // Close the cache so everything writes out
+ mMBC->finish();
+ mMBC.reset();
+
+ // Ensure there is one cache entry
+ ASSERT_EQ(getCacheEntries().size(), 1);
+
+ // Delete the status file
+ std::stringstream statusFile;
+ statusFile << &mTempFile->path[0] << ".multifile/" << kMultifileBlobCacheStatusFile;
+ remove(statusFile.str().c_str());
+
+ // Open the cache again and ensure no cache hits
+ mMBC.reset(new MultifileBlobCache(kMaxKeySize, kMaxValueSize, kMaxTotalSize, kMaxTotalEntries,
+ &mTempFile->path[0]));
+
+ // Ensure we have no entries
+ ASSERT_EQ(getCacheEntries().size(), 0);
+}
+
+// Verify modified cache status file BEGIN causes cache to be cleared
+TEST_F(MultifileBlobCacheTest, ModifiedCacheStatusBeginClears) {
+ // Set one entry
+ mMBC->set("abcd", 4, "efgh", 4);
+
+ // Close the cache so everything writes out
+ mMBC->finish();
+ mMBC.reset();
+
+ // Ensure there is one cache entry
+ ASSERT_EQ(getCacheEntries().size(), 1);
+
+ // Modify the status file
+ std::stringstream statusFile;
+ statusFile << &mTempFile->path[0] << ".multifile/" << kMultifileBlobCacheStatusFile;
+
+ // Stomp on the beginning of the cache file
+ const char* stomp = "BADF00D";
+ std::fstream fs(statusFile.str());
+ fs.seekp(0, std::ios_base::beg);
+ fs.write(stomp, strlen(stomp));
+ fs.flush();
+ fs.close();
+
+ // Open the cache again and ensure no cache hits
+ mMBC.reset(new MultifileBlobCache(kMaxKeySize, kMaxValueSize, kMaxTotalSize, kMaxTotalEntries,
+ &mTempFile->path[0]));
+
+ // Ensure we have no entries
+ ASSERT_EQ(getCacheEntries().size(), 0);
+}
+
+// Verify modified cache status file END causes cache to be cleared
+TEST_F(MultifileBlobCacheTest, ModifiedCacheStatusEndClears) {
+ // Set one entry
+ mMBC->set("abcd", 4, "efgh", 4);
+
+ // Close the cache so everything writes out
+ mMBC->finish();
+ mMBC.reset();
+
+ // Ensure there is one cache entry
+ ASSERT_EQ(getCacheEntries().size(), 1);
+
+ // Modify the status file
+ std::stringstream statusFile;
+ statusFile << &mTempFile->path[0] << ".multifile/" << kMultifileBlobCacheStatusFile;
+
+ // Stomp on the END of the cache status file, modifying its contents
+ const char* stomp = "BADF00D";
+ std::fstream fs(statusFile.str());
+ fs.seekp(-strlen(stomp), std::ios_base::end);
+ fs.write(stomp, strlen(stomp));
+ fs.flush();
+ fs.close();
+
+ // Open the cache again and ensure no cache hits
+ mMBC.reset(new MultifileBlobCache(kMaxKeySize, kMaxValueSize, kMaxTotalSize, kMaxTotalEntries,
+ &mTempFile->path[0]));
+
+ // Ensure we have no entries
+ ASSERT_EQ(getCacheEntries().size(), 0);
+}
+
+// Verify mismatched cacheVersion causes cache to be cleared
+TEST_F(MultifileBlobCacheTest, MismatchedCacheVersionClears) {
+ // Set one entry
+ mMBC->set("abcd", 4, "efgh", 4);
+
+ // Close the cache so everything writes out
+ mMBC->finish();
+ mMBC.reset();
+
+ // Ensure there is one cache entry
+ ASSERT_EQ(getCacheEntries().size(), 1);
+
+ // Set a debug cacheVersion
+ std::string newCacheVersion = std::to_string(kMultifileBlobCacheVersion + 1);
+ ASSERT_TRUE(base::SetProperty("debug.egl.blobcache.cache_version", newCacheVersion.c_str()));
+ ASSERT_TRUE(
+ base::WaitForProperty("debug.egl.blobcache.cache_version", newCacheVersion.c_str()));
+
+ // Open the cache again and ensure no cache hits
+ mMBC.reset(new MultifileBlobCache(kMaxKeySize, kMaxValueSize, kMaxTotalSize, kMaxTotalEntries,
+ &mTempFile->path[0]));
+
+ // Ensure we have no entries
+ ASSERT_EQ(getCacheEntries().size(), 0);
+}
+
+// Verify mismatched buildId causes cache to be cleared
+TEST_F(MultifileBlobCacheTest, MismatchedBuildIdClears) {
+ // Set one entry
+ mMBC->set("abcd", 4, "efgh", 4);
+
+ // Close the cache so everything writes out
+ mMBC->finish();
+ mMBC.reset();
+
+ // Ensure there is one cache entry
+ ASSERT_EQ(getCacheEntries().size(), 1);
+
+ // Set a debug buildId
+ base::SetProperty("debug.egl.blobcache.build_id", "foo");
+ base::WaitForProperty("debug.egl.blobcache.build_id", "foo");
+
+ // Open the cache again and ensure no cache hits
+ mMBC.reset(new MultifileBlobCache(kMaxKeySize, kMaxValueSize, kMaxTotalSize, kMaxTotalEntries,
+ &mTempFile->path[0]));
+
+ // Ensure we have no entries
+ ASSERT_EQ(getCacheEntries().size(), 0);
+}
+
} // namespace android
diff --git a/opengl/tests/EGLTest/egl_cache_test.cpp b/opengl/tests/EGLTest/egl_cache_test.cpp
index f81c68f..ce58182 100644
--- a/opengl/tests/EGLTest/egl_cache_test.cpp
+++ b/opengl/tests/EGLTest/egl_cache_test.cpp
@@ -114,25 +114,26 @@
struct stat info;
if (stat(multifileDirName.c_str(), &info) == 0) {
// Ensure we only have one file to manage
- int realFileCount = 0;
+ int entryFileCount = 0;
- // We have a multifile dir. Return the only real file in it.
+ // We have a multifile dir. Return the only entry file in it.
DIR* dir;
struct dirent* entry;
if ((dir = opendir(multifileDirName.c_str())) != nullptr) {
while ((entry = readdir(dir)) != nullptr) {
- if (entry->d_name == "."s || entry->d_name == ".."s) {
+ if (entry->d_name == "."s || entry->d_name == ".."s ||
+ strcmp(entry->d_name, kMultifileBlobCacheStatusFile) == 0) {
continue;
}
cachefileName = multifileDirName + "/" + entry->d_name;
- realFileCount++;
+ entryFileCount++;
}
} else {
printf("Unable to open %s, error: %s\n",
multifileDirName.c_str(), std::strerror(errno));
}
- if (realFileCount != 1) {
+ if (entryFileCount != 1) {
// If there was more than one real file in the directory, this
// violates test assumptions
cachefileName = "";