Merge "libbinder: service driver fuzzes nested ifaces"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 4b64203..260ee8d 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -67,5 +67,66 @@
         }
       ]
     }
+  ],
+  "hwasan-postsubmit": [
+    {
+      "name": "SurfaceFlinger_test",
+      "options": [
+        {
+          "include-filter": "*CredentialsTest.*"
+        },
+        {
+          "include-filter": "*SurfaceFlingerStress.*"
+        },
+        {
+          "include-filter": "*SurfaceInterceptorTest.*"
+        },
+        {
+          "include-filter": "*LayerTransactionTest.*"
+        },
+        {
+          "include-filter": "*LayerTypeTransactionTest.*"
+        },
+        {
+          "include-filter": "*LayerUpdateTest.*"
+        },
+        {
+          "include-filter": "*GeometryLatchingTest.*"
+        },
+        {
+          "include-filter": "*CropLatchingTest.*"
+        },
+        {
+          "include-filter": "*ChildLayerTest.*"
+        },
+        {
+          "include-filter": "*ScreenCaptureTest.*"
+        },
+        {
+          "include-filter": "*ScreenCaptureChildOnlyTest.*"
+        },
+        {
+          "include-filter": "*DereferenceSurfaceControlTest.*"
+        },
+        {
+          "include-filter": "*BoundlessLayerTest.*"
+        },
+        {
+          "include-filter": "*MultiDisplayLayerBoundsTest.*"
+        },
+        {
+          "include-filter": "*InvalidHandleTest.*"
+        },
+        {
+          "include-filter": "*VirtualDisplayTest.*"
+        },
+        {
+          "include-filter": "*RelativeZTest.*"
+        },
+        {
+          "include-filter": "*RefreshRateOverlayTest.*"
+        }
+      ]
+    }
   ]
 }
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 7aee795..9bd733d 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -1224,10 +1224,7 @@
 
         if (ret < 0) {
             for (int i = optind; i < argc; i++) {
-                if (!setCategoryEnable(argv[i])) {
-                    fprintf(stderr, "error enabling tracing category \"%s\"\n", argv[i]);
-                    exit(1);
-                }
+                setCategoryEnable(argv[i]);
             }
             break;
         }
@@ -1343,10 +1340,10 @@
         // contain entries from only one CPU can cause "begin" entries without a
         // matching "end" entry to show up if a task gets migrated from one CPU to
         // another.
-        if (!onlyUserspace)
+        if (!onlyUserspace) {
             ok = clearTrace();
-
-        writeClockSyncMarker();
+            writeClockSyncMarker();
+        }
         if (ok && !async && !traceStream) {
             // Sleep to allow the trace to be captured.
             struct timespec timeLeft;
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index b6ebfca..b2a6ccf 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -41,6 +41,7 @@
 #include <fstream>
 #include <functional>
 #include <regex>
+#include <unordered_set>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
@@ -54,7 +55,8 @@
 #include <cutils/fs.h>
 #include <cutils/properties.h>
 #include <cutils/sched_policy.h>
-#include <log/log.h>               // TODO: Move everything to base/logging.
+#include <linux/quota.h>
+#include <log/log.h> // TODO: Move everything to base/logging.
 #include <logwrap/logwrap.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_projectid_config.h>
@@ -81,6 +83,7 @@
 // #define GRANULAR_LOCKS
 
 using android::base::ParseUint;
+using android::base::Split;
 using android::base::StringPrintf;
 using std::endl;
 
@@ -115,6 +118,12 @@
 
 static std::atomic<bool> sAppDataIsolationEnabled(false);
 
+/**
+ * Flag to control if project ids are supported for internal storage
+ */
+static std::atomic<bool> sUsingProjectIdsFlag(false);
+static std::once_flag flag;
+
 namespace {
 
 constexpr const char* kDump = "android.permission.DUMP";
@@ -456,14 +465,40 @@
     return res;
 }
 
-static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid) {
-    if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, uid) != 0) {
+static bool internal_storage_has_project_id() {
+    // The following path is populated in setFirstBoot, so if this file is present
+    // then project ids can be used. Using call once to cache the result of this check
+    // to avoid having to check the file presence again and again.
+    std::call_once(flag, []() {
+        auto using_project_ids =
+                StringPrintf("%smisc/installd/using_project_ids", android_data_dir.c_str());
+        sUsingProjectIdsFlag = access(using_project_ids.c_str(), F_OK) == 0;
+    });
+    return sUsingProjectIdsFlag;
+}
+
+static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid, gid_t gid,
+                           long project_id) {
+    if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, gid) != 0) {
         PLOG(ERROR) << "Failed to prepare " << path;
         return -1;
     }
+    if (internal_storage_has_project_id()) {
+        return set_quota_project_id(path, project_id, true);
+    }
     return 0;
 }
 
+static int prepare_app_cache_dir(const std::string& parent, const char* name, mode_t target_mode,
+                                 uid_t uid, gid_t gid, long project_id) {
+    auto path = StringPrintf("%s/%s", parent.c_str(), name);
+    int ret = prepare_app_cache_dir(parent, name, target_mode, uid, gid);
+    if (ret == 0 && internal_storage_has_project_id()) {
+        return set_quota_project_id(path, project_id, true);
+    }
+    return ret;
+}
+
 static bool prepare_app_profile_dir(const std::string& packageName, int32_t appId, int32_t userId) {
     if (!property_get_bool("dalvik.vm.usejitprofiles", false)) {
         return true;
@@ -597,9 +632,9 @@
     }
 }
 
-static binder::Status createAppDataDirs(const std::string& path,
-        int32_t uid, int32_t* previousUid, int32_t cacheGid,
-        const std::string& seInfo, mode_t targetMode) {
+static binder::Status createAppDataDirs(const std::string& path, int32_t uid, int32_t gid,
+                                        int32_t* previousUid, int32_t cacheGid,
+                                        const std::string& seInfo, mode_t targetMode) {
     struct stat st{};
     bool parent_dir_exists = (stat(path.c_str(), &st) == 0);
 
@@ -623,9 +658,11 @@
     }
 
     // Prepare only the parent app directory
-    if (prepare_app_dir(path, targetMode, uid) ||
-            prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid) ||
-            prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid)) {
+    long project_id_app = get_project_id(uid, PROJECT_ID_APP_START);
+    long project_id_cache_app = get_project_id(uid, PROJECT_ID_APP_CACHE_START);
+    if (prepare_app_dir(path, targetMode, uid, gid, project_id_app) ||
+        prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid, project_id_cache_app) ||
+        prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid, project_id_cache_app)) {
         return error("Failed to prepare " + path);
     }
 
@@ -684,7 +721,7 @@
     if (flags & FLAG_STORAGE_CE) {
         auto path = create_data_user_ce_package_path(uuid_, userId, pkgname);
 
-        auto status = createAppDataDirs(path, uid, &previousUid, cacheGid, seInfo, targetMode);
+        auto status = createAppDataDirs(path, uid, uid, &previousUid, cacheGid, seInfo, targetMode);
         if (!status.isOk()) {
             return status;
         }
@@ -709,7 +746,7 @@
     if (flags & FLAG_STORAGE_DE) {
         auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
 
-        auto status = createAppDataDirs(path, uid, &previousUid, cacheGid, seInfo, targetMode);
+        auto status = createAppDataDirs(path, uid, uid, &previousUid, cacheGid, seInfo, targetMode);
         if (!status.isOk()) {
             return status;
         }
@@ -722,38 +759,38 @@
         }
     }
 
-    // TODO(b/220095381): Due to boot time regression, we have omitted call to
-    // createSdkSandboxDataDirectory from here temporarily (unless it's for testing)
-    if (uuid_ != nullptr && strcmp(uuid_, "TEST") == 0) {
-        auto status = createSdkSandboxDataDirectory(uuid, packageName, userId, appId, previousAppId,
-                                                    seInfo, flags);
-        if (!status.isOk()) {
-            return status;
+    if (flags & FLAG_STORAGE_SDK) {
+        // Safe to ignore status since we can retry creating this by calling reconcileSdkData
+        auto ignore = createSdkSandboxDataPackageDirectory(uuid, packageName, userId, appId, flags);
+        if (!ignore.isOk()) {
+            PLOG(WARNING) << "Failed to create sdk data package directory for " << packageName;
         }
+
+    } else {
+        // Package does not need sdk storage. Remove it.
+        destroySdkSandboxDataPackageDirectory(uuid, packageName, userId, flags);
     }
 
     return ok();
 }
 
 /**
- * Responsible for creating /data/misc_{ce|de}/user/0/sdksandbox/<app-name> directory and other
+ * Responsible for creating /data/misc_{ce|de}/user/0/sdksandbox/<package-name> directory and other
  * app level sub directories, such as ./shared
  */
-binder::Status InstalldNativeService::createSdkSandboxDataDirectory(
+binder::Status InstalldNativeService::createSdkSandboxDataPackageDirectory(
         const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
-        int32_t appId, int32_t previousAppId, const std::string& seInfo, int32_t flags) {
+        int32_t appId, int32_t flags) {
     int32_t sdkSandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
     if (sdkSandboxUid == -1) {
         // There no valid sdk sandbox process for this app. Skip creation of data directory
         return ok();
     }
 
-    // TODO(b/211763739): what if uuid is not nullptr or TEST?
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
 
     constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
-    for (int i = 0; i < 2; i++) {
-        int currentFlag = storageFlags[i];
+    for (int currentFlag : storageFlags) {
         if ((flags & currentFlag) == 0) {
             continue;
         }
@@ -762,33 +799,16 @@
         // /data/misc_{ce,de}/<user-id>/sdksandbox directory gets created by vold
         // during user creation
 
-        // Prepare the app directory
-        auto appPath = create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId,
-                                                                 packageName.c_str());
-        if (prepare_app_dir(appPath, 0751, AID_SYSTEM)) {
-            return error("Failed to prepare " + appPath);
+        // Prepare the package directory
+        auto packagePath = create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId,
+                                                                     packageName.c_str());
+#if SDK_DEBUG
+        LOG(DEBUG) << "Creating app-level sdk data directory: " << packagePath;
+#endif
+
+        if (prepare_app_dir(packagePath, 0751, AID_SYSTEM, AID_SYSTEM, 0)) {
+            return error("Failed to prepare " + packagePath);
         }
-
-        // Now prepare the shared directory which will be accessible by all codes
-        auto sharedPath = create_data_misc_sdk_sandbox_shared_path(uuid_, isCeData, userId,
-                                                                   packageName.c_str());
-
-        int32_t previousSdkSandboxUid = multiuser_get_sdk_sandbox_uid(userId, previousAppId);
-        int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
-        if (cacheGid == -1) {
-            return exception(binder::Status::EX_ILLEGAL_STATE,
-                             StringPrintf("cacheGid cannot be -1 for sdksandbox data"));
-        }
-        auto status = createAppDataDirs(sharedPath, sdkSandboxUid, &previousSdkSandboxUid, cacheGid,
-                                        seInfo, 0700);
-        if (!status.isOk()) {
-            return status;
-        }
-
-        // TODO(b/211763739): We also need to handle art profile creations
-
-        // TODO(b/211763739): And return the CE inode of the sdksandbox root directory and
-        // app directory under it so we can clear contents while CE storage is locked
     }
 
     return ok();
@@ -837,6 +857,107 @@
     return ok();
 }
 
+binder::Status InstalldNativeService::reconcileSdkData(
+        const android::os::ReconcileSdkDataArgs& args) {
+    // Locking is performed depeer in the callstack.
+
+    return reconcileSdkData(args.uuid, args.packageName, args.subDirNames, args.userId, args.appId,
+                            args.previousAppId, args.seInfo, args.flags);
+}
+
+/**
+ * Reconciles per-sdk directory under app-level sdk data directory.
+
+ * E.g. `/data/misc_ce/0/sdksandbox/<package-name>/<sdkPackageName>-<randomSuffix>
+ *
+ * - If the sdk data package directory is missing, we create it first.
+ * - If sdkPackageNames is empty, we delete sdk package directory since it's not needed anymore.
+ * - If a sdk level directory we need to prepare already exist, we skip creating it again. This
+ *   is to avoid having same per-sdk directory with different suffix.
+ * - If a sdk level directory exist which is absent from sdkPackageNames, we remove it.
+ */
+binder::Status InstalldNativeService::reconcileSdkData(const std::optional<std::string>& uuid,
+                                                       const std::string& packageName,
+                                                       const std::vector<std::string>& subDirNames,
+                                                       int userId, int appId, int previousAppId,
+                                                       const std::string& seInfo, int flags) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(uuid);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    LOCK_PACKAGE_USER();
+
+#if SDK_DEBUG
+    LOG(DEBUG) << "Creating per sdk data directory for: " << packageName;
+#endif
+
+    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+
+    // Prepare the sdk package directory in case it's missing
+    const auto status =
+            createSdkSandboxDataPackageDirectory(uuid, packageName, userId, appId, flags);
+    if (!status.isOk()) {
+        return status;
+    }
+
+    auto res = ok();
+    // We have to create sdk data for CE and DE storage
+    const int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+    for (int currentFlag : storageFlags) {
+        if ((flags & currentFlag) == 0) {
+            continue;
+        }
+        const bool isCeData = (currentFlag == FLAG_STORAGE_CE);
+
+        const auto packagePath = create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId,
+                                                                           packageName.c_str());
+
+        // Remove existing sub-directories not referred in subDirNames
+        const std::unordered_set<std::string> expectedSubDirNames(subDirNames.begin(),
+                                                                  subDirNames.end());
+        const auto subDirHandler = [&packagePath, &expectedSubDirNames,
+                                    &res](const std::string& subDirName) {
+            // Remove the per-sdk directory if it is not referred in
+            // expectedSubDirNames
+            if (expectedSubDirNames.find(subDirName) == expectedSubDirNames.end()) {
+                auto path = packagePath + "/" + subDirName;
+                if (delete_dir_contents_and_dir(path) != 0) {
+                    res = error("Failed to delete " + path);
+                    return;
+                }
+            }
+        };
+        const int ec = foreach_subdir(packagePath, subDirHandler);
+        if (ec != 0) {
+            res = error("Failed to process subdirs for " + packagePath);
+            continue;
+        }
+
+        // Now create the subDirNames
+        for (const auto& subDirName : subDirNames) {
+            const std::string path =
+                    create_data_misc_sdk_sandbox_sdk_path(uuid_, isCeData, userId,
+                                                          packageName.c_str(), subDirName.c_str());
+
+            // Create the directory along with cache and code_cache
+            const int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
+            if (cacheGid == -1) {
+                return exception(binder::Status::EX_ILLEGAL_STATE,
+                                 StringPrintf("cacheGid cannot be -1 for sdk data"));
+            }
+            const int32_t sandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
+            int32_t previousSandboxUid = multiuser_get_sdk_sandbox_uid(userId, previousAppId);
+            auto status = createAppDataDirs(path, sandboxUid, AID_NOBODY, &previousSandboxUid,
+                                            cacheGid, seInfo, 0700 | S_ISGID);
+            if (!status.isOk()) {
+                res = status;
+                continue;
+            }
+        }
+    }
+
+    return res;
+}
+
 binder::Status InstalldNativeService::migrateAppData(const std::optional<std::string>& uuid,
         const std::string& packageName, int32_t userId, int32_t flags) {
     ENFORCE_UID(AID_SYSTEM);
@@ -982,6 +1103,47 @@
             }
         }
     }
