Merge "Add feature flag for TelephonyManager#get/setAllowedCarriers"
diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk
index e478651..daeebc4 100644
--- a/cmds/dumpstate/Android.mk
+++ b/cmds/dumpstate/Android.mk
@@ -10,7 +10,7 @@
 
 LOCAL_MODULE := dumpstate
 
-LOCAL_SHARED_LIBRARIES := libcutils liblog libselinux libbase libhardware_legacy
+LOCAL_SHARED_LIBRARIES := libcutils libdebuggerd_client liblog libselinux libbase libhardware_legacy
 # ZipArchive support, the order matters here to get all symbols.
 LOCAL_STATIC_LIBRARIES := libziparchive libz libcrypto_static
 LOCAL_HAL_STATIC_LIBRARIES := libdumpstate
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index afb52e7..4ac5b67 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -40,9 +40,9 @@
 #include <vector>
 
 #include <android-base/file.h>
-#include <cutils/debugger.h>
 #include <cutils/properties.h>
 #include <cutils/sockets.h>
+#include <debuggerd/client.h>
 #include <log/log.h>
 #include <private/android_filesystem_config.h>
 
@@ -1021,8 +1021,10 @@
     }
 
     /* create a new, empty traces.txt file to receive stack dumps */
-    int fd = TEMP_FAILURE_RETRY(open(traces_path, O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW | O_CLOEXEC,
-                                     0666));  /* -rw-rw-rw- */
+    int fd = TEMP_FAILURE_RETRY(
+        open(traces_path,
+             O_CREAT | O_WRONLY | O_APPEND | O_TRUNC | O_NOFOLLOW | O_CLOEXEC,
+             0666)); /* -rw-rw-rw- */
     if (fd < 0) {
         MYLOGE("%s: %s\n", traces_path, strerror(errno));
         return NULL;
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 93174bf..33db6db 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -6,6 +6,8 @@
         "-Werror",
     ],
     srcs: [
+        "CacheItem.cpp",
+        "CacheTracker.cpp",
         "InstalldNativeService.cpp",
         "dexopt.cpp",
         "globals.cpp",
diff --git a/cmds/installd/CacheItem.cpp b/cmds/installd/CacheItem.cpp
new file mode 100644
index 0000000..d1bdded
--- /dev/null
+++ b/cmds/installd/CacheItem.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CacheItem.h"
+
+#include <stdint.h>
+#include <inttypes.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+#include "utils.h"
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace installd {
+
+CacheItem::CacheItem(const std::shared_ptr<CacheItem>& parent, FTSENT* p) : mParent(parent) {
+    level = p->fts_level;
+    directory = S_ISDIR(p->fts_statp->st_mode);
+    size = p->fts_statp->st_blocks * 512;
+    modified = p->fts_statp->st_mtime;
+    mName = p->fts_path;
+}
+
+CacheItem::~CacheItem() {
+}
+
+std::string CacheItem::toString() {
+    return StringPrintf("%s size=%" PRId64 " mod=%ld", buildPath().c_str(), size, modified);
+}
+
+std::string CacheItem::buildPath() {
+    std::string res = mName;
+    std::shared_ptr<CacheItem> parent = mParent;
+    while (parent) {
+        res.insert(0, parent->mName);
+        parent = parent->mParent;
+    }
+    return res;
+}
+
+int CacheItem::purge() {
+    auto path = buildPath();
+    if (directory) {
+        return delete_dir_contents_and_dir(path, true);
+    } else {
+        int res = unlink(path.c_str());
+        if (res != 0) {
+            PLOG(WARNING) << "Failed to unlink " << path;
+        }
+        return res;
+    }
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/CacheItem.h b/cmds/installd/CacheItem.h
new file mode 100644
index 0000000..bec8bc8
--- /dev/null
+++ b/cmds/installd/CacheItem.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_INSTALLD_CACHE_ITEM_H
+#define ANDROID_INSTALLD_CACHE_ITEM_H
+
+#include <memory>
+#include <string>
+
+#include <fts.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <android-base/macros.h>
+
+namespace android {
+namespace installd {
+
+/**
+ * Single cache item that can be purged to free up space. This may be an
+ * isolated file, or an entire directory tree that should be atomically
+ * deleted.
+ */
+class CacheItem {
+public:
+    CacheItem(const std::shared_ptr<CacheItem>& parent, FTSENT* p);
+    ~CacheItem();
+
+    std::string toString();
+    std::string buildPath();
+
+    int purge();
+
+    short level;
+    bool directory;
+    int64_t size;
+    time_t modified;
+
+private:
+    std::shared_ptr<CacheItem> mParent;
+    std::string mName;
+
+    DISALLOW_COPY_AND_ASSIGN(CacheItem);
+};
+
+}  // namespace installd
+}  // namespace android
+
+#endif  // ANDROID_INSTALLD_CACHE_ITEM_H
diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp
new file mode 100644
index 0000000..23c4330
--- /dev/null
+++ b/cmds/installd/CacheTracker.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
+
+#include "CacheTracker.h"
+
+#include <fts.h>
+#include <sys/quota.h>
+#include <utils/Trace.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+#include "utils.h"
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace installd {
+
+CacheTracker::CacheTracker(userid_t userId, appid_t appId, const std::string& quotaDevice) :
+        cacheUsed(0), cacheQuota(0), mUserId(userId), mAppId(appId), mQuotaDevice(quotaDevice),
+        mItemsLoaded(false) {
+}
+
+CacheTracker::~CacheTracker() {
+}
+
+std::string CacheTracker::toString() {
+    return StringPrintf("UID=%d used=%" PRId64 " quota=%" PRId64 " ratio=%d",
+            multiuser_get_uid(mUserId, mAppId), cacheUsed, cacheQuota, getCacheRatio());
+}
+
+void CacheTracker::addDataPath(const std::string& dataPath) {
+    mDataPaths.push_back(dataPath);
+}
+
+void CacheTracker::loadStats() {
+    int cacheGid = multiuser_get_cache_gid(mUserId, mAppId);
+    if (cacheGid != -1 && !mQuotaDevice.empty()) {
+        ATRACE_BEGIN("loadStats quota");
+        struct dqblk dq;
+        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), mQuotaDevice.c_str(), cacheGid,
+                reinterpret_cast<char*>(&dq)) != 0) {
+            ATRACE_END();
+            if (errno != ESRCH) {
+                PLOG(ERROR) << "Failed to quotactl " << mQuotaDevice << " for GID " << cacheGid;
+            }
+        } else {
+            cacheUsed = dq.dqb_curspace;
+            ATRACE_END();
+            return;
+        }
+    }
+
+    ATRACE_BEGIN("loadStats tree");
+    cacheUsed = 0;
+    for (auto path : mDataPaths) {
+        auto cachePath = read_path_inode(path, "cache", kXattrInodeCache);
+        auto codeCachePath = read_path_inode(path, "code_cache", kXattrInodeCodeCache);
+        calculate_tree_size(cachePath, &cacheUsed);
+        calculate_tree_size(codeCachePath, &cacheUsed);
+    }
+    ATRACE_END();
+}
+
+void CacheTracker::loadItemsFrom(const std::string& path) {
+    FTS *fts;
+    FTSENT *p;
+    char *argv[] = { (char*) path.c_str(), nullptr };
+    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_XDEV, NULL))) {
+        PLOG(WARNING) << "Failed to fts_open " << path;
+        return;
+    }
+    // TODO: add support for "user.atomic" and "user.tombstone" xattrs
+    while ((p = fts_read(fts)) != NULL) {
+        switch (p->fts_info) {
+        case FTS_D:
+            // Track the newest mtime of anything inside so we consider
+            // deleting the directory last
+            p->fts_number = p->fts_statp->st_mtime;
+            break;
+        case FTS_DP:
+            p->fts_statp->st_mtime = p->fts_number;
+
+            // Ignore the actual top-level cache directories
+            if (p->fts_level == 0) break;
+        case FTS_DEFAULT:
+        case FTS_F:
+        case FTS_SL:
+        case FTS_SLNONE:
+            // TODO: optimize path memory footprint
+            items.push_back(std::shared_ptr<CacheItem>(new CacheItem(nullptr, p)));
+
+            // Track the newest modified item under this tree
+            p->fts_parent->fts_number =
+                    std::max(p->fts_parent->fts_number, p->fts_statp->st_mtime);
+            break;
+        }
+    }
+    fts_close(fts);
+}
+
+void CacheTracker::loadItems() {
+    items.clear();
+
+    ATRACE_BEGIN("loadItems");
+    for (auto path : mDataPaths) {
+        loadItemsFrom(read_path_inode(path, "cache", kXattrInodeCache));
+        loadItemsFrom(read_path_inode(path, "code_cache", kXattrInodeCodeCache));
+    }
+    ATRACE_END();
+
+    ATRACE_BEGIN("sortItems");
+    auto cmp = [](std::shared_ptr<CacheItem> left, std::shared_ptr<CacheItem> right) {
+        // TODO: sort dotfiles last
+        // TODO: sort code_cache last
+        if (left->modified != right->modified) {
+            return (left->modified > right->modified);
+        }
+        if (left->level != right->level) {
+            return (left->level < right->level);
+        }
+        return left->directory;
+    };
+    std::sort(items.begin(), items.end(), cmp);
+    ATRACE_END();
+}
+
+void CacheTracker::ensureItems() {
+    if (mItemsLoaded) {
+        return;
+    } else {
+        loadItems();
+        mItemsLoaded = true;
+    }
+}
+
+int CacheTracker::getCacheRatio() {
+    if (cacheQuota == 0) {
+        return 0;
+    } else {
+        return (cacheUsed * 10000) / cacheQuota;
+    }
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/CacheTracker.h b/cmds/installd/CacheTracker.h
new file mode 100644
index 0000000..91692d7
--- /dev/null
+++ b/cmds/installd/CacheTracker.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_INSTALLD_CACHE_TRACKER_H
+#define ANDROID_INSTALLD_CACHE_TRACKER_H
+
+#include <memory>
+#include <string>
+#include <queue>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <android-base/macros.h>
+#include <cutils/multiuser.h>
+
+#include "CacheItem.h"
+
+namespace android {
+namespace installd {
+
+/**
+ * Cache tracker for a single UID. Each tracker is used in two modes: first
+ * for loading lightweight "stats", and then by loading detailed "items"
+ * which can then be purged to free up space.
+ */
+class CacheTracker {
+public:
+    CacheTracker(userid_t userId, appid_t appId, const std::string& quotaDevice);
+    ~CacheTracker();
+
+    std::string toString();
+
+    void addDataPath(const std::string& dataPath);
+
+    void loadStats();
+    void loadItems();
+
+    void ensureItems();
+
+    int getCacheRatio();
+
+    int64_t cacheUsed;
+    int64_t cacheQuota;
+
+    std::vector<std::shared_ptr<CacheItem>> items;
+
+private:
+    userid_t mUserId;
+    appid_t mAppId;
+    std::string mQuotaDevice;
+    bool mItemsLoaded;
+
+    std::vector<std::string> mDataPaths;
+
+    void loadItemsFrom(const std::string& path);
+
+    DISALLOW_COPY_AND_ASSIGN(CacheTracker);
+};
+
+}  // namespace installd
+}  // namespace android
+
+#endif  // ANDROID_INSTALLD_CACHE_TRACKER_H
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 7fe2e19..914eaae 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -16,6 +16,8 @@
 
 #include "InstalldNativeService.h"
 
+#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
+
 #include <errno.h>
 #include <inttypes.h>
 #include <fstream>
@@ -46,6 +48,7 @@
 #include <private/android_filesystem_config.h>
 #include <selinux/android.h>
 #include <system/thread_defs.h>
+#include <utils/Trace.h>
 
 #include "dexopt.h"
 #include "globals.h"
@@ -53,6 +56,7 @@
 #include "otapreopt_utils.h"
 #include "utils.h"
 
+#include "CacheTracker.h"
 #include "MatchExtensionGen.h"
 
 #ifndef LOG_TAG
@@ -60,6 +64,7 @@
 #endif
 
 using android::base::StringPrintf;
+using std::endl;
 
 namespace android {
 namespace installd {
@@ -82,6 +87,8 @@
 static constexpr int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
 static constexpr int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9;
 static constexpr int FLAG_USE_QUOTA = 1 << 12;
+static constexpr int FLAG_FREE_CACHE_V2 = 1 << 13;
+static constexpr int FLAG_FREE_CACHE_NOOP = 1 << 14;
 
 #define MIN_RESTRICTED_HOME_SDK_VERSION 24 // > M
 namespace {
@@ -188,15 +195,29 @@
 }
 
 status_t InstalldNativeService::dump(int fd, const Vector<String16> & /* args */) {
+    auto out = std::fstream(StringPrintf("/proc/self/fd/%d", fd));
     const binder::Status dump_permission = checkPermission(kDump);
     if (!dump_permission.isOk()) {
-        const String8 msg(dump_permission.toString8());
-        write(fd, msg.string(), msg.size());
+        out << dump_permission.toString8() << endl;
         return PERMISSION_DENIED;
     }
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
-    std::string msg = "installd is happy\n";
-    write(fd, msg.c_str(), strlen(msg.c_str()));
+    out << "installd is happy!" << endl;
+
+    out << endl << "Devices with quota support:" << endl;
+    for (const auto& n : mQuotaDevices) {
+        out << "    " << n.first << " = " << n.second << endl;
+    }
+
+    out << endl << "Per-UID cache quotas:" << endl;
+    for (const auto& n : mCacheQuotas) {
+        out << "    " << n.first << " = " << n.second << endl;
+    }
+
+    out << endl;
+    out.flush();
+
     return NO_ERROR;
 }
 
@@ -287,12 +308,13 @@
         }
     }
 
+    mode_t actual_mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID);
     if (st.st_uid != uid) {
         // Mismatched UID is real trouble; we can't recover
         LOG(ERROR) << "Mismatched UID at " << path << ": found " << st.st_uid
                 << " but expected " << uid;
         return -1;
-    } else if (st.st_gid == gid && st.st_mode == target_mode) {
+    } else if (st.st_gid == gid && actual_mode == target_mode) {
         // Everything looks good!
         return 0;
     }
