194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood/*
294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood** Copyright 2008, The Android Open Source Project
394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood**
4d93707342a61e66bc3eb2145628158452f577f42Dave Allison** Licensed under the Apache License, Version 2.0 (the "License");
5d93707342a61e66bc3eb2145628158452f577f42Dave Allison** you may not use this file except in compliance with the License.
6d93707342a61e66bc3eb2145628158452f577f42Dave Allison** You may obtain a copy of the License at
794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood**
8d93707342a61e66bc3eb2145628158452f577f42Dave Allison**     http://www.apache.org/licenses/LICENSE-2.0
994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood**
10d93707342a61e66bc3eb2145628158452f577f42Dave Allison** Unless required by applicable law or agreed to in writing, software
11d93707342a61e66bc3eb2145628158452f577f42Dave Allison** distributed under the License is distributed on an "AS IS" BASIS,
12d93707342a61e66bc3eb2145628158452f577f42Dave Allison** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d93707342a61e66bc3eb2145628158452f577f42Dave Allison** See the License for the specific language governing permissions and
1494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood** limitations under the License.
1594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood*/
1694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
17f3e30b936ef103dc0f3d8697e0f86ba82b49609eJeff Sharkey#include "InstalldNativeService.h"
1802d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe
19466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
20466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey
2102d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#include <errno.h>
2202d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#include <inttypes.h>
233dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey#include <fstream>
243dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey#include <fts.h>
250354bd0eaf24de533e86885b811f816f1e4d15c8Andreas Gampe#include <regex>
2602d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#include <stdlib.h>
273dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey#include <string.h>
2802d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#include <sys/capability.h>
2902d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#include <sys/file.h>
3002d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#include <sys/resource.h>
313dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey#include <sys/quota.h>
3202d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#include <sys/stat.h>
333dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey#include <sys/statvfs.h>
34cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey#include <sys/types.h>
356a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle#include <sys/wait.h>
36cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey#include <sys/xattr.h>
3702d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#include <unistd.h>
3841ea424413c0381ef2aa15fc5bd5d4b88abd23c4Jeff Sharkey
39afa58d175cc3e9adaa4f8df9bc7a8fac5798a50aAndreas Gampe#include <android-base/logging.h>
40e4ec9eb7b4c452493589983970ba5ccc501728d1Elliott Hughes#include <android-base/stringprintf.h>
416727c2d0bfc876c62d6ee60d8a05d26bef1d56efDavid Sehr#include <android-base/strings.h>
4264b59cc1c89225813295d1b5d6bf4183615da204Roland Levillain#include <android-base/unique_fd.h>
4302d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#include <cutils/fs.h>
4490aff26f0135379db19432ae90c40c0831ba5954Jeff Sharkey#include <cutils/properties.h>
450378aaf257aee92539d30543914a50c4481c6a18Brian Carlstrom#include <cutils/sched_policy.h>
467823e124e00576e20e47ec717cbe8bc89f0f2bf2Mark Salyzyn#include <log/log.h>               // TODO: Move everything to base/logging.
47e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey#include <logwrap/logwrap.h>
4802d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#include <private/android_filesystem_config.h>
49e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey#include <selinux/android.h>
5002d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#include <system/thread_defs.h>
51466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey#include <utils/Trace.h>
52e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey
536c2c056193010cf93b4264810d462c120ce801c8Jeff Sharkey#include "dexopt.h"
54f3e30b936ef103dc0f3d8697e0f86ba82b49609eJeff Sharkey#include "globals.h"
55f3e30b936ef103dc0f3d8697e0f86ba82b49609eJeff Sharkey#include "installd_deps.h"
56f3e30b936ef103dc0f3d8697e0f86ba82b49609eJeff Sharkey#include "otapreopt_utils.h"
57f3e30b936ef103dc0f3d8697e0f86ba82b49609eJeff Sharkey#include "utils.h"
586c2c056193010cf93b4264810d462c120ce801c8Jeff Sharkey
5988ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey#include "CacheTracker.h"
60df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#include "MatchExtensionGen.h"
61df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
6202d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#ifndef LOG_TAG
6302d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#define LOG_TAG "installd"
6402d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#endif
6541ea424413c0381ef2aa15fc5bd5d4b88abd23c4Jeff Sharkey
6641ea424413c0381ef2aa15fc5bd5d4b88abd23c4Jeff Sharkeyusing android::base::StringPrintf;
6766b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkeyusing std::endl;
6894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
6902d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampenamespace android {
7002d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampenamespace installd {
7194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
72cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkeystatic constexpr const char* kCpPath = "/system/bin/cp";
73cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkeystatic constexpr const char* kXattrDefault = "user.default";
74e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey
7540bd3eff694ef1c660af2806bcc51bb5ac038c16Janis Danisevskisstatic constexpr const int MIN_RESTRICTED_HOME_SDK_VERSION = 24; // > M
76eecb2d205366351af42fd0cd9e1a95de3980764eJanis Danisevskis
770354bd0eaf24de533e86885b811f816f1e4d15c8Andreas Gampestatic constexpr const char* PKG_LIB_POSTFIX = "/lib";
780354bd0eaf24de533e86885b811f816f1e4d15c8Andreas Gampestatic constexpr const char* CACHE_DIR_POSTFIX = "/cache";
790354bd0eaf24de533e86885b811f816f1e4d15c8Andreas Gampestatic constexpr const char* CODE_CACHE_DIR_POSTFIX = "/code_cache";
800354bd0eaf24de533e86885b811f816f1e4d15c8Andreas Gampe
815cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seokstatic constexpr const char *kIdMapPath = "/system/bin/idmap";
820354bd0eaf24de533e86885b811f816f1e4d15c8Andreas Gampestatic constexpr const char* IDMAP_PREFIX = "/data/resource-cache/";
830354bd0eaf24de533e86885b811f816f1e4d15c8Andreas Gampestatic constexpr const char* IDMAP_SUFFIX = "@idmap";
840354bd0eaf24de533e86885b811f816f1e4d15c8Andreas Gampe
850354bd0eaf24de533e86885b811f816f1e4d15c8Andreas Gampe// NOTE: keep in sync with Installer
860354bd0eaf24de533e86885b811f816f1e4d15c8Andreas Gampestatic constexpr int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
870354bd0eaf24de533e86885b811f816f1e4d15c8Andreas Gampestatic constexpr int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9;
883dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkeystatic constexpr int FLAG_USE_QUOTA = 1 << 12;
8988ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkeystatic constexpr int FLAG_FREE_CACHE_V2 = 1 << 13;
90871a8f236ef2a055b9955b47a342b2c44c020ef7Jeff Sharkeystatic constexpr int FLAG_FREE_CACHE_V2_DEFY_QUOTA = 1 << 14;
91871a8f236ef2a055b9955b47a342b2c44c020ef7Jeff Sharkeystatic constexpr int FLAG_FREE_CACHE_NOOP = 1 << 15;
92e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkeystatic constexpr int FLAG_FORCE = 1 << 16;
936a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle
940274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkeynamespace {
950274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey
960274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkeyconstexpr const char* kDump = "android.permission.DUMP";
970274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey
98423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkeystatic binder::Status ok() {
99423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return binder::Status::ok();
100423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey}
101423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey
102423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkeystatic binder::Status exception(uint32_t code, const std::string& msg) {
103423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return binder::Status::fromExceptionCode(code, String8(msg.c_str()));
104423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey}
105423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey
106423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkeystatic binder::Status error() {
107423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return binder::Status::fromServiceSpecificError(errno);
108423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey}
109423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey
110423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkeystatic binder::Status error(const std::string& msg) {
111423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    PLOG(ERROR) << msg;
112423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return binder::Status::fromServiceSpecificError(errno, String8(msg.c_str()));
113423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey}
114423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey
115423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkeystatic binder::Status error(uint32_t code, const std::string& msg) {
116423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    LOG(ERROR) << msg << " (" << code << ")";
117423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return binder::Status::fromServiceSpecificError(code, String8(msg.c_str()));
118423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey}
119423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey
1200274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkeybinder::Status checkPermission(const char* permission) {
1210274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    pid_t pid;
1220274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    uid_t uid;
1230274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey
1240274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    if (checkCallingPermission(String16(permission), reinterpret_cast<int32_t*>(&pid),
1250274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey            reinterpret_cast<int32_t*>(&uid))) {
126423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return ok();
1270274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    } else {
128423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return exception(binder::Status::EX_SECURITY,
129423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey                StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, permission));
1300274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    }
1310274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey}
1320274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey
1330274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkeybinder::Status checkUid(uid_t expectedUid) {
1340274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    uid_t uid = IPCThreadState::self()->getCallingUid();
1350274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    if (uid == expectedUid || uid == AID_ROOT) {
136423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return ok();
1370274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    } else {
138423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return exception(binder::Status::EX_SECURITY,
139423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey                StringPrintf("UID %d is not expected UID %d", uid, expectedUid));
140423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    }
141423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey}
142423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey
143423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkeybinder::Status checkArgumentUuid(const std::unique_ptr<std::string>& uuid) {
144423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    if (!uuid || is_valid_filename(*uuid)) {
145423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return ok();
146423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    } else {
147423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
148423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey                StringPrintf("UUID %s is malformed", uuid->c_str()));
149423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    }
150423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey}
151423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey
152423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkeybinder::Status checkArgumentPackageName(const std::string& packageName) {
153423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    if (is_valid_package_name(packageName.c_str())) {
154423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return ok();
155423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    } else {
156423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
157423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey                StringPrintf("Package name %s is malformed", packageName.c_str()));
1580274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    }
1590274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey}
1600274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey
1610274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey#define ENFORCE_UID(uid) {                                  \
1620274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    binder::Status status = checkUid((uid));                \
1630274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    if (!status.isOk()) {                                   \
1640274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey        return status;                                      \
1650274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    }                                                       \
1660274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey}
1670274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey
168423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey#define CHECK_ARGUMENT_UUID(uuid) {                         \
169423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    binder::Status status = checkArgumentUuid((uuid));      \
170423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    if (!status.isOk()) {                                   \
171423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return status;                                      \
172423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    }                                                       \
173423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey}
174423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey
175423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey#define CHECK_ARGUMENT_PACKAGE_NAME(packageName) {          \
176423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    binder::Status status =                                 \
177423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            checkArgumentPackageName((packageName));        \
178423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    if (!status.isOk()) {                                   \
179423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return status;                                      \
180423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    }                                                       \
181423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey}
182423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey
1830274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey}  // namespace
1840274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey
1850274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkeystatus_t InstalldNativeService::start() {
1860274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    IPCThreadState::self()->disableBackgroundScheduling(true);
1870274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    status_t ret = BinderService<InstalldNativeService>::publish();
1880274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    if (ret != android::OK) {
1890274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey        return ret;
1900274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    }
1910274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    sp<ProcessState> ps(ProcessState::self());
1920274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    ps->startThreadPool();
1930274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    ps->giveThreadPoolName();
1940274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    return android::OK;
1950274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey}
1960274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey
1970274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkeystatus_t InstalldNativeService::dump(int fd, const Vector<String16> & /* args */) {
19866b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey    auto out = std::fstream(StringPrintf("/proc/self/fd/%d", fd));
1990274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    const binder::Status dump_permission = checkPermission(kDump);
2000274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    if (!dump_permission.isOk()) {
20166b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey        out << dump_permission.toString8() << endl;
2020274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey        return PERMISSION_DENIED;
2030274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    }
20466b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mLock);
20566b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey
20688ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey    out << "installd is happy!" << endl;
20788ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey
208b26786d647b624498c11405075e5223d1853f30aJeff Sharkey    {
209d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey        std::lock_guard<std::recursive_mutex> lock(mMountsLock);
210d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey        out << endl << "Storage mounts:" << endl;
211d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey        for (const auto& n : mStorageMounts) {
212d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey            out << "    " << n.first << " = " << n.second << endl;
213d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey        }
214d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey
215d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey        out << endl << "Quota reverse mounts:" << endl;
216d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey        for (const auto& n : mQuotaReverseMounts) {
217b26786d647b624498c11405075e5223d1853f30aJeff Sharkey            out << "    " << n.first << " = " << n.second << endl;
218b26786d647b624498c11405075e5223d1853f30aJeff Sharkey        }
21966b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey    }
22088ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey
221b26786d647b624498c11405075e5223d1853f30aJeff Sharkey    {
222d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey        std::lock_guard<std::recursive_mutex> lock(mQuotasLock);
223b26786d647b624498c11405075e5223d1853f30aJeff Sharkey        out << endl << "Per-UID cache quotas:" << endl;
224b26786d647b624498c11405075e5223d1853f30aJeff Sharkey        for (const auto& n : mCacheQuotas) {
225b26786d647b624498c11405075e5223d1853f30aJeff Sharkey            out << "    " << n.first << " = " << n.second << endl;
226b26786d647b624498c11405075e5223d1853f30aJeff Sharkey        }
22788ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey    }
22888ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey
22966b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey    out << endl;
23066b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey    out.flush();
2310274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey
2320274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    return NO_ERROR;
2330274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey}
2340274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey
23522f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey/**
23622f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey * Perform restorecon of the given path, but only perform recursive restorecon
23722f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey * if the label of that top-level file actually changed.  This can save us
23822f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey * significant time by avoiding no-op traversals of large filesystem trees.
23922f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey */
24035b83dff3de2b5fe781a060566ee09266b3c2617Jeff Sharkeystatic int restorecon_app_data_lazy(const std::string& path, const std::string& seInfo, uid_t uid,
24135b83dff3de2b5fe781a060566ee09266b3c2617Jeff Sharkey        bool existing) {
24222f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey    int res = 0;
24322f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey    char* before = nullptr;
24422f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey    char* after = nullptr;
24522f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey
24622f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey    // Note that SELINUX_ANDROID_RESTORECON_DATADATA flag is set by
24722f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey    // libselinux. Not needed here.
24822f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey
2498567ebfaa428d6454431067da68765adde328800Jeff Sharkey    if (lgetfilecon(path.c_str(), &before) < 0) {
25022f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey        PLOG(ERROR) << "Failed before getfilecon for " << path;
25122f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey        goto fail;
25222f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey    }
2530274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    if (selinux_android_restorecon_pkgdir(path.c_str(), seInfo.c_str(), uid, 0) < 0) {
25422f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey        PLOG(ERROR) << "Failed top-level restorecon for " << path;
25522f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey        goto fail;
25622f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey    }
2578567ebfaa428d6454431067da68765adde328800Jeff Sharkey    if (lgetfilecon(path.c_str(), &after) < 0) {
25822f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey        PLOG(ERROR) << "Failed after getfilecon for " << path;
25922f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey        goto fail;
26022f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey    }
26122f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey
26222f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey    // If the initial top-level restorecon above changed the label, then go
26322f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey    // back and restorecon everything recursively
26422f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey    if (strcmp(before, after)) {
26535b83dff3de2b5fe781a060566ee09266b3c2617Jeff Sharkey        if (existing) {
26635b83dff3de2b5fe781a060566ee09266b3c2617Jeff Sharkey            LOG(DEBUG) << "Detected label change from " << before << " to " << after << " at "
26735b83dff3de2b5fe781a060566ee09266b3c2617Jeff Sharkey                    << path << "; running recursive restorecon";
26835b83dff3de2b5fe781a060566ee09266b3c2617Jeff Sharkey        }
2690274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey        if (selinux_android_restorecon_pkgdir(path.c_str(), seInfo.c_str(), uid,
27022f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey                SELINUX_ANDROID_RESTORECON_RECURSE) < 0) {
27122f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey            PLOG(ERROR) << "Failed recursive restorecon for " << path;
27222f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey            goto fail;
27322f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey        }
27422f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey    }
27522f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey
27622f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey    goto done;
27722f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkeyfail:
27822f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey    res = -1;
27922f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkeydone:
28022f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey    free(before);
28122f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey    free(after);
28222f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey    return res;
28322f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey}
28422f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey
2850274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkeystatic int restorecon_app_data_lazy(const std::string& parent, const char* name,
28635b83dff3de2b5fe781a060566ee09266b3c2617Jeff Sharkey        const std::string& seInfo, uid_t uid, bool existing) {
28735b83dff3de2b5fe781a060566ee09266b3c2617Jeff Sharkey    return restorecon_app_data_lazy(StringPrintf("%s/%s", parent.c_str(), name), seInfo, uid,
28835b83dff3de2b5fe781a060566ee09266b3c2617Jeff Sharkey            existing);
2898567ebfaa428d6454431067da68765adde328800Jeff Sharkey}
2908567ebfaa428d6454431067da68765adde328800Jeff Sharkey
29122f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkeystatic int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid) {
2921f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey    if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, uid) != 0) {
2931f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey        PLOG(ERROR) << "Failed to prepare " << path;
2941f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey        return -1;
2951f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey    }
2961f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey    return 0;
2971f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey}
2981f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey
299e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey/**
300e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey * Ensure that we have a hard-limit quota to protect against abusive apps;
301e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey * they should never use more than 90% of blocks or 50% of inodes.
302e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey */
303e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkeystatic int prepare_app_quota(const std::unique_ptr<std::string>& uuid, const std::string& device,
304e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey        uid_t uid) {
305e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey    if (device.empty()) return 0;
306e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey
307e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey    struct dqblk dq;
308e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey    if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
309e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey            reinterpret_cast<char*>(&dq)) != 0) {
310e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey        PLOG(WARNING) << "Failed to find quota for " << uid;
311e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey        return -1;
312e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey    }
313e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey
314e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey    if ((dq.dqb_bhardlimit == 0) || (dq.dqb_ihardlimit == 0)) {
315e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey        auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
316e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey        struct statvfs stat;
317e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey        if (statvfs(path.c_str(), &stat) != 0) {
318e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey            PLOG(WARNING) << "Failed to statvfs " << path;
319e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey            return -1;
320e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey        }
321e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey
322e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey        dq.dqb_valid = QIF_LIMITS;
323e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey        dq.dqb_bhardlimit = (((stat.f_blocks * stat.f_frsize) / 10) * 9) / QIF_DQBLKSIZE;
324e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey        dq.dqb_ihardlimit = (stat.f_files / 2);
325e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey        if (quotactl(QCMD(Q_SETQUOTA, USRQUOTA), device.c_str(), uid,
326e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey                reinterpret_cast<char*>(&dq)) != 0) {
327e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey            PLOG(WARNING) << "Failed to set hard quota for " << uid;
328e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey            return -1;
329e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey        } else {
330e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey            LOG(DEBUG) << "Applied hard quotas for " << uid;
331e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey            return 0;
332e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey        }
333e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey    } else {
334e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey        // Hard quota already set; assume it's reasonable
335e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey        return 0;
336e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey    }
337e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey}
338e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey
3390274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkeybinder::Status InstalldNativeService::createAppData(const std::unique_ptr<std::string>& uuid,
3400274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey        const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
34136a900a0db526d63e899ed5d5b0a463ad7f9236eJeff Sharkey        const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return) {
3420274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
343423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    CHECK_ARGUMENT_UUID(uuid);
344423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
3457a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mLock);
3460274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey
3470274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
3480274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    const char* pkgname = packageName.c_str();
3490274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey
35036a900a0db526d63e899ed5d5b0a463ad7f9236eJeff Sharkey    // Assume invalid inode unless filled in below
35136a900a0db526d63e899ed5d5b0a463ad7f9236eJeff Sharkey    if (_aidl_return != nullptr) *_aidl_return = -1;
35236a900a0db526d63e899ed5d5b0a463ad7f9236eJeff Sharkey
35324ef15bd009204b73ebf0e94ba3d868177a5f44cJeff Sharkey    int32_t uid = multiuser_get_uid(userId, appId);
35424ef15bd009204b73ebf0e94ba3d868177a5f44cJeff Sharkey    int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
3553dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey    mode_t targetMode = targetSdkVersion >= MIN_RESTRICTED_HOME_SDK_VERSION ? 0700 : 0751;
3563dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey
35724ef15bd009204b73ebf0e94ba3d868177a5f44cJeff Sharkey    // If UID doesn't have a specific cache GID, use UID value
35824ef15bd009204b73ebf0e94ba3d868177a5f44cJeff Sharkey    if (cacheGid == -1) {
35924ef15bd009204b73ebf0e94ba3d868177a5f44cJeff Sharkey        cacheGid = uid;
36024ef15bd009204b73ebf0e94ba3d868177a5f44cJeff Sharkey    }
36124ef15bd009204b73ebf0e94ba3d868177a5f44cJeff Sharkey
362aa7ddfd8347fa947618a7668b013521e95722c5cJeff Sharkey    if (flags & FLAG_STORAGE_CE) {
3630274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey        auto path = create_data_user_ce_package_path(uuid_, userId, pkgname);
36435b83dff3de2b5fe781a060566ee09266b3c2617Jeff Sharkey        bool existing = (access(path.c_str(), F_OK) == 0);
36535b83dff3de2b5fe781a060566ee09266b3c2617Jeff Sharkey
3663dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey        if (prepare_app_dir(path, targetMode, uid) ||
3673dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey                prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid) ||
3683dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey                prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid)) {
369423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            return error("Failed to prepare " + path);
37022f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey        }
37122f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey
37222f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey        // Consider restorecon over contents if label changed
37335b83dff3de2b5fe781a060566ee09266b3c2617Jeff Sharkey        if (restorecon_app_data_lazy(path, seInfo, uid, existing) ||
37435b83dff3de2b5fe781a060566ee09266b3c2617Jeff Sharkey                restorecon_app_data_lazy(path, "cache", seInfo, uid, existing) ||
37535b83dff3de2b5fe781a060566ee09266b3c2617Jeff Sharkey                restorecon_app_data_lazy(path, "code_cache", seInfo, uid, existing)) {
376423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            return error("Failed to restorecon " + path);
377c7d1b2250e8245a7e4e144758bc3ccd33b8d6319Jeff Sharkey        }
3781f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey
3791f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey        // Remember inode numbers of cache directories so that we can clear
3801f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey        // contents while CE storage is locked
3811f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey        if (write_path_inode(path, "cache", kXattrInodeCache) ||
3821f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey                write_path_inode(path, "code_cache", kXattrInodeCodeCache)) {
383423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            return error("Failed to write_path_inode for " + path);
384c7d1b2250e8245a7e4e144758bc3ccd33b8d6319Jeff Sharkey        }
38536a900a0db526d63e899ed5d5b0a463ad7f9236eJeff Sharkey
38636a900a0db526d63e899ed5d5b0a463ad7f9236eJeff Sharkey        // And return the CE inode of the top-level data directory so we can
38736a900a0db526d63e899ed5d5b0a463ad7f9236eJeff Sharkey        // clear contents while CE storage is locked
38836a900a0db526d63e899ed5d5b0a463ad7f9236eJeff Sharkey        if ((_aidl_return != nullptr)
38936a900a0db526d63e899ed5d5b0a463ad7f9236eJeff Sharkey                && get_path_inode(path, reinterpret_cast<ino_t*>(_aidl_return)) != 0) {
39036a900a0db526d63e899ed5d5b0a463ad7f9236eJeff Sharkey            return error("Failed to get_path_inode for " + path);
39136a900a0db526d63e899ed5d5b0a463ad7f9236eJeff Sharkey        }
39294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
393aa7ddfd8347fa947618a7668b013521e95722c5cJeff Sharkey    if (flags & FLAG_STORAGE_DE) {
3940274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey        auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
39535b83dff3de2b5fe781a060566ee09266b3c2617Jeff Sharkey        bool existing = (access(path.c_str(), F_OK) == 0);
39635b83dff3de2b5fe781a060566ee09266b3c2617Jeff Sharkey
3973dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey        if (prepare_app_dir(path, targetMode, uid) ||
3983dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey                prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid) ||
3993dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey                prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid)) {
400423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            return error("Failed to prepare " + path);
401c7d1b2250e8245a7e4e144758bc3ccd33b8d6319Jeff Sharkey        }
4026a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle
40322f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey        // Consider restorecon over contents if label changed
4047b6c840c4281aeb2cc42ed022d1708fec0cda2ecJeff Sharkey        if (restorecon_app_data_lazy(path, seInfo, uid, existing) ||
4057b6c840c4281aeb2cc42ed022d1708fec0cda2ecJeff Sharkey                restorecon_app_data_lazy(path, "cache", seInfo, uid, existing) ||
4067b6c840c4281aeb2cc42ed022d1708fec0cda2ecJeff Sharkey                restorecon_app_data_lazy(path, "code_cache", seInfo, uid, existing)) {
407423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            return error("Failed to restorecon " + path);
40822f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey        }
40922f6fd53c3edaa1862cbc3ea54a0f461173c72fbJeff Sharkey
410e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey        if (prepare_app_quota(uuid, findQuotaDeviceForUuid(uuid), uid)) {
411e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey            return error("Failed to set hard quota " + path);
412e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey        }
413e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey
41490aff26f0135379db19432ae90c40c0831ba5954Jeff Sharkey        if (property_get_bool("dalvik.vm.usejitprofiles", false)) {
415114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle            const std::string profile_dir =
416114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle                    create_primary_current_profile_package_dir_path(userId, pkgname);
4176a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle            // read-write-execute only for the app user.
418114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle            if (fs_prepare_dir_strict(profile_dir.c_str(), 0700, uid, uid) != 0) {
419114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle                return error("Failed to prepare " + profile_dir);
4206a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle            }
421114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle            const std::string profile_file = create_current_profile_path(userId, pkgname,
422114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle                    /*is_secondary_dex*/false);
423bc56e7dcf07e633867e1525435373a1231216b22Calin Juravle            // read-write only for the app user.
424bc56e7dcf07e633867e1525435373a1231216b22Calin Juravle            if (fs_prepare_file_strict(profile_file.c_str(), 0600, uid, uid) != 0) {
425114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle                return error("Failed to prepare " + profile_file);
426bc56e7dcf07e633867e1525435373a1231216b22Calin Juravle            }
427114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle            const std::string ref_profile_path =
428114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle                    create_primary_reference_profile_package_dir_path(pkgname);
4296a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle            // dex2oat/profman runs under the shared app gid and it needs to read/write reference
4306a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle            // profiles.
431adddd9876e145879169369913b5afe469b17c02dJeff Sharkey            int shared_app_gid = multiuser_get_shared_gid(0, appId);
4322e6dc9baaaf5d50b42ce36435e13c2559808b837Jeff Sharkey            if ((shared_app_gid != -1) && fs_prepare_dir_strict(
4336a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle                    ref_profile_path.c_str(), 0700, shared_app_gid, shared_app_gid) != 0) {
434423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey                return error("Failed to prepare " + ref_profile_path);
4356a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle            }
4366a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle        }
43794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
438423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return ok();
43994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
44094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
441c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkeybinder::Status InstalldNativeService::migrateAppData(const std::unique_ptr<std::string>& uuid,
442c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey        const std::string& packageName, int32_t userId, int32_t flags) {
443c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
444423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    CHECK_ARGUMENT_UUID(uuid);
445423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
4467a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mLock);
447423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey
448c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
449c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey    const char* pkgname = packageName.c_str();
450c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey
451cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey    // This method only exists to upgrade system apps that have requested
452cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey    // forceDeviceEncrypted, so their default storage always lives in a
453cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey    // consistent location.  This only works on non-FBE devices, since we
454cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey    // never want to risk exposing data on a device with real CE/DE storage.
455cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey
456c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey    auto ce_path = create_data_user_ce_package_path(uuid_, userId, pkgname);
457c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey    auto de_path = create_data_user_de_package_path(uuid_, userId, pkgname);
458cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey
459cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey    // If neither directory is marked as default, assume CE is default
460cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey    if (getxattr(ce_path.c_str(), kXattrDefault, nullptr, 0) == -1
461cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey            && getxattr(de_path.c_str(), kXattrDefault, nullptr, 0) == -1) {
462cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey        if (setxattr(ce_path.c_str(), kXattrDefault, nullptr, 0, 0) != 0) {
463423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            return error("Failed to mark default storage " + ce_path);
464cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey        }
465cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey    }
466cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey
467cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey    // Migrate default data location if needed
468cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey    auto target = (flags & FLAG_STORAGE_DE) ? de_path : ce_path;
469cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey    auto source = (flags & FLAG_STORAGE_DE) ? ce_path : de_path;
470cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey
471cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey    if (getxattr(target.c_str(), kXattrDefault, nullptr, 0) == -1) {
472cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey        LOG(WARNING) << "Requested default storage " << target
473cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey                << " is not active; migrating from " << source;
474cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey        if (delete_dir_contents_and_dir(target) != 0) {
475423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            return error("Failed to delete " + target);
476cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey        }
477cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey        if (rename(source.c_str(), target.c_str()) != 0) {
478423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            return error("Failed to rename " + source + " to " + target);
479cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey        }
480cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey    }
481cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey
482423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return ok();
483cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey}
484cc6281cf8146cddb8ace7cbd58c67321639c1520Jeff Sharkey
4856a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle
486475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkeybinder::Status InstalldNativeService::clearAppProfiles(const std::string& packageName) {
487475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
488423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
4897a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mLock);
490423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey
491423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    binder::Status res = ok();
492114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle    if (!clear_primary_reference_profile(packageName)) {
493423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        res = error("Failed to clear reference profile for " + packageName);
494423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    }
495114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle    if (!clear_primary_current_profiles(packageName)) {
496423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        res = error("Failed to clear current profiles for " + packageName);
497423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    }
498423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return res;
4996a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle}
5006a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle
501c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkeybinder::Status InstalldNativeService::clearAppData(const std::unique_ptr<std::string>& uuid,
502c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey        const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode) {
503c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
504423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    CHECK_ARGUMENT_UUID(uuid);
505423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
5067a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mLock);
507423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey
508c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
509c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey    const char* pkgname = packageName.c_str();
510c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey
511423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    binder::Status res = ok();
512aa7ddfd8347fa947618a7668b013521e95722c5cJeff Sharkey    if (flags & FLAG_STORAGE_CE) {
513c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey        auto path = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInode);
5141f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey        if (flags & FLAG_CLEAR_CACHE_ONLY) {
5151f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey            path = read_path_inode(path, "cache", kXattrInodeCache);
5161f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey        } else if (flags & FLAG_CLEAR_CODE_CACHE_ONLY) {
5171f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey            path = read_path_inode(path, "code_cache", kXattrInodeCodeCache);
5181f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey        }
519c7d1b2250e8245a7e4e144758bc3ccd33b8d6319Jeff Sharkey        if (access(path.c_str(), F_OK) == 0) {
520423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            if (delete_dir_contents(path) != 0) {
521423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey                res = error("Failed to delete contents of " + path);
522423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            }
523c7d1b2250e8245a7e4e144758bc3ccd33b8d6319Jeff Sharkey        }
52494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
525aa7ddfd8347fa947618a7668b013521e95722c5cJeff Sharkey    if (flags & FLAG_STORAGE_DE) {
5261f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey        std::string suffix = "";
5271f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey        bool only_cache = false;
5281f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey        if (flags & FLAG_CLEAR_CACHE_ONLY) {
5291f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey            suffix = CACHE_DIR_POSTFIX;
5301f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey            only_cache = true;
5311f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey        } else if (flags & FLAG_CLEAR_CODE_CACHE_ONLY) {
5321f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey            suffix = CODE_CACHE_DIR_POSTFIX;
5331f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey            only_cache = true;
5341f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey        }
5351f6a7f117dcfa0e2cdb870a1bd4b20d34363ad73Jeff Sharkey
536c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey        auto path = create_data_user_de_package_path(uuid_, userId, pkgname) + suffix;
537c7d1b2250e8245a7e4e144758bc3ccd33b8d6319Jeff Sharkey        if (access(path.c_str(), F_OK) == 0) {
538423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            if (delete_dir_contents(path) != 0) {
539423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey                res = error("Failed to delete contents of " + path);
540423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            }
541c7d1b2250e8245a7e4e144758bc3ccd33b8d6319Jeff Sharkey        }
542edae669f18eb99b9316891fdde627e2f385c3c64Calin Juravle        if (!only_cache) {
543114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle            if (!clear_primary_current_profile(packageName, userId)) {
544423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey                res = error("Failed to clear current profile for " + packageName);
545edae669f18eb99b9316891fdde627e2f385c3c64Calin Juravle            }
546edae669f18eb99b9316891fdde627e2f385c3c64Calin Juravle        }
54794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
548423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return res;
549c7d1b2250e8245a7e4e144758bc3ccd33b8d6319Jeff Sharkey}
55094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
55176268c56febde9a77183387fbd4baabe6694e6b5Calin Juravlestatic int destroy_app_reference_profile(const std::string& pkgname) {
5527535e8e1995398befc866062d63c05d90eb70cccCalin Juravle    return delete_dir_contents_and_dir(
553114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle        create_primary_reference_profile_package_dir_path(pkgname),
5547535e8e1995398befc866062d63c05d90eb70cccCalin Juravle        /*ignore_if_missing*/ true);
5557535e8e1995398befc866062d63c05d90eb70cccCalin Juravle}
5567535e8e1995398befc866062d63c05d90eb70cccCalin Juravle
55776268c56febde9a77183387fbd4baabe6694e6b5Calin Juravlestatic int destroy_app_current_profiles(const std::string& pkgname, userid_t userid) {
558b06f98aabc5381fd6366526d9b31b5d0345481b6Calin Juravle    return delete_dir_contents_and_dir(
559114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle        create_primary_current_profile_package_dir_path(userid, pkgname),
560b06f98aabc5381fd6366526d9b31b5d0345481b6Calin Juravle        /*ignore_if_missing*/ true);
561edae669f18eb99b9316891fdde627e2f385c3c64Calin Juravle}
562edae669f18eb99b9316891fdde627e2f385c3c64Calin Juravle
563475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkeybinder::Status InstalldNativeService::destroyAppProfiles(const std::string& packageName) {
564475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
565423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
5667a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mLock);
567423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey
568423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    binder::Status res = ok();
569edae669f18eb99b9316891fdde627e2f385c3c64Calin Juravle    std::vector<userid_t> users = get_known_users(/*volume_uuid*/ nullptr);
570edae669f18eb99b9316891fdde627e2f385c3c64Calin Juravle    for (auto user : users) {
57176268c56febde9a77183387fbd4baabe6694e6b5Calin Juravle        if (destroy_app_current_profiles(packageName, user) != 0) {
572423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            res = error("Failed to destroy current profiles for " + packageName);
573423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        }
574edae669f18eb99b9316891fdde627e2f385c3c64Calin Juravle    }
57576268c56febde9a77183387fbd4baabe6694e6b5Calin Juravle    if (destroy_app_reference_profile(packageName) != 0) {
576423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        res = error("Failed to destroy reference profile for " + packageName);
577423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    }
578423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return res;
579caa6b809a5ed024a8f3f551c5c109a5ad50ab772Calin Juravle}
580caa6b809a5ed024a8f3f551c5c109a5ad50ab772Calin Juravle
581c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkeybinder::Status InstalldNativeService::destroyAppData(const std::unique_ptr<std::string>& uuid,
582c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey        const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode) {
583c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
584423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    CHECK_ARGUMENT_UUID(uuid);
585423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
5867a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mLock);
587423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey
588c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
589c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey    const char* pkgname = packageName.c_str();
590c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey
591423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    binder::Status res = ok();
592aa7ddfd8347fa947618a7668b013521e95722c5cJeff Sharkey    if (flags & FLAG_STORAGE_CE) {
593423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        auto path = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInode);
594423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        if (delete_dir_contents_and_dir(path) != 0) {
595423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            res = error("Failed to delete " + path);
596423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        }
59794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
598aa7ddfd8347fa947618a7668b013521e95722c5cJeff Sharkey    if (flags & FLAG_STORAGE_DE) {
599423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
600423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        if (delete_dir_contents_and_dir(path) != 0) {
601423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            res = error("Failed to delete " + path);
602423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        }
60376268c56febde9a77183387fbd4baabe6694e6b5Calin Juravle        destroy_app_current_profiles(packageName, userId);
6047535e8e1995398befc866062d63c05d90eb70cccCalin Juravle        // TODO(calin): If the package is still installed by other users it's probably
6057535e8e1995398befc866062d63c05d90eb70cccCalin Juravle        // beneficial to keep the reference profile around.
6067535e8e1995398befc866062d63c05d90eb70cccCalin Juravle        // Verify if it's ok to do that.
60776268c56febde9a77183387fbd4baabe6694e6b5Calin Juravle        destroy_app_reference_profile(packageName);
60894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
609423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return res;
61094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
61194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
612e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkeystatic gid_t get_cache_gid(uid_t uid) {
613e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey    int32_t gid = multiuser_get_cache_gid(multiuser_get_user_id(uid), multiuser_get_app_id(uid));
614e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey    return (gid != -1) ? gid : uid;
615e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey}
616e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey
617e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkeybinder::Status InstalldNativeService::fixupAppData(const std::unique_ptr<std::string>& uuid,
618e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey        int32_t flags) {
619e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
620e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey    CHECK_ARGUMENT_UUID(uuid);
621e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mLock);
622e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey
623e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
624e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey    for (auto user : get_known_users(uuid_)) {
625e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey        ATRACE_BEGIN("fixup user");
626e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey        FTS* fts;
627e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey        FTSENT* p;
628d9ff77fa4b934b54e287ba259cb02a0eee0d9ce8Jeff Sharkey        auto ce_path = create_data_user_ce_path(uuid_, user);
629d9ff77fa4b934b54e287ba259cb02a0eee0d9ce8Jeff Sharkey        auto de_path = create_data_user_de_path(uuid_, user);
630d9ff77fa4b934b54e287ba259cb02a0eee0d9ce8Jeff Sharkey        char *argv[] = { (char*) ce_path.c_str(), (char*) de_path.c_str(), nullptr };
631e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey        if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
632e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey            return error("Failed to fts_open");
633e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey        }
634e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey        while ((p = fts_read(fts)) != nullptr) {
635e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey            if (p->fts_info == FTS_D && p->fts_level == 1) {
636e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                // Track down inodes of cache directories
637e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                uint64_t raw = 0;
638e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                ino_t inode_cache = 0;
639e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                ino_t inode_code_cache = 0;
640e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                if (getxattr(p->fts_path, kXattrInodeCache, &raw, sizeof(raw)) == sizeof(raw)) {
641e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                    inode_cache = raw;
642e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                }
643e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                if (getxattr(p->fts_path, kXattrInodeCodeCache, &raw, sizeof(raw)) == sizeof(raw)) {
644e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                    inode_code_cache = raw;
645e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                }
646e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey
647e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                // Figure out expected GID of each child
648e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                FTSENT* child = fts_children(fts, 0);
649e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                while (child != nullptr) {
650e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                    if ((child->fts_statp->st_ino == inode_cache)
651e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                            || (child->fts_statp->st_ino == inode_code_cache)
652e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                            || !strcmp(child->fts_name, "cache")
653e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                            || !strcmp(child->fts_name, "code_cache")) {
654e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                        child->fts_number = get_cache_gid(p->fts_statp->st_uid);
655e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                    } else {
656e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                        child->fts_number = p->fts_statp->st_uid;
657e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                    }
658e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                    child = child->fts_link;
659e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                }
660e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey            } else if (p->fts_level >= 2) {
661e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                if (p->fts_level > 2) {
662e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                    // Inherit GID from parent once we're deeper into tree
663e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                    p->fts_number = p->fts_parent->fts_number;
664e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                }
665e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey
666e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                uid_t uid = p->fts_parent->fts_statp->st_uid;
667e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                gid_t cache_gid = get_cache_gid(uid);
668e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                gid_t expected = p->fts_number;
669e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                gid_t actual = p->fts_statp->st_gid;
670e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                if (actual == expected) {
671e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey#if FIXUP_DEBUG
672e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                    LOG(DEBUG) << "Ignoring " << p->fts_path << " with expected GID " << expected;
673e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey#endif
674e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                    if (!(flags & FLAG_FORCE)) {
675e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                        fts_set(fts, p, FTS_SKIP);
676e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                    }
677e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                } else if ((actual == uid) || (actual == cache_gid)) {
678e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                    // Only consider fixing up when current GID belongs to app
679e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                    if (p->fts_info != FTS_D) {
680e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                        LOG(INFO) << "Fixing " << p->fts_path << " with unexpected GID " << actual
681e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                                << " instead of " << expected;
682e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                    }
683e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                    switch (p->fts_info) {
684e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                    case FTS_DP:
685e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                        // If we're moving towards cache GID, we need to set S_ISGID
686e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                        if (expected == cache_gid) {
687e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                            if (chmod(p->fts_path, 02771) != 0) {
688e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                                PLOG(WARNING) << "Failed to chmod " << p->fts_path;
689e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                            }
690e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                        }
691e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                        // Intentional fall through to also set GID
692e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                    case FTS_F:
693e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                        if (chown(p->fts_path, -1, expected) != 0) {
694e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                            PLOG(WARNING) << "Failed to chown " << p->fts_path;
695e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                        }
696e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                        break;
697e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                    case FTS_SL:
698e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                    case FTS_SLNONE:
699e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                        if (lchown(p->fts_path, -1, expected) != 0) {
700e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                            PLOG(WARNING) << "Failed to chown " << p->fts_path;
701e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                        }
702e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                        break;
703e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                    }
704e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                } else {
705e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                    // Ignore all other GID transitions, since they're kinda shady
706e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                    LOG(WARNING) << "Ignoring " << p->fts_path << " with unexpected GID " << actual
707e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                            << " instead of " << expected;
708e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey                }
709e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey            }
710e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey        }
711e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey        fts_close(fts);
712e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey        ATRACE_END();
713e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey    }
714e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey    return ok();
715e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey}
716e12d5964a8d14abe7f2eb6e57469cbe7f7391a19Jeff Sharkey
7170274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkeybinder::Status InstalldNativeService::moveCompleteApp(const std::unique_ptr<std::string>& fromUuid,
7180274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey        const std::unique_ptr<std::string>& toUuid, const std::string& packageName,
7190274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey        const std::string& dataAppName, int32_t appId, const std::string& seInfo,
7200274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey        int32_t targetSdkVersion) {
721423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
722423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    CHECK_ARGUMENT_UUID(fromUuid);
723423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    CHECK_ARGUMENT_UUID(toUuid);
724423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
7257a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mLock);
7260274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey
7270274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    const char* from_uuid = fromUuid ? fromUuid->c_str() : nullptr;
7280274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    const char* to_uuid = toUuid ? toUuid->c_str() : nullptr;
7290274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    const char* package_name = packageName.c_str();
7300274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey    const char* data_app_name = dataAppName.c_str();
7310274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey
732423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    binder::Status res = ok();
733e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey    std::vector<userid_t> users = get_known_users(from_uuid);
734e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey
735d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey    // Copy app
736d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey    {
73751c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey        auto from = create_data_app_package_path(from_uuid, data_app_name);
73851c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey        auto to = create_data_app_package_path(to_uuid, data_app_name);
73951c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey        auto to_parent = create_data_app_path(to_uuid);
740d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey
741d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey        char *argv[] = {
742d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey            (char*) kCpPath,
743d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey            (char*) "-F", /* delete any existing destination file first (--remove-destination) */
744d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey            (char*) "-p", /* preserve timestamps, ownership, and permissions */
745d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey            (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */
746d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey            (char*) "-P", /* Do not follow symlinks [default] */
747d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey            (char*) "-d", /* don't dereference symlinks */
748d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey            (char*) from.c_str(),
749d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey            (char*) to_parent.c_str()
750d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey        };
751d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey
752d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey        LOG(DEBUG) << "Copying " << from << " to " << to;
753d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey        int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
754d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey        if (rc != 0) {
755423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            res = error(rc, "Failed copying " + from + " to " + to);
756d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey            goto fail;
757d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey        }
758d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey
759d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey        if (selinux_android_restorecon(to.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
760423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            res = error("Failed to restorecon " + to);
761d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey            goto fail;
762d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey        }
763d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey    }
764d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey
765d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey    // Copy private data for all known users
766e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey    for (auto user : users) {
767e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey
768e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey        // Data source may not exist for all users; that's okay
76951c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey        auto from_ce = create_data_user_ce_package_path(from_uuid, user, package_name);
77051c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey        if (access(from_ce.c_str(), F_OK) != 0) {
77151c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey            LOG(INFO) << "Missing source " << from_ce;
772e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey            continue;
773e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey        }
774e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey
7750274c977e3b10b52936fd5b2eb464857f0ca6358Jeff Sharkey        if (!createAppData(toUuid, packageName, user, FLAG_STORAGE_CE | FLAG_STORAGE_DE, appId,
77636a900a0db526d63e899ed5d5b0a463ad7f9236eJeff Sharkey                seInfo, targetSdkVersion, nullptr).isOk()) {
777423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            res = error("Failed to create package target");
778e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey            goto fail;
779e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey        }
780e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey
781e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey        char *argv[] = {
782e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey            (char*) kCpPath,
783e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey            (char*) "-F", /* delete any existing destination file first (--remove-destination) */
784e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey            (char*) "-p", /* preserve timestamps, ownership, and permissions */
785e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey            (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */
786e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey            (char*) "-P", /* Do not follow symlinks [default] */
787e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey            (char*) "-d", /* don't dereference symlinks */
78851c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey            nullptr,
78951c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey            nullptr
790e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey        };
791e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey
79251c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey        {
79351c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey            auto from = create_data_user_de_package_path(from_uuid, user, package_name);
79451c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey            auto to = create_data_user_de_path(to_uuid, user);
79551c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey            argv[6] = (char*) from.c_str();
79651c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey            argv[7] = (char*) to.c_str();
79751c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey
79851c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey            LOG(DEBUG) << "Copying " << from << " to " << to;
79951c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey            int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
80051c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey            if (rc != 0) {
801423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey                res = error(rc, "Failed copying " + from + " to " + to);
80251c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey                goto fail;
80351c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey            }
80451c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey        }
80551c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey        {
80651c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey            auto from = create_data_user_ce_package_path(from_uuid, user, package_name);
80751c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey            auto to = create_data_user_ce_path(to_uuid, user);
80851c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey            argv[6] = (char*) from.c_str();
80951c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey            argv[7] = (char*) to.c_str();
81051c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey
81151c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey            LOG(DEBUG) << "Copying " << from << " to " << to;
81251c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey            int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
81351c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey            if (rc != 0) {
814423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey                res = error(rc, "Failed copying " + from + " to " + to);
81551c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey                goto fail;
81651c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey            }
817e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey        }
818e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey
819c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey        if (!restoreconAppData(toUuid, packageName, user, FLAG_STORAGE_CE | FLAG_STORAGE_DE,
820c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey                appId, seInfo).isOk()) {
821423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            res = error("Failed to restorecon");
822c7d1b2250e8245a7e4e144758bc3ccd33b8d6319Jeff Sharkey            goto fail;
823c7d1b2250e8245a7e4e144758bc3ccd33b8d6319Jeff Sharkey        }
824e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey    }
825e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey
82631f08986f83fa6f2dcf55523b2cf706460aeed7cJeff Sharkey    // We let the framework scan the new location and persist that before
82731f08986f83fa6f2dcf55523b2cf706460aeed7cJeff Sharkey    // deleting the data in the old location; this ordering ensures that
82831f08986f83fa6f2dcf55523b2cf706460aeed7cJeff Sharkey    // we can recover from things like battery pulls.
829423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return ok();
830e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey
831e36372423000a906bafae68844ebc6c42d09335aJeff Sharkeyfail:
832e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey    // Nuke everything we might have already copied
833d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey    {
83451c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey        auto to = create_data_app_package_path(to_uuid, data_app_name);
835d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey        if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
836d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey            LOG(WARNING) << "Failed to rollback " << to;
837d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey        }
838d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey    }
839e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey    for (auto user : users) {
84051c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey        {
84151c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey            auto to = create_data_user_de_package_path(to_uuid, user, package_name);
84251c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey            if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
84351c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey                LOG(WARNING) << "Failed to rollback " << to;
84451c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey            }
84551c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey        }
84651c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey        {
84751c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey            auto to = create_data_user_ce_package_path(to_uuid, user, package_name);
84851c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey            if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
84951c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey                LOG(WARNING) << "Failed to rollback " << to;
85051c94495be151c1da03c8266592ed33f253d4b48Jeff Sharkey            }
851e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey        }
852e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey    }
853423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return res;
854e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey}
855e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey
856c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkeybinder::Status InstalldNativeService::createUserData(const std::unique_ptr<std::string>& uuid,
857c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey        int32_t userId, int32_t userSerial ATTRIBUTE_UNUSED, int32_t flags) {
858c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
859423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    CHECK_ARGUMENT_UUID(uuid);
8607a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mLock);
861423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey
862c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
863379a12b0072b322c7f86e690a8e8a220e500861cJeff Sharkey    if (flags & FLAG_STORAGE_DE) {
864c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey        if (uuid_ == nullptr) {
865423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            if (ensure_config_user_dirs(userId) != 0) {
8667be5ead81aa4d3b2536556c762bab03445a98155Jeff Sharkey                return error(StringPrintf("Failed to ensure dirs for %d", userId));
867423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            }
868379a12b0072b322c7f86e690a8e8a220e500861cJeff Sharkey        }
86994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
870e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey
871e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey    // Data under /data/media doesn't have an app, but we still want
872e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey    // to limit it to prevent abuse.
873e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey    if (prepare_app_quota(uuid, findQuotaDeviceForUuid(uuid),
874e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey            multiuser_get_uid(userId, AID_MEDIA_RW))) {
875e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey        return error("Failed to set hard quota for media_rw");
876e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey    }
877e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey
8787be5ead81aa4d3b2536556c762bab03445a98155Jeff Sharkey    return ok();
879095c763dd9aa26a206d10ab7c1d7e1c569298fb3Robin Lee}
880095c763dd9aa26a206d10ab7c1d7e1c569298fb3Robin Lee
881c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkeybinder::Status InstalldNativeService::destroyUserData(const std::unique_ptr<std::string>& uuid,
882c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey        int32_t userId, int32_t flags) {
883c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
884423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    CHECK_ARGUMENT_UUID(uuid);
8857a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mLock);
886423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey
887c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
888423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    binder::Status res = ok();
889379a12b0072b322c7f86e690a8e8a220e500861cJeff Sharkey    if (flags & FLAG_STORAGE_DE) {
890423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        auto path = create_data_user_de_path(uuid_, userId);
891423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        if (delete_dir_contents_and_dir(path, true) != 0) {
892423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            res = error("Failed to delete " + path);
893423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        }
894c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey        if (uuid_ == nullptr) {
895423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            path = create_data_misc_legacy_path(userId);
896423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            if (delete_dir_contents_and_dir(path, true) != 0) {
897423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey                res = error("Failed to delete " + path);
898423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            }
899114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle            path = create_primary_cur_profile_dir_path(userId);
900423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            if (delete_dir_contents_and_dir(path, true) != 0) {
901423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey                res = error("Failed to delete " + path);
902423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            }
90341ea424413c0381ef2aa15fc5bd5d4b88abd23c4Jeff Sharkey        }
90494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
905379a12b0072b322c7f86e690a8e8a220e500861cJeff Sharkey    if (flags & FLAG_STORAGE_CE) {
906423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        auto path = create_data_user_ce_path(uuid_, userId);
907423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        if (delete_dir_contents_and_dir(path, true) != 0) {
908423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            res = error("Failed to delete " + path);
909423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        }
910d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey        path = findDataMediaPath(uuid, userId);
911423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        if (delete_dir_contents_and_dir(path, true) != 0) {
912423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            res = error("Failed to delete " + path);
913423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        }
914379a12b0072b322c7f86e690a8e8a220e500861cJeff Sharkey    }
915423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return res;
91694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
91794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
918475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkeybinder::Status InstalldNativeService::freeCache(const std::unique_ptr<std::string>& uuid,
91960f8a5330ca921d936ae306bf6d17596b82b518cJeff Sharkey        int64_t targetFreeBytes, int64_t cacheReservedBytes, int32_t flags) {
920475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
921423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    CHECK_ARGUMENT_UUID(uuid);
9227a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mLock);
923423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey
92488ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
925475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    auto data_path = create_data_path(uuid_);
92688ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey    auto device = findQuotaDeviceForUuid(uuid);
92788ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey    auto noop = (flags & FLAG_FREE_CACHE_NOOP);
92841ea424413c0381ef2aa15fc5bd5d4b88abd23c4Jeff Sharkey
92988ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey    int64_t free = data_disk_free(data_path);
93088ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey    if (free < 0) {
931423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return error("Failed to determine free space for " + data_path);
932475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    }
93394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
93460f8a5330ca921d936ae306bf6d17596b82b518cJeff Sharkey    int64_t cleared = 0;
93560f8a5330ca921d936ae306bf6d17596b82b518cJeff Sharkey    int64_t needed = targetFreeBytes - free;
936ed909ae8db2f44ce7fe7003c6fee457f13669702Jeff Sharkey    LOG(DEBUG) << "Device " << data_path << " has " << free << " free; requested "
93760f8a5330ca921d936ae306bf6d17596b82b518cJeff Sharkey            << targetFreeBytes << "; needed " << needed;
938ed909ae8db2f44ce7fe7003c6fee457f13669702Jeff Sharkey
93960f8a5330ca921d936ae306bf6d17596b82b518cJeff Sharkey    if (free >= targetFreeBytes) {
940ed909ae8db2f44ce7fe7003c6fee457f13669702Jeff Sharkey        return ok();
941ed909ae8db2f44ce7fe7003c6fee457f13669702Jeff Sharkey    }
94288ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey
94388ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey    if (flags & FLAG_FREE_CACHE_V2) {
94488ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey        // This new cache strategy fairly removes files from UIDs by deleting
94588ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey        // files from the UIDs which are most over their allocated quota
94688ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey
94788ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey        // 1. Create trackers for every known UID
94888ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey        ATRACE_BEGIN("create");
94988ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey        std::unordered_map<uid_t, std::shared_ptr<CacheTracker>> trackers;
95088ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey        for (auto user : get_known_users(uuid_)) {
95188ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey            FTS *fts;
95288ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey            FTSENT *p;
953d9ff77fa4b934b54e287ba259cb02a0eee0d9ce8Jeff Sharkey            auto ce_path = create_data_user_ce_path(uuid_, user);
954d9ff77fa4b934b54e287ba259cb02a0eee0d9ce8Jeff Sharkey            auto de_path = create_data_user_de_path(uuid_, user);
955d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey            auto media_path = findDataMediaPath(uuid, user) + "/Android/data/";
956d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey            char *argv[] = { (char*) ce_path.c_str(), (char*) de_path.c_str(),
957d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey                    (char*) media_path.c_str(), nullptr };
958b26786d647b624498c11405075e5223d1853f30aJeff Sharkey            if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
95988ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                return error("Failed to fts_open");
96088ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey            }
96188ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey            while ((p = fts_read(fts)) != NULL) {
96288ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                if (p->fts_info == FTS_D && p->fts_level == 1) {
96388ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                    uid_t uid = p->fts_statp->st_uid;
964d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey                    if (multiuser_get_app_id(uid) == AID_MEDIA_RW) {
965d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey                        uid = (multiuser_get_app_id(p->fts_statp->st_gid) - AID_EXT_GID_START)
966d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey                                + AID_APP_START;
967d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey                    }
96888ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                    auto search = trackers.find(uid);
96988ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                    if (search != trackers.end()) {
97088ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                        search->second->addDataPath(p->fts_path);
97188ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                    } else {
97288ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                        auto tracker = std::shared_ptr<CacheTracker>(new CacheTracker(
97388ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                                multiuser_get_user_id(uid), multiuser_get_app_id(uid), device));
97488ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                        tracker->addDataPath(p->fts_path);
975b26786d647b624498c11405075e5223d1853f30aJeff Sharkey                        {
976d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey                            std::lock_guard<std::recursive_mutex> lock(mQuotasLock);
977b26786d647b624498c11405075e5223d1853f30aJeff Sharkey                            tracker->cacheQuota = mCacheQuotas[uid];
978b26786d647b624498c11405075e5223d1853f30aJeff Sharkey                        }
97988ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                        if (tracker->cacheQuota == 0) {
980ed909ae8db2f44ce7fe7003c6fee457f13669702Jeff Sharkey#if MEASURE_DEBUG
98188ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                            LOG(WARNING) << "UID " << uid << " has no cache quota; assuming 64MB";
982ed909ae8db2f44ce7fe7003c6fee457f13669702Jeff Sharkey#endif
98388ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                            tracker->cacheQuota = 67108864;
98488ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                        }
98588ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                        trackers[uid] = tracker;
98688ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                    }
98788ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                    fts_set(fts, p, FTS_SKIP);
98888ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                }
98988ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey            }
99088ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey            fts_close(fts);
99188ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey        }
99288ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey        ATRACE_END();
99388ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey
99488ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey        // 2. Populate tracker stats and insert into priority queue
99588ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey        ATRACE_BEGIN("populate");
99660f8a5330ca921d936ae306bf6d17596b82b518cJeff Sharkey        int64_t cacheTotal = 0;
99788ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey        auto cmp = [](std::shared_ptr<CacheTracker> left, std::shared_ptr<CacheTracker> right) {
99888ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey            return (left->getCacheRatio() < right->getCacheRatio());
99988ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey        };
100088ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey        std::priority_queue<std::shared_ptr<CacheTracker>,
100188ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                std::vector<std::shared_ptr<CacheTracker>>, decltype(cmp)> queue(cmp);
100288ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey        for (const auto& it : trackers) {
100388ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey            it.second->loadStats();
100488ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey            queue.push(it.second);
100560f8a5330ca921d936ae306bf6d17596b82b518cJeff Sharkey            cacheTotal += it.second->cacheUsed;
100688ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey        }
100788ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey        ATRACE_END();
100888ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey
100988ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey        // 3. Bounce across the queue, freeing items from whichever tracker is
101088ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey        // the most over their assigned quota
101188ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey        ATRACE_BEGIN("bounce");
101288ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey        std::shared_ptr<CacheTracker> active;
101388ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey        while (active || !queue.empty()) {
1014871a8f236ef2a055b9955b47a342b2c44c020ef7Jeff Sharkey            // Only look at apps under quota when explicitly requested
1015871a8f236ef2a055b9955b47a342b2c44c020ef7Jeff Sharkey            if (active && (active->getCacheRatio() < 10000)
1016871a8f236ef2a055b9955b47a342b2c44c020ef7Jeff Sharkey                    && !(flags & FLAG_FREE_CACHE_V2_DEFY_QUOTA)) {
1017871a8f236ef2a055b9955b47a342b2c44c020ef7Jeff Sharkey                LOG(DEBUG) << "Active ratio " << active->getCacheRatio()
1018871a8f236ef2a055b9955b47a342b2c44c020ef7Jeff Sharkey                        << " isn't over quota, and defy not requested";
1019871a8f236ef2a055b9955b47a342b2c44c020ef7Jeff Sharkey                break;
1020871a8f236ef2a055b9955b47a342b2c44c020ef7Jeff Sharkey            }
1021871a8f236ef2a055b9955b47a342b2c44c020ef7Jeff Sharkey
102260f8a5330ca921d936ae306bf6d17596b82b518cJeff Sharkey            // Only keep clearing when we haven't pushed into reserved area
102360f8a5330ca921d936ae306bf6d17596b82b518cJeff Sharkey            if (cacheReservedBytes > 0 && cleared >= (cacheTotal - cacheReservedBytes)) {
102460f8a5330ca921d936ae306bf6d17596b82b518cJeff Sharkey                LOG(DEBUG) << "Refusing to clear cached data in reserved space";
102560f8a5330ca921d936ae306bf6d17596b82b518cJeff Sharkey                break;
102660f8a5330ca921d936ae306bf6d17596b82b518cJeff Sharkey            }
102760f8a5330ca921d936ae306bf6d17596b82b518cJeff Sharkey
102888ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey            // Find the best tracker to work with; this might involve swapping
102988ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey            // if the active tracker is no longer the most over quota
103088ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey            bool nextBetter = active && !queue.empty()
103188ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                    && active->getCacheRatio() < queue.top()->getCacheRatio();
103288ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey            if (!active || nextBetter) {
103388ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                if (active) {
103488ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                    // Current tracker still has items, so we'll consider it
103588ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                    // again later once it bubbles up to surface
103688ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                    queue.push(active);
103788ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                }
103888ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                active = queue.top(); queue.pop();
103988ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                active->ensureItems();
104088ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                continue;
104188ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey            }
104294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
104388ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey            // If no items remain, go find another tracker
104488ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey            if (active->items.empty()) {
104588ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                active = nullptr;
104688ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                continue;
104788ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey            } else {
104888ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                auto item = active->items.back();
104988ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                active->items.pop_back();
105088ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey
105188ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                LOG(DEBUG) << "Purging " << item->toString() << " from " << active->toString();
105288ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                if (!noop) {
105388ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                    item->purge();
105488ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                }
105588ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                active->cacheUsed -= item->size;
105688ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                needed -= item->size;
105760f8a5330ca921d936ae306bf6d17596b82b518cJeff Sharkey                cleared += item->size;
105888ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey            }
105988ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey
106088ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey            // Verify that we're actually done before bailing, since sneaky
106188ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey            // apps might be using hardlinks
106288ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey            if (needed <= 0) {
106388ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                free = data_disk_free(data_path);
106460f8a5330ca921d936ae306bf6d17596b82b518cJeff Sharkey                needed = targetFreeBytes - free;
106588ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                if (needed <= 0) {
106688ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                    break;
106788ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                } else {
106888ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                    LOG(WARNING) << "Expected to be done but still need " << needed;
106988ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey                }
107088ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey            }
107188ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey        }
107288ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey        ATRACE_END();
107388ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey
107488ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey    } else {
10751cb4aafc17daae520a5c3a991f59605ea3ee4ee5Jeff Sharkey        return error("Legacy cache logic no longer supported");
107688ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey    }
107788ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey
107888ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey    free = data_disk_free(data_path);
107960f8a5330ca921d936ae306bf6d17596b82b518cJeff Sharkey    if (free >= targetFreeBytes) {
1080423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return ok();
1081475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    } else {
1082423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return error(StringPrintf("Failed to free up %" PRId64 " on %s; final free space %" PRId64,
108360f8a5330ca921d936ae306bf6d17596b82b518cJeff Sharkey                targetFreeBytes, data_path.c_str(), free));
1084475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    }
108594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
108694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
1087475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkeybinder::Status InstalldNativeService::rmdex(const std::string& codePath,
1088475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey        const std::string& instructionSet) {
1089475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
10907a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mLock);
10917a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey
109294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    char dex_path[PKG_PATH_MAX];
109394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
1094475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    const char* path = codePath.c_str();
1095475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    const char* instruction_set = instructionSet.c_str();
1096475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey
1097770180a4dd86f8bda6af2e6db4676e99a5bb1548Jeff Sharkey    if (validate_apk_path(path) && validate_system_app_path(path)) {
1098423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return error("Invalid path " + codePath);
1099770180a4dd86f8bda6af2e6db4676e99a5bb1548Jeff Sharkey    }
1100770180a4dd86f8bda6af2e6db4676e99a5bb1548Jeff Sharkey
1101475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    if (!create_cache_path(dex_path, path, instruction_set)) {
1102423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return error("Failed to create cache path for " + codePath);
1103475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    }
110494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
110594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    ALOGV("unlink %s\n", dex_path);
110694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (unlink(dex_path) < 0) {
1107249f2d3e018bd98eba74c3184b80bc91b04281cdCalin Juravle        // It's ok if we don't have a dalvik cache path. Report error only when the path exists
1108249f2d3e018bd98eba74c3184b80bc91b04281cdCalin Juravle        // but could not be unlinked.
1109249f2d3e018bd98eba74c3184b80bc91b04281cdCalin Juravle        if (errno != ENOENT) {
1110249f2d3e018bd98eba74c3184b80bc91b04281cdCalin Juravle            return error(StringPrintf("Failed to unlink %s", dex_path));
1111249f2d3e018bd98eba74c3184b80bc91b04281cdCalin Juravle        }
111294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
1113249f2d3e018bd98eba74c3184b80bc91b04281cdCalin Juravle    return ok();
111494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
111594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
11163dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkeystruct stats {
11173dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey    int64_t codeSize;
11183dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey    int64_t dataSize;
11193dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey    int64_t cacheSize;
11203dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey};
11213dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey
1122df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#if MEASURE_DEBUG
1123df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkeystatic std::string toString(std::vector<int64_t> values) {
1124df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    std::stringstream res;
1125df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    res << "[";
1126df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    for (size_t i = 0; i < values.size(); i++) {
1127df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        res << values[i];
1128df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        if (i < values.size() - 1) {
1129df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            res << ",";
1130df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        }
1131df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    }
1132df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    res << "]";
1133df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    return res.str();
1134df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey}
1135df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#endif
11363dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey
1137df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkeystatic void collectQuotaStats(const std::string& device, int32_t userId,
11387bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        int32_t appId, struct stats* stats, struct stats* extStats) {
1139df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    if (device.empty()) return;
1140df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
1141df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    struct dqblk dq;
11423dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey
1143a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey    if (stats != nullptr) {
1144a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        uid_t uid = multiuser_get_uid(userId, appId);
1145a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
11463dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey                reinterpret_cast<char*>(&dq)) != 0) {
11473dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey            if (errno != ESRCH) {
1148a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
11493dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey            }
11503dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey        } else {
1151df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#if MEASURE_DEBUG
1152a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey            LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
1153df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#endif
1154a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey            stats->dataSize += dq.dqb_curspace;
11553dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey        }
11563dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey
1157a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        int cacheGid = multiuser_get_cache_gid(userId, appId);
1158a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        if (cacheGid != -1) {
1159a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey            if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), cacheGid,
1160a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                    reinterpret_cast<char*>(&dq)) != 0) {
1161a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                if (errno != ESRCH) {
1162a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                    PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << cacheGid;
1163a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                }
1164a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey            } else {
1165a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey#if MEASURE_DEBUG
1166a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                LOG(DEBUG) << "quotactl() for GID " << cacheGid << " " << dq.dqb_curspace;
1167a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey#endif
1168a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                stats->cacheSize += dq.dqb_curspace;
11697bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey            }
1170a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        }
1171a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey
1172a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        int sharedGid = multiuser_get_shared_gid(0, appId);
1173a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        if (sharedGid != -1) {
1174a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey            if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), sharedGid,
1175a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                    reinterpret_cast<char*>(&dq)) != 0) {
1176a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                if (errno != ESRCH) {
1177a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                    PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << sharedGid;
1178a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                }
1179a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey            } else {
11807bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey#if MEASURE_DEBUG
1181a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                LOG(DEBUG) << "quotactl() for GID " << sharedGid << " " << dq.dqb_curspace;
11827bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey#endif
1183a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                stats->codeSize += dq.dqb_curspace;
1184a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey            }
11857bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        }
11867bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey    }
11877bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey
1188a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey    if (extStats != nullptr) {
1189a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        int extGid = multiuser_get_ext_gid(userId, appId);
1190a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        if (extGid != -1) {
1191a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey            if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), extGid,
1192a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                    reinterpret_cast<char*>(&dq)) != 0) {
1193a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                if (errno != ESRCH) {
1194a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                    PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << extGid;
1195a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                }
1196a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey            } else {
1197a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey#if MEASURE_DEBUG
1198a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                LOG(DEBUG) << "quotactl() for GID " << extGid << " " << dq.dqb_curspace;
1199a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey#endif
1200a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                extStats->dataSize += dq.dqb_curspace;
12013dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey            }
1202a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        }
1203a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey
1204a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        int extCacheGid = multiuser_get_ext_cache_gid(userId, appId);
1205a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        if (extCacheGid != -1) {
1206a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey            if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), extCacheGid,
1207a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                    reinterpret_cast<char*>(&dq)) != 0) {
1208a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                if (errno != ESRCH) {
1209a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                    PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << extCacheGid;
1210a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                }
1211a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey            } else {
1212df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#if MEASURE_DEBUG
1213a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                LOG(DEBUG) << "quotactl() for GID " << extCacheGid << " " << dq.dqb_curspace;
1214df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#endif
1215a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                extStats->dataSize += dq.dqb_curspace;
1216a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                extStats->cacheSize += dq.dqb_curspace;
1217a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey            }
12183dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey        }
12193dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey    }
1220df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey}
1221df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
1222df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkeystatic void collectManualStats(const std::string& path, struct stats* stats) {
122394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    DIR *d;
122494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    int dfd;
122594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    struct dirent *de;
122694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    struct stat s;
1227d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey
12282f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey    d = opendir(path.c_str());
12292f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey    if (d == nullptr) {
12303dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey        if (errno != ENOENT) {
12313dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey            PLOG(WARNING) << "Failed to open " << path;
12323dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey        }
12332f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey        return;
123494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
12352f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey    dfd = dirfd(d);
12362f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey    while ((de = readdir(d))) {
12372f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey        const char *name = de->d_name;
1238d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey
12393dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey        int64_t size = 0;
12402f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey        if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
12413dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey            size = s.st_blocks * 512;
124294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
124394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
12442f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey        if (de->d_type == DT_DIR) {
12453dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey            if (!strcmp(name, ".")) {
12463dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey                // Don't recurse, but still count node size
12473dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey            } else if (!strcmp(name, "..")) {
12483dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey                // Don't recurse or count node size
12493dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey                continue;
12503dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey            } else {
12513dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey                // Measure all children nodes
12523dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey                size = 0;
12533dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey                calculate_tree_size(StringPrintf("%s/%s", path.c_str(), name), &size);
12542f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey            }
12553dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey
12562f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey            if (!strcmp(name, "cache") || !strcmp(name, "code_cache")) {
12573dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey                stats->cacheSize += size;
12582f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey            }
125994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
12603dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey
12613dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey        // Legacy symlink isn't owned by app
12623dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey        if (de->d_type == DT_LNK && !strcmp(name, "lib")) {
12633dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey            continue;
12643dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey        }
12653dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey
12663dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey        // Everything found inside is considered data
12673dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey        stats->dataSize += size;
126894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
12692f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey    closedir(d);
12702f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey}
127194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
1272df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkeystatic void collectManualStatsForUser(const std::string& path, struct stats* stats,
1273df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        bool exclude_apps = false) {
1274df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    DIR *d;
1275df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    int dfd;
1276df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    struct dirent *de;
1277df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    struct stat s;
1278df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
1279df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    d = opendir(path.c_str());
1280df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    if (d == nullptr) {
1281df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        if (errno != ENOENT) {
1282df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            PLOG(WARNING) << "Failed to open " << path;
1283df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        }
1284df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        return;
1285df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    }
1286df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    dfd = dirfd(d);
1287df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    while ((de = readdir(d))) {
1288df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        if (de->d_type == DT_DIR) {
1289df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            const char *name = de->d_name;
1290df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) != 0) {
1291df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey                continue;
1292df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            }
1293a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey            int32_t user_uid = multiuser_get_app_id(s.st_uid);
1294df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            if (!strcmp(name, ".") || !strcmp(name, "..")) {
1295df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey                continue;
1296a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey            } else if (exclude_apps && (user_uid >= AID_APP_START && user_uid <= AID_APP_END)) {
1297df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey                continue;
1298df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            } else {
1299df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey                collectManualStats(StringPrintf("%s/%s", path.c_str(), name), stats);
1300df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            }
1301df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        }
1302df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    }
1303df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    closedir(d);
1304df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey}
1305df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
13067bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkeystatic void collectManualExternalStatsForUser(const std::string& path, struct stats* stats) {
13077bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey    FTS *fts;
13087bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey    FTSENT *p;
13097bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey    char *argv[] = { (char*) path.c_str(), nullptr };
1310b26786d647b624498c11405075e5223d1853f30aJeff Sharkey    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
13117bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        PLOG(ERROR) << "Failed to fts_open " << path;
13127bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        return;
13137bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey    }
13147bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey    while ((p = fts_read(fts)) != NULL) {
131576ddaeb2017e422de5a8d686ab62844d23d17624Jeff Sharkey        p->fts_number = p->fts_parent->fts_number;
13167bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        switch (p->fts_info) {
13177bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        case FTS_D:
13187bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey            if (p->fts_level == 4
13197bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey                    && !strcmp(p->fts_name, "cache")
13207bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey                    && !strcmp(p->fts_parent->fts_parent->fts_name, "data")
13217bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey                    && !strcmp(p->fts_parent->fts_parent->fts_parent->fts_name, "Android")) {
13227bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey                p->fts_number = 1;
13237bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey            }
13247bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey            // Fall through to count the directory
13257bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        case FTS_DEFAULT:
13267bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        case FTS_F:
13277bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        case FTS_SL:
13287bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        case FTS_SLNONE:
13297bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey            int64_t size = (p->fts_statp->st_blocks * 512);
13307bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey            if (p->fts_number == 1) {
13317bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey                stats->cacheSize += size;
13327bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey            }
13337bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey            stats->dataSize += size;
13347bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey            break;
13357bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        }
13367bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey    }
13377bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey    fts_close(fts);
13387bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey}
13397bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey
13406c2c056193010cf93b4264810d462c120ce801c8Jeff Sharkeybinder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::string>& uuid,
1341df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        const std::vector<std::string>& packageNames, int32_t userId, int32_t flags,
1342df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        int32_t appId, const std::vector<int64_t>& ceDataInodes,
1343df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        const std::vector<std::string>& codePaths, std::vector<int64_t>* _aidl_return) {
13446c2c056193010cf93b4264810d462c120ce801c8Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
1345423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    CHECK_ARGUMENT_UUID(uuid);
1346df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    for (auto packageName : packageNames) {
1347df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        CHECK_ARGUMENT_PACKAGE_NAME(packageName);
1348df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    }
1349b26786d647b624498c11405075e5223d1853f30aJeff Sharkey    // NOTE: Locking is relaxed on this method, since it's limited to
1350b26786d647b624498c11405075e5223d1853f30aJeff Sharkey    // read-only measurements without mutation.
1351423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey
1352df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    // When modifying this logic, always verify using tests:
1353df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    // runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetAppSize
1354df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
1355df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#if MEASURE_DEBUG
1356df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    LOG(INFO) << "Measuring user " << userId << " app " << appId;
1357df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#endif
13586c2c056193010cf93b4264810d462c120ce801c8Jeff Sharkey
13593dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey    // Here's a summary of the common storage locations across the platform,
13603dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey    // and how they're each tagged:
13613dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey    //
13623dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey    // /data/app/com.example                           UID system
13633dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey    // /data/app/com.example/oat                       UID system
1364df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    // /data/user/0/com.example                        UID u0_a10      GID u0_a10
1365df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    // /data/user/0/com.example/cache                  UID u0_a10      GID u0_a10_cache
1366df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    // /data/media/0/foo.txt                           UID u0_media_rw
1367df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    // /data/media/0/bar.jpg                           UID u0_media_rw GID u0_media_image
1368df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    // /data/media/0/Android/data/com.example          UID u0_media_rw GID u0_a10_ext
1369df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    // /data/media/0/Android/data/com.example/cache    UID u0_media_rw GID u0_a10_ext_cache
1370df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    // /data/media/obb/com.example                     UID system
13713dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey
13723dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey    struct stats stats;
1373df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    struct stats extStats;
13743dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey    memset(&stats, 0, sizeof(stats));
1375df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    memset(&extStats, 0, sizeof(extStats));
13763dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey
1377df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
13783dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey
137966b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey    auto device = findQuotaDeviceForUuid(uuid);
138066b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey    if (device.empty()) {
138166b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey        flags &= ~FLAG_USE_QUOTA;
138266b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey    }
138366b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey
1384466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey    ATRACE_BEGIN("obb");
1385df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    for (auto packageName : packageNames) {
1386df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        auto obbCodePath = create_data_media_obb_path(uuid_, packageName.c_str());
1387df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        calculate_tree_size(obbCodePath, &extStats.codeSize);
1388df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    }
1389466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey    ATRACE_END();
13903dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey
1391df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    if (flags & FLAG_USE_QUOTA && appId >= AID_APP_START) {
1392466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey        ATRACE_BEGIN("code");
1393df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        for (auto codePath : codePaths) {
1394df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            calculate_tree_size(codePath, &stats.codeSize, -1,
1395a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                    multiuser_get_shared_gid(0, appId));
13963dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey        }
1397466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey        ATRACE_END();
1398df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
1399466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey        ATRACE_BEGIN("quota");
140066b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey        collectQuotaStats(device, userId, appId, &stats, &extStats);
1401466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey        ATRACE_END();
14023dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey    } else {
1403466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey        ATRACE_BEGIN("code");
1404df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        for (auto codePath : codePaths) {
1405df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            calculate_tree_size(codePath, &stats.codeSize);
1406df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        }
1407466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey        ATRACE_END();
140894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
1409df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        for (size_t i = 0; i < packageNames.size(); i++) {
1410df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            const char* pkgname = packageNames[i].c_str();
141194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
1412466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey            ATRACE_BEGIN("data");
1413df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            auto cePath = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInodes[i]);
1414df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            collectManualStats(cePath, &stats);
1415df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            auto dePath = create_data_user_de_package_path(uuid_, userId, pkgname);
1416df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            collectManualStats(dePath, &stats);
1417466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey            ATRACE_END();
14183dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey
141906a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            if (!uuid) {
142006a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey                ATRACE_BEGIN("profiles");
142106a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey                calculate_tree_size(
142206a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey                        create_primary_current_profile_package_dir_path(userId, pkgname),
142306a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey                        &stats.dataSize);
142406a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey                calculate_tree_size(
142506a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey                        create_primary_reference_profile_package_dir_path(pkgname),
142606a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey                        &stats.codeSize);
142706a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey                ATRACE_END();
142806a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            }
1429df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
1430466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey            ATRACE_BEGIN("external");
143176ddaeb2017e422de5a8d686ab62844d23d17624Jeff Sharkey            auto extPath = create_data_media_package_path(uuid_, userId, "data", pkgname);
1432df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            collectManualStats(extPath, &extStats);
143376ddaeb2017e422de5a8d686ab62844d23d17624Jeff Sharkey            auto mediaPath = create_data_media_package_path(uuid_, userId, "media", pkgname);
1434df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            calculate_tree_size(mediaPath, &extStats.dataSize);
1435466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey            ATRACE_END();
1436df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        }
1437df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
143806a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey        if (!uuid) {
143906a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            ATRACE_BEGIN("dalvik");
1440a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey            int32_t sharedGid = multiuser_get_shared_gid(0, appId);
144106a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            if (sharedGid != -1) {
144206a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey                calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize,
144306a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey                        sharedGid, -1);
144406a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            }
144506a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            ATRACE_END();
1446df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        }
1447df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    }
1448df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
1449df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    std::vector<int64_t> ret;
1450df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    ret.push_back(stats.codeSize);
1451df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    ret.push_back(stats.dataSize);
1452df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    ret.push_back(stats.cacheSize);
1453df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    ret.push_back(extStats.codeSize);
1454df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    ret.push_back(extStats.dataSize);
1455df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    ret.push_back(extStats.cacheSize);
1456df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#if MEASURE_DEBUG
1457df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    LOG(DEBUG) << "Final result " << toString(ret);
1458df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#endif
1459df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    *_aidl_return = ret;
1460df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    return ok();
1461df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey}
1462df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
1463df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkeybinder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::string>& uuid,
1464df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
1465df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        std::vector<int64_t>* _aidl_return) {
1466df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
1467df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    CHECK_ARGUMENT_UUID(uuid);
1468b26786d647b624498c11405075e5223d1853f30aJeff Sharkey    // NOTE: Locking is relaxed on this method, since it's limited to
1469b26786d647b624498c11405075e5223d1853f30aJeff Sharkey    // read-only measurements without mutation.
1470df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
1471df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    // When modifying this logic, always verify using tests:
1472df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    // runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetUserSize
1473df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
1474df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#if MEASURE_DEBUG
1475df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    LOG(INFO) << "Measuring user " << userId;
1476df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#endif
1477df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
1478df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    struct stats stats;
1479df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    struct stats extStats;
1480df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    memset(&stats, 0, sizeof(stats));
1481df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    memset(&extStats, 0, sizeof(extStats));
1482df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
1483df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
1484df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
148566b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey    auto device = findQuotaDeviceForUuid(uuid);
148666b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey    if (device.empty()) {
148766b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey        flags &= ~FLAG_USE_QUOTA;
148866b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey    }
148966b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey
1490df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    if (flags & FLAG_USE_QUOTA) {
14917bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        struct dqblk dq;
14927bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey
14937bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        ATRACE_BEGIN("obb");
14947bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), AID_MEDIA_OBB,
14957bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey                reinterpret_cast<char*>(&dq)) != 0) {
14967bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey            if (errno != ESRCH) {
14977bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey                PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << AID_MEDIA_OBB;
14987bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey            }
14997bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        } else {
15007bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey#if MEASURE_DEBUG
15017bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey            LOG(DEBUG) << "quotactl() for GID " << AID_MEDIA_OBB << " " << dq.dqb_curspace;
15027bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey#endif
15037bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey            extStats.codeSize += dq.dqb_curspace;
15047bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        }
15057bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        ATRACE_END();
15067bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey
1507466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey        ATRACE_BEGIN("code");
1508df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize, -1, -1, true);
1509466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey        ATRACE_END();
1510df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
1511466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey        ATRACE_BEGIN("data");
1512df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        auto cePath = create_data_user_ce_path(uuid_, userId);
1513df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        collectManualStatsForUser(cePath, &stats, true);
1514df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        auto dePath = create_data_user_de_path(uuid_, userId);
1515df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        collectManualStatsForUser(dePath, &stats, true);
1516466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey        ATRACE_END();
1517df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
151806a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey        if (!uuid) {
151906a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            ATRACE_BEGIN("profile");
152006a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            auto userProfilePath = create_primary_cur_profile_dir_path(userId);
152106a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            calculate_tree_size(userProfilePath, &stats.dataSize, -1, -1, true);
152206a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            auto refProfilePath = create_primary_ref_profile_dir_path();
152306a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            calculate_tree_size(refProfilePath, &stats.codeSize, -1, -1, true);
152406a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            ATRACE_END();
152506a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey        }
15263dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey
1527466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey        ATRACE_BEGIN("external");
15287bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW);
15297bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
15307bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey                reinterpret_cast<char*>(&dq)) != 0) {
15317bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey            if (errno != ESRCH) {
15327bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey                PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
15337bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey            }
15347bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        } else {
15357bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey#if MEASURE_DEBUG
15367bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey            LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
1537df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#endif
15387bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey            extStats.dataSize += dq.dqb_curspace;
15397bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        }
15407bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        ATRACE_END();
15413dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey
154206a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey        if (!uuid) {
154306a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            ATRACE_BEGIN("dalvik");
154406a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize,
154506a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey                    -1, -1, true);
154606a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            calculate_tree_size(create_primary_cur_profile_dir_path(userId), &stats.dataSize,
154706a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey                    -1, -1, true);
154806a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            ATRACE_END();
154906a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey        }
1550df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
1551466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey        ATRACE_BEGIN("quota");
1552a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        int64_t dataSize = extStats.dataSize;
1553df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        for (auto appId : appIds) {
1554df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            if (appId >= AID_APP_START) {
1555df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey                collectQuotaStats(device, userId, appId, &stats, &extStats);
1556ec1be62c18b216901d738be0ccc8a05aab8edef0Jeff Sharkey
1557df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#if MEASURE_DEBUG
1558df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey                // Sleep to make sure we don't lose logs
1559df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey                usleep(1);
1560df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#endif
1561df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            }
1562df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        }
1563a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        extStats.dataSize = dataSize;
1564466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey        ATRACE_END();
1565df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    } else {
15667bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        ATRACE_BEGIN("obb");
15677bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        auto obbPath = create_data_path(uuid_) + "/media/obb";
15687bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        calculate_tree_size(obbPath, &extStats.codeSize);
15697bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        ATRACE_END();
15707bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey
1571466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey        ATRACE_BEGIN("code");
1572df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize);
1573466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey        ATRACE_END();
1574df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
1575466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey        ATRACE_BEGIN("data");
1576df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        auto cePath = create_data_user_ce_path(uuid_, userId);
1577df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        collectManualStatsForUser(cePath, &stats);
1578df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        auto dePath = create_data_user_de_path(uuid_, userId);
1579df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        collectManualStatsForUser(dePath, &stats);
1580466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey        ATRACE_END();
1581df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
158206a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey        if (!uuid) {
158306a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            ATRACE_BEGIN("profile");
158406a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            auto userProfilePath = create_primary_cur_profile_dir_path(userId);
158506a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            calculate_tree_size(userProfilePath, &stats.dataSize);
158606a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            auto refProfilePath = create_primary_ref_profile_dir_path();
158706a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            calculate_tree_size(refProfilePath, &stats.codeSize);
158806a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            ATRACE_END();
158906a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey        }
1590df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
1591466459b68da52edf20962c3c80e2fe0325569c18Jeff Sharkey        ATRACE_BEGIN("external");
15927bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        auto dataMediaPath = create_data_media_path(uuid_, userId);
15937bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        collectManualExternalStatsForUser(dataMediaPath, &extStats);
15947bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey#if MEASURE_DEBUG
15957bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        LOG(DEBUG) << "Measured external data " << extStats.dataSize << " cache "
15967bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey                << extStats.cacheSize;
15973dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey#endif
15987bf5b9532e192e846be3a31f28171cdba0f3c830Jeff Sharkey        ATRACE_END();
1599df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
160006a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey        if (!uuid) {
160106a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            ATRACE_BEGIN("dalvik");
160206a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize);
160306a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            calculate_tree_size(create_primary_cur_profile_dir_path(userId), &stats.dataSize);
160406a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey            ATRACE_END();
160506a6184da6c2d80ea8a30f7cf827ecdfe191622dJeff Sharkey        }
16062f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey    }
160794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
16083dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey    std::vector<int64_t> ret;
16093dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey    ret.push_back(stats.codeSize);
16103dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey    ret.push_back(stats.dataSize);
16113dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey    ret.push_back(stats.cacheSize);
1612df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    ret.push_back(extStats.codeSize);
1613df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    ret.push_back(extStats.dataSize);
1614df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    ret.push_back(extStats.cacheSize);
1615df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#if MEASURE_DEBUG
1616df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    LOG(DEBUG) << "Final result " << toString(ret);
1617df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#endif
1618df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    *_aidl_return = ret;
1619df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    return ok();
1620df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey}
1621df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
1622df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkeybinder::Status InstalldNativeService::getExternalSize(const std::unique_ptr<std::string>& uuid,
1623a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
1624a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        std::vector<int64_t>* _aidl_return) {
1625df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
1626df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    CHECK_ARGUMENT_UUID(uuid);
1627b26786d647b624498c11405075e5223d1853f30aJeff Sharkey    // NOTE: Locking is relaxed on this method, since it's limited to
1628b26786d647b624498c11405075e5223d1853f30aJeff Sharkey    // read-only measurements without mutation.
1629df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
1630df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    // When modifying this logic, always verify using tests:
1631df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    // runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetExternalSize
1632df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
1633df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#if MEASURE_DEBUG
1634df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    LOG(INFO) << "Measuring external " << userId;
1635df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#endif
1636df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
1637df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
1638df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
1639df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    int64_t totalSize = 0;
1640df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    int64_t audioSize = 0;
1641df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    int64_t videoSize = 0;
1642df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    int64_t imageSize = 0;
1643a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey    int64_t appSize = 0;
1644df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
164566b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey    auto device = findQuotaDeviceForUuid(uuid);
164666b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey    if (device.empty()) {
164766b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey        flags &= ~FLAG_USE_QUOTA;
164866b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey    }
164966b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey
1650df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    if (flags & FLAG_USE_QUOTA) {
1651df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        struct dqblk dq;
1652df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
1653a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        ATRACE_BEGIN("quota");
1654df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW);
1655df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
1656df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey                reinterpret_cast<char*>(&dq)) != 0) {
1657df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            if (errno != ESRCH) {
1658df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey                PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
1659df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            }
1660df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        } else {
1661df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#if MEASURE_DEBUG
1662a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey            LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
1663df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#endif
1664df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            totalSize = dq.dqb_curspace;
1665df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        }
1666df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
1667df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        gid_t audioGid = multiuser_get_uid(userId, AID_MEDIA_AUDIO);
1668df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), audioGid,
1669df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey                reinterpret_cast<char*>(&dq)) == 0) {
1670df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#if MEASURE_DEBUG
1671a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey            LOG(DEBUG) << "quotactl() for GID " << audioGid << " " << dq.dqb_curspace;
1672df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#endif
1673df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            audioSize = dq.dqb_curspace;
1674df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        }
1675df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        gid_t videoGid = multiuser_get_uid(userId, AID_MEDIA_VIDEO);
1676df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), videoGid,
1677df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey                reinterpret_cast<char*>(&dq)) == 0) {
1678df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#if MEASURE_DEBUG
1679a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey            LOG(DEBUG) << "quotactl() for GID " << videoGid << " " << dq.dqb_curspace;
1680df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#endif
1681df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            videoSize = dq.dqb_curspace;
1682df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        }
1683df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        gid_t imageGid = multiuser_get_uid(userId, AID_MEDIA_IMAGE);
1684df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), imageGid,
1685df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey                reinterpret_cast<char*>(&dq)) == 0) {
1686df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#if MEASURE_DEBUG
1687a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey            LOG(DEBUG) << "quotactl() for GID " << imageGid << " " << dq.dqb_curspace;
1688df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#endif
1689df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            imageSize = dq.dqb_curspace;
1690df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        }
1691a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        ATRACE_END();
1692a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey
1693a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        ATRACE_BEGIN("apps");
1694a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        struct stats extStats;
1695a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        memset(&extStats, 0, sizeof(extStats));
1696a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        for (auto appId : appIds) {
1697a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey            if (appId >= AID_APP_START) {
1698a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                collectQuotaStats(device, userId, appId, nullptr, &extStats);
1699a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey            }
1700a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        }
17014ca8ff98e40023c32e0f05473e1fe906b6537417Jeff Sharkey        appSize = extStats.dataSize;
1702a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        ATRACE_END();
1703df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    } else {
1704a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        ATRACE_BEGIN("manual");
1705df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        FTS *fts;
1706df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        FTSENT *p;
1707df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        auto path = create_data_media_path(uuid_, userId);
1708df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        char *argv[] = { (char*) path.c_str(), nullptr };
1709b26786d647b624498c11405075e5223d1853f30aJeff Sharkey        if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
1710df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            return error("Failed to fts_open " + path);
1711df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        }
1712df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        while ((p = fts_read(fts)) != NULL) {
1713df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            char* ext;
1714df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            int64_t size = (p->fts_statp->st_blocks * 512);
1715df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            switch (p->fts_info) {
1716df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            case FTS_F:
1717df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey                // Only categorize files not belonging to apps
1718444ad1ee82a549c96bf9e5087b9041d6264c93ecJeff Sharkey                if (p->fts_parent->fts_number == 0) {
1719df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey                    ext = strrchr(p->fts_name, '.');
1720df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey                    if (ext != nullptr) {
1721df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey                        switch (MatchExtension(++ext)) {
1722df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey                        case AID_MEDIA_AUDIO: audioSize += size; break;
1723df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey                        case AID_MEDIA_VIDEO: videoSize += size; break;
1724df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey                        case AID_MEDIA_IMAGE: imageSize += size; break;
1725df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey                        }
1726df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey                    }
1727df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey                }
1728df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey                // Fall through to always count against total
1729df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            case FTS_D:
1730444ad1ee82a549c96bf9e5087b9041d6264c93ecJeff Sharkey                // Ignore data belonging to specific apps
1731444ad1ee82a549c96bf9e5087b9041d6264c93ecJeff Sharkey                p->fts_number = p->fts_parent->fts_number;
1732444ad1ee82a549c96bf9e5087b9041d6264c93ecJeff Sharkey                if (p->fts_level == 1 && !strcmp(p->fts_name, "Android")) {
1733444ad1ee82a549c96bf9e5087b9041d6264c93ecJeff Sharkey                    p->fts_number = 1;
1734444ad1ee82a549c96bf9e5087b9041d6264c93ecJeff Sharkey                }
1735df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            case FTS_DEFAULT:
1736df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            case FTS_SL:
1737df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            case FTS_SLNONE:
1738a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                if (p->fts_parent->fts_number == 1) {
1739a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                    appSize += size;
1740a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey                }
1741df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey                totalSize += size;
1742df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey                break;
1743df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey            }
1744df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        }
1745df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey        fts_close(fts);
1746a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey        ATRACE_END();
1747df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    }
1748df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey
1749df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    std::vector<int64_t> ret;
1750df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    ret.push_back(totalSize);
1751df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    ret.push_back(audioSize);
1752df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    ret.push_back(videoSize);
1753df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    ret.push_back(imageSize);
1754a084fcdcd052d71e8205a2eea0955911b99160b9Jeff Sharkey    ret.push_back(appSize);
1755df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#if MEASURE_DEBUG
1756df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey    LOG(DEBUG) << "Final result " << toString(ret);
1757df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#endif
17583dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey    *_aidl_return = ret;
1759423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return ok();
17602f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey}
1761d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey
176288ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkeybinder::Status InstalldNativeService::setAppQuota(const std::unique_ptr<std::string>& uuid,
176388ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey        int32_t userId, int32_t appId, int64_t cacheQuota) {
176488ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey    ENFORCE_UID(AID_SYSTEM);
176588ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey    CHECK_ARGUMENT_UUID(uuid);
1766d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mQuotasLock);
176788ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey
176888ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey    int32_t uid = multiuser_get_uid(userId, appId);
176988ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey    mCacheQuotas[uid] = cacheQuota;
177088ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey
177188ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey    return ok();
177288ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey}
177388ddd94834dae9c5862a07a1e4432b171b2f5d9fJeff Sharkey
17746727c2d0bfc876c62d6ee60d8a05d26bef1d56efDavid Sehr// Dumps the contents of a profile file, using pkgname's dex files for pretty
17756727c2d0bfc876c62d6ee60d8a05d26bef1d56efDavid Sehr// printing the result.
1776475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkeybinder::Status InstalldNativeService::dumpProfiles(int32_t uid, const std::string& packageName,
1777475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey        const std::string& codePaths, bool* _aidl_return) {
1778475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
1779423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
17807a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mLock);
1781475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey
1782475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    const char* pkgname = packageName.c_str();
178390aff26f0135379db19432ae90c40c0831ba5954Jeff Sharkey    const char* code_paths = codePaths.c_str();
17846727c2d0bfc876c62d6ee60d8a05d26bef1d56efDavid Sehr
178590aff26f0135379db19432ae90c40c0831ba5954Jeff Sharkey    *_aidl_return = dump_profiles(uid, pkgname, code_paths);
1786423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return ok();
17876727c2d0bfc876c62d6ee60d8a05d26bef1d56efDavid Sehr}
17886727c2d0bfc876c62d6ee60d8a05d26bef1d56efDavid Sehr
17894d0f825dd76a1972a3d081e771cde28513a1c6ffAndreas Gampe// TODO: Consider returning error codes.
1790475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkeybinder::Status InstalldNativeService::mergeProfiles(int32_t uid, const std::string& packageName,
1791423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        bool* _aidl_return) {
1792475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
1793423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
17947a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mLock);
1795423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey
1796114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle    *_aidl_return = analyze_primary_profiles(uid, packageName);
1797423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return ok();
17984d0f825dd76a1972a3d081e771cde28513a1c6ffAndreas Gampe}
17994d0f825dd76a1972a3d081e771cde28513a1c6ffAndreas Gampe
18006c2c056193010cf93b4264810d462c120ce801c8Jeff Sharkeybinder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t uid,
18016c2c056193010cf93b4264810d462c120ce801c8Jeff Sharkey        const std::unique_ptr<std::string>& packageName, const std::string& instructionSet,
18026c2c056193010cf93b4264810d462c120ce801c8Jeff Sharkey        int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
18036c2c056193010cf93b4264810d462c120ce801c8Jeff Sharkey        const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
1804cb556e340b50d16e8fac41b0c69d8d35bd7915f9Calin Juravle        const std::unique_ptr<std::string>& sharedLibraries,
1805cb556e340b50d16e8fac41b0c69d8d35bd7915f9Calin Juravle        const std::unique_ptr<std::string>& seInfo) {
18066c2c056193010cf93b4264810d462c120ce801c8Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
1807423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    CHECK_ARGUMENT_UUID(uuid);
1808423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    if (packageName && *packageName != "*") {
1809423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        CHECK_ARGUMENT_PACKAGE_NAME(*packageName);
1810423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    }
18117a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mLock);
18126c2c056193010cf93b4264810d462c120ce801c8Jeff Sharkey
18136c2c056193010cf93b4264810d462c120ce801c8Jeff Sharkey    const char* apk_path = apkPath.c_str();
18146c2c056193010cf93b4264810d462c120ce801c8Jeff Sharkey    const char* pkgname = packageName ? packageName->c_str() : "*";
18156c2c056193010cf93b4264810d462c120ce801c8Jeff Sharkey    const char* instruction_set = instructionSet.c_str();
18166c2c056193010cf93b4264810d462c120ce801c8Jeff Sharkey    const char* oat_dir = outputPath ? outputPath->c_str() : nullptr;
18176c2c056193010cf93b4264810d462c120ce801c8Jeff Sharkey    const char* compiler_filter = compilerFilter.c_str();
18186c2c056193010cf93b4264810d462c120ce801c8Jeff Sharkey    const char* volume_uuid = uuid ? uuid->c_str() : nullptr;
18196c2c056193010cf93b4264810d462c120ce801c8Jeff Sharkey    const char* shared_libraries = sharedLibraries ? sharedLibraries->c_str() : nullptr;
1820cb556e340b50d16e8fac41b0c69d8d35bd7915f9Calin Juravle    const char* se_info = seInfo ? seInfo->c_str() : nullptr;
18216c2c056193010cf93b4264810d462c120ce801c8Jeff Sharkey    int res = android::installd::dexopt(apk_path, uid, pkgname, instruction_set, dexoptNeeded,
1822cb556e340b50d16e8fac41b0c69d8d35bd7915f9Calin Juravle            oat_dir, dexFlags, compiler_filter, volume_uuid, shared_libraries, se_info);
1823423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return res ? error(res, "Failed to dexopt") : ok();
18246c2c056193010cf93b4264810d462c120ce801c8Jeff Sharkey}
18256c2c056193010cf93b4264810d462c120ce801c8Jeff Sharkey
1826475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkeybinder::Status InstalldNativeService::markBootComplete(const std::string& instructionSet) {
1827475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
18287a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mLock);
18297a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey
1830475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    const char* instruction_set = instructionSet.c_str();
1831475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey
1832475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    char boot_marker_path[PKG_PATH_MAX];
1833475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    sprintf(boot_marker_path,
183402d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe          "%s/%s/%s/.booting",
183502d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe          android_data_dir.path,
183602d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe          DALVIK_CACHE,
183702d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe          instruction_set);
1838091ea779d4e575856c04d51d82f45cc8a6155b5eNarayan Kamath
1839475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    ALOGV("mark_boot_complete : %s", boot_marker_path);
1840475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    if (unlink(boot_marker_path) != 0) {
1841423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return error(StringPrintf("Failed to unlink %s", boot_marker_path));
1842475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    }
1843423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return ok();
1844091ea779d4e575856c04d51d82f45cc8a6155b5eNarayan Kamath}
1845091ea779d4e575856c04d51d82f45cc8a6155b5eNarayan Kamath
184694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodvoid mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid,
184794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        struct stat* statbuf)
184894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood{
184994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    while (path[basepos] != 0) {
185094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (path[basepos] == '/') {
185194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            path[basepos] = 0;
185294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            if (lstat(path, statbuf) < 0) {
185394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                ALOGV("Making directory: %s\n", path);
185494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                if (mkdir(path, mode) == 0) {
185594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    chown(path, uid, gid);
185694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                } else {
185794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    ALOGW("Unable to make directory %s: %s\n", path, strerror(errno));
185894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                }
185994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            }
186094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            path[basepos] = '/';
186194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            basepos++;
186294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
186394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        basepos++;
186494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
186594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
186694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
1867475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkeybinder::Status InstalldNativeService::linkNativeLibraryDirectory(
1868475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey        const std::unique_ptr<std::string>& uuid, const std::string& packageName,
1869475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey        const std::string& nativeLibPath32, int32_t userId) {
1870475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
1871423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    CHECK_ARGUMENT_UUID(uuid);
1872423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
18737a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mLock);
1874423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey
1875475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
1876475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    const char* pkgname = packageName.c_str();
1877475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    const char* asecLibDir = nativeLibPath32.c_str();
187894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    struct stat s, libStat;
1879423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    binder::Status res = ok();
188094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
1881423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    auto _pkgdir = create_data_user_ce_package_path(uuid_, userId, pkgname);
1882423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    auto _libsymlink = _pkgdir + PKG_LIB_POSTFIX;
1883c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkey
1884c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkey    const char* pkgdir = _pkgdir.c_str();
1885c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkey    const char* libsymlink = _libsymlink.c_str();
188694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
1887475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    if (stat(pkgdir, &s) < 0) {
1888423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return error("Failed to stat " + _pkgdir);
1889475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    }
189094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
189194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (chown(pkgdir, AID_INSTALL, AID_INSTALL) < 0) {
1892423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return error("Failed to chown " + _pkgdir);
189394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
189494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
189594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (chmod(pkgdir, 0700) < 0) {
1896423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        res = error("Failed to chmod " + _pkgdir);
189794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        goto out;
189894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
189994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
190094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (lstat(libsymlink, &libStat) < 0) {
190194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (errno != ENOENT) {
1902423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            res = error("Failed to stat " + _libsymlink);
190394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            goto out;
190494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
190594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    } else {
190694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (S_ISDIR(libStat.st_mode)) {
19073aee2c5c749dc2589f001b26fae1ec958ec89524Narayan Kamath            if (delete_dir_contents(libsymlink, 1, NULL) < 0) {
1908423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey                res = error("Failed to delete " + _libsymlink);
190994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                goto out;
191094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            }
191194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        } else if (S_ISLNK(libStat.st_mode)) {
191294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            if (unlink(libsymlink) < 0) {
1913423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey                res = error("Failed to unlink " + _libsymlink);
191494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                goto out;
191594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            }
191694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
191794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
191894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
191994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (symlink(asecLibDir, libsymlink) < 0) {
1920423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        res = error("Failed to symlink " + _libsymlink + " to " + nativeLibPath32);
192194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        goto out;
192294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
192394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
192494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodout:
192594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (chmod(pkgdir, s.st_mode) < 0) {
1926423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        auto msg = "Failed to cleanup chmod " + _pkgdir;
1927423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        if (res.isOk()) {
1928423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            res = error(msg);
1929423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        } else {
1930423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            PLOG(ERROR) << msg;
1931423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        }
193294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
193394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
193494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (chown(pkgdir, s.st_uid, s.st_gid) < 0) {
1935423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        auto msg = "Failed to cleanup chown " + _pkgdir;
1936423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        if (res.isOk()) {
1937423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            res = error(msg);
1938423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        } else {
1939423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            PLOG(ERROR) << msg;
1940423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        }
194194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
194294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
1943423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return res;
194494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
194563568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad
194663568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstadstatic void run_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd)
194763568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad{
19485cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok    execl(kIdMapPath, kIdMapPath, "--fd", target_apk, overlay_apk,
19495cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok            StringPrintf("%d", idmap_fd).c_str(), (char*)NULL);
19505cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok    PLOG(ERROR) << "execl (" << kIdMapPath << ") failed";
19515cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok}
195263568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad
19535cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seokstatic void run_verify_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd)
19545cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok{
19555cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok    execl(kIdMapPath, kIdMapPath, "--verify", target_apk, overlay_apk,
19565cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok            StringPrintf("%d", idmap_fd).c_str(), (char*)NULL);
19575cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok    PLOG(ERROR) << "execl (" << kIdMapPath << ") failed";
19585cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok}
195963568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad
19605cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seokstatic bool delete_stale_idmap(const char* target_apk, const char* overlay_apk,
19615cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok        const char* idmap_path, int32_t uid) {
19625cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok    int idmap_fd = open(idmap_path, O_RDWR);
19635cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok    if (idmap_fd < 0) {
19645cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok        PLOG(ERROR) << "idmap open failed: " << idmap_path;
19655cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok        unlink(idmap_path);
19665cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok        return true;
19675cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok    }
19685cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok
19695cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok    pid_t pid;
19705cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok    pid = fork();
19715cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok    if (pid == 0) {
19725cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok        /* child -- drop privileges before continuing */
19735cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok        if (setgid(uid) != 0) {
19745cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok            LOG(ERROR) << "setgid(" << uid << ") failed during idmap";
19755cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok            exit(1);
19765cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok        }
19775cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok        if (setuid(uid) != 0) {
19785cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok            LOG(ERROR) << "setuid(" << uid << ") failed during idmap";
19795cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok            exit(1);
19805cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok        }
19815cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok        if (flock(idmap_fd, LOCK_EX | LOCK_NB) != 0) {
19825cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok            PLOG(ERROR) << "flock(" << idmap_path << ") failed during idmap";
19835cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok            exit(1);
19845cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok        }
19855cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok
19865cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok        run_verify_idmap(target_apk, overlay_apk, idmap_fd);
19875cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok        exit(1); /* only if exec call to deleting stale idmap failed */
19885cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok    } else {
19895cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok        int status = wait_child(pid);
19905cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok        close(idmap_fd);
19915cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok
19925cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok        if (status != 0) {
19935cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok            // Failed on verifying if idmap is made from target_apk and overlay_apk.
19945cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok            LOG(DEBUG) << "delete stale idmap: " << idmap_path;
19955cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok            unlink(idmap_path);
19965cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok            return true;
19975cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok        }
19985cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok    }
19995cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok    return false;
200063568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad}
200163568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad
200263568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad// Transform string /a/b/c.apk to (prefix)/a@b@c.apk@(suffix)
200363568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad// eg /a/b/c.apk to /data/resource-cache/a@b@c.apk@idmap
200463568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstadstatic int flatten_path(const char *prefix, const char *suffix,
200563568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        const char *overlay_path, char *idmap_path, size_t N)
200663568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad{
200763568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    if (overlay_path == NULL || idmap_path == NULL) {
200863568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        return -1;
200963568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    }
201063568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    const size_t len_overlay_path = strlen(overlay_path);
201163568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    // will access overlay_path + 1 further below; requires absolute path
201263568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    if (len_overlay_path < 2 || *overlay_path != '/') {
201363568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        return -1;
201463568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    }
201563568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    const size_t len_idmap_root = strlen(prefix);
201663568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    const size_t len_suffix = strlen(suffix);
201763568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    if (SIZE_MAX - len_idmap_root < len_overlay_path ||
201863568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad            SIZE_MAX - (len_idmap_root + len_overlay_path) < len_suffix) {
201963568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        // additions below would cause overflow
202063568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        return -1;
202163568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    }
202263568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    if (N < len_idmap_root + len_overlay_path + len_suffix) {
202363568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        return -1;
202463568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    }
202563568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    memset(idmap_path, 0, N);
202663568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    snprintf(idmap_path, N, "%s%s%s", prefix, overlay_path + 1, suffix);
202763568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    char *ch = idmap_path + len_idmap_root;
202863568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    while (*ch != '\0') {
202963568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        if (*ch == '/') {
203063568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad            *ch = '@';
203163568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        }
203263568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        ++ch;
203363568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    }
203463568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    return 0;
203563568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad}
203663568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad
2037475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkeybinder::Status InstalldNativeService::idmap(const std::string& targetApkPath,
2038475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey        const std::string& overlayApkPath, int32_t uid) {
2039475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
20407a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mLock);
20417a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey
2042475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    const char* target_apk = targetApkPath.c_str();
2043475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    const char* overlay_apk = overlayApkPath.c_str();
204463568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    ALOGV("idmap target_apk=%s overlay_apk=%s uid=%d\n", target_apk, overlay_apk, uid);
204563568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad
204663568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    int idmap_fd = -1;
204763568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    char idmap_path[PATH_MAX];
20485cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok    struct stat idmap_stat;
20495cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok    bool outdated = false;
205063568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad
205163568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    if (flatten_path(IDMAP_PREFIX, IDMAP_SUFFIX, overlay_apk,
205263568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad                idmap_path, sizeof(idmap_path)) == -1) {
205363568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        ALOGE("idmap cannot generate idmap path for overlay %s\n", overlay_apk);
205463568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        goto fail;
205563568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    }
205663568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad
20575cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok    if (stat(idmap_path, &idmap_stat) < 0) {
20585cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok        outdated = true;
20595cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok    } else {
20605cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok        outdated = delete_stale_idmap(target_apk, overlay_apk, idmap_path, uid);
20615cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok    }
20625cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok
20635cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok    if (outdated) {
20645cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok        idmap_fd = open(idmap_path, O_RDWR | O_CREAT | O_EXCL, 0644);
20655cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok    } else {
20665cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok        idmap_fd = open(idmap_path, O_RDWR);
20675cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok    }
20685cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok
206963568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    if (idmap_fd < 0) {
207063568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        ALOGE("idmap cannot open '%s' for output: %s\n", idmap_path, strerror(errno));
207163568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        goto fail;
207263568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    }
207363568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    if (fchown(idmap_fd, AID_SYSTEM, uid) < 0) {
207463568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        ALOGE("idmap cannot chown '%s'\n", idmap_path);
207563568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        goto fail;
207663568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    }
207763568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    if (fchmod(idmap_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) {
207863568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        ALOGE("idmap cannot chmod '%s'\n", idmap_path);
207963568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        goto fail;
208063568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    }
208163568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad
20825cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok    if (!outdated) {
20835cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok        close(idmap_fd);
20845cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok        return ok();
20855cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok    }
20865cb903e0a976a143cd70441dcbd0fcb5a9630daaJaekyun Seok
208763568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    pid_t pid;
208863568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    pid = fork();
208963568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    if (pid == 0) {
209063568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        /* child -- drop privileges before continuing */
209163568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        if (setgid(uid) != 0) {
209263568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad            ALOGE("setgid(%d) failed during idmap\n", uid);
209363568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad            exit(1);
209463568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        }
209563568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        if (setuid(uid) != 0) {
209663568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad            ALOGE("setuid(%d) failed during idmap\n", uid);
209763568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad            exit(1);
209863568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        }
209963568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        if (flock(idmap_fd, LOCK_EX | LOCK_NB) != 0) {
210063568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad            ALOGE("flock(%s) failed during idmap: %s\n", idmap_path, strerror(errno));
210163568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad            exit(1);
210263568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        }
210363568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad
210463568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        run_idmap(target_apk, overlay_apk, idmap_fd);
210563568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        exit(1); /* only if exec call to idmap failed */
210663568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    } else {
210763568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        int status = wait_child(pid);
210863568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        if (status != 0) {
210963568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad            ALOGE("idmap failed, status=0x%04x\n", status);
211063568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad            goto fail;
211163568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        }
211263568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    }
211363568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad
211463568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    close(idmap_fd);
2115423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return ok();
211663568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstadfail:
211763568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    if (idmap_fd >= 0) {
211863568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        close(idmap_fd);
211963568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad        unlink(idmap_path);
212063568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad    }
2121423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return error();
212263568b1430d741f40ca008391c854ef1cc880138MÃ¥rten Kongstad}
2123e9887e46cea4a095e4219927eadbe4c57bb1a5eeRobert Craig
21245c6944c35211accd783d2584fac6421dd0af5bddMÃ¥rten Kongstadbinder::Status InstalldNativeService::removeIdmap(const std::string& overlayApkPath) {
21255c6944c35211accd783d2584fac6421dd0af5bddMÃ¥rten Kongstad    const char* overlay_apk = overlayApkPath.c_str();
21265c6944c35211accd783d2584fac6421dd0af5bddMÃ¥rten Kongstad    char idmap_path[PATH_MAX];
21275c6944c35211accd783d2584fac6421dd0af5bddMÃ¥rten Kongstad
21285c6944c35211accd783d2584fac6421dd0af5bddMÃ¥rten Kongstad    if (flatten_path(IDMAP_PREFIX, IDMAP_SUFFIX, overlay_apk,
21295c6944c35211accd783d2584fac6421dd0af5bddMÃ¥rten Kongstad                idmap_path, sizeof(idmap_path)) == -1) {
21305c6944c35211accd783d2584fac6421dd0af5bddMÃ¥rten Kongstad        ALOGE("idmap cannot generate idmap path for overlay %s\n", overlay_apk);
21315c6944c35211accd783d2584fac6421dd0af5bddMÃ¥rten Kongstad        return error();
21325c6944c35211accd783d2584fac6421dd0af5bddMÃ¥rten Kongstad    }
21335c6944c35211accd783d2584fac6421dd0af5bddMÃ¥rten Kongstad    if (unlink(idmap_path) < 0) {
21345c6944c35211accd783d2584fac6421dd0af5bddMÃ¥rten Kongstad        ALOGE("couldn't unlink idmap file %s\n", idmap_path);
21355c6944c35211accd783d2584fac6421dd0af5bddMÃ¥rten Kongstad        return error();
21365c6944c35211accd783d2584fac6421dd0af5bddMÃ¥rten Kongstad    }
21375c6944c35211accd783d2584fac6421dd0af5bddMÃ¥rten Kongstad    return ok();
21385c6944c35211accd783d2584fac6421dd0af5bddMÃ¥rten Kongstad}
21395c6944c35211accd783d2584fac6421dd0af5bddMÃ¥rten Kongstad
2140c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkeybinder::Status InstalldNativeService::restoreconAppData(const std::unique_ptr<std::string>& uuid,
2141c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey        const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
2142c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey        const std::string& seInfo) {
2143c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
2144423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    CHECK_ARGUMENT_UUID(uuid);
2145423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
21467a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mLock);
2147423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey
2148423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    binder::Status res = ok();
2149e9887e46cea4a095e4219927eadbe4c57bb1a5eeRobert Craig
2150da30dc7336f03ca629fe173db1425fdce989119cRobert Craig    // SELINUX_ANDROID_RESTORECON_DATADATA flag is set by libselinux. Not needed here.
2151c7d1b2250e8245a7e4e144758bc3ccd33b8d6319Jeff Sharkey    unsigned int seflags = SELINUX_ANDROID_RESTORECON_RECURSE;
2152c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
2153c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey    const char* pkgName = packageName.c_str();
2154c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey    const char* seinfo = seInfo.c_str();
2155e9887e46cea4a095e4219927eadbe4c57bb1a5eeRobert Craig
2156c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey    uid_t uid = multiuser_get_uid(userId, appId);
2157aa7ddfd8347fa947618a7668b013521e95722c5cJeff Sharkey    if (flags & FLAG_STORAGE_CE) {
2158c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey        auto path = create_data_user_ce_package_path(uuid_, userId, pkgName);
2159c7d1b2250e8245a7e4e144758bc3ccd33b8d6319Jeff Sharkey        if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, seflags) < 0) {
2160423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            res = error("restorecon failed for " + path);
2161da30dc7336f03ca629fe173db1425fdce989119cRobert Craig        }
2162c7d1b2250e8245a7e4e144758bc3ccd33b8d6319Jeff Sharkey    }
2163aa7ddfd8347fa947618a7668b013521e95722c5cJeff Sharkey    if (flags & FLAG_STORAGE_DE) {
2164c1e93e7d746e07791b0667c80ad43a407c515fa8Jeff Sharkey        auto path = create_data_user_de_package_path(uuid_, userId, pkgName);
2165c7d1b2250e8245a7e4e144758bc3ccd33b8d6319Jeff Sharkey        if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, seflags) < 0) {
2166423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey            res = error("restorecon failed for " + path);
2167da30dc7336f03ca629fe173db1425fdce989119cRobert Craig        }
2168da30dc7336f03ca629fe173db1425fdce989119cRobert Craig    }
2169423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return res;
2170e9887e46cea4a095e4219927eadbe4c57bb1a5eeRobert Craig}
21713aee2c5c749dc2589f001b26fae1ec958ec89524Narayan Kamath
2172475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkeybinder::Status InstalldNativeService::createOatDir(const std::string& oatDir,
2173475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey        const std::string& instructionSet) {
2174475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
21757a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mLock);
21767a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey
2177475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    const char* oat_dir = oatDir.c_str();
2178475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    const char* instruction_set = instructionSet.c_str();
217988ce4ff7a95ea2008fa28f12b880ee526e331440Fyodor Kupolov    char oat_instr_dir[PKG_PATH_MAX];
218088ce4ff7a95ea2008fa28f12b880ee526e331440Fyodor Kupolov
218188ce4ff7a95ea2008fa28f12b880ee526e331440Fyodor Kupolov    if (validate_apk_path(oat_dir)) {
2182423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return error("Invalid path " + oatDir);
218388ce4ff7a95ea2008fa28f12b880ee526e331440Fyodor Kupolov    }
21848eed7e6a9bb527af7380ec13b390c6e2955eba6aFyodor Kupolov    if (fs_prepare_dir(oat_dir, S_IRWXU | S_IRWXG | S_IXOTH, AID_SYSTEM, AID_INSTALL)) {
2185423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return error("Failed to prepare " + oatDir);
218688ce4ff7a95ea2008fa28f12b880ee526e331440Fyodor Kupolov    }
218788ce4ff7a95ea2008fa28f12b880ee526e331440Fyodor Kupolov    if (selinux_android_restorecon(oat_dir, 0)) {
2188423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return error("Failed to restorecon " + oatDir);
218988ce4ff7a95ea2008fa28f12b880ee526e331440Fyodor Kupolov    }
219088ce4ff7a95ea2008fa28f12b880ee526e331440Fyodor Kupolov    snprintf(oat_instr_dir, PKG_PATH_MAX, "%s/%s", oat_dir, instruction_set);
21918eed7e6a9bb527af7380ec13b390c6e2955eba6aFyodor Kupolov    if (fs_prepare_dir(oat_instr_dir, S_IRWXU | S_IRWXG | S_IXOTH, AID_SYSTEM, AID_INSTALL)) {
2192423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return error(StringPrintf("Failed to prepare %s", oat_instr_dir));
219388ce4ff7a95ea2008fa28f12b880ee526e331440Fyodor Kupolov    }
2194423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return ok();
219588ce4ff7a95ea2008fa28f12b880ee526e331440Fyodor Kupolov}
219688ce4ff7a95ea2008fa28f12b880ee526e331440Fyodor Kupolov
2197475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkeybinder::Status InstalldNativeService::rmPackageDir(const std::string& packageDir) {
2198475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
21997a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mLock);
22007a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey
2201423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    if (validate_apk_path(packageDir.c_str())) {
2202423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return error("Invalid path " + packageDir);
2203423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    }
2204423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    if (delete_dir_contents_and_dir(packageDir) != 0) {
2205423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return error("Failed to delete " + packageDir);
220688ce4ff7a95ea2008fa28f12b880ee526e331440Fyodor Kupolov    }
2207423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return ok();
220888ce4ff7a95ea2008fa28f12b880ee526e331440Fyodor Kupolov}
220988ce4ff7a95ea2008fa28f12b880ee526e331440Fyodor Kupolov
2210475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkeybinder::Status InstalldNativeService::linkFile(const std::string& relativePath,
2211475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey        const std::string& fromBase, const std::string& toBase) {
2212475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
22137a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mLock);
22147a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey
2215475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    const char* relative_path = relativePath.c_str();
2216475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    const char* from_base = fromBase.c_str();
2217475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    const char* to_base = toBase.c_str();
2218d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath    char from_path[PKG_PATH_MAX];
2219d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath    char to_path[PKG_PATH_MAX];
2220d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath    snprintf(from_path, PKG_PATH_MAX, "%s/%s", from_base, relative_path);
2221d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath    snprintf(to_path, PKG_PATH_MAX, "%s/%s", to_base, relative_path);
2222d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath
2223d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath    if (validate_apk_path_subdirs(from_path)) {
2224423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return error(StringPrintf("Invalid from path %s", from_path));
2225d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath    }
2226d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath
2227d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath    if (validate_apk_path_subdirs(to_path)) {
2228423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return error(StringPrintf("Invalid to path %s", to_path));
2229d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath    }
2230d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath
2231423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    if (link(from_path, to_path) < 0) {
2232423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey        return error(StringPrintf("Failed to link from %s to %s", from_path, to_path));
2233d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath    }
2234d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath
2235423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return ok();
2236d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath}
2237d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath
2238475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkeybinder::Status InstalldNativeService::moveAb(const std::string& apkPath,
2239475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey        const std::string& instructionSet, const std::string& outputPath) {
2240475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
22417a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mLock);
224290aff26f0135379db19432ae90c40c0831ba5954Jeff Sharkey
2243475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    const char* apk_path = apkPath.c_str();
2244475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    const char* instruction_set = instructionSet.c_str();
2245475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    const char* oat_dir = outputPath.c_str();
22460354bd0eaf24de533e86885b811f816f1e4d15c8Andreas Gampe
224790aff26f0135379db19432ae90c40c0831ba5954Jeff Sharkey    bool success = move_ab(apk_path, instruction_set, oat_dir);
2248423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey    return success ? ok() : error();
2249e65b4faa798269ab6ee0d27dab03b8b5caa6f956Andreas Gampe}
2250e65b4faa798269ab6ee0d27dab03b8b5caa6f956Andreas Gampe
2251475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkeybinder::Status InstalldNativeService::deleteOdex(const std::string& apkPath,
2252c523409f0fd03aa498cedc486f85e9a4b7257f3aAndreas Gampe        const std::string& instructionSet, const std::unique_ptr<std::string>& outputPath) {
2253475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
22547a9059e8ed297a8e025c843b632c7c8571682b46Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mLock);
225590aff26f0135379db19432ae90c40c0831ba5954Jeff Sharkey
2256475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    const char* apk_path = apkPath.c_str();
2257475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey    const char* instruction_set = instructionSet.c_str();
2258c523409f0fd03aa498cedc486f85e9a4b7257f3aAndreas Gampe    const char* oat_dir = outputPath ? outputPath->c_str() : nullptr;
2259475c6f9743e5f6696c38fb22b8b8e9d49a82ab56Jeff Sharkey
226090aff26f0135379db19432ae90c40c0831ba5954Jeff Sharkey    bool res = delete_odex(apk_path, instruction_set, oat_dir);
226190aff26f0135379db19432ae90c40c0831ba5954Jeff Sharkey    return res ? ok() : error();
22623964da0636624ff9af42d1f316bed0752e37c490Andreas Gampe}
22633964da0636624ff9af42d1f316bed0752e37c490Andreas Gampe
2264bd9683607d391a29b1422a50f8972267e9bddc47Calin Juravlebinder::Status InstalldNativeService::reconcileSecondaryDexFile(
2265bd9683607d391a29b1422a50f8972267e9bddc47Calin Juravle        const std::string& dexPath, const std::string& packageName, int32_t uid,
2266bd9683607d391a29b1422a50f8972267e9bddc47Calin Juravle        const std::vector<std::string>& isas, const std::unique_ptr<std::string>& volumeUuid,
2267bd9683607d391a29b1422a50f8972267e9bddc47Calin Juravle        int32_t storage_flag, bool* _aidl_return) {
2268bd9683607d391a29b1422a50f8972267e9bddc47Calin Juravle    ENFORCE_UID(AID_SYSTEM);
2269bd9683607d391a29b1422a50f8972267e9bddc47Calin Juravle    CHECK_ARGUMENT_UUID(volumeUuid);
2270bd9683607d391a29b1422a50f8972267e9bddc47Calin Juravle    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
2271bd9683607d391a29b1422a50f8972267e9bddc47Calin Juravle
2272bd9683607d391a29b1422a50f8972267e9bddc47Calin Juravle    std::lock_guard<std::recursive_mutex> lock(mLock);
2273bd9683607d391a29b1422a50f8972267e9bddc47Calin Juravle    bool result = android::installd::reconcile_secondary_dex_file(
2274bd9683607d391a29b1422a50f8972267e9bddc47Calin Juravle            dexPath, packageName, uid, isas, volumeUuid, storage_flag, _aidl_return);
2275bd9683607d391a29b1422a50f8972267e9bddc47Calin Juravle    return result ? ok() : error();
2276bd9683607d391a29b1422a50f8972267e9bddc47Calin Juravle}
2277bd9683607d391a29b1422a50f8972267e9bddc47Calin Juravle
227866b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkeybinder::Status InstalldNativeService::invalidateMounts() {
227966b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey    ENFORCE_UID(AID_SYSTEM);
2280d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
228166b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey
2282d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey    mStorageMounts.clear();
2283d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey    mQuotaReverseMounts.clear();
228466b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey
228566b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey    std::ifstream in("/proc/mounts");
228666b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey    if (!in.is_open()) {
228766b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey        return error("Failed to read mounts");
228866b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey    }
228966b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey
229066b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey    std::string source;
229166b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey    std::string target;
229266b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey    std::string ignored;
229366b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey    while (!in.eof()) {
229466b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey        std::getline(in, source, ' ');
229566b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey        std::getline(in, target, ' ');
229666b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey        std::getline(in, ignored);
229766b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey
2298d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey#if !BYPASS_SDCARDFS
2299d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey        if (target.compare(0, 21, "/mnt/runtime/default/") == 0) {
2300d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey            LOG(DEBUG) << "Found storage mount " << source << " at " << target;
2301d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey            mStorageMounts[source] = target;
2302d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey        }
2303d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey#endif
2304d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey
2305d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey#if !BYPASS_QUOTA
230666b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey        if (source.compare(0, 11, "/dev/block/") == 0) {
2307d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey            struct dqblk dq;
230866b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey            if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0,
230966b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey                    reinterpret_cast<char*>(&dq)) == 0) {
2310d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey                LOG(DEBUG) << "Found quota mount " << source << " at " << target;
2311d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey                mQuotaReverseMounts[target] = source;
2312e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey
2313e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey                // ext4 only enables DQUOT_USAGE_ENABLED by default, so we
2314e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey                // need to kick it again to enable DQUOT_LIMITS_ENABLED.
2315e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey                if (quotactl(QCMD(Q_QUOTAON, USRQUOTA), source.c_str(), QFMT_VFS_V1, nullptr) != 0
2316e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey                        && errno != EBUSY) {
2317e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey                    PLOG(ERROR) << "Failed to enable USRQUOTA on " << source;
2318e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey                }
2319e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey                if (quotactl(QCMD(Q_QUOTAON, GRPQUOTA), source.c_str(), QFMT_VFS_V1, nullptr) != 0
2320e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey                        && errno != EBUSY) {
2321e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey                    PLOG(ERROR) << "Failed to enable GRPQUOTA on " << source;
2322e59c85cc0e78bfcc8fec6acc8e37e6a472ffc07fJeff Sharkey                }
232366b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey            }
232466b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey        }
2325d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey#endif
232666b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey    }
232766b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey    return ok();
232866b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey}
232966b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey
2330d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkeystd::string InstalldNativeService::findDataMediaPath(
2331d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey        const std::unique_ptr<std::string>& uuid, userid_t userid) {
2332d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
2333d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
2334d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey    auto path = StringPrintf("%s/media", create_data_path(uuid_).c_str());
2335d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey    auto resolved = mStorageMounts[path];
2336d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey    if (resolved.empty()) {
2337d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey        LOG(WARNING) << "Failed to find storage mount for " << path;
2338d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey        resolved = path;
2339d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey    }
2340d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey    return StringPrintf("%s/%u", resolved.c_str(), userid);
2341d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey}
2342d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey
234366b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkeystd::string InstalldNativeService::findQuotaDeviceForUuid(
234466b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey        const std::unique_ptr<std::string>& uuid) {
2345d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
234666b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey    auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
2347d712f0ccc120357e1267a04ac6de9dd732b27e76Jeff Sharkey    return mQuotaReverseMounts[path];
234866b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey}
234966b1a12e7a120f85042669bb58f1db864616b506Jeff Sharkey
2350325b8c94a5ae47b7903ea5fe386a78466d6cb3b7Jeff Sharkeybinder::Status InstalldNativeService::isQuotaSupported(
2351325b8c94a5ae47b7903ea5fe386a78466d6cb3b7Jeff Sharkey        const std::unique_ptr<std::string>& volumeUuid, bool* _aidl_return) {
2352325b8c94a5ae47b7903ea5fe386a78466d6cb3b7Jeff Sharkey    *_aidl_return = !findQuotaDeviceForUuid(volumeUuid).empty();
2353325b8c94a5ae47b7903ea5fe386a78466d6cb3b7Jeff Sharkey    return ok();
2354325b8c94a5ae47b7903ea5fe386a78466d6cb3b7Jeff Sharkey}
2355325b8c94a5ae47b7903ea5fe386a78466d6cb3b7Jeff Sharkey
235602d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe}  // namespace installd
235702d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe}  // namespace android
2358