Merge "dumpstate: handle errors gracefully"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 53b3a00..39b3aac 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -192,10 +192,12 @@
         { REQ,      "events/cpufreq_interactive/enable" },
     } },
     { "sync",       "Synchronization",  0, {
-        // before linux kernel 4.9
+        // linux kernel < 4.9
         { OPT,      "events/sync/enable" },
-        // starting in linux kernel 4.9
+        // linux kernel == 4.9.x
         { OPT,      "events/fence/enable" },
+        // linux kernel > 4.9
+        { OPT,      "events/dma_fence/enable" },
     } },
     { "workq",      "Kernel Workqueues", 0, {
         { REQ,      "events/workqueue/enable" },
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index a282424..66c9cc6 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -91,6 +91,8 @@
     chmod 0666 /sys/kernel/tracing/events/sync/enable
     chmod 0666 /sys/kernel/debug/tracing/events/fence/enable
     chmod 0666 /sys/kernel/tracing/events/fence/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/dma_fence/enable
+    chmod 0666 /sys/kernel/tracing/events/dma_fence/enable
     chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/enable
     chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/enable
     chmod 0666 /sys/kernel/debug/tracing/events/kmem/ion_heap_grow/enable
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index 768cb4f..ddae9ea 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -127,7 +127,7 @@
     if (ds_ != nullptr) {
         MYLOGE("Error! There is already a bugreport in progress. Returning.");
         if (listener != nullptr) {
-            listener->onError(IDumpstateListener::BUGREPORT_ERROR_CONCURRENT_BUGREPORTS_FORBIDDEN);
+            listener->onError(IDumpstateListener::BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS);
         }
         return exception(binder::Status::EX_SERVICE_SPECIFIC,
                          "There is already a bugreport in progress");
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
index 42858e0..ea1e467 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
@@ -50,7 +50,7 @@
     const int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4;
 
     /* There is currently a bugreport running. The caller should try again later. */
-    const int BUGREPORT_ERROR_CONCURRENT_BUGREPORTS_FORBIDDEN = 5;
+    const int BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS = 5;
 
     /**
      * Called on an error condition with one of the error codes listed above.
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 555badd..fc3642c 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -475,7 +475,7 @@
     EXPECT_FALSE(status.isOk());
     WaitTillExecutionComplete(listener2.get());
     EXPECT_EQ(listener2->getErrorCode(),
-              IDumpstateListener::BUGREPORT_ERROR_CONCURRENT_BUGREPORTS_FORBIDDEN);
+              IDumpstateListener::BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS);
 
     // Meanwhile the first call works as expected. Service should not die in this case.
     WaitTillExecutionComplete(listener1.get());
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 68d514b..2a5516d 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -108,6 +108,8 @@
         if (log_only_) {
             MYLOGD("Duration of '%s': %.3fs\n", title_.c_str(), (float)elapsed / NANOS_PER_SEC);
         } else {
+            // TODO(124089395): Remove or rewrite when bugreport latency is fixed.
+            MYLOGD("Duration of '%s': %.3fs\n", title_.c_str(), (float)elapsed / NANOS_PER_SEC);
             // Use "Yoda grammar" to make it easier to grep|sort sections.
             printf("------ %.3fs was the duration of '%s' ------\n", (float)elapsed / NANOS_PER_SEC,
                    title_.c_str());
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 9d3a234..c5a8f49 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -34,6 +34,7 @@
         "libprocessgroup",
         "libselinux",
         "libutils",
+        "server_configurable_flags",
     ],
 
     product_variables: {
@@ -225,6 +226,7 @@
         "libprocessgroup",
         "libselinux",
         "libutils",
+        "server_configurable_flags",
     ],
 }
 
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index ccffd29..a51946d 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -39,6 +39,7 @@
 #include <sys/xattr.h>
 #include <unistd.h>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
 #include <android-base/scopeguard.h>
@@ -80,6 +81,8 @@
 // An uuid used in unit tests.
 static constexpr const char* kTestUuid = "TEST";
 
+static constexpr const mode_t kRollbackFolderMode = 0700;
+
 static constexpr const char* kCpPath = "/system/bin/cp";
 static constexpr const char* kXattrDefault = "user.default";
 
@@ -784,8 +787,8 @@
 
 binder::Status InstalldNativeService::snapshotAppData(
         const std::unique_ptr<std::string>& volumeUuid,
-        const std::string& packageName, int32_t user, int32_t storageFlags,
-        int64_t* _aidl_return) {
+        const std::string& packageName, int32_t user, int32_t snapshotId,
+        int32_t storageFlags, int64_t* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
@@ -802,16 +805,19 @@
     bool clear_ce_on_exit = false;
     bool clear_de_on_exit = false;
 
-    auto deleter = [&clear_ce_on_exit, &clear_de_on_exit, &volume_uuid, &user, &package_name] {
+    auto deleter = [&clear_ce_on_exit, &clear_de_on_exit, &volume_uuid, &user, &package_name,
+            &snapshotId] {
         if (clear_de_on_exit) {
-            auto to = create_data_misc_de_rollback_package_path(volume_uuid, user, package_name);
+            auto to = create_data_misc_de_rollback_package_path(volume_uuid, user, snapshotId,
+                    package_name);
             if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
                 LOG(WARNING) << "Failed to delete app data snapshot: " << to;
             }
         }
 
         if (clear_ce_on_exit) {
-            auto to = create_data_misc_ce_rollback_package_path(volume_uuid, user, package_name);
+            auto to = create_data_misc_ce_rollback_package_path(volume_uuid, user, snapshotId,
+                    package_name);
             if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
                 LOG(WARNING) << "Failed to delete app data snapshot: " << to;
             }
@@ -847,15 +853,21 @@
 
     if (storageFlags & FLAG_STORAGE_DE) {
         auto from = create_data_user_de_package_path(volume_uuid, user, package_name);
-        auto to = create_data_misc_de_rollback_path(volume_uuid, user);
+        auto to = create_data_misc_de_rollback_path(volume_uuid, user, snapshotId);
+        auto rollback_package_path = create_data_misc_de_rollback_package_path(volume_uuid, user,
+            snapshotId, package_name);
 
-        int rd = delete_dir_contents(to, true /* ignore_if_missing */);
-        if (rd != 0) {
-            res = error(rd, "Failed clearing existing snapshot " + to);
-            return res;
+        int rc = create_dir_if_needed(to.c_str(), kRollbackFolderMode);
+        if (rc != 0) {
+            return error(rc, "Failed to create folder " + to);
         }
 
-        int rc = copy_directory_recursive(from.c_str(), to.c_str());
+        rc = delete_dir_contents(rollback_package_path, true /* ignore_if_missing */);
+        if (rc != 0) {
+            return error(rc, "Failed clearing existing snapshot " + rollback_package_path);
+        }
+
+        rc = copy_directory_recursive(from.c_str(), to.c_str());
         if (rc != 0) {
             res = error(rc, "Failed copying " + from + " to " + to);
             clear_de_on_exit = true;
@@ -865,15 +877,21 @@
 
     if (storageFlags & FLAG_STORAGE_CE) {
         auto from = create_data_user_ce_package_path(volume_uuid, user, package_name);
-        auto to = create_data_misc_ce_rollback_path(volume_uuid, user);
+        auto to = create_data_misc_ce_rollback_path(volume_uuid, user, snapshotId);
+        auto rollback_package_path = create_data_misc_ce_rollback_package_path(volume_uuid, user,
+            snapshotId, package_name);
 
-        int rd = delete_dir_contents(to, true /* ignore_if_missing */);
-        if (rd != 0) {
-            res = error(rd, "Failed clearing existing snapshot " + to);
-            return res;
+        int rc = create_dir_if_needed(to.c_str(), kRollbackFolderMode);
+        if (rc != 0) {
+            return error(rc, "Failed to create folder " + to);
         }
 
-        int rc = copy_directory_recursive(from.c_str(), to.c_str());
+        rc = delete_dir_contents(rollback_package_path, true /* ignore_if_missing */);
+        if (rc != 0) {
+            return error(rc, "Failed clearing existing snapshot " + rollback_package_path);
+        }
+
+        rc = copy_directory_recursive(from.c_str(), to.c_str());
         if (rc != 0) {
             res = error(rc, "Failed copying " + from + " to " + to);
             clear_ce_on_exit = true;
@@ -881,7 +899,7 @@
         }
         if (_aidl_return != nullptr) {
             auto ce_snapshot_path = create_data_misc_ce_rollback_package_path(volume_uuid, user,
-                    package_name);
+                    snapshotId, package_name);
             rc = get_path_inode(ce_snapshot_path, reinterpret_cast<ino_t*>(_aidl_return));
             if (rc != 0) {
                 res = error(rc, "Failed to get_path_inode for " + ce_snapshot_path);
@@ -896,8 +914,8 @@
 
 binder::Status InstalldNativeService::restoreAppDataSnapshot(
         const std::unique_ptr<std::string>& volumeUuid, const std::string& packageName,
-        const int32_t appId, const int64_t ceDataInode, const std::string& seInfo,
-        const int32_t user, int32_t storageFlags) {
+        const int32_t appId, const std::string& seInfo, const int32_t user,
+        const int32_t snapshotId, int32_t storageFlags) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
@@ -907,9 +925,9 @@
     const char* package_name = packageName.c_str();
 
     auto from_ce = create_data_misc_ce_rollback_package_path(volume_uuid,
-            user, package_name);
+            user, snapshotId, package_name);
     auto from_de = create_data_misc_de_rollback_package_path(volume_uuid,
-            user, package_name);
+            user, snapshotId, package_name);
 
     const bool needs_ce_rollback = (storageFlags & FLAG_STORAGE_CE) &&
         (access(from_ce.c_str(), F_OK) == 0);
@@ -926,7 +944,11 @@
     // app with no data in those cases is arguably better than leaving the app
     // with mismatched / stale data.
     LOG(INFO) << "Clearing app data for " << packageName << " to restore snapshot.";
-    binder::Status res = clearAppData(volumeUuid, packageName, user, storageFlags, ceDataInode);
+    // It's fine to pass 0 as ceDataInode here, because restoreAppDataSnapshot
+    // can only be called when user unlocks the phone, meaning that CE user data
+    // is decrypted.
+    binder::Status res = clearAppData(volumeUuid, packageName, user, storageFlags,
+            0 /* ceDataInode */);
     if (!res.isOk()) {
         return res;
     }
@@ -962,7 +984,8 @@
 
 binder::Status InstalldNativeService::destroyAppDataSnapshot(
         const std::unique_ptr<std::string> &volumeUuid, const std::string& packageName,
-        const int32_t user, const int64_t ceSnapshotInode, int32_t storageFlags) {
+        const int32_t user, const int64_t ceSnapshotInode, const int32_t snapshotId,
+        int32_t storageFlags) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
@@ -973,7 +996,7 @@
 
     if (storageFlags & FLAG_STORAGE_DE) {
         auto de_snapshot_path = create_data_misc_de_rollback_package_path(volume_uuid,
-                user, package_name);
+                user, snapshotId, package_name);
 
         int res = delete_dir_contents_and_dir(de_snapshot_path, true /* ignore_if_missing */);
         if (res != 0) {
@@ -983,7 +1006,7 @@
 
     if (storageFlags & FLAG_STORAGE_CE) {
         auto ce_snapshot_path = create_data_misc_ce_rollback_package_path(volume_uuid,
-                user, package_name, ceSnapshotInode);
+                user, snapshotId, package_name, ceSnapshotInode);
         int res = delete_dir_contents_and_dir(ce_snapshot_path, true /* ignore_if_missing */);
         if (res != 0) {
             return error(res, "Failed clearing snapshot " + ce_snapshot_path);
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 578132d..0e91cb2 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -61,14 +61,14 @@
     binder::Status fixupAppData(const std::unique_ptr<std::string>& uuid, int32_t flags);
 
     binder::Status snapshotAppData(const std::unique_ptr<std::string>& volumeUuid,
-            const std::string& packageName, const int32_t user, int32_t storageFlags,
-            int64_t* _aidl_return);
+            const std::string& packageName, const int32_t user, const int32_t snapshotId,
+            int32_t storageFlags, int64_t* _aidl_return);
     binder::Status restoreAppDataSnapshot(const std::unique_ptr<std::string>& volumeUuid,
-            const std::string& packageName, const int32_t appId, const int64_t ceDataInode,
-            const std::string& seInfo, const int32_t user, int32_t storageFlags);
+            const std::string& packageName, const int32_t appId, const std::string& seInfo,
+            const int32_t user, const int32_t snapshotId, int32_t storageFlags);
     binder::Status destroyAppDataSnapshot(const std::unique_ptr<std::string> &volumeUuid,
             const std::string& packageName, const int32_t user, const int64_t ceSnapshotInode,
-            int32_t storageFlags);
+            const int32_t snapshotId, int32_t storageFlags);
 
     binder::Status getAppSize(const std::unique_ptr<std::string>& uuid,
             const std::vector<std::string>& packageNames, int32_t userId, int32_t flags,
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 377074a..51fe66b 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -106,11 +106,11 @@
         @nullable @utf8InCpp String dexMetadata);
 
     long snapshotAppData(@nullable @utf8InCpp String uuid, in @utf8InCpp String packageName,
-            int userId, int storageFlags);
+            int userId, int snapshotId, int storageFlags);
     void restoreAppDataSnapshot(@nullable @utf8InCpp String uuid, in @utf8InCpp String packageName,
-            int appId, long ceDataInode, @utf8InCpp String seInfo, int user, int storageflags);
+            int appId, @utf8InCpp String seInfo, int user, int snapshotId, int storageflags);
     void destroyAppDataSnapshot(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
-            int userId, long ceSnapshotInode, int storageFlags);
+            int userId, long ceSnapshotInode, int snapshotId, int storageFlags);
 
     const int FLAG_STORAGE_DE = 0x1;
     const int FLAG_STORAGE_CE = 0x2;
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index acc0647..ffd1191 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -45,6 +45,7 @@
 #include <private/android_filesystem_config.h>
 #include <processgroup/sched_policy.h>
 #include <selinux/android.h>
+#include <server_configurable_flags/get_flags.h>
 #include <system/thread_defs.h>
 
 #include "dexopt.h"
@@ -260,6 +261,47 @@
   return "";
 }
 