@@ -336,6 +358,7 @@
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     const char* pkgname = packageName.c_str();
@@ -343,10 +366,15 @@
     // Assume invalid inode unless filled in below
     if (_aidl_return != nullptr) *_aidl_return = -1;
 
-    uid_t uid = multiuser_get_uid(userId, appId);
-    gid_t cacheGid = multiuser_get_cache_gid(userId, appId);
+    int32_t uid = multiuser_get_uid(userId, appId);
+    int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
     mode_t targetMode = targetSdkVersion >= MIN_RESTRICTED_HOME_SDK_VERSION ? 0700 : 0751;
 
+    // If UID doesn't have a specific cache GID, use UID value
+    if (cacheGid == -1) {
+        cacheGid = uid;
+    }
+
     if (flags & FLAG_STORAGE_CE) {
         auto path = create_data_user_ce_package_path(uuid_, userId, pkgname);
         bool existing = (access(path.c_str(), F_OK) == 0);
@@ -422,6 +450,7 @@
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     const char* pkgname = packageName.c_str();
@@ -464,6 +493,7 @@
 binder::Status InstalldNativeService::clearAppProfiles(const std::string& packageName) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* pkgname = packageName.c_str();
     binder::Status res = ok();
@@ -481,6 +511,7 @@
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     const char* pkgname = packageName.c_str();
@@ -540,6 +571,7 @@
 binder::Status InstalldNativeService::destroyAppProfiles(const std::string& packageName) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* pkgname = packageName.c_str();
     binder::Status res = ok();
@@ -560,6 +592,7 @@
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     const char* pkgname = packageName.c_str();
@@ -593,6 +626,7 @@
     CHECK_ARGUMENT_UUID(fromUuid);
     CHECK_ARGUMENT_UUID(toUuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* from_uuid = fromUuid ? fromUuid->c_str() : nullptr;
     const char* to_uuid = toUuid ? toUuid->c_str() : nullptr;
@@ -727,6 +761,7 @@
         int32_t userId, int32_t userSerial ATTRIBUTE_UNUSED, int32_t flags) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     if (flags & FLAG_STORAGE_DE) {
@@ -743,6 +778,7 @@
         int32_t userId, int32_t flags) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     binder::Status res = ok();
@@ -783,51 +819,172 @@
  * when just reading from the cache, which is pretty awful.
  */
 binder::Status InstalldNativeService::freeCache(const std::unique_ptr<std::string>& uuid,
-        int64_t freeStorageSize) {
+        int64_t freeStorageSize, int32_t flags) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    // TODO: remove this once framework is more robust
+    invalidateMounts();
 
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
-    cache_t* cache;
-    int64_t avail;
-
     auto data_path = create_data_path(uuid_);
+    auto device = findQuotaDeviceForUuid(uuid);
+    auto noop = (flags & FLAG_FREE_CACHE_NOOP);
 
-    avail = data_disk_free(data_path);
-    if (avail < 0) {
+    int64_t free = data_disk_free(data_path);
+    int64_t needed = freeStorageSize - free;
+    if (free < 0) {
         return error("Failed to determine free space for " + data_path);
-    }
-
-    ALOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", freeStorageSize, avail);
-    if (avail >= freeStorageSize) {
+    } else if (free >= freeStorageSize) {
         return ok();
     }
 
-    cache = start_cache_collection();
+    LOG(DEBUG) << "Found " << data_path << " with " << free << " free; caller requested "
+            << freeStorageSize;
 
-    auto users = get_known_users(uuid_);
-    for (auto user : users) {
-        add_cache_files(cache, create_data_user_ce_path(uuid_, user));
-        add_cache_files(cache, create_data_user_de_path(uuid_, user));
-        add_cache_files(cache,
-                StringPrintf("%s/Android/data", create_data_media_path(uuid_, user).c_str()));
+    if (flags & FLAG_FREE_CACHE_V2) {
+        // This new cache strategy fairly removes files from UIDs by deleting
+        // files from the UIDs which are most over their allocated quota
+
+        // 1. Create trackers for every known UID
+        ATRACE_BEGIN("create");
+        std::unordered_map<uid_t, std::shared_ptr<CacheTracker>> trackers;
+        for (auto user : get_known_users(uuid_)) {
+            FTS *fts;
+            FTSENT *p;
+            char *argv[] = {
+                    (char*) create_data_user_ce_path(uuid_, user).c_str(),
+                    (char*) create_data_user_de_path(uuid_, user).c_str(),
+                    nullptr
+            };
+            if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_XDEV, NULL))) {
+                return error("Failed to fts_open");
+            }
+            while ((p = fts_read(fts)) != NULL) {
+                if (p->fts_info == FTS_D && p->fts_level == 1) {
+                    uid_t uid = p->fts_statp->st_uid;
+                    auto search = trackers.find(uid);
+                    if (search != trackers.end()) {
+                        search->second->addDataPath(p->fts_path);
+                    } else {
+                        auto tracker = std::shared_ptr<CacheTracker>(new CacheTracker(
+                                multiuser_get_user_id(uid), multiuser_get_app_id(uid), device));
+                        tracker->addDataPath(p->fts_path);
+                        tracker->cacheQuota = mCacheQuotas[uid];
+                        if (tracker->cacheQuota == 0) {
+                            LOG(WARNING) << "UID " << uid << " has no cache quota; assuming 64MB";
+                            tracker->cacheQuota = 67108864;
+                        }
+                        trackers[uid] = tracker;
+                    }
+                    fts_set(fts, p, FTS_SKIP);
+                }
+            }
+            fts_close(fts);
+        }
+        ATRACE_END();
+
+        // 2. Populate tracker stats and insert into priority queue
+        ATRACE_BEGIN("populate");
+        auto cmp = [](std::shared_ptr<CacheTracker> left, std::shared_ptr<CacheTracker> right) {
+            return (left->getCacheRatio() < right->getCacheRatio());
+        };
+        std::priority_queue<std::shared_ptr<CacheTracker>,
+                std::vector<std::shared_ptr<CacheTracker>>, decltype(cmp)> queue(cmp);
+        for (const auto& it : trackers) {
+            it.second->loadStats();
+            queue.push(it.second);
+        }
+        ATRACE_END();
+
+        // 3. Bounce across the queue, freeing items from whichever tracker is
+        // the most over their assigned quota
+        ATRACE_BEGIN("bounce");
+        std::shared_ptr<CacheTracker> active;
+        while (active || !queue.empty()) {
+            // Find the best tracker to work with; this might involve swapping
+            // if the active tracker is no longer the most over quota
+            bool nextBetter = active && !queue.empty()
+                    && active->getCacheRatio() < queue.top()->getCacheRatio();
+            if (!active || nextBetter) {
+                if (active) {
+                    // Current tracker still has items, so we'll consider it
+                    // again later once it bubbles up to surface
+                    queue.push(active);
+                }
+                active = queue.top(); queue.pop();
+                active->ensureItems();
+                continue;
+            }
+
+            // If no items remain, go find another tracker
+            if (active->items.empty()) {
+                active = nullptr;
+                continue;
+            } else {
+                auto item = active->items.back();
+                active->items.pop_back();
+
+                LOG(DEBUG) << "Purging " << item->toString() << " from " << active->toString();
+                if (!noop) {
+                    item->purge();
+                }
+                active->cacheUsed -= item->size;
+                needed -= item->size;
+            }
+
+            // Verify that we're actually done before bailing, since sneaky
+            // apps might be using hardlinks
+            if (needed <= 0) {
+                free = data_disk_free(data_path);
+                needed = freeStorageSize - free;
+                if (needed <= 0) {
+                    break;
+                } else {
+                    LOG(WARNING) << "Expected to be done but still need " << needed;
+                }
+            }
+        }
+        ATRACE_END();
+
+    } else {
+        ATRACE_BEGIN("start");
+        cache_t* cache = start_cache_collection();
+        ATRACE_END();
+
+        ATRACE_BEGIN("add");
+        for (auto user : get_known_users(uuid_)) {
+            add_cache_files(cache, create_data_user_ce_path(uuid_, user));
+            add_cache_files(cache, create_data_user_de_path(uuid_, user));
+            add_cache_files(cache,
+                    StringPrintf("%s/Android/data", create_data_media_path(uuid_, user).c_str()));
+        }
+        ATRACE_END();
+
+        ATRACE_BEGIN("clear");
+        clear_cache_files(data_path, cache, freeStorageSize);
+        ATRACE_END();
+
+        ATRACE_BEGIN("finish");
+        finish_cache_collection(cache);
+        ATRACE_END();
     }
 