+    auto status = clearSdkSandboxDataPackageDirectory(uuid, packageName, userId, flags);
+    if (!status.isOk()) {
+        res = status;
+    }
+    return res;
+}
+
+binder::Status InstalldNativeService::clearSdkSandboxDataPackageDirectory(
+        const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
+        int32_t flags) {
+    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+    const char* pkgname = packageName.c_str();
+
+    binder::Status res = ok();
+    constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+    for (int i = 0; i < 2; i++) {
+        int currentFlag = storageFlags[i];
+        if ((flags & currentFlag) == 0) {
+            continue;
+        }
+        bool isCeData = (currentFlag == FLAG_STORAGE_CE);
+        std::string suffix;
+        if (flags & FLAG_CLEAR_CACHE_ONLY) {
+            suffix = CACHE_DIR_POSTFIX;
+        } else if (flags & FLAG_CLEAR_CODE_CACHE_ONLY) {
+            suffix = CODE_CACHE_DIR_POSTFIX;
+        }
+
+        auto appPath = create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId, pkgname);
+        if (access(appPath.c_str(), F_OK) != 0) continue;
+        const auto subDirHandler = [&appPath, &res, &suffix](const std::string& filename) {
+            auto filepath = appPath + "/" + filename + suffix;
+            if (delete_dir_contents(filepath, true) != 0) {
+                res = error("Failed to clear contents of " + filepath);
+            }
+        };
+        const int ec = foreach_subdir(appPath, subDirHandler);
+        if (ec != 0) {
+            res = error("Failed to process subdirs for " + appPath);
+        }
+    }
     return res;
 }
 
@@ -1078,6 +1240,32 @@
             }
         }
     }
+    auto status = destroySdkSandboxDataPackageDirectory(uuid, packageName, userId, flags);
+    if (!status.isOk()) {
+        res = status;
+    }
+    return res;
+}
+
+binder::Status InstalldNativeService::destroySdkSandboxDataPackageDirectory(
+        const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
+        int32_t flags) {
+    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+    const char* pkgname = packageName.c_str();
+
+    binder::Status res = ok();
+    constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+    for (int i = 0; i < 2; i++) {
+        int currentFlag = storageFlags[i];
+        if ((flags & currentFlag) == 0) {
+            continue;
+        }
+        bool isCeData = (currentFlag == FLAG_STORAGE_CE);
+        auto appPath = create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId, pkgname);
+        if (rename_delete_dir_contents_and_dir(appPath) != 0) {
+            res = error("Failed to delete " + appPath);
+        }
+    }
     return res;
 }
 
@@ -1563,6 +1751,36 @@
         }
     }
 
+    // Copy sdk data for all known users
+    for (auto userId : users) {
+        LOCK_USER();
+
+        constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+        for (int currentFlag : storageFlags) {
+            const bool isCeData = currentFlag == FLAG_STORAGE_CE;
+
+            const auto from = create_data_misc_sdk_sandbox_package_path(from_uuid, isCeData, userId,
+                                                                        package_name);
+            if (access(from.c_str(), F_OK) != 0) {
+                LOG(INFO) << "Missing source " << from;
+                continue;
+            }
+            const auto to = create_data_misc_sdk_sandbox_path(to_uuid, isCeData, userId);
+
+            const int rc = copy_directory_recursive(from.c_str(), to.c_str());
+            if (rc != 0) {
+                res = error(rc, "Failed copying " + from + " to " + to);
+                goto fail;
+            }
+        }
+
+        if (!restoreconSdkDataLocked(toUuid, packageName, userId, FLAG_STORAGE_CE | FLAG_STORAGE_DE,
+                                     appId, seInfo)
+                     .isOk()) {
+            res = error("Failed to restorecon");
+            goto fail;
+        }
+    }
     // We let the framework scan the new location and persist that before
     // deleting the data in the old location; this ordering ensures that
     // we can recover from things like battery pulls.
@@ -1590,6 +1808,18 @@
             }
         }
     }
+    for (auto userId : users) {
+        LOCK_USER();
+        constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+        for (int currentFlag : storageFlags) {
+            const bool isCeData = currentFlag == FLAG_STORAGE_CE;
+            const auto to = create_data_misc_sdk_sandbox_package_path(to_uuid, isCeData, userId,
+                                                                      package_name);
+            if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
+                LOG(WARNING) << "Failed to rollback " << to;
+            }
+        }
+    }
     return res;
 }
 
@@ -1624,6 +1854,11 @@
         if (delete_dir_contents_and_dir(path, true) != 0) {
             res = error("Failed to delete " + path);
         }