+// Determines which binary we should use for execution (the debug or non-debug version).
+// e.g. dex2oatd vs dex2oat
+static const char* select_execution_binary(const char* binary, const char* debug_binary,
+        bool background_job_compile) {
+    return select_execution_binary(
+        binary,
+        debug_binary,
+        background_job_compile,
+        is_debug_runtime(),
+        (android::base::GetProperty("ro.build.version.codename", "") == "REL"),
+        is_debuggable_build());
+}
+
+// Determines which binary we should use for execution (the debug or non-debug version).
+// e.g. dex2oatd vs dex2oat
+// This is convenient method which is much easier to test because it doesn't read
+// system properties.
+const char* select_execution_binary(
+        const char* binary,
+        const char* debug_binary,
+        bool background_job_compile,
+        bool is_debug_runtime,
+        bool is_release,
+        bool is_debuggable_build) {
+    // Do not use debug binaries for release candidates (to give more soak time).
+    bool is_debug_bg_job = background_job_compile && is_debuggable_build && !is_release;
+
+    // If the runtime was requested to use libartd.so, we'll run the debug version - assuming
+    // the file is present (it may not be on images with very little space available).
+    bool useDebug = (is_debug_runtime || is_debug_bg_job) && (access(debug_binary, X_OK) == 0);
+
+    return useDebug ? debug_binary : binary;
+}
+
+// Namespace for Android Runtime flags applied during boot time.
+static const char* RUNTIME_NATIVE_BOOT_NAMESPACE = "runtime_native_boot";
+// Feature flag name for running the JIT in Zygote experiment, b/119800099.
+static const char* ENABLE_APEX_IMAGE = "enable_apex_image";
+// Location of the apex image.
+static const char* kApexImage = "/system/framework/apex.art";
+
 class RunDex2Oat : public ExecVHelper {
   public:
     RunDex2Oat(int zip_fd,
@@ -293,6 +335,14 @@
                 : "dalvik.vm.boot-dex2oat-threads";
         std::string dex2oat_threads_arg = MapPropertyToArg(threads_property, "-j%s");
 
+        std::string bootclasspath;
+        char* dex2oat_bootclasspath = getenv("DEX2OATBOOTCLASSPATH");
+        if (dex2oat_bootclasspath != nullptr) {
+            bootclasspath = StringPrintf("-Xbootclasspath:%s", dex2oat_bootclasspath);
+        }
+        // If DEX2OATBOOTCLASSPATH is not in the environment, dex2oat is going to query
+        // BOOTCLASSPATH.
+
         const std::string dex2oat_isa_features_key =
                 StringPrintf("dalvik.vm.isa.%s.features", instruction_set);
         std::string instruction_set_features_arg =
@@ -338,21 +388,23 @@
         std::string dex2oat_large_app_threshold_arg =
             MapPropertyToArg("dalvik.vm.dex2oat-very-large", "--very-large-app-threshold=%s");
 
-        // If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat.
-        const char* dex2oat_bin = kDex2oatPath;
-        // Do not use dex2oatd for release candidates (give dex2oat more soak time).
-        bool is_release = android::base::GetProperty("ro.build.version.codename", "") == "REL";
-        if (is_debug_runtime() ||
-                (background_job_compile && is_debuggable_build() && !is_release)) {
-            if (access(kDex2oatDebugPath, X_OK) == 0) {
-                dex2oat_bin = kDex2oatDebugPath;
-            }
-        }
+
+        const char* dex2oat_bin = select_execution_binary(
+            kDex2oatPath, kDex2oatDebugPath, background_job_compile);
 
         bool generate_minidebug_info = kEnableMinidebugInfo &&
                 GetBoolProperty(kMinidebugInfoSystemProperty, kMinidebugInfoSystemPropertyDefault);
 
-        std::string boot_image = MapPropertyToArg("dalvik.vm.boot-image", "-Ximage:%s");
+        std::string boot_image;
+        std::string use_apex_image =
+            server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,
+                                                                 ENABLE_APEX_IMAGE,
+                                                                 /*default_value=*/ "");
+        if (use_apex_image == "true") {
+          boot_image = StringPrintf("-Ximage:%s", kApexImage);
+        } else {
+          boot_image = MapPropertyToArg("dalvik.vm.boot-image", "-Ximage:%s");
+        }
 
         // clang FORTIFY doesn't let us use strlen in constant array bounds, so we
         // use arraysize instead.
@@ -440,6 +492,7 @@
         AddArg(instruction_set_features_arg);
 
         AddRuntimeArg(boot_image);
+        AddRuntimeArg(bootclasspath);
         AddRuntimeArg(dex2oat_Xms_arg);
         AddRuntimeArg(dex2oat_Xmx_arg);
 
@@ -650,7 +703,12 @@
                   const std::vector<std::string>& dex_locations,
                   bool copy_and_update,
                   bool store_aggregation_counters) {
-        const char* profman_bin = is_debug_runtime() ? kProfmanDebugPath: kProfmanPath;
+
+        // TODO(calin): Assume for now we run in the bg compile job (which is in
+        // most of the invocation). With the current data flow, is not very easy or
+        // clean to discover this in RunProfman (it will require quite a messy refactoring).
+        const char* profman_bin = select_execution_binary(
+            kProfmanPath, kProfmanDebugPath, /*background_job_compile=*/ true);
 
         if (copy_and_update) {
             CHECK_EQ(1u, profile_fds.size());
@@ -1465,8 +1523,10 @@
                     bool downgrade,
                     const char* class_loader_context) {
         CHECK_GE(zip_fd, 0);
-        const char* dexoptanalyzer_bin =
-            is_debug_runtime() ? kDexoptanalyzerDebugPath : kDexoptanalyzerPath;
+
+        // We always run the analyzer in the background job.
+        const char* dexoptanalyzer_bin = select_execution_binary(
+             kDexoptanalyzerPath, kDexoptanalyzerDebugPath, /*background_job_compile=*/ true);
 
         std::string dex_file_arg = "--dex-file=" + dex_file;
         std::string oat_fd_arg = "--oat-fd=" + std::to_string(oat_fd);
@@ -1961,11 +2021,6 @@
         /* child -- drop privileges before continuing */
         drop_capabilities(uid);
 
-        // Clear BOOTCLASSPATH.
-        // Let dex2oat use the BCP from boot image, excluding updatable BCP
-        // modules for AOT to avoid app recompilation after their upgrades.
-        unsetenv("BOOTCLASSPATH");
-
         SetDex2OatScheduling(boot_complete);
         if (flock(out_oat_fd.get(), LOCK_EX | LOCK_NB) != 0) {
             PLOG(ERROR) << "flock(" << out_oat_path << ") failed";
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 5902659..a8c48c5 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -36,7 +36,7 @@
 // Location of binaries in the Android Runtime APEX.
 static constexpr const char* kDex2oatPath = ANDROID_RUNTIME_APEX_BIN "/dex2oat";
 static constexpr const char* kDex2oatDebugPath = ANDROID_RUNTIME_APEX_BIN "/dex2oatd";
-static constexpr const char* kProfmanPath = ANDROID_RUNTIME_APEX_BIN "/profmand";
+static constexpr const char* kProfmanPath = ANDROID_RUNTIME_APEX_BIN "/profman";
 static constexpr const char* kProfmanDebugPath = ANDROID_RUNTIME_APEX_BIN "/profmand";
 static constexpr const char* kDexoptanalyzerPath = ANDROID_RUNTIME_APEX_BIN "/dexoptanalyzer";
 static constexpr const char* kDexoptanalyzerDebugPath = ANDROID_RUNTIME_APEX_BIN "/dexoptanalyzerd";
@@ -128,6 +128,14 @@
 
 bool move_ab(const char* apk_path, const char* instruction_set, const char* output_path);
 
+const char* select_execution_binary(
+        const char* binary,
+        const char* debug_binary,
+        bool background_job_compile,
+        bool is_debug_runtime,
+        bool is_release,
+        bool is_debuggable_build);
+
 }  // namespace installd
 }  // namespace android
 
diff --git a/cmds/installd/globals.cpp b/cmds/installd/globals.cpp
index b3a6daf..f52c2e7 100644
--- a/cmds/installd/globals.cpp
+++ b/cmds/installd/globals.cpp
@@ -44,6 +44,8 @@
 static constexpr const char* PRIVATE_APP_SUBDIR = "app-private/"; // sub-directory under
                                                                   // ANDROID_DATA
 
+static constexpr const char* STAGING_SUBDIR = "pkg_staging/"; // sub-directory under ANDROID_DATA
+
 std::string android_app_dir;
 std::string android_app_ephemeral_dir;
 std::string android_app_lib_dir;
@@ -54,6 +56,7 @@
 std::string android_mnt_expand_dir;
 std::string android_profiles_dir;
 std::string android_root_dir;
+std::string android_staging_dir;
 
 std::vector<std::string> android_system_dirs;
 
@@ -110,6 +113,9 @@
     // Get the android profiles directory.
     android_profiles_dir = android_data_dir + PROFILES_SUBDIR;
 
+    // Get the android session staging directory.
+    android_staging_dir = android_data_dir + STAGING_SUBDIR;
+
     // Take note of the system and vendor directories.
     android_system_dirs.clear();
     android_system_dirs.push_back(android_root_dir + APP_SUBDIR);
diff --git a/cmds/installd/globals.h b/cmds/installd/globals.h
index 633e33b..a88a86e 100644
--- a/cmds/installd/globals.h
+++ b/cmds/installd/globals.h
@@ -38,6 +38,7 @@
 extern std::string android_mnt_expand_dir;
 extern std::string android_profiles_dir;
 extern std::string android_root_dir;
+extern std::string android_staging_dir;
 
 extern std::vector<std::string> android_system_dirs;
 
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 9c9db0f..1ed49a0 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -31,6 +31,7 @@
         "libprocessgroup",
         "libselinux",
         "libutils",
+        "server_configurable_flags",
     ],
     static_libs: [
         "libdiskusage",
@@ -54,6 +55,7 @@
         "libprocessgroup",
         "libselinux",
         "libutils",
+        "server_configurable_flags",
     ],
     static_libs: [
         "libdiskusage",
@@ -77,6 +79,7 @@
         "libprocessgroup",
         "libselinux",
         "libutils",
+        "server_configurable_flags",
     ],
     static_libs: [
         "libdiskusage",
@@ -96,6 +99,7 @@
         "libbase",
         "libcutils",
         "libutils",
+        "server_configurable_flags",
     ],
     static_libs: [
         "liblog",
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 78edce0..71b710b 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -1175,5 +1175,64 @@
     ASSERT_TRUE(std::find(profiles.begin(), profiles.end(), ref_prof) != profiles.end());
 }
 