-    clear_cache_files(data_path, cache, freeStorageSize);
-    finish_cache_collection(cache);
-
-    avail = data_disk_free(data_path);
-    if (avail >= freeStorageSize) {
+    free = data_disk_free(data_path);
+    if (free >= freeStorageSize) {
         return ok();
     } else {
         return error(StringPrintf("Failed to free up %" PRId64 " on %s; final free space %" PRId64,
-                freeStorageSize, data_path.c_str(), avail));
+                freeStorageSize, data_path.c_str(), free));
     }
 }
 
 binder::Status InstalldNativeService::rmdex(const std::string& codePath,
         const std::string& instructionSet) {
     ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
     char dex_path[PKG_PATH_MAX];
 
     const char* path = codePath.c_str();
@@ -870,30 +1027,8 @@
 }
 #endif
 
-static std::string findDeviceForUuid(const std::unique_ptr<std::string>& uuid) {
-    auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
-    std::ifstream in("/proc/mounts");
-    if (!in.is_open()) {
-        PLOG(ERROR) << "Failed to read mounts";
-        return "";
-    }
-    std::string source;
-    std::string target;
-    while (!in.eof()) {
-        std::getline(in, source, ' ');
-        std::getline(in, target, ' ');
-        if (target == path) {
-            return source;
-        }
-        // Skip to next line
-        std::getline(in, source);
-    }
-    PLOG(ERROR) << "Failed to resolve block device for " << path;
-    return "";
-}
-
 static void collectQuotaStats(const std::string& device, int32_t userId,
-        int32_t appId, struct stats* stats, struct stats* extStats ATTRIBUTE_UNUSED) {
+        int32_t appId, struct stats* stats, struct stats* extStats) {
     if (device.empty()) return;
 
     struct dqblk dq;
@@ -920,13 +1055,28 @@
             }
         } else {
 #if MEASURE_DEBUG
-        LOG(DEBUG) << "quotactl() for GID " << cacheGid << " " << dq.dqb_curspace;
+            LOG(DEBUG) << "quotactl() for GID " << cacheGid << " " << dq.dqb_curspace;
 #endif
             stats->cacheSize += dq.dqb_curspace;
         }
     }
 
-    int sharedGid = multiuser_get_shared_app_gid(uid);
+    int extGid = multiuser_get_ext_gid(userId, appId);
+    if (extGid != -1) {
+        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), extGid,
+                reinterpret_cast<char*>(&dq)) != 0) {
+            if (errno != ESRCH) {
+                PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << extGid;
+            }
+        } else {
+#if MEASURE_DEBUG
+            LOG(DEBUG) << "quotactl() for GID " << extGid << " " << dq.dqb_curspace;
+#endif
+            extStats->dataSize += dq.dqb_curspace;
+        }
+    }
+
+    int sharedGid = multiuser_get_shared_gid(userId, appId);
     if (sharedGid != -1) {
         if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), sharedGid,
                 reinterpret_cast<char*>(&dq)) != 0) {
@@ -935,20 +1085,11 @@
             }
         } else {
 #if MEASURE_DEBUG
-        LOG(DEBUG) << "quotactl() for GID " << sharedGid << " " << dq.dqb_curspace;
+            LOG(DEBUG) << "quotactl() for GID " << sharedGid << " " << dq.dqb_curspace;
 #endif
             stats->codeSize += dq.dqb_curspace;
         }
     }
-
-#if MEASURE_EXTERNAL
-    // TODO: measure using external GIDs
-#endif
-}
-
-static void collectQuotaStats(const std::unique_ptr<std::string>& uuid, int32_t userId,
-        int32_t appId, struct stats* stats, struct stats* extStats) {
-    collectQuotaStats(findDeviceForUuid(uuid), userId, appId, stats, extStats);
 }
 
 static void collectManualStats(const std::string& path, struct stats* stats) {
@@ -1034,6 +1175,40 @@
     closedir(d);
 }
 
