Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 027f242a authored by Cody Northrop's avatar Cody Northrop
Browse files

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
parent b5267034
Loading
Loading
Loading
Loading
+196 −7
Original line number Diff line number Diff line
@@ -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 @@ namespace android {
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 @@ MultifileBlobCache::MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, s
        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 @@ MultifileBlobCache::MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, s
    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 @@ MultifileBlobCache::MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, s
                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 @@ MultifileBlobCache::MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, s
                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 @@ MultifileBlobCache::MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, s
                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 @@ MultifileBlobCache::MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, s
                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 @@ MultifileBlobCache::MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, s

                // 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 @@ MultifileBlobCache::MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, s
        // 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 @@ void MultifileBlobCache::finish() {
    }
}

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 @@ bool MultifileBlobCache::applyLRU(size_t cacheSizeLimit, size_t cacheEntryLimit)
    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
+24 −0
Original line number Diff line number Diff line
@@ -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 @@ struct MultifileEntryStats {
    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 @@ public:
    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 @@ private:
    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 @@ private:
    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;
+217 −1
Original line number Diff line number Diff line
@@ -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 @@ constexpr size_t kMaxTotalEntries = 64;
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 @@ TEST_F(MultifileBlobCacheTest, EnsureFileDescriptorsClosed) {
    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
+6 −5
Original line number Diff line number Diff line
@@ -114,25 +114,26 @@ std::string EGLCacheTest::getCachefileName() {
    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 = "";