+TEST_F(DexoptTest, select_execution_binary) {
+    LOG(INFO) << "DexoptTestselect_execution_binary";
+
+    std::string release_str = app_private_dir_ce_  + "/release";
+    std::string debug_str = app_private_dir_ce_  + "/debug";
+
+    // Setup the binaries. Note that we only need executable files to actually
+    // test the execution binary selection
+    run_cmd("touch " + release_str);
+    run_cmd("touch " + debug_str);
+    run_cmd("chmod 777 " + release_str);
+    run_cmd("chmod 777 " + debug_str);
+
+    const char* release = release_str.c_str();
+    const char* debug = debug_str.c_str();
+
+    ASSERT_STREQ(release, select_execution_binary(
+        release,
+        debug,
+        /*background_job_compile=*/ false,
+        /*is_debug_runtime=*/ false,
+        /*is_release=*/ false,
+        /*is_debuggable_build=*/ false));
+
+    ASSERT_STREQ(release, select_execution_binary(
+        release,
+        debug,
+        /*background_job_compile=*/ true,
+        /*is_debug_runtime=*/ false,
+        /*is_release=*/ true,
+        /*is_debuggable_build=*/ true));
+
+    ASSERT_STREQ(debug, select_execution_binary(
+        release,
+        debug,
+        /*background_job_compile=*/ false,
+        /*is_debug_runtime=*/ true,
+        /*is_release=*/ false,
+        /*is_debuggable_build=*/ false));
+
+    ASSERT_STREQ(debug, select_execution_binary(
+        release,
+        debug,
+        /*background_job_compile=*/ true,
+        /*is_debug_runtime=*/ false,
+        /*is_release=*/ false,
+        /*is_debuggable_build=*/ true));
+
+
+    // Select the release when the debug file is not there.
+    ASSERT_STREQ(release, select_execution_binary(
+        release,
+        "does_not_exist",
+        /*background_job_compile=*/ false,
+        /*is_debug_runtime=*/ true,
+        /*is_release=*/ false,
+        /*is_debuggable_build=*/ false));
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index ed1a0f4..cd63931 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -259,32 +259,59 @@
         return false;
     }
 