+static void collectManualExternalStatsForUser(const std::string& path, struct stats* stats) {
+    FTS *fts;
+    FTSENT *p;
+    char *argv[] = { (char*) path.c_str(), nullptr };
+    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_XDEV, NULL))) {
+        PLOG(ERROR) << "Failed to fts_open " << path;
+        return;
+    }
+    while ((p = fts_read(fts)) != NULL) {
+        switch (p->fts_info) {
+        case FTS_D:
+            if (p->fts_level == 4
+                    && !strcmp(p->fts_name, "cache")
+                    && !strcmp(p->fts_parent->fts_parent->fts_name, "data")
+                    && !strcmp(p->fts_parent->fts_parent->fts_parent->fts_name, "Android")) {
+                p->fts_number = 1;
+            }
+            p->fts_number = p->fts_parent->fts_number;
+            // Fall through to count the directory
+        case FTS_DEFAULT:
+        case FTS_F:
+        case FTS_SL:
+        case FTS_SLNONE:
+            int64_t size = (p->fts_statp->st_blocks * 512);
+            if (p->fts_number == 1) {
+                stats->cacheSize += size;
+            }
+            stats->dataSize += size;
+            break;
+        }
+    }
+    fts_close(fts);
+}
+
 binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::string>& uuid,
         const std::vector<std::string>& packageNames, int32_t userId, int32_t flags,
         int32_t appId, const std::vector<int64_t>& ceDataInodes,
@@ -1043,6 +1218,7 @@
     for (auto packageName : packageNames) {
         CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     }
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     // When modifying this logic, always verify using tests:
     // runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetAppSize
@@ -1071,56 +1247,71 @@
 
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
 
+    auto device = findQuotaDeviceForUuid(uuid);
+    if (device.empty()) {
+        flags &= ~FLAG_USE_QUOTA;
+    }
+
+    ATRACE_BEGIN("obb");
     for (auto packageName : packageNames) {
         auto obbCodePath = create_data_media_obb_path(uuid_, packageName.c_str());
         calculate_tree_size(obbCodePath, &extStats.codeSize);
     }
+    ATRACE_END();
 
     if (flags & FLAG_USE_QUOTA && appId >= AID_APP_START) {
+        ATRACE_BEGIN("code");
         for (auto codePath : codePaths) {
             calculate_tree_size(codePath, &stats.codeSize, -1,
                     multiuser_get_shared_gid(userId, appId));
         }
+        ATRACE_END();
 
-        collectQuotaStats(uuid, userId, appId, &stats, &extStats);
+        ATRACE_BEGIN("quota");
+        collectQuotaStats(device, userId, appId, &stats, &extStats);
+        ATRACE_END();
 
     } else {
+        ATRACE_BEGIN("code");
         for (auto codePath : codePaths) {
             calculate_tree_size(codePath, &stats.codeSize);
         }
+        ATRACE_END();
 
         for (size_t i = 0; i < packageNames.size(); i++) {
             const char* pkgname = packageNames[i].c_str();
 
+            ATRACE_BEGIN("data");
             auto cePath = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInodes[i]);
             collectManualStats(cePath, &stats);
-
             auto dePath = create_data_user_de_package_path(uuid_, userId, pkgname);
             collectManualStats(dePath, &stats);
+            ATRACE_END();
 
+            ATRACE_BEGIN("profiles");
             auto userProfilePath = create_data_user_profile_package_path(userId, pkgname);
             calculate_tree_size(userProfilePath, &stats.dataSize);
-
             auto refProfilePath = create_data_ref_profile_package_path(pkgname);
             calculate_tree_size(refProfilePath, &stats.codeSize);
+            ATRACE_END();
 
-#if MEASURE_EXTERNAL
+            ATRACE_BEGIN("external");
             auto extPath = create_data_media_package_path(uuid_, userId, pkgname, "data");
             collectManualStats(extPath, &extStats);
-
             auto mediaPath = create_data_media_package_path(uuid_, userId, pkgname, "media");
             calculate_tree_size(mediaPath, &extStats.dataSize);
-#endif
+            ATRACE_END();
         }
 
+        ATRACE_BEGIN("dalvik");
         int32_t sharedGid = multiuser_get_shared_gid(userId, appId);
         if (sharedGid != -1) {
             calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize,
                     sharedGid, -1);
         }
-
         calculate_tree_size(create_data_misc_foreign_dex_path(userId), &stats.dataSize,
                 multiuser_get_uid(userId, appId), -1);
+        ATRACE_END();
     }
 
     std::vector<int64_t> ret;
@@ -1142,6 +1333,7 @@
         std::vector<int64_t>* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     // When modifying this logic, always verify using tests:
     // runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetUserSize
@@ -1157,35 +1349,69 @@
 
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
 
-    auto obbPath = create_data_path(uuid_) + "/media/obb";
-    calculate_tree_size(obbPath, &extStats.codeSize);
+    auto device = findQuotaDeviceForUuid(uuid);
+    if (device.empty()) {
+        flags &= ~FLAG_USE_QUOTA;
+    }
 
     if (flags & FLAG_USE_QUOTA) {
-        calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize, -1, -1, true);
+        struct dqblk dq;
 
+        ATRACE_BEGIN("obb");
+        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), AID_MEDIA_OBB,
+                reinterpret_cast<char*>(&dq)) != 0) {
+            if (errno != ESRCH) {
+                PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << AID_MEDIA_OBB;
+            }
+        } else {
+#if MEASURE_DEBUG
+            LOG(DEBUG) << "quotactl() for GID " << AID_MEDIA_OBB << " " << dq.dqb_curspace;
+#endif
+            extStats.codeSize += dq.dqb_curspace;
+        }
+        ATRACE_END();
+
+        ATRACE_BEGIN("code");
+        calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize, -1, -1, true);
+        ATRACE_END();
+
+        ATRACE_BEGIN("data");
         auto cePath = create_data_user_ce_path(uuid_, userId);
         collectManualStatsForUser(cePath, &stats, true);
-
         auto dePath = create_data_user_de_path(uuid_, userId);
         collectManualStatsForUser(dePath, &stats, true);
+        ATRACE_END();
 
+        ATRACE_BEGIN("profile");
         auto userProfilePath = create_data_user_profile_path(userId);
         calculate_tree_size(userProfilePath, &stats.dataSize, -1, -1, true);
-
         auto refProfilePath = create_data_ref_profile_path();
         calculate_tree_size(refProfilePath, &stats.codeSize, -1, -1, true);
+        ATRACE_END();
 
-#if MEASURE_EXTERNAL
-        // TODO: measure external storage paths
+        ATRACE_BEGIN("external");
+        uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW);
+        if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
+                reinterpret_cast<char*>(&dq)) != 0) {
+            if (errno != ESRCH) {
+                PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
+            }
+        } else {
+#if MEASURE_DEBUG
+            LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
 #endif
+            extStats.dataSize += dq.dqb_curspace;
+        }
+        ATRACE_END();
 
+        ATRACE_BEGIN("dalvik");
         calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize,
                 -1, -1, true);
-
         calculate_tree_size(create_data_misc_foreign_dex_path(userId), &stats.dataSize,
                 -1, -1, true);
+        ATRACE_END();
 
-        auto device = findDeviceForUuid(uuid);
+        ATRACE_BEGIN("quota");
         for (auto appId : appIds) {
             if (appId >= AID_APP_START) {
                 collectQuotaStats(device, userId, appId, &stats, &extStats);
@@ -1195,28 +1421,44 @@
 #endif
             }
         }
+        ATRACE_END();
     } else {
-        calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize);
+        ATRACE_BEGIN("obb");
+        auto obbPath = create_data_path(uuid_) + "/media/obb";
+        calculate_tree_size(obbPath, &extStats.codeSize);
+        ATRACE_END();
 
+        ATRACE_BEGIN("code");
+        calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize);
+        ATRACE_END();
+
+        ATRACE_BEGIN("data");
         auto cePath = create_data_user_ce_path(uuid_, userId);
         collectManualStatsForUser(cePath, &stats);
-
         auto dePath = create_data_user_de_path(uuid_, userId);
         collectManualStatsForUser(dePath, &stats);
+        ATRACE_END();
 
+        ATRACE_BEGIN("profile");
         auto userProfilePath = create_data_user_profile_path(userId);
         calculate_tree_size(userProfilePath, &stats.dataSize);
-
         auto refProfilePath = create_data_ref_profile_path();
         calculate_tree_size(refProfilePath, &stats.codeSize);
+        ATRACE_END();
 
-#if MEASURE_EXTERNAL
-        // TODO: measure external storage paths
+        ATRACE_BEGIN("external");
+        auto dataMediaPath = create_data_media_path(uuid_, userId);
+        collectManualExternalStatsForUser(dataMediaPath, &extStats);
+#if MEASURE_DEBUG
+        LOG(DEBUG) << "Measured external data " << extStats.dataSize << " cache "
+                << extStats.cacheSize;
 #endif
+        ATRACE_END();
 
+        ATRACE_BEGIN("dalvik");
         calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize);
-
         calculate_tree_size(create_data_misc_foreign_dex_path(userId), &stats.dataSize);
+        ATRACE_END();
     }
 
     std::vector<int64_t> ret;
