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

Commit aec27c30 authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Android (Google) Code Review
Browse files

Merge "Logic for atmoic/tombstone behavior; split mode."

parents 358ad56a 871a8f23
Loading
Loading
Loading
Loading
+55 −9
Original line number Diff line number Diff line
@@ -16,8 +16,9 @@

#include "CacheItem.h"

#include <stdint.h>
#include <inttypes.h>
#include <stdint.h>
#include <sys/xattr.h>

#include <android-base/logging.h>
#include <android-base/stringprintf.h>
@@ -29,13 +30,24 @@ using android::base::StringPrintf;
namespace android {
namespace installd {

CacheItem::CacheItem(const std::shared_ptr<CacheItem>& parent, FTSENT* p) : mParent(parent) {
CacheItem::CacheItem(FTSENT* p) {
    level = p->fts_level;
    directory = S_ISDIR(p->fts_statp->st_mode);
    size = p->fts_statp->st_blocks * 512;
    modified = p->fts_statp->st_mtime;

    mParent = static_cast<CacheItem*>(p->fts_parent->fts_pointer);
    if (mParent) {
        atomic = mParent->atomic;
        tombstone = mParent->tombstone;
        mName = p->fts_name;
        mName.insert(0, "/");
    } else {
        atomic = false;
        tombstone = false;
        mName = p->fts_path;
    }
}

CacheItem::~CacheItem() {
}
@@ -46,7 +58,7 @@ std::string CacheItem::toString() {

std::string CacheItem::buildPath() {
    std::string res = mName;
    std::shared_ptr<CacheItem> parent = mParent;
    CacheItem* parent = mParent;
    while (parent) {
        res.insert(0, parent->mName);
        parent = parent->mParent;
@@ -57,13 +69,47 @@ std::string CacheItem::buildPath() {
int CacheItem::purge() {
    auto path = buildPath();
    if (directory) {
        return delete_dir_contents_and_dir(path, true);
        FTS *fts;
        FTSENT *p;
        char *argv[] = { (char*) path.c_str(), nullptr };
        if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_XDEV, NULL))) {
            PLOG(WARNING) << "Failed to fts_open " << path;
            return -1;
        }
        while ((p = fts_read(fts)) != nullptr) {
            switch (p->fts_info) {
            case FTS_D:
                if (p->fts_level == 0) {
                    p->fts_number = tombstone;
                } else {
        int res = unlink(path.c_str());
        if (res != 0) {
            PLOG(WARNING) << "Failed to unlink " << path;
                    p->fts_number = p->fts_parent->fts_number
                            | (getxattr(p->fts_path, kXattrCacheTombstone, nullptr, 0) >= 0);
                }
                break;
            case FTS_F:
                if (p->fts_parent->fts_number) {
                    truncate(p->fts_path, 0);
                } else {
                    unlink(p->fts_path);
                }
                break;
            case FTS_DEFAULT:
            case FTS_SL:
            case FTS_SLNONE:
                unlink(p->fts_path);
                break;
            case FTS_DP:
                rmdir(p->fts_path);
                break;
            }
        }
        return 0;
    } else {
        if (tombstone) {
            return truncate(path.c_str(), 0);
        } else {
            return unlink(path.c_str());
        }
        return res;
    }
}

+4 −2
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@ namespace installd {
 */
class CacheItem {
public:
    CacheItem(const std::shared_ptr<CacheItem>& parent, FTSENT* p);
    CacheItem(FTSENT* p);
    ~CacheItem();

    std::string toString();
@@ -46,11 +46,13 @@ public:

    short level;
    bool directory;
    bool atomic;
    bool tombstone;
    int64_t size;
    time_t modified;

private:
    std::shared_ptr<CacheItem> mParent;
    CacheItem* mParent;
    std::string mName;

    DISALLOW_COPY_AND_ASSIGN(CacheItem);
+49 −19
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@

#include <fts.h>
#include <sys/quota.h>
#include <sys/xattr.h>
#include <utils/Trace.h>

#include <android-base/logging.h>
@@ -86,30 +87,59 @@ void CacheTracker::loadItemsFrom(const std::string& path) {
        PLOG(WARNING) << "Failed to fts_open " << path;
        return;
    }
    // TODO: add support for "user.atomic" and "user.tombstone" xattrs
    while ((p = fts_read(fts)) != NULL) {
    while ((p = fts_read(fts)) != nullptr) {
        if (p->fts_level == 0) continue;

        // Create tracking nodes for everything we encounter
        switch (p->fts_info) {
        case FTS_D:
            // Track the newest mtime of anything inside so we consider
            // deleting the directory last
            p->fts_number = p->fts_statp->st_mtime;
            break;
        case FTS_DP:
            p->fts_statp->st_mtime = p->fts_number;
        case FTS_DEFAULT:
        case FTS_F:
        case FTS_SL:
        case FTS_SLNONE: {
            auto item = std::shared_ptr<CacheItem>(new CacheItem(p));
            p->fts_pointer = static_cast<void*>(item.get());
            items.push_back(item);
        }
        }

            // Ignore the actual top-level cache directories
            if (p->fts_level == 0) break;
        switch (p->fts_info) {
        case FTS_D: {
            auto item = static_cast<CacheItem*>(p->fts_pointer);
            item->atomic |= (getxattr(p->fts_path, kXattrCacheAtomic, nullptr, 0) >= 0);
            item->tombstone |= (getxattr(p->fts_path, kXattrCacheTombstone, nullptr, 0) >= 0);

            // When atomic, immediately collect all files under tree
            if (item->atomic) {
                while ((p = fts_read(fts)) != nullptr) {
                    if (p->fts_info == FTS_DP && p->fts_level == item->level) break;
                    switch (p->fts_info) {
                    case FTS_D:
                    case FTS_DEFAULT:
                    case FTS_F:
                    case FTS_SL:
                    case FTS_SLNONE:
            // TODO: optimize path memory footprint
            items.push_back(std::shared_ptr<CacheItem>(new CacheItem(nullptr, p)));
                        item->size += p->fts_statp->st_blocks * 512;
                        item->modified = std::max(item->modified, p->fts_statp->st_mtime);
                    }
                }
            }
        }
        }

            // Track the newest modified item under this tree
            p->fts_parent->fts_number =
                    std::max(p->fts_parent->fts_number, p->fts_statp->st_mtime);
            break;
        // Bubble up modified time to parent
        switch (p->fts_info) {
        case FTS_DP:
        case FTS_DEFAULT:
        case FTS_F:
        case FTS_SL:
        case FTS_SLNONE: {
            auto item = static_cast<CacheItem*>(p->fts_pointer);
            auto parent = static_cast<CacheItem*>(p->fts_parent->fts_pointer);
            if (parent) {
                parent->modified = std::max(parent->modified, item->modified);
            }
        }
        }
    }
    fts_close(fts);
@@ -137,7 +167,7 @@ void CacheTracker::loadItems() {
        }
        return left->directory;
    };
    std::sort(items.begin(), items.end(), cmp);
    std::stable_sort(items.begin(), items.end(), cmp);
    ATRACE_END();
}

+10 −1
Original line number Diff line number Diff line
@@ -86,7 +86,8 @@ static constexpr int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
static constexpr int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9;
static constexpr int FLAG_USE_QUOTA = 1 << 12;
static constexpr int FLAG_FREE_CACHE_V2 = 1 << 13;
static constexpr int FLAG_FREE_CACHE_NOOP = 1 << 14;
static constexpr int FLAG_FREE_CACHE_V2_DEFY_QUOTA = 1 << 14;
static constexpr int FLAG_FREE_CACHE_NOOP = 1 << 15;

namespace {

@@ -833,6 +834,14 @@ binder::Status InstalldNativeService::freeCache(const std::unique_ptr<std::strin
        ATRACE_BEGIN("bounce");
        std::shared_ptr<CacheTracker> active;
        while (active || !queue.empty()) {
            // Only look at apps under quota when explicitly requested
            if (active && (active->getCacheRatio() < 10000)
                    && !(flags & FLAG_FREE_CACHE_V2_DEFY_QUOTA)) {
                LOG(DEBUG) << "Active ratio " << active->getCacheRatio()
                        << " isn't over quota, and defy not requested";
                break;
            }

            // Find the best tracker to work with; this might involve swapping
            // if the active tracker is no longer the most over quota
            bool nextBetter = active && !queue.empty()
+19 −0
Original line number Diff line number Diff line
@@ -14,3 +14,22 @@ cc_test {
        "libdiskusage",
    ],
}

cc_test {
    name: "installd_cache_test",
    clang: true,
    srcs: ["installd_cache_test.cpp"],
    shared_libs: [
        "libbase",
        "libbinder",
        "libcutils",
        "liblog",
        "liblogwrap",
        "libselinux",
        "libutils",
    ],
    static_libs: [
        "libinstalld",
        "libdiskusage",
    ],
}
Loading