diff options
-rw-r--r-- | cmds/installd/InstalldNativeService.cpp | 443 | ||||
-rw-r--r-- | cmds/installd/InstalldNativeService.h | 12 | ||||
-rw-r--r-- | cmds/installd/MatchExtensionGen.h | 628 | ||||
-rw-r--r-- | cmds/installd/binder/android/os/IInstalld.aidl | 9 | ||||
-rw-r--r-- | cmds/installd/matchgen.py | 80 | ||||
-rw-r--r-- | cmds/installd/utils.cpp | 41 | ||||
-rw-r--r-- | cmds/installd/utils.h | 10 |
7 files changed, 1128 insertions, 95 deletions
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index ed5fc4aaee..72efd55912 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -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,54 +849,54 @@ 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; - } - std::string source; - std::string target; - while (!in.eof()) { - std::getline(in, source, ' '); - std::getline(in, target, ' '); - if (target == path) { - device = source; - break; - } - // Skip to next line - std::getline(in, source); + std::ifstream in("/proc/mounts"); + if (!in.is_open()) { + PLOG(ERROR) << "Failed to read mounts"; + return ""; + } + std::string source; + std::string target; + while (!in.eof()) { + std::getline(in, source, ' '); + std::getline(in, target, ' '); + if (target == path) { + return source; } + // Skip to next line + std::getline(in, source); } - if (device.empty()) { - PLOG(ERROR) << "Failed to resolve block device for " << path; - return; - } + PLOG(ERROR) << "Failed to resolve block device for " << path; + 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, @@ -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 collectManualStats(std::string& path, struct stats* stats) { +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(const std::string& path, struct stats* stats) { DIR *d; int dfd; struct dirent *de; @@ -983,80 +1001,343 @@ 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); - CHECK_ARGUMENT_PACKAGE_NAME(packageName); + 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: // // /data/app/com.example UID system // /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/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/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 { - calculate_tree_size(codePath, &stats.codeSize); + for (auto codePath : codePaths) { + calculate_tree_size(codePath, &stats.codeSize); + } - auto cePath = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInode); - collectManualStats(cePath, &stats); + for (size_t i = 0; i < packageNames.size(); i++) { + const char* pkgname = packageNames[i].c_str(); - auto dePath = create_data_user_de_package_path(uuid_, userId, pkgname); - collectManualStats(dePath, &stats); + auto cePath = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInodes[i]); + collectManualStats(cePath, &stats); - auto userProfilePath = create_data_user_profile_package_path(userId, pkgname); - calculate_tree_size(userProfilePath, &stats.dataSize); + auto dePath = create_data_user_de_package_path(uuid_, userId, pkgname); + collectManualStats(dePath, &stats); - auto refProfilePath = create_data_ref_profile_package_path(pkgname); - calculate_tree_size(refProfilePath, &stats.codeSize); + auto userProfilePath = create_data_user_profile_package_path(userId, pkgname); + calculate_tree_size(userProfilePath, &stats.dataSize); - calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize, - multiuser_get_shared_gid(userId, appId), 0); + 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, + 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(); } diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h index cad9e436e2..5397a744cf 100644 --- a/cmds/installd/InstalldNativeService.h +++ b/cmds/installd/InstalldNativeService.h @@ -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, diff --git a/cmds/installd/MatchExtensionGen.h b/cmds/installd/MatchExtensionGen.h new file mode 100644 index 0000000000..fded6b7935 --- /dev/null +++ b/cmds/installd/MatchExtensionGen.h @@ -0,0 +1,628 @@ +/* + * 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) { + + switch (ext[0]) { + case '3': + switch (ext[1]) { + case 'g': case 'G': + switch (ext[2]) { + case '2': + switch (ext[3]) { + case '\0': return AID_MEDIA_VIDEO; + } + case 'p': case 'P': + switch (ext[3]) { + case '\0': return AID_MEDIA_VIDEO; + case 'p': case 'P': + switch (ext[4]) { + case '\0': return AID_MEDIA_VIDEO; + case '2': + switch (ext[5]) { + case '\0': return AID_MEDIA_VIDEO; + } + } + } + } + } + case 'a': case 'A': + switch (ext[1]) { + case 'a': case 'A': + switch (ext[2]) { + case 'c': case 'C': + switch (ext[3]) { + case '\0': return AID_MEDIA_AUDIO; + } + } + case 'i': case 'I': + switch (ext[2]) { + case 'f': case 'F': + switch (ext[3]) { + case '\0': return AID_MEDIA_AUDIO; + case 'c': case 'C': + switch (ext[4]) { + case '\0': return AID_MEDIA_AUDIO; + } + case 'f': case 'F': + switch (ext[4]) { + case '\0': return AID_MEDIA_AUDIO; + } + } + } + case 'm': case 'M': + switch (ext[2]) { + case 'r': case 'R': + switch (ext[3]) { + case '\0': return AID_MEDIA_AUDIO; + } + } + case 'r': case 'R': + switch (ext[2]) { + case 't': case 'T': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + case 'w': case 'W': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + case 's': case 'S': + switch (ext[2]) { + case 'f': case 'F': + switch (ext[3]) { + case '\0': return AID_MEDIA_VIDEO; + } + case 'x': case 'X': + switch (ext[3]) { + case '\0': return AID_MEDIA_VIDEO; + } + } + case 'v': case 'V': + switch (ext[2]) { + case 'i': case 'I': + switch (ext[3]) { + case '\0': return AID_MEDIA_VIDEO; + } + } + case 'w': case 'W': + switch (ext[2]) { + case 'b': case 'B': + switch (ext[3]) { + case '\0': return AID_MEDIA_AUDIO; + } + } + } + case 'b': case 'B': + switch (ext[1]) { + case 'm': case 'M': + switch (ext[2]) { + case 'p': case 'P': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + } + case 'c': case 'C': + switch (ext[1]) { + case 'r': case 'R': + switch (ext[2]) { + case '2': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + } + case 'd': case 'D': + switch (ext[1]) { + case 'i': case 'I': + switch (ext[2]) { + case 'f': case 'F': + switch (ext[3]) { + case '\0': return AID_MEDIA_VIDEO; + } + } + case 'l': case 'L': + switch (ext[2]) { + case '\0': return AID_MEDIA_VIDEO; + } + case 'n': case 'N': + switch (ext[2]) { + case 'g': case 'G': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + case 'v': case 'V': + switch (ext[2]) { + case '\0': return AID_MEDIA_VIDEO; + } + } + case 'f': case 'F': + switch (ext[1]) { + case 'l': case 'L': + switch (ext[2]) { + case 'a': case 'A': + switch (ext[3]) { + case 'c': case 'C': + switch (ext[4]) { + case '\0': return AID_MEDIA_AUDIO; + } + } + case 'i': case 'I': + switch (ext[3]) { + case '\0': return AID_MEDIA_VIDEO; + } + } + } + case 'g': case 'G': + switch (ext[1]) { + case 'i': case 'I': + switch (ext[2]) { + case 'f': case 'F': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + case 's': case 'S': + switch (ext[2]) { + case 'm': case 'M': + switch (ext[3]) { + case '\0': return AID_MEDIA_AUDIO; + } + } + } + case 'j': case 'J': + switch (ext[1]) { + case 'n': case 'N': + switch (ext[2]) { + case 'g': case 'G': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + case 'p': case 'P': + switch (ext[2]) { + case 'e': case 'E': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + case 'g': case 'G': + switch (ext[4]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + case 'g': case 'G': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + } + case 'l': case 'L': + switch (ext[1]) { + case 's': case 'S': + switch (ext[2]) { + case 'f': case 'F': + switch (ext[3]) { + case '\0': return AID_MEDIA_VIDEO; + } + case 'x': case 'X': + switch (ext[3]) { + case '\0': return AID_MEDIA_VIDEO; + } + } + } + case 'm': case 'M': + switch (ext[1]) { + case '3': + switch (ext[2]) { + case 'u': case 'U': + switch (ext[3]) { + case '\0': return AID_MEDIA_AUDIO; + } + } + case '4': + switch (ext[2]) { + case 'a': case 'A': + switch (ext[3]) { + case '\0': return AID_MEDIA_AUDIO; + } + case 'v': case 'V': + switch (ext[3]) { + case '\0': return AID_MEDIA_VIDEO; + } + } + case 'k': case 'K': + switch (ext[2]) { + case 'a': case 'A': + switch (ext[3]) { + case '\0': return AID_MEDIA_AUDIO; + } + case 'v': case 'V': + switch (ext[3]) { + case '\0': return AID_MEDIA_VIDEO; + } + } + case 'n': case 'N': + switch (ext[2]) { + case 'g': case 'G': + switch (ext[3]) { + case '\0': return AID_MEDIA_VIDEO; + } + } + case 'o': case 'O': + switch (ext[2]) { + case 'v': case 'V': + switch (ext[3]) { + case '\0': return AID_MEDIA_VIDEO; + case 'i': case 'I': + switch (ext[4]) { + case 'e': case 'E': + switch (ext[5]) { + case '\0': return AID_MEDIA_VIDEO; + } + } + } + } + case 'p': case 'P': + switch (ext[2]) { + case '2': + switch (ext[3]) { + case '\0': return AID_MEDIA_AUDIO; + } + case '3': + switch (ext[3]) { + case '\0': return AID_MEDIA_AUDIO; + } + case '4': + switch (ext[3]) { + case '\0': return AID_MEDIA_VIDEO; + } + case 'e': case 'E': + switch (ext[3]) { + case '\0': return AID_MEDIA_VIDEO; + case 'g': case 'G': + switch (ext[4]) { + case '\0': return AID_MEDIA_VIDEO; + case 'a': case 'A': + switch (ext[5]) { + case '\0': return AID_MEDIA_AUDIO; + } + } + } + case 'g': case 'G': + switch (ext[3]) { + case '\0': return AID_MEDIA_VIDEO; + case 'a': case 'A': + switch (ext[4]) { + case '\0': return AID_MEDIA_AUDIO; + } + } + } + case 'x': case 'X': + switch (ext[2]) { + case 'u': case 'U': + switch (ext[3]) { + case '\0': return AID_MEDIA_VIDEO; + } + } + } + case 'n': case 'N': + switch (ext[1]) { + case 'e': case 'E': + switch (ext[2]) { + case 'f': case 'F': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + case 'r': case 'R': + switch (ext[2]) { + case 'w': case 'W': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + } + case 'o': case 'O': + switch (ext[1]) { + case 'g': case 'G': + switch (ext[2]) { + case 'a': case 'A': + switch (ext[3]) { + case '\0': return AID_MEDIA_AUDIO; + } + case 'g': case 'G': + switch (ext[3]) { + case '\0': return AID_MEDIA_AUDIO; + } + } + case 'r': case 'R': + switch (ext[2]) { + case 'f': case 'F': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + } + case 'p': case 'P': + switch (ext[1]) { + case 'b': case 'B': + switch (ext[2]) { + case 'm': case 'M': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + case 'c': case 'C': + switch (ext[2]) { + case 'x': case 'X': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + case 'e': case 'E': + switch (ext[2]) { + case 'f': case 'F': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + case 'g': case 'G': + switch (ext[2]) { + case 'm': case 'M': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + case 'l': case 'L': + switch (ext[2]) { + case 's': case 'S': + switch (ext[3]) { + case '\0': return AID_MEDIA_AUDIO; + } + } + case 'n': case 'N': + switch (ext[2]) { + case 'g': case 'G': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + case 'm': case 'M': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + case 'p': case 'P': + switch (ext[2]) { + case 'm': case 'M': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + case 's': case 'S': + switch (ext[2]) { + case 'd': case 'D': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + } + case 'q': case 'Q': + switch (ext[1]) { + case 't': case 'T': + switch (ext[2]) { + case '\0': return AID_MEDIA_VIDEO; + } + } + case 'r': case 'R': + switch (ext[1]) { + case 'a': case 'A': + switch (ext[2]) { + case '\0': return AID_MEDIA_AUDIO; + case 'm': case 'M': + switch (ext[3]) { + case '\0': return AID_MEDIA_AUDIO; + } + case 's': case 'S': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + case 'g': case 'G': + switch (ext[2]) { + case 'b': case 'B': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + case 'm': case 'M': + switch (ext[2]) { + case '\0': return AID_MEDIA_AUDIO; + } + case 'w': case 'W': + switch (ext[2]) { + case '2': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + } + case 's': case 'S': + switch (ext[1]) { + case 'd': case 'D': + switch (ext[2]) { + case '2': + switch (ext[3]) { + case '\0': return AID_MEDIA_AUDIO; + } + } + case 'n': case 'N': + switch (ext[2]) { + case 'd': case 'D': + switch (ext[3]) { + case '\0': return AID_MEDIA_AUDIO; + } + } + case 'r': case 'R': + switch (ext[2]) { + case 'w': case 'W': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + case 'v': case 'V': + switch (ext[2]) { + case 'g': case 'G': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + case 'z': case 'Z': + switch (ext[4]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + } + } + case 't': case 'T': + switch (ext[1]) { + case 'i': case 'I': + switch (ext[2]) { + case 'f': case 'F': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + case 'f': case 'F': + switch (ext[4]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + } + case 's': case 'S': + switch (ext[2]) { + case '\0': return AID_MEDIA_VIDEO; + } + } + case 'v': case 'V': + switch (ext[1]) { + case 'o': case 'O': + switch (ext[2]) { + case 'b': case 'B': + switch (ext[3]) { + case '\0': return AID_MEDIA_VIDEO; + } + } + } + case 'w': case 'W': + switch (ext[1]) { + case 'a': case 'A': + switch (ext[2]) { + case 'v': case 'V': + switch (ext[3]) { + case '\0': return AID_MEDIA_AUDIO; + } + case 'x': case 'X': + switch (ext[3]) { + case '\0': return AID_MEDIA_AUDIO; + } + } + case 'b': case 'B': + switch (ext[2]) { + case 'm': case 'M': + switch (ext[3]) { + case 'p': case 'P': + switch (ext[4]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + } + case 'e': case 'E': + switch (ext[2]) { + case 'b': case 'B': + switch (ext[3]) { + case 'm': case 'M': + switch (ext[4]) { + case '\0': return AID_MEDIA_VIDEO; + } + case 'p': case 'P': + switch (ext[4]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + } + case 'm': case 'M': + switch (ext[2]) { + case '\0': return AID_MEDIA_VIDEO; + case 'a': case 'A': + switch (ext[3]) { + case '\0': return AID_MEDIA_AUDIO; + } + case 'v': case 'V': + switch (ext[3]) { + case '\0': return AID_MEDIA_VIDEO; + } + case 'x': case 'X': + switch (ext[3]) { + case '\0': return AID_MEDIA_VIDEO; + } + } + case 'r': case 'R': + switch (ext[2]) { + case 'f': case 'F': + switch (ext[3]) { + case '\0': return AID_MEDIA_VIDEO; + } + } + case 'v': case 'V': + switch (ext[2]) { + case 'x': case 'X': + switch (ext[3]) { + case '\0': return AID_MEDIA_VIDEO; + } + } + } + case 'x': case 'X': + switch (ext[1]) { + case 'b': case 'B': + switch (ext[2]) { + case 'm': case 'M': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + case 'p': case 'P': + switch (ext[2]) { + case 'm': case 'M': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + case 'w': case 'W': + switch (ext[2]) { + case 'd': case 'D': + switch (ext[3]) { + case '\0': return AID_MEDIA_IMAGE; + } + } + } + } + + return 0; +} diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl index 8c5d2f4a4b..6e4d7fa7ab 100644 --- a/cmds/installd/binder/android/os/IInstalld.aidl +++ b/cmds/installd/binder/android/os/IInstalld.aidl @@ -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, diff --git a/cmds/installd/matchgen.py b/cmds/installd/matchgen.py new file mode 100644 index 0000000000..b37352bc59 --- /dev/null +++ b/cmds/installd/matchgen.py @@ -0,0 +1,80 @@ +#!/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; +} +""" diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp index e1a59d4d9a..9849a0f89f 100644 --- a/cmds/installd/utils.cpp +++ b/cmds/installd/utils.cpp @@ -199,6 +199,10 @@ std::string create_data_media_path(const char* volume_uuid, userid_t userid) { return StringPrintf("%s/media/%u", create_data_path(volume_uuid).c_str(), userid); } +std::string create_data_media_obb_path(const char* volume_uuid, const char* package_name) { + return StringPrintf("%s/media/obb/%s", create_data_path(volume_uuid).c_str(), package_name); +} + std::string create_data_media_package_path(const char* volume_uuid, userid_t userid, const char* data_type, const char* package_name) { return StringPrintf("%s/Android/%s/%s", create_data_media_path(volume_uuid, userid).c_str(), @@ -209,13 +213,17 @@ std::string create_data_misc_legacy_path(userid_t userid) { return StringPrintf("%s/misc/user/%u", create_data_path(nullptr).c_str(), userid); } -std::string create_data_user_profiles_path(userid_t userid) { +std::string create_data_user_profile_path(userid_t userid) { return StringPrintf("%s/cur/%u", android_profiles_dir.path, userid); } std::string create_data_user_profile_package_path(userid_t user, const char* package_name) { check_package_name(package_name); - return StringPrintf("%s/%s",create_data_user_profiles_path(user).c_str(), package_name); + return StringPrintf("%s/%s",create_data_user_profile_path(user).c_str(), package_name); +} + +std::string create_data_ref_profile_path() { + return StringPrintf("%s/ref", android_profiles_dir.path); } std::string create_data_ref_profile_package_path(const char* package_name) { @@ -271,9 +279,10 @@ std::vector<userid_t> get_known_users(const char* volume_uuid) { } int calculate_tree_size(const std::string& path, int64_t* size, - gid_t include_gid, gid_t exclude_gid) { + int32_t include_gid, int32_t exclude_gid, bool exclude_apps) { FTS *fts; FTSENT *p; + int64_t matchedSize = 0; char *argv[] = { (char*) path.c_str(), nullptr }; if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_XDEV, NULL))) { if (errno != ENOENT) { @@ -288,17 +297,37 @@ int calculate_tree_size(const std::string& path, int64_t* size, case FTS_F: case FTS_SL: case FTS_SLNONE: - if (include_gid != 0 && p->fts_statp->st_gid != include_gid) { + int32_t uid = p->fts_statp->st_uid; + int32_t gid = p->fts_statp->st_gid; + int32_t user_uid = multiuser_get_app_id(uid); + int32_t user_gid = multiuser_get_app_id(gid); + if (exclude_apps && ((user_uid >= AID_APP_START && user_uid <= AID_APP_END) + || (user_gid >= AID_CACHE_GID_START && user_gid <= AID_CACHE_GID_END) + || (user_gid >= AID_SHARED_GID_START && user_gid <= AID_SHARED_GID_END))) { + // Don't traverse inside or measure + fts_set(fts, p, FTS_SKIP); break; } - if (exclude_gid != 0 && p->fts_statp->st_gid == exclude_gid) { + if (include_gid != -1 && gid != include_gid) { break; } - *size += (p->fts_statp->st_blocks * 512); + if (exclude_gid != -1 && gid == exclude_gid) { + break; + } + matchedSize += (p->fts_statp->st_blocks * 512); break; } } fts_close(fts); +#if MEASURE_DEBUG + if ((include_gid == -1) && (exclude_gid == -1)) { + LOG(DEBUG) << "Measured " << path << " size " << matchedSize; + } else { + LOG(DEBUG) << "Measured " << path << " size " << matchedSize << "; include " << include_gid + << " exclude " << exclude_gid; + } +#endif + *size += matchedSize; return 0; } diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h index ff041183cb..f2f0cbb030 100644 --- a/cmds/installd/utils.h +++ b/cmds/installd/utils.h @@ -30,6 +30,9 @@ #include <installd_constants.h> +#define MEASURE_DEBUG 0 +#define MEASURE_EXTERNAL 0 + namespace android { namespace installd { @@ -86,13 +89,16 @@ std::string create_data_user_de_package_path(const char* volume_uuid, userid_t user, const char* package_name); std::string create_data_media_path(const char* volume_uuid, userid_t userid); +std::string create_data_media_obb_path(const char* volume_uuid, const char* package_name); std::string create_data_media_package_path(const char* volume_uuid, userid_t userid, const char* data_type, const char* package_name); std::string create_data_misc_legacy_path(userid_t userid); -std::string create_data_user_profiles_path(userid_t userid); +std::string create_data_user_profile_path(userid_t userid); std::string create_data_user_profile_package_path(userid_t user, const char* package_name); + +std::string create_data_ref_profile_path(); std::string create_data_ref_profile_package_path(const char* package_name); std::string create_data_dalvik_cache_path(); @@ -103,7 +109,7 @@ std::string create_primary_profile(const std::string& profile_dir); std::vector<userid_t> get_known_users(const char* volume_uuid); int calculate_tree_size(const std::string& path, int64_t* size, - gid_t include_gid = 0, gid_t exclude_gid = 0); + int32_t include_gid = -1, int32_t exclude_gid = -1, bool exclude_apps = false); int create_user_config_path(char path[PKG_PATH_MAX], userid_t userid); |