@@ -1237,6 +1479,7 @@
         int32_t userId, int32_t flags, std::vector<int64_t>* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     // When modifying this logic, always verify using tests:
     // runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetExternalSize
@@ -1252,11 +1495,14 @@
     int64_t videoSize = 0;
     int64_t imageSize = 0;
 
+    auto device = findQuotaDeviceForUuid(uuid);
+    if (device.empty()) {
+        flags &= ~FLAG_USE_QUOTA;
+    }
+
     if (flags & FLAG_USE_QUOTA) {
         struct dqblk dq;
 
-        auto device = findDeviceForUuid(uuid);
-
         uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW);
         if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
                 reinterpret_cast<char*>(&dq)) != 0) {
@@ -1342,12 +1588,25 @@
     return ok();
 }
 
+binder::Status InstalldNativeService::setAppQuota(const std::unique_ptr<std::string>& uuid,
+        int32_t userId, int32_t appId, int64_t cacheQuota) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(uuid);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    int32_t uid = multiuser_get_uid(userId, appId);
+    mCacheQuotas[uid] = cacheQuota;
+
+    return ok();
+}
+
 // Dumps the contents of a profile file, using pkgname's dex files for pretty
 // printing the result.
 binder::Status InstalldNativeService::dumpProfiles(int32_t uid, const std::string& packageName,
         const std::string& codePaths, bool* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* pkgname = packageName.c_str();
     const char* code_paths = codePaths.c_str();
@@ -1361,6 +1620,7 @@
         bool* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* pkgname = packageName.c_str();
     *_aidl_return = analyse_profiles(uid, pkgname);
@@ -1377,6 +1637,7 @@
     if (packageName && *packageName != "*") {
         CHECK_ARGUMENT_PACKAGE_NAME(*packageName);
     }
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* apk_path = apkPath.c_str();
     const char* pkgname = packageName ? packageName->c_str() : "*";
@@ -1393,6 +1654,8 @@
 
 binder::Status InstalldNativeService::markBootComplete(const std::string& instructionSet) {
     ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
     const char* instruction_set = instructionSet.c_str();
 
     char boot_marker_path[PKG_PATH_MAX];
@@ -1436,6 +1699,7 @@
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     const char* pkgname = packageName.c_str();
@@ -1558,6 +1822,8 @@
 binder::Status InstalldNativeService::idmap(const std::string& targetApkPath,
         const std::string& overlayApkPath, int32_t uid) {
     ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
     const char* target_apk = targetApkPath.c_str();
     const char* overlay_apk = overlayApkPath.c_str();
     ALOGV("idmap target_apk=%s overlay_apk=%s uid=%d\n", target_apk, overlay_apk, uid);
@@ -1629,6 +1895,7 @@
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     binder::Status res = ok();
 
@@ -1657,6 +1924,8 @@
 binder::Status InstalldNativeService::createOatDir(const std::string& oatDir,
         const std::string& instructionSet) {
     ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
     const char* oat_dir = oatDir.c_str();
     const char* instruction_set = instructionSet.c_str();
     char oat_instr_dir[PKG_PATH_MAX];
@@ -1679,6 +1948,8 @@
 
 binder::Status InstalldNativeService::rmPackageDir(const std::string& packageDir) {
     ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
     if (validate_apk_path(packageDir.c_str())) {
         return error("Invalid path " + packageDir);
     }
@@ -1691,6 +1962,8 @@
 binder::Status InstalldNativeService::linkFile(const std::string& relativePath,
         const std::string& fromBase, const std::string& toBase) {
     ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
     const char* relative_path = relativePath.c_str();
     const char* from_base = fromBase.c_str();
     const char* to_base = toBase.c_str();
@@ -1717,6 +1990,7 @@
 binder::Status InstalldNativeService::moveAb(const std::string& apkPath,
         const std::string& instructionSet, const std::string& outputPath) {
     ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* apk_path = apkPath.c_str();
     const char* instruction_set = instructionSet.c_str();
@@ -1729,6 +2003,7 @@
 binder::Status InstalldNativeService::deleteOdex(const std::string& apkPath,
         const std::string& instructionSet, const std::string& outputPath) {
     ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* apk_path = apkPath.c_str();
     const char* instruction_set = instructionSet.c_str();
@@ -1738,5 +2013,42 @@
     return res ? ok() : error();
 }
 
+binder::Status InstalldNativeService::invalidateMounts() {
+    ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    mQuotaDevices.clear();
+
+    std::ifstream in("/proc/mounts");
+    if (!in.is_open()) {
+        return error("Failed to read mounts");
+    }
+
+    std::string source;
+    std::string target;
+    std::string ignored;
+    struct dqblk dq;
+    while (!in.eof()) {
+        std::getline(in, source, ' ');
+        std::getline(in, target, ' ');
+        std::getline(in, ignored);
+
+        if (source.compare(0, 11, "/dev/block/") == 0) {
+            if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0,
+                    reinterpret_cast<char*>(&dq)) == 0) {
+                LOG(DEBUG) << "Found " << source << " with quota";
+                mQuotaDevices[target] = source;
+            }
+        }
+    }
+    return ok();
+}
+
+std::string InstalldNativeService::findQuotaDeviceForUuid(
+        const std::unique_ptr<std::string>& uuid) {
+    auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
+    return mQuotaDevices[path];
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 5397a74..0a9f12f 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -22,7 +22,9 @@
 #include <unistd.h>
 
 #include <vector>
+#include <unordered_map>
 
+#include <android-base/macros.h>
 #include <binder/BinderService.h>
 #include <cutils/multiuser.h>
 
@@ -66,6 +68,9 @@
     binder::Status getExternalSize(const std::unique_ptr<std::string>& uuid,
             int32_t userId, int32_t flags, std::vector<int64_t>* _aidl_return);
 
+    binder::Status setAppQuota(const std::unique_ptr<std::string>& uuid,
+            int32_t userId, int32_t appId, int64_t cacheQuota);
+
     binder::Status moveCompleteApp(const std::unique_ptr<std::string>& fromUuid,
             const std::unique_ptr<std::string>& toUuid, const std::string& packageName,
             const std::string& dataAppName, int32_t appId, const std::string& seInfo,
@@ -89,7 +94,8 @@
             int32_t uid);
     binder::Status rmPackageDir(const std::string& packageDir);
     binder::Status markBootComplete(const std::string& instructionSet);
-    binder::Status freeCache(const std::unique_ptr<std::string>& uuid, int64_t freeStorageSize);
+    binder::Status freeCache(const std::unique_ptr<std::string>& uuid, int64_t freeStorageSize,
+            int32_t flags);
     binder::Status linkNativeLibraryDirectory(const std::unique_ptr<std::string>& uuid,
             const std::string& packageName, const std::string& nativeLibPath32, int32_t userId);
     binder::Status createOatDir(const std::string& oatDir, const std::string& instructionSet);
@@ -99,6 +105,18 @@
             const std::string& outputPath);
     binder::Status deleteOdex(const std::string& apkPath, const std::string& instructionSet,
             const std::string& outputPath);
+
+    binder::Status invalidateMounts();
+
+private:
+    std::recursive_mutex mLock;
+
+    /* Map from mount point to underlying device node */
+    std::unordered_map<std::string, std::string> mQuotaDevices;
+    /* Map from UID to cache quota size */
+    std::unordered_map<uid_t, int64_t> mCacheQuotas;
+
+    std::string findQuotaDeviceForUuid(const std::unique_ptr<std::string>& uuid);
 };
 
 }  // namespace installd
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 6e4d7fa..aa5e4f2 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -38,6 +38,8 @@
     long[] getUserSize(@nullable @utf8InCpp String uuid, int userId, int flags, in int[] appIds);
     long[] getExternalSize(@nullable @utf8InCpp String uuid, int userId, int flags);
 
+    void setAppQuota(@nullable @utf8InCpp String uuid, int userId, int appId, long cacheQuota);
+
     void moveCompleteApp(@nullable @utf8InCpp String fromUuid, @nullable @utf8InCpp String toUuid,
             @utf8InCpp String packageName, @utf8InCpp String dataAppName, int appId,
             @utf8InCpp String seInfo, int targetSdkVersion);
@@ -58,7 +60,7 @@
     void idmap(@utf8InCpp String targetApkPath, @utf8InCpp String overlayApkPath, int uid);
     void rmPackageDir(@utf8InCpp String packageDir);
     void markBootComplete(@utf8InCpp String instructionSet);
-    void freeCache(@nullable @utf8InCpp String uuid, long freeStorageSize);
+    void freeCache(@nullable @utf8InCpp String uuid, long freeStorageSize, int flags);
     void linkNativeLibraryDirectory(@nullable @utf8InCpp String uuid,
             @utf8InCpp String packageName, @utf8InCpp String nativeLibPath32, int userId);
     void createOatDir(@utf8InCpp String oatDir, @utf8InCpp String instructionSet);
@@ -68,4 +70,6 @@
             @utf8InCpp String outputPath);
     void deleteOdex(@utf8InCpp String apkPath, @utf8InCpp String instructionSet,
             @utf8InCpp String outputPath);
+
+    void invalidateMounts();
 }
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 76d5695..1565d0d 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -904,7 +904,7 @@
 //
 // Usage example:
 //
-//   Dex2oatFileWrapper<std::function<void ()>> file(open(...),
+//   Dex2oatFileWrapper file(open(...),
 //                                                   [name]() {
 //                                                       unlink(name.c_str());
 //                                                   });
@@ -927,14 +927,30 @@
 //   // At this point, when the Dex2oatFileWrapper is destructed, the cleanup function will not run
 //   // (leaving the file around; after the fd is closed).
 //
-template <typename Cleanup>
 class Dex2oatFileWrapper {
  public:
-    Dex2oatFileWrapper() : value_(-1), cleanup_(), do_cleanup_(true) {
+    Dex2oatFileWrapper() : value_(-1), cleanup_(), do_cleanup_(true), auto_close_(true) {
     }
 
-    Dex2oatFileWrapper(int value, Cleanup cleanup)
-            : value_(value), cleanup_(cleanup), do_cleanup_(true) {}
+    Dex2oatFileWrapper(int value, std::function<void ()> cleanup)
+            : value_(value), cleanup_(cleanup), do_cleanup_(true), auto_close_(true) {}
+
+    Dex2oatFileWrapper(Dex2oatFileWrapper&& other) {
+        value_ = other.value_;
+        cleanup_ = other.cleanup_;
+        do_cleanup_ = other.do_cleanup_;
+        auto_close_ = other.auto_close_;
+        other.release();
+    }
+
+    Dex2oatFileWrapper& operator=(Dex2oatFileWrapper&& other) {
+        value_ = other.value_;
+        cleanup_ = other.cleanup_;
+        do_cleanup_ = other.do_cleanup_;
+        auto_close_ = other.auto_close_;
+        other.release();
+        return *this;
+    }
 
     ~Dex2oatFileWrapper() {
         reset(-1);
@@ -949,7 +965,7 @@
     }
 
     void reset(int new_value) {
-        if (value_ >= 0) {
+        if (auto_close_ && value_ >= 0) {
             close(value_);
         }
         if (do_cleanup_ && cleanup_ != nullptr) {
@@ -959,8 +975,8 @@
         value_ = new_value;
     }
 
-    void reset(int new_value, Cleanup new_cleanup) {
-        if (value_ >= 0) {
+    void reset(int new_value, std::function<void ()> new_cleanup) {
+        if (auto_close_ && value_ >= 0) {
             close(value_);
         }
         if (do_cleanup_ && cleanup_ != nullptr) {
@@ -971,77 +987,125 @@
         cleanup_ = new_cleanup;
     }
 
+    void DisableAutoClose() {
+        auto_close_ = false;
+    }
+
  private:
+    void release() {
+        value_ = -1;
+        do_cleanup_ = false;
+        cleanup_ = nullptr;
+    }
     int value_;
-    Cleanup cleanup_;
+    std::function<void ()> cleanup_;
     bool do_cleanup_;
+    bool auto_close_;
 };
 
-int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* instruction_set,
-        int dexopt_needed, const char* oat_dir, int dexopt_flags,const char* compiler_filter,
-        const char* volume_uuid ATTRIBUTE_UNUSED, const char* shared_libraries) {
-    bool is_public = ((dexopt_flags & DEXOPT_PUBLIC) != 0);
-    bool vm_safe_mode = (dexopt_flags & DEXOPT_SAFEMODE) != 0;
-    bool debuggable = (dexopt_flags & DEXOPT_DEBUGGABLE) != 0;
-    bool boot_complete = (dexopt_flags & DEXOPT_BOOTCOMPLETE) != 0;
-    bool profile_guided = (dexopt_flags & DEXOPT_PROFILE_GUIDED) != 0;
+// (re)Creates the app image if needed.
+Dex2oatFileWrapper maybe_open_app_image(const char* out_oat_path, bool profile_guided,
+        bool is_public, int uid) {
+    // Use app images only if it is enabled (by a set image format) and we are compiling
+    // profile-guided (so the app image doesn't conservatively contain all classes).
+    if (!profile_guided) {
+        return Dex2oatFileWrapper();
+    }
 
-    CHECK(pkgname != nullptr);
-    CHECK(pkgname[0] != 0);
+    const std::string image_path = create_image_filename(out_oat_path);
+    if (image_path.empty()) {
+        // Happens when the out_oat_path has an unknown extension.
+        return Dex2oatFileWrapper();
+    }
+    char app_image_format[kPropertyValueMax];
+    bool have_app_image_format =
+            get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
+    if (!have_app_image_format) {
+        return Dex2oatFileWrapper();
+    }
+    // Recreate is true since we do not want to modify a mapped image. If the app is
+    // already running and we modify the image file, it can cause crashes (b/27493510).
+    Dex2oatFileWrapper wrapper_fd(
+            open_output_file(image_path.c_str(), true /*recreate*/, 0600 /*permissions*/),
+            [image_path]() { unlink(image_path.c_str()); });
+    if (wrapper_fd.get() < 0) {
+        // Could not create application image file. Go on since we can compile without it.
+        LOG(ERROR) << "installd could not create '" << image_path
+                << "' for image file during dexopt";
+         // If we have a valid image file path but no image fd, explicitly erase the image file.
+        if (unlink(image_path.c_str()) < 0) {
+            if (errno != ENOENT) {
+                PLOG(ERROR) << "Couldn't unlink image file " << image_path;
+            }
+        }
+    } else if (!set_permissions_and_ownership(
+                wrapper_fd.get(), is_public, uid, image_path.c_str())) {
+        ALOGE("installd cannot set owner '%s' for image during dexopt\n", image_path.c_str());
+        wrapper_fd.reset(-1);
+    }
 
+    return wrapper_fd;
+}
+
+// Creates the dexopt swap file if necessary and return its fd.
+// Returns -1 if there's no need for a swap or in case of errors.
+base::unique_fd maybe_open_dexopt_swap_file(const char* out_oat_path) {
+    if (!ShouldUseSwapFileForDexopt()) {
+        return base::unique_fd();
+    }
+    // Make sure there really is enough space.
+    char swap_file_name[PKG_PATH_MAX];
+    strcpy(swap_file_name, out_oat_path);
+    if (!add_extension_to_file_name(swap_file_name, ".swap")) {
+        return base::unique_fd();
+    }
+    base::unique_fd swap_fd(open_output_file(
+            swap_file_name, /*recreate*/true, /*permissions*/0600));
+    if (swap_fd.get() < 0) {
+        // Could not create swap file. Optimistically go on and hope that we can compile
+        // without it.
+        ALOGE("installd could not create '%s' for swap during dexopt\n", swap_file_name);
+    } else {
+        // Immediately unlink. We don't really want to hit flash.
+        if (unlink(swap_file_name) < 0) {
+            PLOG(ERROR) << "Couldn't unlink swap file " << swap_file_name;
+        }
+    }
+    return swap_fd;
+}
+
+// Opens the reference profiles if needed.
+// Note that the reference profile might not exist so it's OK if the fd will be -1.
+Dex2oatFileWrapper maybe_open_reference_profile(const char* pkgname, bool profile_guided,
+        bool is_public, int uid) {
     // Public apps should not be compiled with profile information ever. Same goes for the special
     // package '*' used for the system server.
-    Dex2oatFileWrapper<std::function<void ()>> reference_profile_fd;
-    if (!is_public && pkgname[0] != '*') {
+    if (profile_guided && !is_public && (pkgname[0] != '*')) {
         // Open reference profile in read only mode as dex2oat does not get write permissions.
         const std::string pkgname_str(pkgname);
-        reference_profile_fd.reset(open_reference_profile(uid, pkgname, /*read_write*/ false),
-                                   [pkgname_str]() {
-                                       clear_reference_profile(pkgname_str.c_str());
-                                   });
-        // Note: it's OK to not find a profile here.
+        return Dex2oatFileWrapper(
+                open_reference_profile(uid, pkgname, /*read_write*/ false),
+                [pkgname_str]() {
+                    clear_reference_profile(pkgname_str.c_str());
+                });
+    } else {
+        return Dex2oatFileWrapper();
     }
+}
 
-    if ((dexopt_flags & ~DEXOPT_MASK) != 0) {
-        LOG_FATAL("dexopt flags contains unknown fields\n");
-    }
-
-    char out_oat_path[PKG_PATH_MAX];
-    if (!create_oat_out_path(apk_path, instruction_set, oat_dir, out_oat_path)) {
-        return false;
-    }
-
-    const char *input_file = apk_path;
-    struct stat input_stat;
-    memset(&input_stat, 0, sizeof(input_stat));
-    stat(input_file, &input_stat);
-
-    // Open the input file.
-    base::unique_fd input_fd(open(input_file, O_RDONLY, 0));
-    if (input_fd.get() < 0) {
-        ALOGE("installd cannot open '%s' for input during dexopt\n", input_file);
-        return -1;
-    }
-
-    // Create the output OAT file.
-    const std::string out_oat_path_str(out_oat_path);
-    Dex2oatFileWrapper<std::function<void ()>> out_oat_fd(
-            open_output_file(out_oat_path, /*recreate*/true, /*permissions*/0644),
-            [out_oat_path_str]() { unlink(out_oat_path_str.c_str()); });
-    if (out_oat_fd.get() < 0) {
-        ALOGE("installd cannot open '%s' for output during dexopt\n", out_oat_path);
-        return -1;
-    }
-    if (!set_permissions_and_ownership(out_oat_fd.get(), is_public, uid, out_oat_path)) {
-        return -1;
-    }
-
+// Opens the vdex files and assigns the input fd to in_vdex_wrapper_fd and the output fd to
+// out_vdex_wrapper_fd. Returns true for success or false in case of errors.
+bool open_vdex_files(const char* apk_path, const char* out_oat_path, int dexopt_needed,
+        const char* instruction_set, bool is_public, int uid,
+        Dex2oatFileWrapper* in_vdex_wrapper_fd,
+        Dex2oatFileWrapper* out_vdex_wrapper_fd) {
+    CHECK(in_vdex_wrapper_fd != nullptr);
+    CHECK(out_vdex_wrapper_fd != nullptr);
     // Open the existing VDEX. We do this before creating the new output VDEX, which will
     // unlink the old one.
     char in_odex_path[PKG_PATH_MAX];
     int dexopt_action = abs(dexopt_needed);
     bool is_odex_location = dexopt_needed < 0;
-    base::unique_fd in_vdex_fd;
     std::string in_vdex_path_str;
     if (dexopt_action != DEX2OAT_FROM_SCRATCH) {
         // Open the possibly existing vdex. If none exist, we pass -1 to dex2oat for input-vdex-fd.
@@ -1051,7 +1115,7 @@
                 path = in_odex_path;
             } else {
                 ALOGE("installd cannot compute input vdex location for '%s'\n", apk_path);
-                return -1;
+                return false;
             }
         } else {
             path = out_oat_path;
@@ -1059,108 +1123,138 @@
         in_vdex_path_str = create_vdex_filename(path);
         if (in_vdex_path_str.empty()) {
             ALOGE("installd cannot compute input vdex location for '%s'\n", path);
-            return -1;
+            return false;
         }
         if (dexopt_action == DEX2OAT_FOR_BOOT_IMAGE) {
             // When we dex2oat because iof boot image change, we are going to update
             // in-place the vdex file.
-            in_vdex_fd.reset(open(in_vdex_path_str.c_str(), O_RDWR, 0));
+            in_vdex_wrapper_fd->reset(open(in_vdex_path_str.c_str(), O_RDWR, 0));
         } else {
-            in_vdex_fd.reset(open(in_vdex_path_str.c_str(), O_RDONLY, 0));
+            in_vdex_wrapper_fd->reset(open(in_vdex_path_str.c_str(), O_RDONLY, 0));
         }
     }
 
     // Infer the name of the output VDEX and create it.
-    const std::string out_vdex_path_str = create_vdex_filename(out_oat_path_str);
+    const std::string out_vdex_path_str = create_vdex_filename(out_oat_path);
     if (out_vdex_path_str.empty()) {
-        return -1;
+        return false;
     }
-    Dex2oatFileWrapper<std::function<void ()>> out_vdex_wrapper_fd;
-    int out_vdex_fd = -1;
 
     // If we are compiling because the boot image is out of date, we do not
     // need to recreate a vdex, and can use the same existing one.
     if (dexopt_action == DEX2OAT_FOR_BOOT_IMAGE &&
-            in_vdex_fd != -1 &&
+            in_vdex_wrapper_fd->get() != -1 &&
             in_vdex_path_str == out_vdex_path_str) {
-        out_vdex_fd = in_vdex_fd;
+        out_vdex_wrapper_fd->reset(in_vdex_wrapper_fd->get());
+        // Disable auto close for the in wrapper fd (it will be done when destructing the out
+        // wrapper).
+        in_vdex_wrapper_fd->DisableAutoClose();
     } else {
-        out_vdex_wrapper_fd.reset(
+        out_vdex_wrapper_fd->reset(
               open_output_file(out_vdex_path_str.c_str(), /*recreate*/true, /*permissions*/0644),
               [out_vdex_path_str]() { unlink(out_vdex_path_str.c_str()); });
-        out_vdex_fd = out_vdex_wrapper_fd.get();
-        if (out_vdex_fd < 0) {
-            ALOGE("installd cannot open '%s' for output during dexopt\n", out_vdex_path_str.c_str());
-            return -1;
+        if (out_vdex_wrapper_fd->get() < 0) {
+            ALOGE("installd cannot open vdex'%s' during dexopt\n", out_vdex_path_str.c_str());
+            return false;
         }
     }
-    if (!set_permissions_and_ownership(out_vdex_fd, is_public,
-                uid, out_vdex_path_str.c_str())) {
+    if (!set_permissions_and_ownership(out_vdex_wrapper_fd->get(), is_public, uid,
+            out_vdex_path_str.c_str())) {
+        ALOGE("installd cannot set owner '%s' for vdex during dexopt\n", out_vdex_path_str.c_str());
+        return false;
+    }
+
+    // If we got here we successfully opened the vdex files.
+    return true;
+}
+
+// Opens the output oat file for the given apk.
+// If successful it stores the output path into out_oat_path and returns true.
+Dex2oatFileWrapper open_oat_out_file(const char* apk_path, const char* oat_dir,
+        bool is_public, int uid, const char* instruction_set, char* out_oat_path) {
+    if (!create_oat_out_path(apk_path, instruction_set, oat_dir, out_oat_path)) {
+        return Dex2oatFileWrapper();
+    }
+    const std::string out_oat_path_str(out_oat_path);
+    Dex2oatFileWrapper wrapper_fd(
+            open_output_file(out_oat_path, /*recreate*/true, /*permissions*/0644),
+            [out_oat_path_str]() { unlink(out_oat_path_str.c_str()); });
+    if (wrapper_fd.get() < 0) {
+        ALOGE("installd cannot open '%s' for output during dexopt\n", out_oat_path);
+    } else if (!set_permissions_and_ownership(wrapper_fd.get(), is_public, uid, out_oat_path)) {
+        ALOGE("installd cannot set owner '%s' for output during dexopt\n", out_oat_path);
+        wrapper_fd.reset(-1);
+    }
+    return wrapper_fd;
+}
+
+// Updates the access times of out_oat_path based on those from apk_path.
+void update_out_oat_access_times(const char* apk_path, const char* out_oat_path) {
+    struct stat input_stat;
+    memset(&input_stat, 0, sizeof(input_stat));
+    if (stat(apk_path, &input_stat) != 0) {
+        PLOG(ERROR) << "Could not stat " << apk_path << " during dexopt";
+        return;
+    }
+
+    struct utimbuf ut;
+    ut.actime = input_stat.st_atime;
+    ut.modtime = input_stat.st_mtime;
+    if (utime(out_oat_path, &ut) != 0) {
+        PLOG(WARNING) << "Could not update access times for " << apk_path << " during dexopt";
+    }
+}
+
+int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* instruction_set,
+        int dexopt_needed, const char* oat_dir, int dexopt_flags,const char* compiler_filter,
+        const char* volume_uuid ATTRIBUTE_UNUSED, const char* shared_libraries) {
+    CHECK(pkgname != nullptr);
+    CHECK(pkgname[0] != 0);
+    if ((dexopt_flags & ~DEXOPT_MASK) != 0) {
+        LOG_FATAL("dexopt flags contains unknown fields\n");
+    }
+
+    bool is_public = ((dexopt_flags & DEXOPT_PUBLIC) != 0);
+    bool vm_safe_mode = (dexopt_flags & DEXOPT_SAFEMODE) != 0;
+    bool debuggable = (dexopt_flags & DEXOPT_DEBUGGABLE) != 0;
+    bool boot_complete = (dexopt_flags & DEXOPT_BOOTCOMPLETE) != 0;
+    bool profile_guided = (dexopt_flags & DEXOPT_PROFILE_GUIDED) != 0;
+
+    // Open the input file.
+    base::unique_fd input_fd(open(apk_path, O_RDONLY, 0));
+    if (input_fd.get() < 0) {
+        ALOGE("installd cannot open '%s' for input during dexopt\n", apk_path);
+        return -1;
+    }
+
+    // Create the output OAT file.
+    char out_oat_path[PKG_PATH_MAX];
+    Dex2oatFileWrapper out_oat_fd = open_oat_out_file(apk_path, oat_dir, is_public, uid,
+            instruction_set, out_oat_path);
+    if (out_oat_fd.get() < 0) {
+        return -1;
+    }
+
+    // Open vdex files.
+    Dex2oatFileWrapper in_vdex_fd;
+    Dex2oatFileWrapper out_vdex_fd;
+    if (!open_vdex_files(apk_path, out_oat_path, dexopt_needed, instruction_set, is_public, uid,
+            &in_vdex_fd, &out_vdex_fd)) {
         return -1;
     }
 
     // Create a swap file if necessary.
-    base::unique_fd swap_fd;
-    if (ShouldUseSwapFileForDexopt()) {
-        // Make sure there really is enough space.
-        char swap_file_name[PKG_PATH_MAX];
-        strcpy(swap_file_name, out_oat_path);
-        if (add_extension_to_file_name(swap_file_name, ".swap")) {
-            swap_fd.reset(open_output_file(swap_file_name, /*recreate*/true, /*permissions*/0600));
-        }
-        if (swap_fd.get() < 0) {
-            // Could not create swap file. Optimistically go on and hope that we can compile
-            // without it.
-            ALOGE("installd could not create '%s' for swap during dexopt\n", swap_file_name);
-        } else {
-            // Immediately unlink. We don't really want to hit flash.
-            if (unlink(swap_file_name) < 0) {
-                PLOG(ERROR) << "Couldn't unlink swap file " << swap_file_name;
-            }
-        }
-    }
+    base::unique_fd swap_fd = maybe_open_dexopt_swap_file(out_oat_path);
 
-    // Avoid generating an app image for extract only since it will not contain any classes.
-    Dex2oatFileWrapper<std::function<void ()>> image_fd;
-    const std::string image_path = create_image_filename(out_oat_path);
-    if (!image_path.empty()) {
-        char app_image_format[kPropertyValueMax];
-        bool have_app_image_format =
-                get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
-        // Use app images only if it is enabled (by a set image format) and we are compiling
-        // profile-guided (so the app image doesn't conservatively contain all classes).
-        if (profile_guided && have_app_image_format) {
-            // Recreate is true since we do not want to modify a mapped image. If the app is
-            // already running and we modify the image file, it can cause crashes (b/27493510).
-            image_fd.reset(open_output_file(image_path.c_str(),
-                                            true /*recreate*/,
-                                            0600 /*permissions*/),
-                           [image_path]() { unlink(image_path.c_str()); }
-                           );
-            if (image_fd.get() < 0) {
-                // Could not create application image file. Go on since we can compile without
-                // it.
-                LOG(ERROR) << "installd could not create '"
-                        << image_path
-                        << "' for image file during dexopt";
-            } else if (!set_permissions_and_ownership(image_fd.get(),
-                                                      is_public,
-                                                      uid,
-                                                      image_path.c_str())) {
-                image_fd.reset(-1);
-            }
-        }
-        // If we have a valid image file path but no image fd, explicitly erase the image file.
-        if (image_fd.get() < 0) {
-            if (unlink(image_path.c_str()) < 0) {
-                if (errno != ENOENT) {
-                    PLOG(ERROR) << "Couldn't unlink image file " << image_path;
-                }
-            }
-        }
-    }
+    // Create the app image file if needed.
+    Dex2oatFileWrapper image_fd =
+            maybe_open_app_image(out_oat_path, profile_guided, is_public, uid);
 
-    ALOGV("DexInv: --- BEGIN '%s' ---\n", input_file);
+    // Open the reference profile if needed.
+    Dex2oatFileWrapper reference_profile_fd =
+            maybe_open_reference_profile(pkgname, profile_guided, is_public, uid);
+
+    ALOGV("DexInv: --- BEGIN '%s' ---\n", apk_path);
 
     pid_t pid = fork();
     if (pid == 0) {
@@ -1174,11 +1268,11 @@
         }
 
         // Pass dex2oat the relative path to the input file.
-        const char *input_file_name = get_location_from_path(input_file);
+        const char *input_file_name = get_location_from_path(apk_path);
         run_dex2oat(input_fd.get(),
                     out_oat_fd.get(),
                     in_vdex_fd.get(),
-                    out_vdex_fd,
+                    out_vdex_fd.get(),
                     image_fd.get(),
                     input_file_name,
                     out_oat_path,
@@ -1194,21 +1288,18 @@
     } else {
         int res = wait_child(pid);
         if (res == 0) {
-            ALOGV("DexInv: --- END '%s' (success) ---\n", input_file);
+            ALOGV("DexInv: --- END '%s' (success) ---\n", apk_path);
         } else {
-            ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", input_file, res);
+            ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", apk_path, res);
             return -1;
         }
     }
 
-    struct utimbuf ut;
-    ut.actime = input_stat.st_atime;
-    ut.modtime = input_stat.st_mtime;
-    utime(out_oat_path, &ut);
+    update_out_oat_access_times(apk_path, out_oat_path);
 
     // We've been successful, don't delete output.
     out_oat_fd.SetCleanup(false);
-    out_vdex_wrapper_fd.SetCleanup(false);
+    out_vdex_fd.SetCleanup(false);
     image_fd.SetCleanup(false);
     reference_profile_fd.SetCleanup(false);
 
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index f2f0cbb..5e396c7 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -31,7 +31,6 @@
 #include <installd_constants.h>
 
 #define MEASURE_DEBUG 0
-#define MEASURE_EXTERNAL 0
 
 namespace android {
 namespace installd {
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index a31e3c7..43c4c8b 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -363,6 +363,7 @@
 int main()
 {
     struct binder_state *bs;
+    union selinux_callback cb;
 
     bs = binder_open(128*1024);
     if (!bs) {
@@ -375,6 +376,11 @@
         return -1;
     }
 
+    cb.func_audit = audit_callback;
+    selinux_set_callback(SELINUX_CB_AUDIT, cb);
+    cb.func_log = selinux_log_callback;
+    selinux_set_callback(SELINUX_CB_LOG, cb);
+
     sehandle = selinux_android_service_context_handle();
     selinux_status_open(true);
 
@@ -388,11 +394,6 @@
         abort();
     }
 
-    union selinux_callback cb;
-    cb.func_audit = audit_callback;
-    selinux_set_callback(SELINUX_CB_AUDIT, cb);
-    cb.func_log = selinux_log_callback;
-    selinux_set_callback(SELINUX_CB_LOG, cb);
 
     binder_loop(bs, svcmgr_handler);
 
diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp
index 7510429..2c87562 100644
--- a/libs/gui/Sensor.cpp
+++ b/libs/gui/Sensor.cpp
@@ -219,7 +219,10 @@
         break;
     case SENSOR_TYPE_DYNAMIC_SENSOR_META:
         mStringType = SENSOR_STRING_TYPE_DYNAMIC_SENSOR_META;
-        mFlags = SENSOR_FLAG_SPECIAL_REPORTING_MODE; // special trigger and non-wake up
+        mFlags |= SENSOR_FLAG_SPECIAL_REPORTING_MODE; // special trigger
+        if (halVersion < SENSORS_DEVICE_API_VERSION_1_3) {
+            mFlags |= SENSOR_FLAG_WAKE_UP;
+        }
         break;
     case SENSOR_TYPE_POSE_6DOF:
         mStringType = SENSOR_STRING_TYPE_POSE_6DOF;
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 493c0b8..48bf676 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -740,6 +740,7 @@
         case GGL_PIXEL_FORMAT_RGB_565:      size *= 2; break;
         case GGL_PIXEL_FORMAT_RGBA_8888:    size *= 4; break;
         case GGL_PIXEL_FORMAT_RGBX_8888:    size *= 4; break;
+        case GGL_PIXEL_FORMAT_BGRA_8888:    size *= 4; break;
         default:
             ALOGE("incompatible pixel format for pbuffer (format=%d)", f);
             pbuffer.data = 0;
@@ -1027,6 +1028,19 @@
         { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
 };
 
+// BGRA 8888 config
+static config_pair_t const config_8_attribute_list[] = {
+        { EGL_BUFFER_SIZE,     32 },
+        { EGL_ALPHA_SIZE,       8 },
+        { EGL_BLUE_SIZE,        8 },
+        { EGL_GREEN_SIZE,       8 },
+        { EGL_RED_SIZE,         8 },
+        { EGL_DEPTH_SIZE,       0 },
+        { EGL_CONFIG_ID,        8 },
+        { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_BGRA_8888 },
+        { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
 static configs_t const gConfigs[] = {
         { config_0_attribute_list, NELEM(config_0_attribute_list) },
         { config_1_attribute_list, NELEM(config_1_attribute_list) },
@@ -1036,6 +1050,7 @@
         { config_5_attribute_list, NELEM(config_5_attribute_list) },
         { config_6_attribute_list, NELEM(config_6_attribute_list) },
         { config_7_attribute_list, NELEM(config_7_attribute_list) },
+        { config_8_attribute_list, NELEM(config_8_attribute_list) },
 };
 
 static config_management_t const gConfigManagement[] = {
@@ -1118,6 +1133,10 @@
         pixelFormat = GGL_PIXEL_FORMAT_A_8;
         depthFormat = GGL_PIXEL_FORMAT_Z_16;
         break;
+    case 8:
+        pixelFormat = GGL_PIXEL_FORMAT_BGRA_8888;
+        depthFormat = 0;
+        break;
     default:
         return NAME_NOT_FOUND;
     }