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

Commit 4d9746d7 authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Gerrit Code Review
Browse files

Merge "Methods to calculate user and external disk usage."

parents b73de86f df2d754b
Loading
Loading
Loading
Loading
+362 −81
Original line number Diff line number Diff line
@@ -53,12 +53,12 @@
#include "otapreopt_utils.h"
#include "utils.h"

#include "MatchExtensionGen.h"

#ifndef LOG_TAG
#define LOG_TAG "installd"
#endif

#define MEASURE_EXTERNAL 0

using android::base::StringPrintf;

namespace android {
@@ -756,7 +756,7 @@ binder::Status InstalldNativeService::destroyUserData(const std::unique_ptr<std:
            if (delete_dir_contents_and_dir(path, true) != 0) {
                res = error("Failed to delete " + path);
            }
            path = create_data_user_profiles_path(userId);
            path = create_data_user_profile_path(userId);
            if (delete_dir_contents_and_dir(path, true) != 0) {
                res = error("Failed to delete " + path);
            }
@@ -849,36 +849,33 @@ binder::Status InstalldNativeService::rmdex(const std::string& codePath,
    }
}

static bool uuidEquals(const std::unique_ptr<std::string>& a,
        const std::unique_ptr<std::string>& b) {
    if (!a && !b) {
        return true;
    } else if (!a && b) {
        return false;
    } else if (a && !b) {
        return false;
    } else {
        return *a == *b;
    }
}

struct stats {
    int64_t codeSize;
    int64_t dataSize;
    int64_t cacheSize;
};

static void collectQuotaStats(const std::unique_ptr<std::string>& uuid, int32_t userId,
        int32_t appId, struct stats* stats) {
    struct dqblk dq;
#if MEASURE_DEBUG
static std::string toString(std::vector<int64_t> values) {
    std::stringstream res;
    res << "[";
    for (size_t i = 0; i < values.size(); i++) {
        res << values[i];
        if (i < values.size() - 1) {
            res << ",";
        }
    }
    res << "]";
    return res.str();
}
#endif

static std::string findDeviceForUuid(const std::unique_ptr<std::string>& uuid) {
    auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
    std::string device;
    {
    std::ifstream in("/proc/mounts");
    if (!in.is_open()) {
        PLOG(ERROR) << "Failed to read mounts";
            return;
        return "";
    }
    std::string source;
    std::string target;
@@ -886,18 +883,21 @@ static void collectQuotaStats(const std::unique_ptr<std::string>& uuid, int32_t
        std::getline(in, source, ' ');
        std::getline(in, target, ' ');
        if (target == path) {
                device = source;
                break;
            return source;
        }
        // Skip to next line
        std::getline(in, source);
    }
    }
    if (device.empty()) {
    PLOG(ERROR) << "Failed to resolve block device for " << path;
        return;
    return "";
}

static void collectQuotaStats(const std::string& device, int32_t userId,
        int32_t appId, struct stats* stats, struct stats* extStats ATTRIBUTE_UNUSED) {
    if (device.empty()) return;

    struct dqblk dq;

    uid_t uid = multiuser_get_uid(userId, appId);
    if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
            reinterpret_cast<char*>(&dq)) != 0) {
@@ -905,6 +905,9 @@ static void collectQuotaStats(const std::unique_ptr<std::string>& uuid, int32_t
            PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
        }
    } else {
#if MEASURE_DEBUG
        LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
#endif
        stats->dataSize += dq.dqb_curspace;
    }

@@ -916,6 +919,9 @@ static void collectQuotaStats(const std::unique_ptr<std::string>& uuid, int32_t
                PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << cacheGid;
            }
        } else {
#if MEASURE_DEBUG
        LOG(DEBUG) << "quotactl() for GID " << cacheGid << " " << dq.dqb_curspace;
#endif
            stats->cacheSize += dq.dqb_curspace;
        }
    }
@@ -928,12 +934,24 @@ static void collectQuotaStats(const std::unique_ptr<std::string>& uuid, int32_t
                PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << sharedGid;
            }
        } else {
#if MEASURE_DEBUG
        LOG(DEBUG) << "quotactl() for GID " << sharedGid << " " << dq.dqb_curspace;
#endif
            stats->codeSize += dq.dqb_curspace;
        }
    }

#if MEASURE_EXTERNAL
    // TODO: measure using external GIDs
#endif
}

static void collectQuotaStats(const std::unique_ptr<std::string>& uuid, int32_t userId,
        int32_t appId, struct stats* stats, struct stats* extStats) {
    collectQuotaStats(findDeviceForUuid(uuid), userId, appId, stats, extStats);
}