-    return (::mkdir(path.c_str(), mode) != -1);
+    if (::mkdir(path.c_str(), mode) != 0) {
+        PLOG(DEBUG) << "Failed to create folder " << path;
+        return false;
+    }
+    return true;
 }
 
-TEST_F(ServiceTest, CreateAppDataSnapshot) {
-  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
-  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+class AppDataSnapshotTest : public testing::Test {
+private:
+    std::string rollback_ce_base_dir;
+    std::string rollback_de_base_dir;
 
-  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
-  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
+protected:
+    InstalldNativeService* service;
 
-  auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
-  auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
+    std::string fake_package_ce_path;
+    std::string fake_package_de_path;
 
-  ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
-  ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
+    virtual void SetUp() {
+        setenv("ANDROID_LOG_TAGS", "*:v", 1);
+        android::base::InitLogging(nullptr);
 
-  auto deleter = [&rollback_ce_dir, &rollback_de_dir,
-          &fake_package_ce_path, &fake_package_de_path]() {
-      delete_dir_contents(rollback_ce_dir, true);
-      delete_dir_contents(rollback_de_dir, true);
-      delete_dir_contents(fake_package_ce_path, true);
-      delete_dir_contents(fake_package_de_path, true);
-      rmdir(rollback_ce_dir.c_str());
-      rmdir(rollback_de_dir.c_str());
-  };
-  auto scope_guard = android::base::make_scope_guard(deleter);
+        service = new InstalldNativeService();
+        ASSERT_TRUE(mkdirs("/data/local/tmp/user/0", 0700));
+
+        init_globals_from_data_and_root();
+
+        rollback_ce_base_dir = create_data_misc_ce_rollback_base_path("TEST", 0);
+        rollback_de_base_dir = create_data_misc_de_rollback_base_path("TEST", 0);
+
+        fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
+        fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
+
+        ASSERT_TRUE(mkdirs(rollback_ce_base_dir, 0700));
+        ASSERT_TRUE(mkdirs(rollback_de_base_dir, 0700));
+        ASSERT_TRUE(mkdirs(fake_package_ce_path, 0700));
+        ASSERT_TRUE(mkdirs(fake_package_de_path, 0700));
+    }
+
+    virtual void TearDown() {
+        ASSERT_EQ(0, delete_dir_contents_and_dir(rollback_ce_base_dir, true));
+        ASSERT_EQ(0, delete_dir_contents_and_dir(rollback_de_base_dir, true));
+        ASSERT_EQ(0, delete_dir_contents(fake_package_ce_path, true));
+        ASSERT_EQ(0, delete_dir_contents(fake_package_de_path, true));
+
+        delete service;
+        ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user/0", true));
+    }
+};
+
+TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 37);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 37);
 
   ASSERT_TRUE(android::base::WriteStringToFile(
           "TEST_CONTENT_CE", fake_package_ce_path + "/file1",
@@ -296,7 +323,7 @@
   // Request a snapshot of the CE content but not the DE content.
   int64_t ce_snapshot_inode;
   ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
-          "com.foo", 0, FLAG_STORAGE_CE, &ce_snapshot_inode));
+          "com.foo", 0, 37, FLAG_STORAGE_CE, &ce_snapshot_inode));
   struct stat buf;
   memset(&buf, 0, sizeof(buf));
   ASSERT_EQ(0, stat((rollback_ce_dir + "/com.foo").c_str(), &buf));