+        auto sdk_sandbox_de_path =
+                create_data_misc_sdk_sandbox_path(uuid_, /*isCeData=*/false, userId);
+        if (delete_dir_contents_and_dir(sdk_sandbox_de_path, true) != 0) {
+            res = error("Failed to delete " + sdk_sandbox_de_path);
+        }
         if (uuid_ == nullptr) {
             path = create_data_misc_legacy_path(userId);
             if (delete_dir_contents_and_dir(path, true) != 0) {
@@ -1640,6 +1875,11 @@
         if (delete_dir_contents_and_dir(path, true) != 0) {
             res = error("Failed to delete " + path);
         }
+        auto sdk_sandbox_ce_path =
+                create_data_misc_sdk_sandbox_path(uuid_, /*isCeData=*/true, userId);
+        if (delete_dir_contents_and_dir(sdk_sandbox_ce_path, true) != 0) {
+            res = error("Failed to delete " + sdk_sandbox_ce_path);
+        }
         path = findDataMediaPath(uuid, userId);
         if (delete_dir_contents_and_dir(path, true) != 0) {
             res = error("Failed to delete " + path);
@@ -1879,20 +2119,70 @@
     return res.str();
 }
 #endif
+// On devices without sdcardfs, if internal and external are on
+// the same volume, a uid such as u0_a123 is used for both
+// internal and external storage; therefore, subtract that
+// amount from internal to make sure we don't count it double.
+// This needs to happen for data, cache and OBB
+static void deductDoubleSpaceIfNeeded(stats* stats, int64_t doubleSpaceToBeDeleted, uid_t uid,
+                                      const std::string& uuid) {
+    if (!supports_sdcardfs()) {
+        stats->dataSize -= doubleSpaceToBeDeleted;
+        long obbProjectId = get_project_id(uid, PROJECT_ID_EXT_OBB_START);
+        int64_t appObbSize = GetOccupiedSpaceForProjectId(uuid, obbProjectId);
+        stats->dataSize -= appObbSize;
+    }
+}
 
 static void collectQuotaStats(const std::string& uuid, int32_t userId,
         int32_t appId, struct stats* stats, struct stats* extStats) {
-    int64_t space;
+    int64_t space, doubleSpaceToBeDeleted = 0;
     uid_t uid = multiuser_get_uid(userId, appId);
-    if (stats != nullptr) {
-        if ((space = GetOccupiedSpaceForUid(uuid, uid)) != -1) {
-            stats->dataSize += space;
+    static const bool supportsProjectId = internal_storage_has_project_id();
+
+    if (extStats != nullptr) {
+        space = get_occupied_app_space_external(uuid, userId, appId);
+
+        if (space != -1) {
+            extStats->dataSize += space;
+            doubleSpaceToBeDeleted += space;
         }
 
-        int cacheGid = multiuser_get_cache_gid(userId, appId);
-        if (cacheGid != -1) {
-            if ((space = GetOccupiedSpaceForGid(uuid, cacheGid)) != -1) {
+        space = get_occupied_app_cache_space_external(uuid, userId, appId);
+        if (space != -1) {
+            extStats->dataSize += space; // cache counts for "data"
+            extStats->cacheSize += space;
+            doubleSpaceToBeDeleted += space;
+        }
+    }
+
+    if (stats != nullptr) {
+        if (!supportsProjectId) {
+            if ((space = GetOccupiedSpaceForUid(uuid, uid)) != -1) {
+                stats->dataSize += space;
+            }
+            deductDoubleSpaceIfNeeded(stats, doubleSpaceToBeDeleted, uid, uuid);
+            int sdkSandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
+            if (sdkSandboxUid != -1) {
+                if ((space = GetOccupiedSpaceForUid(uuid, sdkSandboxUid)) != -1) {
+                    stats->dataSize += space;
+                }
+            }
+            int cacheGid = multiuser_get_cache_gid(userId, appId);
+            if (cacheGid != -1) {
+                if ((space = GetOccupiedSpaceForGid(uuid, cacheGid)) != -1) {
+                    stats->cacheSize += space;
+                }
+            }
+        } else {
+            long projectId = get_project_id(uid, PROJECT_ID_APP_START);
+            if ((space = GetOccupiedSpaceForProjectId(uuid, projectId)) != -1) {
+                stats->dataSize += space;
+            }
+            projectId = get_project_id(uid, PROJECT_ID_APP_CACHE_START);
+            if ((space = GetOccupiedSpaceForProjectId(uuid, projectId)) != -1) {
                 stats->cacheSize += space;
+                stats->dataSize += space;
             }
         }
 
@@ -1903,47 +2193,6 @@
             }
         }
     }
-
-    if (extStats != nullptr) {
-        static const bool supportsSdCardFs = supports_sdcardfs();
-        space = get_occupied_app_space_external(uuid, userId, appId);
-
-        if (space != -1) {
-            extStats->dataSize += space;
-            if (!supportsSdCardFs && stats != nullptr) {
-                // On devices without sdcardfs, if internal and external are on
-                // the same volume, a uid such as u0_a123 is used for
-                // application dirs on both internal and external storage;
-                // therefore, substract that amount from internal to make sure
-                // we don't count it double.
-                stats->dataSize -= space;
-            }
-        }
-
-        space = get_occupied_app_cache_space_external(uuid, userId, appId);
-        if (space != -1) {
-            extStats->dataSize += space; // cache counts for "data"
-            extStats->cacheSize += space;
-            if (!supportsSdCardFs && stats != nullptr) {
-                // On devices without sdcardfs, if internal and external are on
-                // the same volume, a uid such as u0_a123 is used for both
-                // internal and external storage; therefore, substract that
-                // amount from internal to make sure we don't count it double.
-                stats->dataSize -= space;
-            }
-        }
-
-        if (!supportsSdCardFs && stats != nullptr) {
-            // On devices without sdcardfs, the UID of OBBs on external storage
-            // matches the regular app UID (eg u0_a123); therefore, to avoid
-            // OBBs being include in stats->dataSize, compute the OBB size for
-            // this app, and substract it from the size reported on internal
-            // storage
-            long obbProjectId = uid - AID_APP_START + PROJECT_ID_EXT_OBB_START;
-            int64_t appObbSize = GetOccupiedSpaceForProjectId(uuid, obbProjectId);
-            stats->dataSize -= appObbSize;
-        }
-    }
 }
 
 static void collectManualStats(const std::string& path, struct stats* stats) {
@@ -1996,8 +2245,17 @@
     closedir(d);
 }
 
+void collectManualStatsForSubDirectories(const std::string& path, struct stats* stats) {
+    const auto subDirHandler = [&path, &stats](const std::string& subDir) {
+        auto fullpath = path + "/" + subDir;
+        collectManualStats(fullpath, stats);
+    };
+    foreach_subdir(path, subDirHandler);
+}
+
 static void collectManualStatsForUser(const std::string& path, struct stats* stats,
-        bool exclude_apps = false) {
+                                      bool exclude_apps = false,
+                                      bool is_sdk_sandbox_storage = false) {
     DIR *d;
     int dfd;
     struct dirent *de;
@@ -2022,6 +2280,11 @@
                 continue;
             } else if (exclude_apps && (user_uid >= AID_APP_START && user_uid <= AID_APP_END)) {
                 continue;
+            } else if (is_sdk_sandbox_storage) {
+                // In case of sdk sandbox storage (e.g. /data/misc_ce/0/sdksandbox/<package-name>),
+                // collect individual stats of each subdirectory (shared, storage of each sdk etc.)
+                collectManualStatsForSubDirectories(StringPrintf("%s/%s", path.c_str(), name),
+                                                    stats);
             } else {
                 collectManualStats(StringPrintf("%s/%s", path.c_str(), name), stats);
             }
@@ -2064,6 +2327,11 @@
     fts_close(fts);
 }
 static bool ownsExternalStorage(int32_t appId) {
+    // if project id calculation is supported then, there is no need to
+    // calculate in a different way and project_id based calculation can work
+    if (internal_storage_has_project_id()) {
+        return false;
+    }
     //  Fetch external storage owner appid  and check if it is the same as the
     //  current appId whose size is calculated
     struct stat s;
@@ -2164,6 +2432,19 @@
             collectManualStats(dePath, &stats);
             ATRACE_END();
 
+            // In case of sdk sandbox storage (e.g. /data/misc_ce/0/sdksandbox/<package-name>),
+            // collect individual stats of each subdirectory (shared, storage of each sdk etc.)
+            if (appId >= AID_APP_START && appId <= AID_APP_END) {
+                ATRACE_BEGIN("sdksandbox");
+                auto sdkSandboxCePath =
+                        create_data_misc_sdk_sandbox_package_path(uuid_, true, userId, pkgname);
+                collectManualStatsForSubDirectories(sdkSandboxCePath, &stats);
+                auto sdkSandboxDePath =
+                        create_data_misc_sdk_sandbox_package_path(uuid_, false, userId, pkgname);
+                collectManualStatsForSubDirectories(sdkSandboxDePath, &stats);
+                ATRACE_END();
+            }
+
             if (!uuid) {
                 ATRACE_BEGIN("profiles");
                 calculate_tree_size(
@@ -2400,6 +2681,13 @@
         collectManualStatsForUser(dePath, &stats);
         ATRACE_END();
 
+        ATRACE_BEGIN("sdksandbox");
+        auto sdkSandboxCePath = create_data_misc_sdk_sandbox_path(uuid_, true, userId);
+        collectManualStatsForUser(sdkSandboxCePath, &stats, false, true);
+        auto sdkSandboxDePath = create_data_misc_sdk_sandbox_path(uuid_, false, userId);
+        collectManualStatsForUser(sdkSandboxDePath, &stats, false, true);
+        ATRACE_END();
+
         if (!uuid) {
             ATRACE_BEGIN("profile");
             auto userProfilePath = create_primary_cur_profile_dir_path(userId);
@@ -2921,6 +3209,49 @@
     return res;
 }
 
+binder::Status InstalldNativeService::restoreconSdkDataLocked(
+        const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
+        int32_t flags, int32_t appId, const std::string& seInfo) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(uuid);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+
+    binder::Status res = ok();
+
+    // SELINUX_ANDROID_RESTORECON_DATADATA flag is set by libselinux. Not needed here.
+    unsigned int seflags = SELINUX_ANDROID_RESTORECON_RECURSE;
+    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+    const char* pkgName = packageName.c_str();
+    const char* seinfo = seInfo.c_str();
+
+    uid_t uid = multiuser_get_sdk_sandbox_uid(userId, appId);
+    constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+    for (int currentFlag : storageFlags) {
+        if ((flags & currentFlag) == 0) {
+            continue;
+        }
+        const bool isCeData = (currentFlag == FLAG_STORAGE_CE);
+        const auto packagePath =
+                create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId, pkgName);
+        if (access(packagePath.c_str(), F_OK) != 0) {
+            LOG(INFO) << "Missing source " << packagePath;
+            continue;
+        }
+        const auto subDirHandler = [&packagePath, &seinfo, &uid, &seflags,
+                                    &res](const std::string& subDir) {
+            const auto& fullpath = packagePath + "/" + subDir;
+            if (selinux_android_restorecon_pkgdir(fullpath.c_str(), seinfo, uid, seflags) < 0) {
+                res = error("restorecon failed for " + fullpath);
+            }
+        };
+        const auto ec = foreach_subdir(packagePath, subDirHandler);
+        if (ec != 0) {
+            res = error("Failed to restorecon for subdirs of " + packagePath);
+        }
+    }
+    return res;
+}
+
 binder::Status InstalldNativeService::createOatDir(const std::string& oatDir,
         const std::string& instructionSet) {
     ENFORCE_UID(AID_SYSTEM);
@@ -3055,6 +3386,33 @@
     return result ? ok() : error();
 }
 
+bool check_if_ioctl_feature_is_supported() {
+    bool result = false;
+    auto temp_path = StringPrintf("%smisc/installd/ioctl_check", android_data_dir.c_str());
+    if (access(temp_path.c_str(), F_OK) != 0) {
+        open(temp_path.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0644);
+        result = set_quota_project_id(temp_path, 0, true) == 0;
+        // delete the temp file
+        // remove the external file
+        remove(temp_path.c_str());
+    }
+    return result;
+}
+
+binder::Status InstalldNativeService::setFirstBoot() {
+    ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+    std::string uuid;
+    if (GetOccupiedSpaceForProjectId(uuid, 0) != -1 && check_if_ioctl_feature_is_supported()) {
+        auto first_boot_path =
+                StringPrintf("%smisc/installd/using_project_ids", android_data_dir.c_str());
+        if (access(first_boot_path.c_str(), F_OK) != 0) {
+            open(first_boot_path.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0644);
+        }
+    }
+    return ok();
+}
+
 binder::Status InstalldNativeService::invalidateMounts() {
     ENFORCE_UID(AID_SYSTEM);
     std::lock_guard<std::recursive_mutex> lock(mMountsLock);
@@ -3258,11 +3616,17 @@
     if (flags & FLAG_STORAGE_CE) {
         auto ce_path = create_data_user_ce_path(uuid_cstr, userId);
         cleanup_invalid_package_dirs_under_path(ce_path);
+        auto sdksandbox_ce_path =
+                create_data_misc_sdk_sandbox_path(uuid_cstr, /*isCeData=*/true, userId);
+        cleanup_invalid_package_dirs_under_path(sdksandbox_ce_path);
     }
 
     if (flags & FLAG_STORAGE_DE) {
         auto de_path = create_data_user_de_path(uuid_cstr, userId);
         cleanup_invalid_package_dirs_under_path(de_path);
+        auto sdksandbox_de_path =
+                create_data_misc_sdk_sandbox_path(uuid_cstr, /*isCeData=*/false, userId);
+        cleanup_invalid_package_dirs_under_path(sdksandbox_de_path);
     }
 
     return ok();
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index b2bad1d..95ac516 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -58,12 +58,12 @@
             const std::vector<android::os::CreateAppDataArgs>& args,
             std::vector<android::os::CreateAppDataResult>* _aidl_return);
 
+    binder::Status reconcileSdkData(const android::os::ReconcileSdkDataArgs& args);
+
     binder::Status restoreconAppData(const std::optional<std::string>& uuid,
             const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
             const std::string& seInfo);
-    binder::Status restoreconAppDataLocked(const std::optional<std::string>& uuid,
-                                           const std::string& packageName, int32_t userId,
-                                           int32_t flags, int32_t appId, const std::string& seInfo);
+
     binder::Status migrateAppData(const std::optional<std::string>& uuid,
             const std::string& packageName, int32_t userId, int32_t flags);
     binder::Status clearAppData(const std::optional<std::string>& uuid,
@@ -167,6 +167,7 @@
         int32_t storageFlag, std::vector<uint8_t>* _aidl_return);
 
     binder::Status invalidateMounts();
+    binder::Status setFirstBoot();
     binder::Status isQuotaSupported(const std::optional<std::string>& volumeUuid,
             bool* _aidl_return);
     binder::Status tryMountDataMirror(const std::optional<std::string>& volumeUuid);
@@ -203,11 +204,28 @@
                                        int32_t flags, int32_t appId, int32_t previousAppId,
                                        const std::string& seInfo, int32_t targetSdkVersion,
                                        int64_t* _aidl_return);
+    binder::Status restoreconAppDataLocked(const std::optional<std::string>& uuid,
+                                           const std::string& packageName, int32_t userId,
+                                           int32_t flags, int32_t appId, const std::string& seInfo);
 
-    binder::Status createSdkSandboxDataDirectory(const std::optional<std::string>& uuid,
-                                                 const std::string& packageName, int32_t userId,
-                                                 int32_t appId, int32_t previousAppId,
-                                                 const std::string& seInfo, int32_t flags);
+    binder::Status createSdkSandboxDataPackageDirectory(const std::optional<std::string>& uuid,
+                                                        const std::string& packageName,
+                                                        int32_t userId, int32_t appId,
+                                                        int32_t flags);
+    binder::Status clearSdkSandboxDataPackageDirectory(const std::optional<std::string>& uuid,
+                                                       const std::string& packageName,
+                                                       int32_t userId, int32_t flags);
+    binder::Status destroySdkSandboxDataPackageDirectory(const std::optional<std::string>& uuid,
+                                                         const std::string& packageName,
+                                                         int32_t userId, int32_t flags);
+    binder::Status reconcileSdkData(const std::optional<std::string>& uuid,
+                                    const std::string& packageName,
+                                    const std::vector<std::string>& subDirNames, int32_t userId,
+                                    int32_t appId, int32_t previousAppId, const std::string& seInfo,
+                                    int flags);
+    binder::Status restoreconSdkDataLocked(const std::optional<std::string>& uuid,
+                                           const std::string& packageName, int32_t userId,
+                                           int32_t flags, int32_t appId, const std::string& seInfo);
 };
 
 }  // namespace installd
diff --git a/cmds/installd/TEST_MAPPING b/cmds/installd/TEST_MAPPING
index 3f0fb6d..8ccab4c 100644
--- a/cmds/installd/TEST_MAPPING
+++ b/cmds/installd/TEST_MAPPING
@@ -30,6 +30,9 @@
     },
     {
       "name": "CtsCompilationTestCases"
+    },
+    {
+      "name": "SdkSandboxStorageHostTest"
     }
   ]
 }
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index f4fd9a9..c17c6bf 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -20,10 +20,12 @@
 interface IInstalld {
     void createUserData(@nullable @utf8InCpp String uuid, int userId, int userSerial, int flags);
     void destroyUserData(@nullable @utf8InCpp String uuid, int userId, int flags);
-
+    void setFirstBoot();
     android.os.CreateAppDataResult createAppData(in android.os.CreateAppDataArgs args);
     android.os.CreateAppDataResult[] createAppDataBatched(in android.os.CreateAppDataArgs[] args);
 
+    void reconcileSdkData(in android.os.ReconcileSdkDataArgs args);
+
     void restoreconAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
             int userId, int flags, int appId, @utf8InCpp String seInfo);
     void migrateAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