static void collectManualStats(std::string& path, struct stats* stats) {
static void collectManualStats(const std::string& path, struct stats* stats) {
    DIR *d;
    int dfd;
    struct dirent *de;
@@ -983,17 +1001,55 @@ static void collectManualStats(std::string& path, struct stats* stats) {
    closedir(d);
}

static void collectManualStatsForUser(const std::string& path, struct stats* stats,
        bool exclude_apps = false) {
    DIR *d;
    int dfd;
    struct dirent *de;
    struct stat s;

    d = opendir(path.c_str());
    if (d == nullptr) {
        if (errno != ENOENT) {
            PLOG(WARNING) << "Failed to open " << path;
        }
        return;
    }
    dfd = dirfd(d);
    while ((de = readdir(d))) {
        if (de->d_type == DT_DIR) {
            const char *name = de->d_name;
            if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) != 0) {
                continue;
            }
            if (!strcmp(name, ".") || !strcmp(name, "..")) {
                continue;
            } else if (exclude_apps && (s.st_uid >= AID_APP_START && s.st_uid <= AID_APP_END)) {
                continue;
            } else {
                collectManualStats(StringPrintf("%s/%s", path.c_str(), name), stats);
            }
        }
    }
    closedir(d);
}

binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::string>& uuid,
        const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
        int64_t ceDataInode, const std::string& codePath,
        const std::unique_ptr<std::string>& externalUuid, std::vector<int64_t>* _aidl_return) {
        const std::vector<std::string>& packageNames, int32_t userId, int32_t flags,
        int32_t appId, const std::vector<int64_t>& ceDataInodes,
        const std::vector<std::string>& codePaths, std::vector<int64_t>* _aidl_return) {
    ENFORCE_UID(AID_SYSTEM);
    CHECK_ARGUMENT_UUID(uuid);
    for (auto packageName : packageNames) {
        CHECK_ARGUMENT_PACKAGE_NAME(packageName);
    }

    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
    const char* extuuid_ = externalUuid ? externalUuid->c_str() : nullptr;
    const char* pkgname = packageName.c_str();
    // When modifying this logic, always verify using tests:
    // runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetAppSize

#if MEASURE_DEBUG
    LOG(INFO) << "Measuring user " << userId << " app " << appId;
#endif

    // Here's a summary of the common storage locations across the platform,
    // and how they're each tagged:
@@ -1002,31 +1058,41 @@ binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::stri
    // /data/app/com.example/oat                       UID system
    // /data/user/0/com.example                        UID u0_a10      GID u0_a10
    // /data/user/0/com.example/cache                  UID u0_a10      GID u0_a10_cache
    // /data/media/0/Android/data/com.example          UID u0_a10 GID u0_a10
    // /data/media/0/Android/data/com.example/cache    UID u0_a10 GID u0_a10_cache
    // /data/media/0/Android/obb/com.example           UID system
    // /data/media/0/foo.txt                           UID u0_media_rw
    // /data/media/0/bar.jpg                           UID u0_media_rw GID u0_media_image
    // /data/media/0/Android/data/com.example          UID u0_media_rw GID u0_a10_ext
    // /data/media/0/Android/data/com.example/cache    UID u0_media_rw GID u0_a10_ext_cache
    // /data/media/obb/com.example                     UID system

    struct stats stats;
    struct stats extStats;
    memset(&stats, 0, sizeof(stats));
    memset(&extStats, 0, sizeof(extStats));

    auto obbCodePath = create_data_media_package_path(extuuid_, userId, pkgname, "obb");
    calculate_tree_size(obbCodePath, &stats.codeSize);

    if (flags & FLAG_USE_QUOTA) {
        calculate_tree_size(codePath, &stats.codeSize,
                0, multiuser_get_shared_gid(userId, appId));
    const char* uuid_ = uuid ? uuid->c_str() : nullptr;

        collectQuotaStats(uuid, userId, appId, &stats);
    for (auto packageName : packageNames) {
        auto obbCodePath = create_data_media_obb_path(uuid_, packageName.c_str());
        calculate_tree_size(obbCodePath, &extStats.codeSize);
    }

        // If external storage lives on a different storage device, also
        // collect quota stats from that block device
        if (!uuidEquals(uuid, externalUuid)) {
            collectQuotaStats(externalUuid, userId, appId, &stats);
    if (flags & FLAG_USE_QUOTA && appId >= AID_APP_START) {
        for (auto codePath : codePaths) {
            calculate_tree_size(codePath, &stats.codeSize, -1,
                    multiuser_get_shared_gid(userId, appId));
        }

        collectQuotaStats(uuid, userId, appId, &stats, &extStats);

    } else {
        for (auto codePath : codePaths) {
            calculate_tree_size(codePath, &stats.codeSize);
        }

        for (size_t i = 0; i < packageNames.size(); i++) {
            const char* pkgname = packageNames[i].c_str();

        auto cePath = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInode);
            auto cePath = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInodes[i]);
            collectManualStats(cePath, &stats);

            auto dePath = create_data_user_de_package_path(uuid_, userId, pkgname);
@@ -1038,25 +1104,240 @@ binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::stri
            auto refProfilePath = create_data_ref_profile_package_path(pkgname);
            calculate_tree_size(refProfilePath, &stats.codeSize);

#if MEASURE_EXTERNAL
            auto extPath = create_data_media_package_path(uuid_, userId, pkgname, "data");
            collectManualStats(extPath, &extStats);

            auto mediaPath = create_data_media_package_path(uuid_, userId, pkgname, "media");
            calculate_tree_size(mediaPath, &extStats.dataSize);
#endif
        }

        int32_t sharedGid = multiuser_get_shared_gid(userId, appId);
        if (sharedGid != -1) {
            calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize,
                multiuser_get_shared_gid(userId, appId), 0);
                    sharedGid, -1);
        }

        calculate_tree_size(create_data_misc_foreign_dex_path(userId), &stats.dataSize,
                multiuser_get_uid(userId, appId), 0);
                multiuser_get_uid(userId, appId), -1);
    }

    std::vector<int64_t> ret;
    ret.push_back(stats.codeSize);
    ret.push_back(stats.dataSize);
    ret.push_back(stats.cacheSize);
    ret.push_back(extStats.codeSize);
    ret.push_back(extStats.dataSize);
    ret.push_back(extStats.cacheSize);