@@ -318,7 +345,7 @@
 
   // Request a snapshot of the DE content but not the CE content.
   ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
-          "com.foo", 0, FLAG_STORAGE_DE, &ce_snapshot_inode));
+          "com.foo", 0, 37, FLAG_STORAGE_DE, &ce_snapshot_inode));
   // Only DE content snapshot was requested.
   ASSERT_EQ(ce_snapshot_inode, 0);
 
@@ -339,7 +366,7 @@
 
   // Request a snapshot of both the CE as well as the DE content.
   ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
-          "com.foo", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
+          "com.foo", 0, 37, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
 
   ASSERT_TRUE(android::base::ReadFileToString(
       rollback_ce_dir + "/com.foo/file1", &ce_content, false /* follow_symlinks */));
@@ -349,27 +376,73 @@
   ASSERT_EQ("TEST_CONTENT_DE_MODIFIED", de_content);
 }
 
-TEST_F(ServiceTest, CreateAppDataSnapshot_AppDataAbsent) {
-  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
-  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_TwoSnapshotsWithTheSameId) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 67);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 67);
 
-  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
-  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
+  auto another_fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.bar");
+  auto another_fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.bar");
 
-  auto deleter = [&rollback_ce_dir, &rollback_de_dir]() {
-      delete_dir_contents(rollback_ce_dir, true);
-      delete_dir_contents(rollback_de_dir, true);
-      rmdir(rollback_ce_dir.c_str());
-      rmdir(rollback_de_dir.c_str());
+  // Since this test sets up data for another package, some bookkeeping is required.
+  auto deleter = [&]() {
+      ASSERT_EQ(0, delete_dir_contents_and_dir(another_fake_package_ce_path, true));
+      ASSERT_EQ(0, delete_dir_contents_and_dir(another_fake_package_de_path, true));
   };
-
   auto scope_guard = android::base::make_scope_guard(deleter);
 
+  ASSERT_TRUE(mkdirs(another_fake_package_ce_path, 0700));
+  ASSERT_TRUE(mkdirs(another_fake_package_de_path, 0700));
+
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_CE", fake_package_ce_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_DE", fake_package_de_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "ANOTHER_TEST_CONTENT_CE", another_fake_package_ce_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "ANOTHER_TEST_CONTENT_DE", another_fake_package_de_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+
+  // Request snapshot for the package com.foo.
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+          "com.foo", 0, 67, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
+  // Now request snapshot with the same id for the package com.bar
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+          "com.bar", 0, 67, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
+
+  // Check that both snapshots have correct data in them.
+  std::string com_foo_ce_content, com_foo_de_content;
+  std::string com_bar_ce_content, com_bar_de_content;
+  ASSERT_TRUE(android::base::ReadFileToString(
+      rollback_ce_dir + "/com.foo/file1", &com_foo_ce_content, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::ReadFileToString(
+      rollback_de_dir + "/com.foo/file1", &com_foo_de_content, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::ReadFileToString(
+      rollback_ce_dir + "/com.bar/file1", &com_bar_ce_content, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::ReadFileToString(
+      rollback_de_dir + "/com.bar/file1", &com_bar_de_content, false /* follow_symlinks */));
+  ASSERT_EQ("TEST_CONTENT_CE", com_foo_ce_content);
+  ASSERT_EQ("TEST_CONTENT_DE", com_foo_de_content);
+  ASSERT_EQ("ANOTHER_TEST_CONTENT_CE", com_bar_ce_content);
+  ASSERT_EQ("ANOTHER_TEST_CONTENT_DE", com_bar_de_content);
+}
+
+TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_AppDataAbsent) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 73);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 73);
+
+  // Similuating app data absence.
+  ASSERT_EQ(0, delete_dir_contents_and_dir(fake_package_ce_path, true));
+  ASSERT_EQ(0, delete_dir_contents_and_dir(fake_package_de_path, true));
+
   int64_t ce_snapshot_inode;
   ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
-          "com.foo", 0, FLAG_STORAGE_CE, &ce_snapshot_inode));
+          "com.foo", 0, 73, FLAG_STORAGE_CE, &ce_snapshot_inode));
   ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
-          "com.foo", 0, FLAG_STORAGE_DE, nullptr));
+          "com.foo", 0, 73, FLAG_STORAGE_DE, nullptr));
   // No CE content snapshot was performed.
   ASSERT_EQ(ce_snapshot_inode, 0);
 
@@ -380,29 +453,12 @@
   ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
 }
 
-TEST_F(ServiceTest, CreateAppDataSnapshot_ClearsExistingSnapshot) {
-  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
-  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_ClearsExistingSnapshot) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_package_path("TEST", 0, 13, "com.foo");
+  auto rollback_de_dir = create_data_misc_de_rollback_package_path("TEST", 0, 13, "com.foo");
 
-  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
-  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
-  auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
-  auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
-
-  ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
-  ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-
-  auto deleter = [&rollback_ce_dir, &rollback_de_dir,
-          &fake_package_ce_path, &fake_package_de_path]() {
-      delete_dir_contents(rollback_ce_dir, true);
-      delete_dir_contents(rollback_de_dir, true);
-      delete_dir_contents(fake_package_ce_path, true);
-      delete_dir_contents(fake_package_de_path, true);
-      rmdir(rollback_ce_dir.c_str());
-      rmdir(rollback_de_dir.c_str());
-  };
-  auto scope_guard = android::base::make_scope_guard(deleter);
+  ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
 
   // Simulate presence of an existing snapshot
   ASSERT_TRUE(android::base::WriteStringToFile(
@@ -421,62 +477,40 @@
           0700, 10000, 20000, false /* follow_symlinks */));
 
   ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
-          "com.foo", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
+          "com.foo", 0, 13, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
 
   // Previous snapshot (with data for file1) must be cleared.
   struct stat sb;
-  ASSERT_EQ(-1, stat((rollback_ce_dir + "/com.foo/file1").c_str(), &sb));
-  ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo/file1").c_str(), &sb));
+  ASSERT_EQ(-1, stat((rollback_ce_dir + "/file1").c_str(), &sb));
+  ASSERT_EQ(-1, stat((rollback_de_dir + "/file1").c_str(), &sb));
+  // New snapshot (with data for file2) must be present.
+  ASSERT_NE(-1, stat((rollback_ce_dir + "/file2").c_str(), &sb));
+  ASSERT_NE(-1, stat((rollback_de_dir + "/file2").c_str(), &sb));
 }
 
-TEST_F(ServiceTest, SnapshotAppData_WrongVolumeUuid) {
-  // Setup app data to make sure that fails due to wrong volumeUuid being
+TEST_F(AppDataSnapshotTest, SnapshotAppData_WrongVolumeUuid) {
+  // Setup rollback folders to make sure that fails due to wrong volumeUuid being
   // passed, not because of some other reason.
-  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
-  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 17);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 17);
 
-  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
-  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
-  auto deleter = [&rollback_ce_dir, &rollback_de_dir]() {
-      delete_dir_contents(rollback_ce_dir, true);
-      delete_dir_contents(rollback_de_dir, true);
-      rmdir(rollback_ce_dir.c_str());
-      rmdir(rollback_de_dir.c_str());
-  };
-  auto scope_guard = android::base::make_scope_guard(deleter);
+  ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
 
   EXPECT_BINDER_FAIL(service->snapshotAppData(std::make_unique<std::string>("FOO"),
-          "com.foo", 0, FLAG_STORAGE_DE, nullptr));
+          "com.foo", 0, 17, FLAG_STORAGE_DE, nullptr));
 }
 