@@ -131,6 +133,7 @@
     const int FLAG_STORAGE_DE = 0x1;
     const int FLAG_STORAGE_CE = 0x2;
     const int FLAG_STORAGE_EXTERNAL = 0x4;
+    const int FLAG_STORAGE_SDK = 0x8;
 
     const int FLAG_CLEAR_CACHE_ONLY = 0x10;
     const int FLAG_CLEAR_CODE_CACHE_ONLY = 0x20;
diff --git a/cmds/installd/binder/android/os/ReconcileSdkDataArgs.aidl b/cmds/installd/binder/android/os/ReconcileSdkDataArgs.aidl
new file mode 100644
index 0000000..583a36d
--- /dev/null
+++ b/cmds/installd/binder/android/os/ReconcileSdkDataArgs.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+package android.os;
+
+/** {@hide} */
+parcelable ReconcileSdkDataArgs {
+    @nullable @utf8InCpp String uuid;
+    @utf8InCpp String packageName;
+    @utf8InCpp List<String> subDirNames;
+    int userId;
+    int appId;
+    int previousAppId;
+    @utf8InCpp String seInfo;
+    int flags;
+}
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index e390bab..b3baca5 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -26,6 +26,7 @@
         "libasync_safe",
         "libdiskusage",
         "libext2_uuid",
+        "libgmock",
         "libinstalld",
         "liblog",
     ],
@@ -106,6 +107,7 @@
         "libziparchive",
         "liblog",
         "liblogwrap",
+        "libc++fs",
     ],
     test_config: "installd_service_test.xml",
 
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index 21ab5b8..cf88856 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -32,16 +32,20 @@
 #include <android-base/stringprintf.h>
 #include <cutils/properties.h>
 #include <gtest/gtest.h>
+#include <filesystem>
+#include <fstream>
 
 #include <android/content/pm/IPackageManagerNative.h>
 #include <binder/IServiceManager.h>
 #include "InstalldNativeService.h"
+#include "binder/Status.h"
 #include "binder_test_utils.h"
 #include "dexopt.h"
 #include "globals.h"
 #include "utils.h"
 
 using android::base::StringPrintf;