#if MEASURE_DEBUG
    LOG(DEBUG) << "Final result " << toString(ret);
#endif
    *_aidl_return = ret;
    return ok();
}

binder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::string>& uuid,
        int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
        std::vector<int64_t>* _aidl_return) {
    ENFORCE_UID(AID_SYSTEM);
    CHECK_ARGUMENT_UUID(uuid);

    // When modifying this logic, always verify using tests:
    // runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetUserSize

#if MEASURE_DEBUG
    LOG(INFO) << "Measuring user " << userId;
#endif

    struct stats stats;
    struct stats extStats;
    memset(&stats, 0, sizeof(stats));
    memset(&extStats, 0, sizeof(extStats));

    const char* uuid_ = uuid ? uuid->c_str() : nullptr;

    auto obbPath = create_data_path(uuid_) + "/media/obb";
    calculate_tree_size(obbPath, &extStats.codeSize);

    if (flags & FLAG_USE_QUOTA) {
        calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize, -1, -1, true);

        auto cePath = create_data_user_ce_path(uuid_, userId);
        collectManualStatsForUser(cePath, &stats, true);

        auto dePath = create_data_user_de_path(uuid_, userId);
        collectManualStatsForUser(dePath, &stats, true);

        auto userProfilePath = create_data_user_profile_path(userId);
        calculate_tree_size(userProfilePath, &stats.dataSize, -1, -1, true);

        auto refProfilePath = create_data_ref_profile_path();
        calculate_tree_size(refProfilePath, &stats.codeSize, -1, -1, true);

#if MEASURE_EXTERNAL
        auto extPath = create_data_media_package_path(extuuid_, userId, pkgname, "data");
        collectManualStats(extPath, &stats);
        // TODO: measure external storage paths
#endif

        auto mediaPath = create_data_media_package_path(extuuid_, userId, pkgname, "media");
        calculate_tree_size(mediaPath, &stats.dataSize);
        calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize,
                -1, -1, true);

        calculate_tree_size(create_data_misc_foreign_dex_path(userId), &stats.dataSize,
                -1, -1, true);

        auto device = findDeviceForUuid(uuid);
        for (auto appId : appIds) {
            if (appId >= AID_APP_START) {
                collectQuotaStats(device, userId, appId, &stats, &extStats);
#if MEASURE_DEBUG
                // Sleep to make sure we don't lose logs
                usleep(1);
#endif
            }
        }
    } else {
        calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize);

        auto cePath = create_data_user_ce_path(uuid_, userId);
        collectManualStatsForUser(cePath, &stats);

        auto dePath = create_data_user_de_path(uuid_, userId);
        collectManualStatsForUser(dePath, &stats);

        auto userProfilePath = create_data_user_profile_path(userId);
        calculate_tree_size(userProfilePath, &stats.dataSize);

        auto refProfilePath = create_data_ref_profile_path();
        calculate_tree_size(refProfilePath, &stats.codeSize);