-TEST_F(ServiceTest, CreateAppDataSnapshot_ClearsCache) {
-  auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
-  auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
+TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_ClearsCache) {
   auto fake_package_ce_cache_path = fake_package_ce_path + "/cache";
   auto fake_package_ce_code_cache_path = fake_package_ce_path + "/code_cache";
   auto fake_package_de_cache_path = fake_package_de_path + "/cache";
   auto fake_package_de_code_cache_path = fake_package_de_path + "/code_cache";
-  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
-  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
 
-  ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
-  ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-  ASSERT_TRUE(mkdirs(fake_package_ce_cache_path, 700));
-  ASSERT_TRUE(mkdirs(fake_package_ce_code_cache_path, 700));
-  ASSERT_TRUE(mkdirs(fake_package_de_cache_path, 700));
-  ASSERT_TRUE(mkdirs(fake_package_de_code_cache_path, 700));
-  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
-  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
-  auto deleter = [&fake_package_ce_path, &fake_package_de_path,
-          &rollback_ce_dir, &rollback_de_dir]() {
-      delete_dir_contents(fake_package_ce_path, true);
-      delete_dir_contents(fake_package_de_path, true);
-      delete_dir_contents_and_dir(rollback_ce_dir, true);
-      delete_dir_contents_and_dir(rollback_de_dir, true);
-  };
-  auto scope_guard = android::base::make_scope_guard(deleter);
+  ASSERT_TRUE(mkdirs(fake_package_ce_cache_path, 0700));
+  ASSERT_TRUE(mkdirs(fake_package_ce_code_cache_path, 0700));
+  ASSERT_TRUE(mkdirs(fake_package_de_cache_path, 0700));
+  ASSERT_TRUE(mkdirs(fake_package_de_code_cache_path, 0700));
 
   ASSERT_TRUE(android::base::WriteStringToFile(
           "TEST_CONTENT_CE", fake_package_ce_cache_path + "/file1",
@@ -491,7 +525,7 @@
           "TEST_CONTENT_DE", fake_package_de_code_cache_path + "/file1",
           0700, 10000, 20000, false /* follow_symlinks */));
   ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
-          "com.foo", 0, FLAG_STORAGE_CE | FLAG_STORAGE_DE, nullptr));
+          "com.foo", 0, 23, FLAG_STORAGE_CE | FLAG_STORAGE_DE, nullptr));
   // The snapshot call must clear cache.
   struct stat sb;
   ASSERT_EQ(-1, stat((fake_package_ce_cache_path + "/file1").c_str(), &sb));
@@ -500,34 +534,17 @@
   ASSERT_EQ(-1, stat((fake_package_de_code_cache_path + "/file1").c_str(), &sb));
 }
 
-TEST_F(ServiceTest, RestoreAppDataSnapshot) {
-  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
-  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+TEST_F(AppDataSnapshotTest, RestoreAppDataSnapshot) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 239);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 239);
 
-  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
-  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
-  auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
-  auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
-
-  ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
-  ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-
-  auto deleter = [&rollback_ce_dir, &rollback_de_dir,
-          &fake_package_ce_path, &fake_package_de_path]() {
-      delete_dir_contents(rollback_ce_dir, true);
-      delete_dir_contents(rollback_de_dir, true);
-      delete_dir_contents(fake_package_ce_path, true);
-      delete_dir_contents(fake_package_de_path, true);
-      rmdir(rollback_ce_dir.c_str());
-      rmdir(rollback_de_dir.c_str());
-  };
-  auto scope_guard = android::base::make_scope_guard(deleter);
+  ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
 
   // Write contents to the rollback location. We'll write the same files to the
   // app data location and make sure the restore has overwritten them.
-  ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 700));
-  ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 700));
+  ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 0700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 0700));
   ASSERT_TRUE(android::base::WriteStringToFile(
           "CE_RESTORE_CONTENT", rollback_ce_dir + "/com.foo/file1",
           0700, 10000, 20000, false /* follow_symlinks */));
@@ -542,7 +559,7 @@
           0700, 10000, 20000, false /* follow_symlinks */));
 
   ASSERT_BINDER_SUCCESS(service->restoreAppDataSnapshot(std::make_unique<std::string>("TEST"),
-          "com.foo", 10000, -1, "", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE));
+          "com.foo", 10000, "", 0, 239, FLAG_STORAGE_DE | FLAG_STORAGE_CE));
 
   std::string ce_content, de_content;
   ASSERT_TRUE(android::base::ReadFileToString(
@@ -553,29 +570,9 @@
   ASSERT_EQ("DE_RESTORE_CONTENT", de_content);
 }
 
-TEST_F(ServiceTest, CreateSnapshotThenDestroyIt) {
-  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
-  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
-
-  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
-  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
-  auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
-  auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
-
-  ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
-  ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-
-  auto deleter = [&rollback_ce_dir, &rollback_de_dir,
-          &fake_package_ce_path, &fake_package_de_path]() {
-      delete_dir_contents(rollback_ce_dir, true);
-      delete_dir_contents(rollback_de_dir, true);
-      delete_dir_contents(fake_package_ce_path, true);
-      delete_dir_contents(fake_package_de_path, true);
-      rmdir(rollback_ce_dir.c_str());
-      rmdir(rollback_de_dir.c_str());
-  };
-  auto scope_guard = android::base::make_scope_guard(deleter);
+TEST_F(AppDataSnapshotTest, CreateSnapshotThenDestroyIt) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 57);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 57);
 
   // Prepare data for snapshot.
   ASSERT_TRUE(android::base::WriteStringToFile(
@@ -588,7 +585,7 @@
   int64_t ce_snapshot_inode;
   // Request a snapshot of both the CE as well as the DE content.
   ASSERT_TRUE(service->snapshotAppData(std::make_unique<std::string>("TEST"),
-          "com.foo", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, &ce_snapshot_inode).isOk());
+          "com.foo", 0, 57, FLAG_STORAGE_DE | FLAG_STORAGE_CE, &ce_snapshot_inode).isOk());
   // Because CE data snapshot was requested, ce_snapshot_inode can't be null.
   ASSERT_NE(0, ce_snapshot_inode);
   // Check snapshot is there.
@@ -598,39 +595,19 @@
 
 
   ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique<std::string>("TEST"),
-          "com.foo", 0, ce_snapshot_inode, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
+          "com.foo", 0, ce_snapshot_inode, 57, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
   // Check snapshot is deleted.
   ASSERT_EQ(-1, stat((rollback_ce_dir + "/com.foo").c_str(), &sb));
   ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
 }
 
-TEST_F(ServiceTest, DestroyAppDataSnapshot_CeSnapshotInodeIsZero) {
-  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
-  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
-
-  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
-  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
-  auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
-  auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
-
-  ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
-  ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-
-  auto deleter = [&rollback_ce_dir, &rollback_de_dir,
-          &fake_package_ce_path, &fake_package_de_path]() {
-      delete_dir_contents(rollback_ce_dir, true);
-      delete_dir_contents(rollback_de_dir, true);
-      delete_dir_contents(fake_package_ce_path, true);
-      delete_dir_contents(fake_package_de_path, true);
-      rmdir(rollback_ce_dir.c_str());
-      rmdir(rollback_de_dir.c_str());
-  };
-  auto scope_guard = android::base::make_scope_guard(deleter);
+TEST_F(AppDataSnapshotTest, DestroyAppDataSnapshot_CeSnapshotInodeIsZero) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 1543);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 1543);
 
   // Create a snapshot
-  ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 700));
-  ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 700));
+  ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 0700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 0700));
   ASSERT_TRUE(android::base::WriteStringToFile(
           "CE_RESTORE_CONTENT", rollback_ce_dir + "/com.foo/file1",
           0700, 10000, 20000, false /* follow_symlinks */));
@@ -639,7 +616,7 @@
           0700, 10000, 20000, false /* follow_symlinks */));
 
   ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique<std::string>("TEST"),