+using std::filesystem::is_empty;
 
 namespace android {
 std::string get_package_name(uid_t uid) {
@@ -75,12 +79,18 @@
 namespace installd {
 
 static constexpr const char* kTestUuid = "TEST";
-static constexpr const char* kTestPath = "/data/local/tmp/user/0";
+static const std::string kTestPath = "/data/local/tmp";
+static constexpr const uid_t kNobodyUid = 9999;
 static constexpr const uid_t kSystemUid = 1000;
 static constexpr const int32_t kTestUserId = 0;
 static constexpr const uid_t kTestAppId = 19999;
+static constexpr const int FLAG_STORAGE_SDK = InstalldNativeService::FLAG_STORAGE_SDK;
+static constexpr const int FLAG_CLEAR_CACHE_ONLY = InstalldNativeService::FLAG_CLEAR_CACHE_ONLY;
+static constexpr const int FLAG_CLEAR_CODE_CACHE_ONLY =
+        InstalldNativeService::FLAG_CLEAR_CODE_CACHE_ONLY;
 
 const gid_t kTestAppUid = multiuser_get_uid(kTestUserId, kTestAppId);
+const gid_t kTestCacheGid = multiuser_get_cache_gid(kTestUserId, kTestAppId);
 const uid_t kTestSdkSandboxUid = multiuser_get_sdk_sandbox_uid(kTestUserId, kTestAppId);
 
 #define FLAG_FORCE InstalldNativeService::FLAG_FORCE
@@ -103,18 +113,18 @@
     return create_cache_path_default(path, src, instruction_set);
 }
 
-static std::string get_full_path(const char* path) {
-    return StringPrintf("%s/%s", kTestPath, path);
+static std::string get_full_path(const std::string& path) {
+    return StringPrintf("%s/%s", kTestPath.c_str(), path.c_str());
 }
 
-static void mkdir(const char* path, uid_t owner, gid_t group, mode_t mode) {
+static void mkdir(const std::string& path, uid_t owner, gid_t group, mode_t mode) {
     const std::string fullPath = get_full_path(path);
     EXPECT_EQ(::mkdir(fullPath.c_str(), mode), 0);
     EXPECT_EQ(::chown(fullPath.c_str(), owner, group), 0);
     EXPECT_EQ(::chmod(fullPath.c_str(), mode), 0);
 }
 
-static int create(const char* path, uid_t owner, gid_t group, mode_t mode) {
+static int create(const std::string& path, uid_t owner, gid_t group, mode_t mode) {
     int fd = ::open(get_full_path(path).c_str(), O_RDWR | O_CREAT, mode);
     EXPECT_NE(fd, -1);
     EXPECT_EQ(::fchown(fd, owner, group), 0);
@@ -122,8 +132,8 @@
     return fd;
 }
 
-static void touch(const char* path, uid_t owner, gid_t group, mode_t mode) {
-    EXPECT_EQ(::close(create(path, owner, group, mode)), 0);
+static void touch(const std::string& path, uid_t owner, gid_t group, mode_t mode) {
+    EXPECT_EQ(::close(create(path.c_str(), owner, group, mode)), 0);
 }
 
 static int stat_gid(const char* path) {
@@ -138,7 +148,7 @@
     return buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID);
 }
 
-static bool exists(const char* path) {
+static bool exists(const std::string& path) {
     return ::access(get_full_path(path).c_str(), F_OK) == 0;
 }
 
@@ -161,8 +171,8 @@
     return result;
 }
 
-static bool exists_renamed_deleted_dir() {
-    return find_file(kTestPath, [](const std::string& name, bool is_dir) {
+static bool exists_renamed_deleted_dir(const std::string& rootDirectory) {
+    return find_file((kTestPath + rootDirectory).c_str(), [](const std::string& name, bool is_dir) {
         return is_dir && is_renamed_deleted_dir(name);
     });
 }
@@ -179,197 +189,205 @@
         service = new InstalldNativeService();
         testUuid = kTestUuid;
         system("rm -rf /data/local/tmp/user");
+        system("rm -rf /data/local/tmp/misc_ce");
+        system("rm -rf /data/local/tmp/misc_de");
         system("mkdir -p /data/local/tmp/user/0");
-
+        system("mkdir -p /data/local/tmp/misc_ce/0/sdksandbox");
+        system("mkdir -p /data/local/tmp/misc_de/0/sdksandbox");
         init_globals_from_data_and_root();
     }
 
     virtual void TearDown() {
         delete service;
         system("rm -rf /data/local/tmp/user");
+        system("rm -rf /data/local/tmp/misc_ce");
+        system("rm -rf /data/local/tmp/misc_de");
     }
 };
 
 TEST_F(ServiceTest, FixupAppData_Upgrade) {
     LOG(INFO) << "FixupAppData_Upgrade";
 
-    mkdir("com.example", 10000, 10000, 0700);
-    mkdir("com.example/normal", 10000, 10000, 0700);
-    mkdir("com.example/cache", 10000, 10000, 0700);
-    touch("com.example/cache/file", 10000, 10000, 0700);
+    mkdir("user/0/com.example", 10000, 10000, 0700);
+    mkdir("user/0/com.example/normal", 10000, 10000, 0700);
+    mkdir("user/0/com.example/cache", 10000, 10000, 0700);
+    touch("user/0/com.example/cache/file", 10000, 10000, 0700);
 
     service->fixupAppData(testUuid, 0);
 
-    EXPECT_EQ(10000, stat_gid("com.example/normal"));
-    EXPECT_EQ(20000, stat_gid("com.example/cache"));
-    EXPECT_EQ(20000, stat_gid("com.example/cache/file"));
+    EXPECT_EQ(10000, stat_gid("user/0/com.example/normal"));
+    EXPECT_EQ(20000, stat_gid("user/0/com.example/cache"));
+    EXPECT_EQ(20000, stat_gid("user/0/com.example/cache/file"));
 
-    EXPECT_EQ(0700, stat_mode("com.example/normal"));
-    EXPECT_EQ(02771, stat_mode("com.example/cache"));
-    EXPECT_EQ(0700, stat_mode("com.example/cache/file"));
+    EXPECT_EQ(0700, stat_mode("user/0/com.example/normal"));
+    EXPECT_EQ(02771, stat_mode("user/0/com.example/cache"));
+    EXPECT_EQ(0700, stat_mode("user/0/com.example/cache/file"));
 }
 
 TEST_F(ServiceTest, FixupAppData_Moved) {
     LOG(INFO) << "FixupAppData_Moved";
 
-    mkdir("com.example", 10000, 10000, 0700);
-    mkdir("com.example/foo", 10000, 10000, 0700);
-    touch("com.example/foo/file", 10000, 20000, 0700);
-    mkdir("com.example/bar", 10000, 20000, 0700);
-    touch("com.example/bar/file", 10000, 20000, 0700);
+    mkdir("user/0/com.example", 10000, 10000, 0700);
+    mkdir("user/0/com.example/foo", 10000, 10000, 0700);
+    touch("user/0/com.example/foo/file", 10000, 20000, 0700);
+    mkdir("user/0/com.example/bar", 10000, 20000, 0700);
+    touch("user/0/com.example/bar/file", 10000, 20000, 0700);
 
     service->fixupAppData(testUuid, 0);
 
-    EXPECT_EQ(10000, stat_gid("com.example/foo"));
-    EXPECT_EQ(20000, stat_gid("com.example/foo/file"));
-    EXPECT_EQ(10000, stat_gid("com.example/bar"));
-    EXPECT_EQ(10000, stat_gid("com.example/bar/file"));
+    EXPECT_EQ(10000, stat_gid("user/0/com.example/foo"));
+    EXPECT_EQ(20000, stat_gid("user/0/com.example/foo/file"));
+    EXPECT_EQ(10000, stat_gid("user/0/com.example/bar"));
+    EXPECT_EQ(10000, stat_gid("user/0/com.example/bar/file"));
 
     service->fixupAppData(testUuid, FLAG_FORCE);
 
-    EXPECT_EQ(10000, stat_gid("com.example/foo"));
-    EXPECT_EQ(10000, stat_gid("com.example/foo/file"));
-    EXPECT_EQ(10000, stat_gid("com.example/bar"));
-    EXPECT_EQ(10000, stat_gid("com.example/bar/file"));
+    EXPECT_EQ(10000, stat_gid("user/0/com.example/foo"));
+    EXPECT_EQ(10000, stat_gid("user/0/com.example/foo/file"));
+    EXPECT_EQ(10000, stat_gid("user/0/com.example/bar"));
+    EXPECT_EQ(10000, stat_gid("user/0/com.example/bar/file"));
 }
 
 TEST_F(ServiceTest, DestroyUserData) {
     LOG(INFO) << "DestroyUserData";
 
-    mkdir("com.example", 10000, 10000, 0700);
-    mkdir("com.example/foo", 10000, 10000, 0700);
-    touch("com.example/foo/file", 10000, 20000, 0700);
-    mkdir("com.example/bar", 10000, 20000, 0700);
-    touch("com.example/bar/file", 10000, 20000, 0700);
+    mkdir("user/0/com.example", 10000, 10000, 0700);
+    mkdir("user/0/com.example/foo", 10000, 10000, 0700);
+    touch("user/0/com.example/foo/file", 10000, 20000, 0700);
+    mkdir("user/0/com.example/bar", 10000, 20000, 0700);
+    touch("user/0/com.example/bar/file", 10000, 20000, 0700);
 
-    EXPECT_TRUE(exists("com.example/foo"));
-    EXPECT_TRUE(exists("com.example/foo/file"));
-    EXPECT_TRUE(exists("com.example/bar"));
-    EXPECT_TRUE(exists("com.example/bar/file"));
+    EXPECT_TRUE(exists("user/0/com.example/foo"));
+    EXPECT_TRUE(exists("user/0/com.example/foo/file"));
+    EXPECT_TRUE(exists("user/0/com.example/bar"));
+    EXPECT_TRUE(exists("user/0/com.example/bar/file"));
 
     service->destroyUserData(testUuid, 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE);
 
-    EXPECT_FALSE(exists("com.example/foo"));
-    EXPECT_FALSE(exists("com.example/foo/file"));
-    EXPECT_FALSE(exists("com.example/bar"));
-    EXPECT_FALSE(exists("com.example/bar/file"));
+    EXPECT_FALSE(exists("user/0/com.example/foo"));
+    EXPECT_FALSE(exists("user/0/com.example/foo/file"));
+    EXPECT_FALSE(exists("user/0/com.example/bar"));
+    EXPECT_FALSE(exists("user/0/com.example/bar/file"));
 
-    EXPECT_FALSE(exists_renamed_deleted_dir());
+    EXPECT_FALSE(exists_renamed_deleted_dir("/user/0"));
 }
 
 TEST_F(ServiceTest, DestroyAppData) {
     LOG(INFO) << "DestroyAppData";
 
-    mkdir("com.example", 10000, 10000, 0700);
-    mkdir("com.example/foo", 10000, 10000, 0700);
-    touch("com.example/foo/file", 10000, 20000, 0700);
-    mkdir("com.example/bar", 10000, 20000, 0700);
-    touch("com.example/bar/file", 10000, 20000, 0700);
+    mkdir("user/0/com.example", 10000, 10000, 0700);
+    mkdir("user/0/com.example/foo", 10000, 10000, 0700);
+    touch("user/0/com.example/foo/file", 10000, 20000, 0700);
+    mkdir("user/0/com.example/bar", 10000, 20000, 0700);
+    touch("user/0/com.example/bar/file", 10000, 20000, 0700);
 
-    EXPECT_TRUE(exists("com.example/foo"));
-    EXPECT_TRUE(exists("com.example/foo/file"));
-    EXPECT_TRUE(exists("com.example/bar"));
-    EXPECT_TRUE(exists("com.example/bar/file"));
+    EXPECT_TRUE(exists("user/0/com.example/foo"));
+    EXPECT_TRUE(exists("user/0/com.example/foo/file"));
+    EXPECT_TRUE(exists("user/0/com.example/bar"));
+    EXPECT_TRUE(exists("user/0/com.example/bar/file"));
 
     service->destroyAppData(testUuid, "com.example", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, 0);
 
-    EXPECT_FALSE(exists("com.example/foo"));
-    EXPECT_FALSE(exists("com.example/foo/file"));
-    EXPECT_FALSE(exists("com.example/bar"));
-    EXPECT_FALSE(exists("com.example/bar/file"));
+    EXPECT_FALSE(exists("user/0/com.example/foo"));
+    EXPECT_FALSE(exists("user/0/com.example/foo/file"));
+    EXPECT_FALSE(exists("user/0/com.example/bar"));
+    EXPECT_FALSE(exists("user/0/com.example/bar/file"));
 
-    EXPECT_FALSE(exists_renamed_deleted_dir());
+    EXPECT_FALSE(exists_renamed_deleted_dir("/user/0"));
 }
 
 TEST_F(ServiceTest, CleanupInvalidPackageDirs) {
     LOG(INFO) << "CleanupInvalidPackageDirs";
 
-    mkdir("5b14b6458a44==deleted==", 10000, 10000, 0700);
-    mkdir("5b14b6458a44==deleted==/foo", 10000, 10000, 0700);
-    touch("5b14b6458a44==deleted==/foo/file", 10000, 20000, 0700);
-    mkdir("5b14b6458a44==deleted==/bar", 10000, 20000, 0700);
-    touch("5b14b6458a44==deleted==/bar/file", 10000, 20000, 0700);
+    std::string rootDirectoryPrefix[] = {"user/0", "misc_ce/0/sdksandbox", "misc_de/0/sdksandbox"};
+    for (auto& prefix : rootDirectoryPrefix) {
+        mkdir(prefix + "/5b14b6458a44==deleted==", 10000, 10000, 0700);
+        mkdir(prefix + "/5b14b6458a44==deleted==/foo", 10000, 10000, 0700);
+        touch(prefix + "/5b14b6458a44==deleted==/foo/file", 10000, 20000, 0700);
+        mkdir(prefix + "/5b14b6458a44==deleted==/bar", 10000, 20000, 0700);
+        touch(prefix + "/5b14b6458a44==deleted==/bar/file", 10000, 20000, 0700);
 
-    auto fd = create("5b14b6458a44==deleted==/bar/opened_file", 10000, 20000, 0700);
+        auto fd = create(prefix + "/5b14b6458a44==deleted==/bar/opened_file", 10000, 20000, 0700);
 
-    mkdir("b14b6458a44NOTdeleted", 10000, 10000, 0700);
-    mkdir("b14b6458a44NOTdeleted/foo", 10000, 10000, 0700);
-    touch("b14b6458a44NOTdeleted/foo/file", 10000, 20000, 0700);
-    mkdir("b14b6458a44NOTdeleted/bar", 10000, 20000, 0700);
-    touch("b14b6458a44NOTdeleted/bar/file", 10000, 20000, 0700);
+        mkdir(prefix + "/b14b6458a44NOTdeleted", 10000, 10000, 0700);
+        mkdir(prefix + "/b14b6458a44NOTdeleted/foo", 10000, 10000, 0700);
+        touch(prefix + "/b14b6458a44NOTdeleted/foo/file", 10000, 20000, 0700);
+        mkdir(prefix + "/b14b6458a44NOTdeleted/bar", 10000, 20000, 0700);
+        touch(prefix + "/b14b6458a44NOTdeleted/bar/file", 10000, 20000, 0700);
 
-    mkdir("com.example", 10000, 10000, 0700);
-    mkdir("com.example/foo", 10000, 10000, 0700);
-    touch("com.example/foo/file", 10000, 20000, 0700);
-    mkdir("com.example/bar", 10000, 20000, 0700);
-    touch("com.example/bar/file", 10000, 20000, 0700);
+        mkdir(prefix + "/com.example", 10000, 10000, 0700);
+        mkdir(prefix + "/com.example/foo", 10000, 10000, 0700);
+        touch(prefix + "/com.example/foo/file", 10000, 20000, 0700);
+        mkdir(prefix + "/com.example/bar", 10000, 20000, 0700);
+        touch(prefix + "/com.example/bar/file", 10000, 20000, 0700);
 
-    mkdir("==deleted==", 10000, 10000, 0700);
-    mkdir("==deleted==/foo", 10000, 10000, 0700);
-    touch("==deleted==/foo/file", 10000, 20000, 0700);
-    mkdir("==deleted==/bar", 10000, 20000, 0700);
-    touch("==deleted==/bar/file", 10000, 20000, 0700);
+        mkdir(prefix + "/==deleted==", 10000, 10000, 0700);
+        mkdir(prefix + "/==deleted==/foo", 10000, 10000, 0700);
+        touch(prefix + "/==deleted==/foo/file", 10000, 20000, 0700);
+        mkdir(prefix + "/==deleted==/bar", 10000, 20000, 0700);
+        touch(prefix + "/==deleted==/bar/file", 10000, 20000, 0700);
 
-    EXPECT_TRUE(exists("5b14b6458a44==deleted==/foo"));
-    EXPECT_TRUE(exists("5b14b6458a44==deleted==/foo/file"));
-    EXPECT_TRUE(exists("5b14b6458a44==deleted==/bar"));
-    EXPECT_TRUE(exists("5b14b6458a44==deleted==/bar/file"));
-    EXPECT_TRUE(exists("5b14b6458a44==deleted==/bar/opened_file"));
+        EXPECT_TRUE(exists(prefix + "/5b14b6458a44==deleted==/foo"));
+        EXPECT_TRUE(exists(prefix + "/5b14b6458a44==deleted==/foo/file"));
+        EXPECT_TRUE(exists(prefix + "/5b14b6458a44==deleted==/bar"));
+        EXPECT_TRUE(exists(prefix + "/5b14b6458a44==deleted==/bar/file"));
+        EXPECT_TRUE(exists(prefix + "/5b14b6458a44==deleted==/bar/opened_file"));
 
-    EXPECT_TRUE(exists("b14b6458a44NOTdeleted/foo"));
-    EXPECT_TRUE(exists("b14b6458a44NOTdeleted/foo/file"));
-    EXPECT_TRUE(exists("b14b6458a44NOTdeleted/bar"));
-    EXPECT_TRUE(exists("b14b6458a44NOTdeleted/bar/file"));
+        EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/foo"));
+        EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/foo/file"));
+        EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/bar"));
+        EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/bar/file"));
 
-    EXPECT_TRUE(exists("com.example/foo"));
-    EXPECT_TRUE(exists("com.example/foo/file"));
-    EXPECT_TRUE(exists("com.example/bar"));
-    EXPECT_TRUE(exists("com.example/bar/file"));
+        EXPECT_TRUE(exists(prefix + "/com.example/foo"));
+        EXPECT_TRUE(exists(prefix + "/com.example/foo/file"));
+        EXPECT_TRUE(exists(prefix + "/com.example/bar"));
+        EXPECT_TRUE(exists(prefix + "/com.example/bar/file"));
 
-    EXPECT_TRUE(exists("==deleted==/foo"));
-    EXPECT_TRUE(exists("==deleted==/foo/file"));
-    EXPECT_TRUE(exists("==deleted==/bar"));
-    EXPECT_TRUE(exists("==deleted==/bar/file"));
+        EXPECT_TRUE(exists(prefix + "/==deleted==/foo"));
+        EXPECT_TRUE(exists(prefix + "/==deleted==/foo/file"));
+        EXPECT_TRUE(exists(prefix + "/==deleted==/bar"));
+        EXPECT_TRUE(exists(prefix + "/==deleted==/bar/file"));
 
-    EXPECT_TRUE(exists_renamed_deleted_dir());
+        EXPECT_TRUE(exists_renamed_deleted_dir("/" + prefix));
 
-    service->cleanupInvalidPackageDirs(testUuid, 0, FLAG_STORAGE_CE | FLAG_STORAGE_DE);
+        service->cleanupInvalidPackageDirs(testUuid, 0, FLAG_STORAGE_CE | FLAG_STORAGE_DE);
 
-    EXPECT_EQ(::close(fd), 0);
+        EXPECT_EQ(::close(fd), 0);
 
-    EXPECT_FALSE(exists("5b14b6458a44==deleted==/foo"));
-    EXPECT_FALSE(exists("5b14b6458a44==deleted==/foo/file"));
-    EXPECT_FALSE(exists("5b14b6458a44==deleted==/bar"));
-    EXPECT_FALSE(exists("5b14b6458a44==deleted==/bar/file"));
-    EXPECT_FALSE(exists("5b14b6458a44==deleted==/bar/opened_file"));
+        EXPECT_FALSE(exists(prefix + "/5b14b6458a44==deleted==/foo"));
+        EXPECT_FALSE(exists(prefix + "/5b14b6458a44==deleted==/foo/file"));
+        EXPECT_FALSE(exists(prefix + "/5b14b6458a44==deleted==/bar"));
+        EXPECT_FALSE(exists(prefix + "/5b14b6458a44==deleted==/bar/file"));
+        EXPECT_FALSE(exists(prefix + "/5b14b6458a44==deleted==/bar/opened_file"));
 
-    EXPECT_TRUE(exists("b14b6458a44NOTdeleted/foo"));
-    EXPECT_TRUE(exists("b14b6458a44NOTdeleted/foo/file"));
-    EXPECT_TRUE(exists("b14b6458a44NOTdeleted/bar"));
-    EXPECT_TRUE(exists("b14b6458a44NOTdeleted/bar/file"));
+        EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/foo"));
+        EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/foo/file"));
+        EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/bar"));
+        EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/bar/file"));
 
-    EXPECT_TRUE(exists("com.example/foo"));
-    EXPECT_TRUE(exists("com.example/foo/file"));
-    EXPECT_TRUE(exists("com.example/bar"));
-    EXPECT_TRUE(exists("com.example/bar/file"));
+        EXPECT_TRUE(exists(prefix + "/com.example/foo"));
+        EXPECT_TRUE(exists(prefix + "/com.example/foo/file"));
+        EXPECT_TRUE(exists(prefix + "/com.example/bar"));
+        EXPECT_TRUE(exists(prefix + "/com.example/bar/file"));
 
-    EXPECT_FALSE(exists("==deleted==/foo"));
-    EXPECT_FALSE(exists("==deleted==/foo/file"));
-    EXPECT_FALSE(exists("==deleted==/bar"));
-    EXPECT_FALSE(exists("==deleted==/bar/file"));
+        EXPECT_FALSE(exists(prefix + "/==deleted==/foo"));
+        EXPECT_FALSE(exists(prefix + "/==deleted==/foo/file"));
+        EXPECT_FALSE(exists(prefix + "/==deleted==/bar"));
+        EXPECT_FALSE(exists(prefix + "/==deleted==/bar/file"));
 
-    EXPECT_FALSE(exists_renamed_deleted_dir());
+        EXPECT_FALSE(exists_renamed_deleted_dir(prefix));
+    }
 }
 
 TEST_F(ServiceTest, HashSecondaryDex) {
     LOG(INFO) << "HashSecondaryDex";
 
-    mkdir("com.example", 10000, 10000, 0700);
-    mkdir("com.example/foo", 10000, 10000, 0700);
-    touch("com.example/foo/file", 10000, 20000, 0700);
+    mkdir("user/0/com.example", 10000, 10000, 0700);
+    mkdir("user/0/com.example/foo", 10000, 10000, 0700);
+    touch("user/0/com.example/foo/file", 10000, 20000, 0700);
 
     std::vector<uint8_t> result;
-    std::string dexPath = get_full_path("com.example/foo/file");
+    std::string dexPath = get_full_path("user/0/com.example/foo/file");
     EXPECT_BINDER_SUCCESS(service->hashSecondaryDexFile(
         dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result));
 
@@ -389,7 +407,7 @@
     LOG(INFO) << "HashSecondaryDex_NoSuch";
 
     std::vector<uint8_t> result;
-    std::string dexPath = get_full_path("com.example/foo/file");
+    std::string dexPath = get_full_path("user/0/com.example/foo/file");
     EXPECT_BINDER_SUCCESS(service->hashSecondaryDexFile(
         dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result));
 
@@ -399,12 +417,12 @@
 TEST_F(ServiceTest, HashSecondaryDex_Unreadable) {
     LOG(INFO) << "HashSecondaryDex_Unreadable";
 
-    mkdir("com.example", 10000, 10000, 0700);
-    mkdir("com.example/foo", 10000, 10000, 0700);
-    touch("com.example/foo/file", 10000, 20000, 0300);
+    mkdir("user/0/com.example", 10000, 10000, 0700);
+    mkdir("user/0/com.example/foo", 10000, 10000, 0700);
+    touch("user/0/com.example/foo/file", 10000, 20000, 0300);
 
     std::vector<uint8_t> result;
-    std::string dexPath = get_full_path("com.example/foo/file");
+    std::string dexPath = get_full_path("user/0/com.example/foo/file");
     EXPECT_BINDER_SUCCESS(service->hashSecondaryDexFile(
         dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result));
 
@@ -414,12 +432,12 @@
 TEST_F(ServiceTest, HashSecondaryDex_WrongApp) {
     LOG(INFO) << "HashSecondaryDex_WrongApp";
 
-    mkdir("com.example", 10000, 10000, 0700);
-    mkdir("com.example/foo", 10000, 10000, 0700);
-    touch("com.example/foo/file", 10000, 20000, 0700);
+    mkdir("user/0/com.example", 10000, 10000, 0700);
+    mkdir("user/0/com.example/foo", 10000, 10000, 0700);
+    touch("user/0/com.example/foo/file", 10000, 20000, 0700);
 
     std::vector<uint8_t> result;
-    std::string dexPath = get_full_path("com.example/foo/file");
+    std::string dexPath = get_full_path("user/0/com.example/foo/file");
     EXPECT_BINDER_FAIL(service->hashSecondaryDexFile(
         dexPath, "com.wrong", 10000, testUuid, FLAG_STORAGE_CE, &result));
 }
@@ -447,7 +465,7 @@
     EXPECT_TRUE(create_cache_path(buf, "/path/to/file.apk", "isa"));
     EXPECT_EQ("/data/dalvik-cache/isa/path@to@file.apk@classes.dex", std::string(buf));
 }
-TEST_F(ServiceTest, GetAppSize) {
+TEST_F(ServiceTest, GetAppSizeManualForMedia) {
     struct stat s;
 
     std::string externalPicDir =
@@ -491,6 +509,81 @@
         system(removeCommand.c_str());
     }
 }
+TEST_F(ServiceTest, GetAppSizeProjectID_UID) {
+    struct stat s;
+    std::string externalPicDir =
+            StringPrintf("%s/Pictures", create_data_media_path(nullptr, 0).c_str());
+    if (stat(externalPicDir.c_str(), &s) == 0) {
+        // fetch the appId from the uid of the external storage owning app
+        int32_t externalStorageAppId = multiuser_get_app_id(s.st_uid);
+        // Fetch Package Name for the external storage owning app uid
+        std::string pkg = get_package_name(s.st_uid);
+
+        std::vector<int64_t> externalStorageSize, externalStorageSizeAfterAddingCacheFile;
+        std::vector<int64_t> ceDataInodes;
+
+        std::vector<std::string> codePaths;
+        std::vector<std::string> packageNames;
+        // set up parameters
+        packageNames.push_back(pkg);
+        ceDataInodes.push_back(0);
+        // initialise the mounts
+        service->invalidateMounts();
+        auto using_project_ids =
+                StringPrintf("%smisc/installd/using_project_ids", android_data_dir.c_str());
+        bool usingProjectIds = access(using_project_ids.c_str(), F_OK) == 0;
+        if (!usingProjectIds) {
+            service->setFirstBoot();
+        }
+        // call the getAppSize to get the current size of the external storage owning app
+        service->getAppSize(std::nullopt, packageNames, 0, InstalldNativeService::FLAG_USE_QUOTA,
+                            externalStorageAppId, ceDataInodes, codePaths, &externalStorageSize);
+        // add a file with 20MB size to the external storage
+        std::string externalStorageCacheDir =
+                StringPrintf("%s/%s/cache", create_data_user_ce_path(nullptr, 0).c_str(),
+                             pkg.c_str());
+        std::string cacheFileLocation =
+                StringPrintf("%s/%s", externalStorageCacheDir.c_str(), "External.jpg");
+        std::string externalFileContentCommand =
+                StringPrintf("dd if=/dev/zero of=%s bs=1M count=20", cacheFileLocation.c_str());
+        system(externalFileContentCommand.c_str());
+        // call the getAppSize again to get the new size of the external storage owning app
+        service->getAppSize(std::nullopt, packageNames, 0, InstalldNativeService::FLAG_USE_QUOTA,
+                            externalStorageAppId, ceDataInodes, codePaths,
+                            &externalStorageSizeAfterAddingCacheFile);
+        // check that the size of cache and data increases when cache file is added
+        int64_t sizeDiffData = externalStorageSizeAfterAddingCacheFile[1] - externalStorageSize[1];
+        int64_t sizeDiffCache = externalStorageSizeAfterAddingCacheFile[2] - externalStorageSize[2];
+        ASSERT_TRUE(sizeDiffData == sizeDiffCache);
+        // remove the external file
+        std::string removeCommand = StringPrintf("rm -f %s", cacheFileLocation.c_str());
+        system(removeCommand.c_str());
+        // remove the setFirstBoot setting
+        std::string removeCommand2 = "rm -f /data/misc/installd/using_project_ids";
+        system(removeCommand2.c_str());
+        // Do now without project id
+        std::vector<int64_t> sizeWithUID, sizeWithUIDAfterAddingCacheFile;
+        // call the getAppSize to get the current size of the external storage owning app
+        service->getAppSize(std::nullopt, packageNames, 0, InstalldNativeService::FLAG_USE_QUOTA,
+                            externalStorageAppId, ceDataInodes, codePaths, &sizeWithUID);
+        // add a file with 20MB size to the external storage
+        system(externalFileContentCommand.c_str());
+        // call the getAppSize again to get the new size of the external storage owning app
+        service->getAppSize(std::nullopt, packageNames, 0, InstalldNativeService::FLAG_USE_QUOTA,
+                            externalStorageAppId, ceDataInodes, codePaths,
+                            &sizeWithUIDAfterAddingCacheFile);
+        // check that the size of cache and data increases when cache file is added
+        sizeDiffData = sizeWithUIDAfterAddingCacheFile[1] - sizeWithUID[1];
+        sizeDiffCache = sizeWithUIDAfterAddingCacheFile[2] - sizeWithUID[2];
+        ASSERT_TRUE(sizeDiffData == sizeDiffCache);
+        // remove the external file
+        system(removeCommand.c_str());
+        // reset the using_project_id if it was initially set
+        if (usingProjectIds) {
+            service->setFirstBoot();
+        }
+    }
+}
 TEST_F(ServiceTest, GetAppSizeWrongSizes) {
     int32_t externalStorageAppId = -1;
     std::vector<int64_t> externalStorageSize;
@@ -951,26 +1044,42 @@
 
 class SdkSandboxDataTest : public testing::Test {
 public:
-    void CheckFileAccess(const std::string& path, uid_t uid, mode_t mode) {
+    void CheckFileAccess(const std::string& path, uid_t uid, gid_t gid, mode_t mode) {
         const auto fullPath = "/data/local/tmp/" + path;
         ASSERT_TRUE(exists(fullPath.c_str())) << "For path: " << fullPath;
         struct stat st;
         ASSERT_EQ(0, stat(fullPath.c_str(), &st));
         ASSERT_EQ(uid, st.st_uid) << "For path: " << fullPath;
-        ASSERT_EQ(uid, st.st_gid) << "For path: " << fullPath;
+        ASSERT_EQ(gid, st.st_gid) << "For path: " << fullPath;
         ASSERT_EQ(mode, st.st_mode) << "For path: " << fullPath;
     }
 
     bool exists(const char* path) { return ::access(path, F_OK) == 0; }
 
     // Creates a default CreateAppDataArgs object
-    android::os::CreateAppDataArgs createAppDataArgs() {
+    android::os::CreateAppDataArgs createAppDataArgs(const std::string& packageName) {
         android::os::CreateAppDataArgs args;
         args.uuid = kTestUuid;
-        args.packageName = "com.foo";
+        args.packageName = packageName;
         args.userId = kTestUserId;
         args.appId = kTestAppId;
         args.seInfo = "default";
+        args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
+        return args;
+    }
+
+    android::os::ReconcileSdkDataArgs reconcileSdkDataArgs(
+            const std::string& packageName, const std::vector<std::string>& subDirNames) {
+        android::os::ReconcileSdkDataArgs args;
+        args.uuid = kTestUuid;
+        args.packageName = packageName;
+        for (const auto& subDirName : subDirNames) {
+            args.subDirNames.push_back(subDirName);
+        }
+        args.userId = kTestUserId;
+        args.appId = kTestAppId;
+        args.previousAppId = -1;
+        args.seInfo = "default";
         args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;
         return args;
     }
@@ -999,58 +1108,72 @@
 
 private:
     void clearAppData() {
+        ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user", true));
         ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user_de", true));
         ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/misc_ce", true));
         ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/misc_de", true));
-        ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user_de", true));
     }
 };
 
-TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSupplementalAppData) {
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData) {
     android::os::CreateAppDataResult result;
-    android::os::CreateAppDataArgs args = createAppDataArgs();
-    args.packageName = "com.foo";
+    android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+
+    // Create the app user data.
+    ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+
+    const std::string fooCePath = "misc_ce/0/sdksandbox/com.foo";
+    CheckFileAccess(fooCePath, kSystemUid, kSystemUid, S_IFDIR | 0751);
+
+    const std::string fooDePath = "misc_de/0/sdksandbox/com.foo";
+    CheckFileAccess(fooDePath, kSystemUid, kSystemUid, S_IFDIR | 0751);
+}
+
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData_WithoutSdkFlag) {
+    android::os::CreateAppDataResult result;
+    android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
     args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;
 
     // Create the app user data.
     ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
 
-    CheckFileAccess("misc_ce/0/sdksandbox/com.foo", kSystemUid, S_IFDIR | 0751);
-    CheckFileAccess("misc_ce/0/sdksandbox/com.foo/shared", kTestSdkSandboxUid, S_IFDIR | 0700);
-    CheckFileAccess("misc_ce/0/sdksandbox/com.foo/shared/cache", kTestSdkSandboxUid,
-                    S_IFDIR | S_ISGID | 0771);
-    CheckFileAccess("misc_ce/0/sdksandbox/com.foo/shared/code_cache", kTestSdkSandboxUid,
-                    S_IFDIR | S_ISGID | 0771);
-
-    CheckFileAccess("misc_de/0/sdksandbox/com.foo", kSystemUid, S_IFDIR | 0751);
-    CheckFileAccess("misc_de/0/sdksandbox/com.foo/shared", kTestSdkSandboxUid, S_IFDIR | 0700);
-    CheckFileAccess("misc_de/0/sdksandbox/com.foo/shared/cache", kTestSdkSandboxUid,
-                    S_IFDIR | S_ISGID | 0771);
-    CheckFileAccess("misc_de/0/sdksandbox/com.foo/shared/code_cache", kTestSdkSandboxUid,
-                    S_IFDIR | S_ISGID | 0771);
+    ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+    ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
 }
 
-TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSupplementalAppData_WithoutDeFlag) {
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData_WithoutSdkFlagDeletesExisting) {
     android::os::CreateAppDataResult result;
-    android::os::CreateAppDataArgs args = createAppDataArgs();
-    args.packageName = "com.foo";
-    args.flags = FLAG_STORAGE_CE;
+    android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+    // Create the app user data.
+    ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+    ASSERT_TRUE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+    ASSERT_TRUE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
+
+    args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;
+    ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+    ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+    ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
+}
+
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData_WithoutDeFlag) {
+    android::os::CreateAppDataResult result;
+    android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+    args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_SDK;
 
     // Create the app user data.
     ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
 
     // Only CE paths should exist
-    CheckFileAccess("misc_ce/0/sdksandbox/com.foo", kSystemUid, S_IFDIR | 0751);
+    CheckFileAccess("misc_ce/0/sdksandbox/com.foo", kSystemUid, kSystemUid, S_IFDIR | 0751);
 
     // DE paths should not exist
     ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
 }
 
-TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSupplementalAppData_WithoutCeFlag) {
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData_WithoutCeFlag) {
     android::os::CreateAppDataResult result;
-    android::os::CreateAppDataArgs args = createAppDataArgs();
-    args.packageName = "com.foo";
-    args.flags = FLAG_STORAGE_DE;
+    android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+    args.flags = FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
 
     // Create the app user data.
     ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
@@ -1059,7 +1182,223 @@
     ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
 
     // Only DE paths should exist
-    CheckFileAccess("misc_de/0/sdksandbox/com.foo", kSystemUid, S_IFDIR | 0751);
+    CheckFileAccess("misc_de/0/sdksandbox/com.foo", kSystemUid, kSystemUid, S_IFDIR | 0751);
+}
+
+TEST_F(SdkSandboxDataTest, ReconcileSdkData) {
+    android::os::ReconcileSdkDataArgs args =
+            reconcileSdkDataArgs("com.foo", {"bar@random1", "baz@random2"});
+
+    // Create the sdk data.
+    ASSERT_BINDER_SUCCESS(service->reconcileSdkData(args));
+
+    const std::string barCePath = "misc_ce/0/sdksandbox/com.foo/bar@random1";
+    CheckFileAccess(barCePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | S_ISGID | 0700);
+    CheckFileAccess(barCePath + "/cache", kTestSdkSandboxUid, kTestCacheGid,
+                    S_IFDIR | S_ISGID | 0771);
+    CheckFileAccess(barCePath + "/code_cache", kTestSdkSandboxUid, kTestCacheGid,
+                    S_IFDIR | S_ISGID | 0771);
+
+    const std::string bazCePath = "misc_ce/0/sdksandbox/com.foo/baz@random2";
+    CheckFileAccess(bazCePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | S_ISGID | 0700);
+    CheckFileAccess(bazCePath + "/cache", kTestSdkSandboxUid, kTestCacheGid,
+                    S_IFDIR | S_ISGID | 0771);
+    CheckFileAccess(bazCePath + "/code_cache", kTestSdkSandboxUid, kTestCacheGid,
+                    S_IFDIR | S_ISGID | 0771);
+
+    const std::string barDePath = "misc_de/0/sdksandbox/com.foo/bar@random1";
+    CheckFileAccess(barDePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | S_ISGID | 0700);
+    CheckFileAccess(barDePath + "/cache", kTestSdkSandboxUid, kTestCacheGid,
+                    S_IFDIR | S_ISGID | 0771);
+    CheckFileAccess(barDePath + "/code_cache", kTestSdkSandboxUid, kTestCacheGid,
+                    S_IFDIR | S_ISGID | 0771);
+
+    const std::string bazDePath = "misc_de/0/sdksandbox/com.foo/baz@random2";
+    CheckFileAccess(bazDePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | S_ISGID | 0700);
+    CheckFileAccess(bazDePath + "/cache", kTestSdkSandboxUid, kTestCacheGid,
+                    S_IFDIR | S_ISGID | 0771);
+    CheckFileAccess(bazDePath + "/code_cache", kTestSdkSandboxUid, kTestCacheGid,
+                    S_IFDIR | S_ISGID | 0771);
+}
+
+TEST_F(SdkSandboxDataTest, ReconcileSdkData_ExtraCodeDirectoriesAreDeleted) {
+    android::os::ReconcileSdkDataArgs args =
+            reconcileSdkDataArgs("com.foo", {"bar@random1", "baz@random2"});
+
+    // Create the sdksandbox data.
+    ASSERT_BINDER_SUCCESS(service->reconcileSdkData(args));
+
+    // Retry with different package name
+    args.subDirNames[0] = "bar.diff@random1";
+
+    // Create the sdksandbox data again
+    ASSERT_BINDER_SUCCESS(service->reconcileSdkData(args));
+
+    // New directoris should exist
+    CheckFileAccess("misc_ce/0/sdksandbox/com.foo/bar.diff@random1", kTestSdkSandboxUid, kNobodyUid,
+                    S_IFDIR | S_ISGID | 0700);
+    CheckFileAccess("misc_ce/0/sdksandbox/com.foo/baz@random2", kTestSdkSandboxUid, kNobodyUid,
+                    S_IFDIR | S_ISGID | 0700);
+    // Directory for old unreferred sdksandbox package name should be removed
+    ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/bar@random1"));
+}
+
+class DestroyAppDataTest : public SdkSandboxDataTest {};
+
+TEST_F(DestroyAppDataTest, DestroySdkSandboxDataDirectories_WithCeAndDeFlag) {
+    android::os::CreateAppDataResult result;
+    android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+    args.packageName = "com.foo";
+    // Create the app user data.
+    ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+    // Destroy the app user data.
+    ASSERT_BINDER_SUCCESS(service->destroyAppData(args.uuid, args.packageName, args.userId,
+                                                  args.flags, result.ceDataInode));
+    ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+    ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
+}
+
+TEST_F(DestroyAppDataTest, DestroySdkSandboxDataDirectories_WithoutDeFlag) {
+    android::os::CreateAppDataResult result;
+    android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+    args.packageName = "com.foo";
+    // Create the app user data.
+    ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+    // Destroy the app user data.
+    ASSERT_BINDER_SUCCESS(service->destroyAppData(args.uuid, args.packageName, args.userId,
+                                                  FLAG_STORAGE_CE, result.ceDataInode));
+    ASSERT_TRUE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
+    ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+}
+
+TEST_F(DestroyAppDataTest, DestroySdkSandboxDataDirectories_WithoutCeFlag) {
+    android::os::CreateAppDataResult result;
+    android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+    args.packageName = "com.foo";
+    // Create the app user data.
+    ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+    // Destroy the app user data.
+    ASSERT_BINDER_SUCCESS(service->destroyAppData(args.uuid, args.packageName, args.userId,
+                                                  FLAG_STORAGE_DE, result.ceDataInode));
+    ASSERT_TRUE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+    ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
+}
+
+class ClearAppDataTest : public SdkSandboxDataTest {
+public:
+    void createTestSdkData(const std::string& packageName, std::vector<std::string> sdkNames) {
+        const auto& cePackagePath = "/data/local/tmp/misc_ce/0/sdksandbox/" + packageName;
+        const auto& dePackagePath = "/data/local/tmp/misc_de/0/sdksandbox/" + packageName;
+        ASSERT_TRUE(mkdirs(cePackagePath, 0700));
+        ASSERT_TRUE(mkdirs(dePackagePath, 0700));
+        const std::vector<std::string> packagePaths = {cePackagePath, dePackagePath};
+        for (const auto& packagePath : packagePaths) {
+            for (auto sdkName : sdkNames) {
+                ASSERT_TRUE(mkdirs(packagePath + "/" + sdkName + "/cache", 0700));
+                ASSERT_TRUE(mkdirs(packagePath + "/" + sdkName + "/code_cache", 0700));
+                std::ofstream{packagePath + "/" + sdkName + "/cache/cachedTestData.txt"};
+                std::ofstream{packagePath + "/" + sdkName + "/code_cache/cachedTestData.txt"};
+            }
+        }
+    }
+};
+
+TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithCeAndClearCacheFlag) {
+    createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
+    // Clear the app user data.
+    ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0,
+                                                FLAG_STORAGE_CE | FLAG_CLEAR_CACHE_ONLY, -1));
+
+    const std::string packagePath = kTestPath + "/misc_ce/0/sdksandbox/com.foo";
+    ASSERT_TRUE(is_empty(packagePath + "/shared/cache"));
+    ASSERT_TRUE(is_empty(packagePath + "/sdk1/cache"));
+    ASSERT_TRUE(is_empty(packagePath + "/sdk2/cache"));
+}
+
+TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithCeAndClearCodeCacheFlag) {
+    createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
+    // Clear the app user data.
+    ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0,
+                                                FLAG_STORAGE_CE | FLAG_CLEAR_CODE_CACHE_ONLY, -1));
+
+    const std::string packagePath = kTestPath + "/misc_ce/0/sdksandbox/com.foo";
+    ASSERT_TRUE(is_empty(packagePath + "/shared/code_cache"));
+    ASSERT_TRUE(is_empty(packagePath + "/sdk1/code_cache"));
+    ASSERT_TRUE(is_empty(packagePath + "/sdk2/code_cache"));
+}
+
+TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithDeAndClearCacheFlag) {
+    createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
+    // Clear the app user data
+    ASSERT_BINDER_SUCCESS(
+            service->clearAppData(kTestUuid, "com.foo", 0,
+                                  FLAG_STORAGE_DE | (InstalldNativeService::FLAG_CLEAR_CACHE_ONLY),
+                                  -1));
+
+    const std::string packagePath = kTestPath + "/misc_de/0/sdksandbox/com.foo";
+    ASSERT_TRUE(is_empty(packagePath + "/shared/cache"));
+    ASSERT_TRUE(is_empty(packagePath + "/sdk1/cache"));
+    ASSERT_TRUE(is_empty(packagePath + "/sdk2/cache"));
+}
+
+TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithDeAndClearCodeCacheFlag) {
+    createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
+    // Clear the app user data.
+    ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0,
+                                                FLAG_STORAGE_DE | FLAG_CLEAR_CODE_CACHE_ONLY, -1));
+
+    const std::string packagePath = kTestPath + "/misc_de/0/sdksandbox/com.foo";
+    ASSERT_TRUE(is_empty(packagePath + "/shared/code_cache"));
+    ASSERT_TRUE(is_empty(packagePath + "/sdk1/code_cache"));
+    ASSERT_TRUE(is_empty(packagePath + "/sdk2/code_cache"));
+}
+
+TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithCeAndWithoutAnyCacheFlag) {
+    createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
+    // Clear the app user data.
+    ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0, FLAG_STORAGE_CE, -1));
+
+    const std::string packagePath = kTestPath + "/misc_ce/0/sdksandbox/com.foo";
+    ASSERT_TRUE(is_empty(packagePath + "/shared"));
+    ASSERT_TRUE(is_empty(packagePath + "/sdk1"));
+    ASSERT_TRUE(is_empty(packagePath + "/sdk2"));
+}
+
+TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithDeAndWithoutAnyCacheFlag) {
+    createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
+    // Clear the app user data.
+    ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0, FLAG_STORAGE_DE, -1));
+
+    const std::string packagePath = kTestPath + "/misc_de/0/sdksandbox/com.foo";
+    ASSERT_TRUE(is_empty(packagePath + "/shared"));
+    ASSERT_TRUE(is_empty(packagePath + "/sdk1"));
+    ASSERT_TRUE(is_empty(packagePath + "/sdk2"));
+}
+
+class DestroyUserDataTest : public SdkSandboxDataTest {};
+
+TEST_F(DestroyUserDataTest, DestroySdkData_WithCeFlag) {
+    android::os::CreateAppDataResult result;
+    android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+    args.packageName = "com.foo";
+    // Create the app user data.
+    ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+    // Destroy user data
+    ASSERT_BINDER_SUCCESS(service->destroyUserData(args.uuid, args.userId, FLAG_STORAGE_CE));
+    ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox"));
+    ASSERT_TRUE(exists("/data/local/tmp/misc_de/0/sdksandbox"));
+}
+
+TEST_F(DestroyUserDataTest, DestroySdkData_WithDeFlag) {
+    android::os::CreateAppDataResult result;
+    android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+    args.packageName = "com.foo";
+    // Create the app user data.
+    ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+    // Destroy user data
+    ASSERT_BINDER_SUCCESS(service->destroyUserData(args.uuid, args.userId, FLAG_STORAGE_DE));
+    ASSERT_TRUE(exists("/data/local/tmp/misc_ce/0/sdksandbox"));
+    ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox"));
 }
 
 }  // namespace installd
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 17802a3..910cd63 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -21,6 +21,7 @@
 
 #include <android-base/logging.h>
 #include <android-base/scopeguard.h>
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
 #include "InstalldNativeService.h"