#if MEASURE_EXTERNAL
        // TODO: measure external storage paths
#endif

        calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize);

        calculate_tree_size(create_data_misc_foreign_dex_path(userId), &stats.dataSize);
    }

    std::vector<int64_t> ret;
    ret.push_back(stats.codeSize);
    ret.push_back(stats.dataSize);
    ret.push_back(stats.cacheSize);
    ret.push_back(extStats.codeSize);
    ret.push_back(extStats.dataSize);
    ret.push_back(extStats.cacheSize);
#if MEASURE_DEBUG
    LOG(DEBUG) << "Final result " << toString(ret);
#endif
    *_aidl_return = ret;
    return ok();
}

binder::Status InstalldNativeService::getExternalSize(const std::unique_ptr<std::string>& uuid,
        int32_t userId, int32_t flags, std::vector<int64_t>* _aidl_return) {
    ENFORCE_UID(AID_SYSTEM);
    CHECK_ARGUMENT_UUID(uuid);

    // When modifying this logic, always verify using tests:
    // runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetExternalSize

#if MEASURE_DEBUG
    LOG(INFO) << "Measuring external " << userId;
#endif

    const char* uuid_ = uuid ? uuid->c_str() : nullptr;

    int64_t totalSize = 0;
    int64_t audioSize = 0;
    int64_t videoSize = 0;
    int64_t imageSize = 0;

    if (flags & FLAG_USE_QUOTA) {
        struct dqblk dq;

        auto device = findDeviceForUuid(uuid);

        uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW);
        if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
                reinterpret_cast<char*>(&dq)) != 0) {
            if (errno != ESRCH) {
                PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
            }
        } else {
#if MEASURE_DEBUG
        LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
#endif
            totalSize = dq.dqb_curspace;
        }

        gid_t audioGid = multiuser_get_uid(userId, AID_MEDIA_AUDIO);
        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), audioGid,
                reinterpret_cast<char*>(&dq)) == 0) {
#if MEASURE_DEBUG
        LOG(DEBUG) << "quotactl() for GID " << audioGid << " " << dq.dqb_curspace;
#endif
            audioSize = dq.dqb_curspace;
        }
        gid_t videoGid = multiuser_get_uid(userId, AID_MEDIA_VIDEO);
        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), videoGid,
                reinterpret_cast<char*>(&dq)) == 0) {
#if MEASURE_DEBUG
        LOG(DEBUG) << "quotactl() for GID " << videoGid << " " << dq.dqb_curspace;
#endif
            videoSize = dq.dqb_curspace;
        }
        gid_t imageGid = multiuser_get_uid(userId, AID_MEDIA_IMAGE);
        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), imageGid,
                reinterpret_cast<char*>(&dq)) == 0) {
#if MEASURE_DEBUG
        LOG(DEBUG) << "quotactl() for GID " << imageGid << " " << dq.dqb_curspace;
#endif
            imageSize = dq.dqb_curspace;
        }
    } else {
        FTS *fts;
        FTSENT *p;
        auto path = create_data_media_path(uuid_, userId);
        char *argv[] = { (char*) path.c_str(), nullptr };
        if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_XDEV, NULL))) {
            return error("Failed to fts_open " + path);
        }
        while ((p = fts_read(fts)) != NULL) {
            char* ext;
            int64_t size = (p->fts_statp->st_blocks * 512);
            switch (p->fts_info) {
            case FTS_F:
                // Only categorize files not belonging to apps
                if (p->fts_statp->st_gid < AID_APP_START) {
                    ext = strrchr(p->fts_name, '.');
                    if (ext != nullptr) {
                        switch (MatchExtension(++ext)) {
                        case AID_MEDIA_AUDIO: audioSize += size; break;
                        case AID_MEDIA_VIDEO: videoSize += size; break;
                        case AID_MEDIA_IMAGE: imageSize += size; break;
                        }
                    }
                }
                // Fall through to always count against total
            case FTS_D:
            case FTS_DEFAULT:
            case FTS_SL:
            case FTS_SLNONE:
                totalSize += size;
                break;
            }
        }
        fts_close(fts);
    }

    std::vector<int64_t> ret;
    ret.push_back(totalSize);
    ret.push_back(audioSize);
    ret.push_back(videoSize);
    ret.push_back(imageSize);
#if MEASURE_DEBUG
    LOG(DEBUG) << "Final result " << toString(ret);