-          "com.foo", 0, 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
+          "com.foo", 0, 0, 1543, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
 
   // Check snapshot is deleted.
   struct stat sb;
@@ -648,67 +625,33 @@
 
   // Check that deleting already deleted snapshot is no-op.
   ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique<std::string>("TEST"),
-          "com.foo", 0, 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
+          "com.foo", 0, 0, 1543, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
 }
 
-TEST_F(ServiceTest, DestroyAppDataSnapshot_WrongVolumeUuid) {
+TEST_F(AppDataSnapshotTest, DestroyAppDataSnapshot_WrongVolumeUuid) {
   // Setup rollback data to make sure that test fails due to wrong volumeUuid
   // being passed, not because of some other reason.
-  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
-  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 43);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 43);
 
-  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
-  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
-  auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
-  auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
-
-  ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
-  ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-
-  auto deleter = [&rollback_ce_dir, &rollback_de_dir,
-          &fake_package_ce_path, &fake_package_de_path]() {
-      delete_dir_contents(rollback_ce_dir, true);
-      delete_dir_contents(rollback_de_dir, true);
-      delete_dir_contents(fake_package_ce_path, true);
-      delete_dir_contents(fake_package_de_path, true);
-      rmdir(rollback_ce_dir.c_str());
-      rmdir(rollback_de_dir.c_str());
-  };
-  auto scope_guard = android::base::make_scope_guard(deleter);
+  ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
 
   ASSERT_FALSE(service->destroyAppDataSnapshot(std::make_unique<std::string>("BAR"),
-          "com.foo", 0, 0, FLAG_STORAGE_DE).isOk());
+          "com.foo", 0, 0, 43, FLAG_STORAGE_DE).isOk());
 }
 
-TEST_F(ServiceTest, RestoreAppDataSnapshot_WrongVolumeUuid) {
+TEST_F(AppDataSnapshotTest, RestoreAppDataSnapshot_WrongVolumeUuid) {
   // Setup rollback data to make sure that fails due to wrong volumeUuid being
   // passed, not because of some other reason.
-  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
-  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 41);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 41);
 
-  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
-  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
-  auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
-  auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
-
-  ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
-  ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-
-  auto deleter = [&rollback_ce_dir, &rollback_de_dir,
-          &fake_package_ce_path, &fake_package_de_path]() {
-      delete_dir_contents(rollback_ce_dir, true);
-      delete_dir_contents(rollback_de_dir, true);
-      delete_dir_contents(fake_package_ce_path, true);
-      delete_dir_contents(fake_package_de_path, true);
-      rmdir(rollback_ce_dir.c_str());
-      rmdir(rollback_de_dir.c_str());
-  };
-  auto scope_guard = android::base::make_scope_guard(deleter);
+  ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
 
   EXPECT_BINDER_FAIL(service->restoreAppDataSnapshot(std::make_unique<std::string>("BAR"),
-          "com.foo", 10000, -1, "", 0, FLAG_STORAGE_DE));
+          "com.foo", 10000, "", 0, 41, FLAG_STORAGE_DE));
 }
 
 }  // namespace installd
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 1782aa2..e61eb6e 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -546,56 +546,86 @@
 }
 
 TEST_F(UtilsTest, TestRollbackPaths) {
-    EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
-            create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo"));
-    EXPECT_EQ("/data/misc_ce/10/rollback/com.foo",
-            create_data_misc_ce_rollback_package_path(nullptr, 10, "com.foo"));
+    EXPECT_EQ("/data/misc_ce/0/rollback/239/com.foo",
+            create_data_misc_ce_rollback_package_path(nullptr, 0, 239, "com.foo"));
+    EXPECT_EQ("/data/misc_ce/10/rollback/37/com.foo",
+            create_data_misc_ce_rollback_package_path(nullptr, 10, 37, "com.foo"));
 
-    EXPECT_EQ("/data/misc_de/0/rollback/com.foo",
-            create_data_misc_de_rollback_package_path(nullptr, 0, "com.foo"));
-    EXPECT_EQ("/data/misc_de/10/rollback/com.foo",
-            create_data_misc_de_rollback_package_path(nullptr, 10, "com.foo"));
+    EXPECT_EQ("/data/misc_de/0/rollback/73/com.foo",
+            create_data_misc_de_rollback_package_path(nullptr, 0, 73, "com.foo"));
+    EXPECT_EQ("/data/misc_de/10/rollback/13/com.foo",
+            create_data_misc_de_rollback_package_path(nullptr, 10, 13, "com.foo"));
 
-    EXPECT_EQ("/data/misc_ce/0/rollback",
-            create_data_misc_ce_rollback_path(nullptr, 0));
-    EXPECT_EQ("/data/misc_ce/10/rollback",
-            create_data_misc_ce_rollback_path(nullptr, 10));
+    EXPECT_EQ("/data/misc_ce/0/rollback/57",
+            create_data_misc_ce_rollback_path(nullptr, 0, 57));
+    EXPECT_EQ("/data/misc_ce/10/rollback/1543",
+            create_data_misc_ce_rollback_path(nullptr, 10, 1543));
 
-    EXPECT_EQ("/data/misc_de/0/rollback",
-            create_data_misc_de_rollback_path(nullptr, 0));
-    EXPECT_EQ("/data/misc_de/10/rollback",
-            create_data_misc_de_rollback_path(nullptr, 10));
+    EXPECT_EQ("/data/misc_de/0/rollback/43",
+            create_data_misc_de_rollback_path(nullptr, 0, 43));
+    EXPECT_EQ("/data/misc_de/10/rollback/41",
+            create_data_misc_de_rollback_path(nullptr, 10, 41));
 
-    EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
-            create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo", 0));
-    EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
-            create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo", 239));
+    EXPECT_EQ("/data/misc_ce/0/rollback/17/com.foo",
+            create_data_misc_ce_rollback_package_path(nullptr, 0, 17, "com.foo", 0));
+    EXPECT_EQ("/data/misc_ce/0/rollback/19/com.foo",
+            create_data_misc_ce_rollback_package_path(nullptr, 0, 19, "com.foo", 239));
 
-    auto rollback_ce_package_path = create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo");
-    auto deleter = [&rollback_ce_package_path]() {
-        delete_dir_contents_and_dir(rollback_ce_package_path, true /* ignore_if_missing */);
+    auto rollback_ce_path = create_data_misc_ce_rollback_path(nullptr, 0, 53);
+    auto rollback_ce_package_path = create_data_misc_ce_rollback_package_path(nullptr, 0, 53,
+            "com.foo");
+    auto deleter = [&rollback_ce_path]() {
+        delete_dir_contents_and_dir(rollback_ce_path, true /* ignore_if_missing */);
     };
     auto scope_guard = android::base::make_scope_guard(deleter);
 
-    ASSERT_NE(-1, mkdir(rollback_ce_package_path.c_str(), 700));
+    EXPECT_NE(-1, mkdir(rollback_ce_path.c_str(), 700));
+    EXPECT_NE(-1, mkdir(rollback_ce_package_path.c_str(), 700));
 
     ino_t ce_data_inode;
-    ASSERT_EQ(0, get_path_inode(rollback_ce_package_path, &ce_data_inode));
+    EXPECT_EQ(0, get_path_inode(rollback_ce_package_path, &ce_data_inode));
 
-    EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
-            create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo", ce_data_inode));
+    EXPECT_EQ("/data/misc_ce/0/rollback/53/com.foo",
+            create_data_misc_ce_rollback_package_path(nullptr, 0, 53, "com.foo", ce_data_inode));
     // Check that path defined by inode is picked even if it's not the same as
     // the fallback one.
-    EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
-            create_data_misc_ce_rollback_package_path(nullptr, 0, "com.bar", ce_data_inode));
+    EXPECT_EQ("/data/misc_ce/0/rollback/53/com.foo",
+            create_data_misc_ce_rollback_package_path(nullptr, 0, 53, "com.bar", ce_data_inode));
 
     // These last couple of cases are never exercised in production because we
     // only snapshot apps in the primary data partition. Exercise them here for
     // the sake of completeness.
-    EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/misc_ce/0/rollback/com.example",
-            create_data_misc_ce_rollback_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, "com.example"));
-    EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/misc_de/0/rollback/com.example",
-            create_data_misc_de_rollback_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, "com.example"));
+    EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/misc_ce/0/rollback/7/com.example",
+            create_data_misc_ce_rollback_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, 7,
+                    "com.example"));
+    EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/misc_de/0/rollback/11/com.example",
+            create_data_misc_de_rollback_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, 11,
+                    "com.example"));
+}
+
+TEST_F(UtilsTest, TestCreateDirIfNeeded) {
+    system("mkdir -p /data/local/tmp/user/0");
+
+    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);
+
+    // Create folder and check it's permissions.
+    ASSERT_EQ(0, create_dir_if_needed("/data/local/tmp/user/0/foo", 0700));
+    struct stat st;
+    ASSERT_EQ(0, stat("/data/local/tmp/user/0/foo", &st));
+    ASSERT_EQ(0700, st.st_mode & ALLPERMS);
+
+    // Check that create_dir_if_needed is no-op if folder already exists with
+    // correct permissions.
+    ASSERT_EQ(0, create_dir_if_needed("/data/local/tmp/user/0/foo", 0700));
+
+    // Check -1 is returned if folder exists but with different permissions.
+    ASSERT_EQ(-1, create_dir_if_needed("/data/local/tmp/user/0/foo", 0750));
+
+    // Check that call fails if parent doesn't exist.
+    ASSERT_NE(0, create_dir_if_needed("/data/local/tmp/user/0/bar/baz", 0700));
 }
 
 }  // namespace installd
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 5b487bb..da097db 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -197,32 +197,44 @@
     return StringPrintf("%s/user_de/%u", data.c_str(), userid);
 }
 