@@ -47,6 +48,8 @@
 namespace android {
 namespace installd {
 
+using ::testing::UnorderedElementsAre;
+
 class UtilsTest : public testing::Test {
 protected:
     virtual void SetUp() {
@@ -658,6 +661,23 @@
     ASSERT_NE(0, create_dir_if_needed("/data/local/tmp/user/0/bar/baz", 0700));
 }
 
+TEST_F(UtilsTest, TestForEachSubdir) {
+    auto deleter = [&]() {
+        delete_dir_contents_and_dir("/data/local/tmp/user/0", true /* ignore_if_missing */);
+    };
+    auto scope_guard = android::base::make_scope_guard(deleter);
+
+    system("mkdir -p /data/local/tmp/user/0/com.foo");
+    system("mkdir -p /data/local/tmp/user/0/com.bar");
+    system("touch /data/local/tmp/user/0/some-file");
+
+    std::vector<std::string> result;
+    foreach_subdir("/data/local/tmp/user/0",
+                   [&](const std::string &filename) { result.push_back(filename); });
+
+    EXPECT_THAT(result, UnorderedElementsAre("com.foo", "com.bar"));
+}
+
 TEST_F(UtilsTest, TestSdkSandboxDataPaths) {
     // Ce data paths
     EXPECT_EQ("/data/misc_ce/0/sdksandbox",
@@ -670,9 +690,11 @@
               create_data_misc_sdk_sandbox_package_path(nullptr, true, 10, "com.foo"));
 
     EXPECT_EQ("/data/misc_ce/0/sdksandbox/com.foo/shared",
-              create_data_misc_sdk_sandbox_shared_path(nullptr, true, 0, "com.foo"));
+              create_data_misc_sdk_sandbox_sdk_path(nullptr, true, 0, "com.foo", "shared"));
     EXPECT_EQ("/data/misc_ce/10/sdksandbox/com.foo/shared",
-              create_data_misc_sdk_sandbox_shared_path(nullptr, true, 10, "com.foo"));
+              create_data_misc_sdk_sandbox_sdk_path(nullptr, true, 10, "com.foo", "shared"));
+    EXPECT_EQ("/data/misc_ce/10/sdksandbox/com.foo/bar@random",
+              create_data_misc_sdk_sandbox_sdk_path(nullptr, true, 10, "com.foo", "bar@random"));
 
     // De data paths
     EXPECT_EQ("/data/misc_de/0/sdksandbox",
@@ -685,9 +707,11 @@
               create_data_misc_sdk_sandbox_package_path(nullptr, false, 10, "com.foo"));
 
     EXPECT_EQ("/data/misc_de/0/sdksandbox/com.foo/shared",
-              create_data_misc_sdk_sandbox_shared_path(nullptr, false, 0, "com.foo"));
+              create_data_misc_sdk_sandbox_sdk_path(nullptr, false, 0, "com.foo", "shared"));
     EXPECT_EQ("/data/misc_de/10/sdksandbox/com.foo/shared",
-              create_data_misc_sdk_sandbox_shared_path(nullptr, false, 10, "com.foo"));
+              create_data_misc_sdk_sandbox_sdk_path(nullptr, false, 10, "com.foo", "shared"));
+    EXPECT_EQ("/data/misc_de/10/sdksandbox/com.foo/bar@random",
+              create_data_misc_sdk_sandbox_sdk_path(nullptr, false, 10, "com.foo", "bar@random"));
 }
 
 TEST_F(UtilsTest, WaitChild) {
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 992425d..2ed971d 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -37,6 +37,7 @@
 #include <android-base/unique_fd.h>
 #include <cutils/fs.h>
 #include <cutils/properties.h>
+#include <linux/fs.h>
 #include <log/log.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_projectid_config.h>
@@ -212,7 +213,7 @@
 
 /**
  * Create the path name where code data for all codes in a particular app will be stored.
- * E.g. /data/misc_ce/0/sdksandbox/<app-name>
+ * E.g. /data/misc_ce/0/sdksandbox/<package-name>
  */
 std::string create_data_misc_sdk_sandbox_package_path(const char* volume_uuid, bool isCeData,
                                                       userid_t user, const char* package_name) {
@@ -223,15 +224,17 @@
 }
 
 /**
- * Create the path name where shared code data for a particular app will be stored.
- * E.g. /data/misc_ce/0/sdksandbox/<app-name>/shared
+ * Create the path name where sdk data for a particular sdk will be stored.
+ * E.g. /data/misc_ce/0/sdksandbox/<package-name>/com.foo@randomstrings
  */
-std::string create_data_misc_sdk_sandbox_shared_path(const char* volume_uuid, bool isCeData,
-                                                     userid_t user, const char* package_name) {
-    return StringPrintf("%s/shared",
+std::string create_data_misc_sdk_sandbox_sdk_path(const char* volume_uuid, bool isCeData,
+                                                  userid_t user, const char* package_name,
+                                                  const char* sub_dir_name) {
+    return StringPrintf("%s/%s",
                         create_data_misc_sdk_sandbox_package_path(volume_uuid, isCeData, user,
                                                                   package_name)
-                                .c_str());
+                                .c_str(),
+                        sub_dir_name);
 }
 
 std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user) {
@@ -421,7 +424,44 @@
 
     return users;
 }
+long get_project_id(uid_t uid, long start_project_id_range) {
+    return uid - AID_APP_START + start_project_id_range;
+}
 
+int set_quota_project_id(const std::string& path, long project_id, bool set_inherit) {
+    struct fsxattr fsx;
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
+    if (fd == -1) {
+        PLOG(ERROR) << "Failed to open " << path << " to set project id.";
+        return -1;
+    }
+
+    if (ioctl(fd, FS_IOC_FSGETXATTR, &fsx) == -1) {
+        PLOG(ERROR) << "Failed to get extended attributes for " << path << " to get project id.";
+        return -1;
+    }
+
+    fsx.fsx_projid = project_id;
+    if (ioctl(fd, FS_IOC_FSSETXATTR, &fsx) == -1) {
+        PLOG(ERROR) << "Failed to set project id on " << path;
+        return -1;
+    }
+    if (set_inherit) {
+        unsigned int flags;
+        if (ioctl(fd, FS_IOC_GETFLAGS, &flags) == -1) {
+            PLOG(ERROR) << "Failed to get flags for " << path << " to set project id inheritance.";
+            return -1;
+        }
+
+        flags |= FS_PROJINHERIT_FL;
+
+        if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == -1) {
+            PLOG(ERROR) << "Failed to set flags for " << path << " to set project id inheritance.";
+            return -1;
+        }
+    }
+    return 0;
+}
 int calculate_tree_size(const std::string& path, int64_t* size,
         int32_t include_gid, int32_t exclude_gid, bool exclude_apps) {
     FTS *fts;
@@ -696,6 +736,34 @@
     return std::unique_ptr<DIR, DirCloser>(::opendir(dir));
 }
 