#endif
    *_aidl_return = ret;
    return ok();
}
+9 −3
Original line number Diff line number Diff line
@@ -55,10 +55,16 @@ public:
            const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode);
    binder::Status destroyAppData(const std::unique_ptr<std::string>& uuid,
            const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode);

    binder::Status getAppSize(const std::unique_ptr<std::string>& uuid,
            const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
            int64_t ceDataInode, const std::string& codePath,
            const std::unique_ptr<std::string>& externalUuid, std::vector<int64_t>* _aidl_return);
            const std::vector<std::string>& packageNames, int32_t userId, int32_t flags,
            int32_t appId, const std::vector<int64_t>& ceDataInodes,
            const std::vector<std::string>& codePaths, std::vector<int64_t>* _aidl_return);
    binder::Status getUserSize(const std::unique_ptr<std::string>& uuid,
            int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
            std::vector<int64_t>* _aidl_return);
    binder::Status getExternalSize(const std::unique_ptr<std::string>& uuid,
            int32_t userId, int32_t flags, std::vector<int64_t>* _aidl_return);

    binder::Status moveCompleteApp(const std::unique_ptr<std::string>& fromUuid,
            const std::unique_ptr<std::string>& toUuid, const std::string& packageName,
+628 −0

File added.

Preview size limit exceeded, changes collapsed.

+6 −3
Original line number Diff line number Diff line
@@ -31,9 +31,12 @@ interface IInstalld {
            int userId, int flags, long ceDataInode);
    void destroyAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
            int userId, int flags, long ceDataInode);
    long[] getAppSize(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
            int userId, int flags, int appId, long ceDataInode, @utf8InCpp String codePath,
            @nullable @utf8InCpp String externalUuid);

    long[] getAppSize(@nullable @utf8InCpp String uuid, in @utf8InCpp String[] packageNames,
            int userId, int flags, int appId, in long[] ceDataInodes,
            in @utf8InCpp String[] codePaths);
    long[] getUserSize(@nullable @utf8InCpp String uuid, int userId, int flags, in int[] appIds);
    long[] getExternalSize(@nullable @utf8InCpp String uuid, int userId, int flags);

    void moveCompleteApp(@nullable @utf8InCpp String fromUuid, @nullable @utf8InCpp String toUuid,
            @utf8InCpp String packageName, @utf8InCpp String dataAppName, int appId,
+80 −0
Original line number Diff line number Diff line
#!/usr/bin/env python

# Copyright (C) 2017 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an 'AS IS' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import collections

TYPES = {
    "AID_MEDIA_AUDIO": ["aac","aac","amr","awb","snd","flac","flac","mp3","mpga","mpega","mp2","m4a","aif","aiff","aifc","gsm","mka","m3u","wma","wax","ra","rm","ram","ra","pls","sd2","wav","ogg","oga"],
    "AID_MEDIA_VIDEO": ["3gpp","3gp","3gpp2","3g2","avi","dl","dif","dv","fli","m4v","ts","mpeg","mpg","mpe","mp4","vob","qt","mov","mxu","webm","lsf","lsx","mkv","mng","asf","asx","wm","wmv","wmx","wvx","movie","wrf"],
    "AID_MEDIA_IMAGE": ["bmp","gif","jpg","jpeg","jpe","pcx","png","svg","svgz","tiff","tif","wbmp","webp","dng","cr2","ras","art","jng","nef","nrw","orf","rw2","pef","psd","pnm","pbm","pgm","ppm","srw","arw","rgb","xbm","xpm","xwd"]
}

print """/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/******************************************************************
 * THIS CODE WAS GENERATED BY matchgen.py, DO NOT MODIFY DIRECTLY *
 ******************************************************************/

#include <private/android_filesystem_config.h>

int MatchExtension(const char* ext) {
"""

trie = collections.defaultdict(lambda: collections.defaultdict(lambda: collections.defaultdict(lambda: collections.defaultdict(lambda: collections.defaultdict(lambda: collections.defaultdict(lambda: ""))))))

for t in TYPES:
    for v in TYPES[t]:
        v = v.lower()
        target = trie
        for c in v:
            target = target[c]
        target["\0"] = t

def dump(target, index):
    prefix = "    " * (index + 1)
    print "%sswitch (ext[%d]) {" % (prefix, index)
    for k in sorted(target.keys()):
        if k == "\0":
            print "%scase '\\0': return %s;" % (prefix, target[k])
        else:
            upper = k.upper()
            if k != upper:
                print "%scase '%s': case '%s':" % (prefix, k, upper)
            else:
                print "%scase '%s':" % (prefix, k)
            dump(target[k], index + 1)
    print "%s}" % (prefix)

dump(trie, 0)

print """
    return 0;
}
"""
Loading