-
-std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user) {
+std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user) {
     return StringPrintf("%s/misc_ce/%u/rollback", create_data_path(volume_uuid).c_str(), user);
 }
 
-std::string create_data_misc_de_rollback_path(const char* volume_uuid, userid_t user) {
+std::string create_data_misc_de_rollback_base_path(const char* volume_uuid, userid_t user) {
     return StringPrintf("%s/misc_de/%u/rollback", create_data_path(volume_uuid).c_str(), user);
 }
 
-std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
-        userid_t user, const char* package_name) {
-    return StringPrintf("%s/%s",
-           create_data_misc_ce_rollback_path(volume_uuid, user).c_str(), package_name);
+std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user,
+        int32_t snapshot_id) {
+    return StringPrintf("%s/%d", create_data_misc_ce_rollback_base_path(volume_uuid, user).c_str(),
+          snapshot_id);
+}
+
+std::string create_data_misc_de_rollback_path(const char* volume_uuid, userid_t user,
+        int32_t snapshot_id) {
+    return StringPrintf("%s/%d", create_data_misc_de_rollback_base_path(volume_uuid, user).c_str(),
+          snapshot_id);
 }
 
 std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
-        userid_t user, const char* package_name, ino_t ce_rollback_inode) {
-    auto fallback = create_data_misc_ce_rollback_package_path(volume_uuid, user, package_name);
-    auto user_path = create_data_misc_ce_rollback_path(volume_uuid, user);
+        userid_t user, int32_t snapshot_id, const char* package_name) {
+    return StringPrintf("%s/%s",
+           create_data_misc_ce_rollback_path(volume_uuid, user, snapshot_id).c_str(), package_name);
+}
+
+std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
+        userid_t user, int32_t snapshot_id, const char* package_name, ino_t ce_rollback_inode) {
+    auto fallback = create_data_misc_ce_rollback_package_path(volume_uuid, user, snapshot_id,
+            package_name);
+    auto user_path = create_data_misc_ce_rollback_path(volume_uuid, user, snapshot_id);
     return resolve_ce_path_by_inode_or_fallback(user_path, ce_rollback_inode, fallback);
 }
 
 std::string create_data_misc_de_rollback_package_path(const char* volume_uuid,
-        userid_t user, const char* package_name) {
+        userid_t user, int32_t snapshot_id, const char* package_name) {
     return StringPrintf("%s/%s",
-           create_data_misc_de_rollback_path(volume_uuid, user).c_str(), package_name);
+           create_data_misc_de_rollback_path(volume_uuid, user, snapshot_id).c_str(), package_name);
 }
 
 /**
@@ -528,6 +540,30 @@
     return result;
 }
 
+int create_dir_if_needed(const std::string& pathname, mode_t perms) {
+    struct stat st;
+
+    int rc;
+    if ((rc = stat(pathname.c_str(), &st)) != 0) {
+        if (errno == ENOENT) {
+            return mkdir(pathname.c_str(), perms);
+        } else {
+            return rc;
+        }
+    } else if (!S_ISDIR(st.st_mode)) {
+        LOG(DEBUG) << pathname << " is not a folder";
+        return -1;
+    }
+
+    mode_t actual_perms = st.st_mode & ALLPERMS;
+    if (actual_perms != perms) {
+        LOG(WARNING) << pathname << " permissions " << actual_perms << " expected " << perms;
+        return -1;
+    }
+
+    return 0;
+}
+
 int delete_dir_contents(const std::string& pathname, bool ignore_if_missing) {
     return delete_dir_contents(pathname.c_str(), 0, nullptr, ignore_if_missing);
 }
@@ -892,6 +928,8 @@
 static int validate_apk_path_internal(const std::string& path, int maxSubdirs) {
     if (validate_path(android_app_dir, path, maxSubdirs) == 0) {
         return 0;
+    } else if (validate_path(android_staging_dir, path, maxSubdirs) == 0) {
+        return 0;
     } else if (validate_path(android_app_private_dir, path, maxSubdirs) == 0) {
         return 0;
     } else if (validate_path(android_app_ephemeral_dir, path, maxSubdirs) == 0) {
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 5d3a97d..91d9e13 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -61,14 +61,18 @@
 std::string create_data_user_ce_package_path_as_user_link(
         const char* volume_uuid, userid_t userid, const char* package_name);
 
-std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user);
-std::string create_data_misc_de_rollback_path(const char* volume_uuid, userid_t user);
+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);
+std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user,
+        int32_t snapshot_id);
+std::string create_data_misc_de_rollback_path(const char* volume_uuid, userid_t user,
+        int32_t snapshot_id);
 std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
-        userid_t user, const char* package_name);
+        userid_t user, int32_t snapshot_id, const char* package_name);
 std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
-        userid_t user, const char* package_name, ino_t ce_rollback_inode);
+        userid_t user, int32_t snapshot_id, const char* package_name, ino_t ce_rollback_inode);
 std::string create_data_misc_de_rollback_package_path(const char* volume_uuid,
-        userid_t user, const char* package_name);
+        userid_t user, int32_t snapshot_id, const char* package_name);
 
 std::string create_data_media_path(const char* volume_uuid, userid_t userid);
 std::string create_data_media_obb_path(const char* volume_uuid, const char* package_name);
@@ -109,6 +113,8 @@
 bool is_valid_filename(const std::string& name);
 bool is_valid_package_name(const std::string& packageName);
 
+int create_dir_if_needed(const std::string& pathname, mode_t mode);
+
 int delete_dir_contents(const std::string& pathname, bool ignore_if_missing = false);
 int delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing = false);