+// Collects filename of subdirectories of given directory and passes it to the function
+int foreach_subdir(const std::string& pathname, const std::function<void(const std::string&)> fn) {
+    auto dir = open_dir(pathname.c_str());
+    if (!dir) return -1;
+
+    int dfd = dirfd(dir.get());
+    if (dfd < 0) {
+        ALOGE("Couldn't dirfd %s: %s\n", pathname.c_str(), strerror(errno));
+        return -1;
+    }
+
+    struct dirent* de;
+    while ((de = readdir(dir.get()))) {
+        if (de->d_type != DT_DIR) {
+            continue;
+        }
+
+        std::string name{de->d_name};
+        // always skip "." and ".."
+        if (name == "." || name == "..") {
+            continue;
+        }
+        fn(name);
+    }
+
+    return 0;
+}
+
 void cleanup_invalid_package_dirs_under_path(const std::string& pathname) {
     auto dir = open_dir(pathname.c_str());
     if (!dir) {
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 4b56f99..ecea1d2 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -32,6 +32,7 @@
 
 #define MEASURE_DEBUG 0
 #define FIXUP_DEBUG 0
+#define SDK_DEBUG 1
 
 #define BYPASS_QUOTA 0
 #define BYPASS_SDCARDFS 0
@@ -64,8 +65,9 @@
                                               userid_t userid);
 std::string create_data_misc_sdk_sandbox_package_path(const char* volume_uuid, bool isCeData,
                                                       userid_t userid, const char* package_name);
-std::string create_data_misc_sdk_sandbox_shared_path(const char* volume_uuid, bool isCeData,
-                                                     userid_t userid, const char* package_name);
+std::string create_data_misc_sdk_sandbox_sdk_path(const char* volume_uuid, bool isCeData,
+                                                  userid_t userid, const char* package_name,
+                                                  const char* sub_dir_name);
 
 std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user);
 std::string create_data_misc_de_rollback_base_path(const char* volume_uuid, userid_t user);
@@ -130,6 +132,8 @@
 bool is_renamed_deleted_dir(const std::string& path);
 int rename_delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing = true);
 
+int foreach_subdir(const std::string& pathname, std::function<void(const std::string&)> fn);
+
 void cleanup_invalid_package_dirs_under_path(const std::string& pathname);
 
 int delete_dir_contents(const char *pathname,
@@ -167,6 +171,8 @@
         uid_t uid, gid_t gid);
 
 bool supports_sdcardfs();
+long get_project_id(uid_t uid, long start_project_id_range);
+int set_quota_project_id(const std::string& path, long project_id, bool set_inherit);
 int64_t get_occupied_app_space_external(const std::string& uuid, int32_t userId, int32_t appId);
 int64_t get_occupied_app_cache_space_external(const std::string& uuid, int32_t userId, int32_t appId);
 
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 555be1e..3cfe529 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -295,28 +295,27 @@
 Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) {
     auto ctx = mAccess->getCallingContext();
 
-    // apps cannot add services
     if (multiuser_get_app_id(ctx.uid) >= AID_APP) {
-        return Status::fromExceptionCode(Status::EX_SECURITY);
+        return Status::fromExceptionCode(Status::EX_SECURITY, "App UIDs cannot add services");
     }
 
     if (!mAccess->canAdd(ctx, name)) {
-        return Status::fromExceptionCode(Status::EX_SECURITY);
+        return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denial");
     }
 
     if (binder == nullptr) {
-        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Null binder");
     }
 
     if (!isValidServiceName(name)) {
         LOG(ERROR) << "Invalid service name: " << name;
-        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Invalid service name");
     }
 
 #ifndef VENDORSERVICEMANAGER
     if (!meetsDeclarationRequirements(binder, name)) {
         // already logged
-        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "VINTF declaration error");
     }
 #endif  // !VENDORSERVICEMANAGER
 
@@ -324,7 +323,7 @@
     if (binder->remoteBinder() != nullptr &&
         binder->linkToDeath(sp<ServiceManager>::fromExisting(this)) != OK) {
         LOG(ERROR) << "Could not linkToDeath when adding " << name;
-        return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "linkToDeath failure");
     }
 
     // Overwrite the old service if it exists
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 467e51e..5d6206d 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -1086,7 +1086,7 @@
     {
         $( #[$attr:meta] )*
         $enum:ident : [$backing:ty; $size:expr] {
-            $( $name:ident = $value:expr, )*
+            $( $( #[$value_attr:meta] )* $name:ident = $value:expr, )*
         }
     } => {
         $( #[$attr] )*
@@ -1094,7 +1094,7 @@
         #[allow(missing_docs)]
         pub struct $enum(pub $backing);
         impl $enum {
-            $( #[allow(missing_docs)] pub const $name: Self = Self($value); )*
+            $( $( #[$value_attr] )* #[allow(missing_docs)] pub const $name: Self = Self($value); )*
 
             #[inline(always)]
             #[allow(missing_docs)]
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index ec67312..0b9ba05 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -714,7 +714,7 @@
 
     bool wide_color_support = false;
     uint64_t consumer_usage = 0;
-    bool swapchain_ext =
+    bool colorspace_ext =
         instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
     if (surface_handle == VK_NULL_HANDLE) {
         ProcHook::Extension surfaceless = ProcHook::GOOGLE_surfaceless_query;
@@ -743,7 +743,7 @@
 
         consumer_usage = surface.consumer_usage;
     }
-    wide_color_support = wide_color_support && swapchain_ext;
+    wide_color_support = wide_color_support && colorspace_ext;
 
     AHardwareBuffer_Desc desc = {};
     desc.width = 1;
@@ -757,6 +757,11 @@
         {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
         {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}};
 
+    if (colorspace_ext) {
+        all_formats.emplace_back(VkSurfaceFormatKHR{
+            VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_BT709_LINEAR_EXT});
+    }
+
     if (wide_color_support) {
         all_formats.emplace_back(VkSurfaceFormatKHR{
             VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT});