Enable clang-tidy for sensitive domain.

Since installd has broad access to lots of sensitive data, enable
as many security-related tidy checks as possible to help avoid bugs.

This change provides a default implementation of create_cache_path(),
calculate_odex_file_path(), and calculate_oat_file_path(), along
with tests to verify behavior against old code.

Replace "dir_rec_t" with std::string, since that's really what it's
been all along.  Increase paranoia of path checking to reject any
paths containing "..", regardless of where it occurs in path string.
Stricter checking of instruction set values.

Remove now-unused char* manipulation utility methods; people should
be using std::string instead.

(cherry picked from commit 1b9d9a6006f4159e2cc2c41330f316b1fdc53fe1)

Test: adb shell /data/nativetest/installd_cache_test/installd_cache_test
Test: adb shell /data/nativetest/installd_service_test/installd_service_test
Test: adb shell /data/nativetest/installd_utils_test/installd_utils_test
Bug: 36655947
Merged-In: Ib706f0b8c1878be64710c00f56dccdfbe215570f
Change-Id: Ib706f0b8c1878be64710c00f56dccdfbe215570f
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 33db6db..56470d6 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -4,6 +4,7 @@
     cflags: [
         "-Wall",
         "-Werror",
+        "-Wextra",
     ],
     srcs: [
         "CacheItem.cpp",
@@ -25,6 +26,17 @@
     ],
 
     clang: true,
+
+    tidy: true,
+    tidy_checks: [
+        "-*",
+        "clang-analyzer-security*",
+        "cert-*",
+        "-cert-err58-cpp",
+    ],
+    tidy_flags: [
+        "-warnings-as-errors=clang-analyzer-security*,cert-*"
+    ],
 }
 
 //
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 7a397d1..4246536 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1869,7 +1869,7 @@
     char boot_marker_path[PKG_PATH_MAX];
     sprintf(boot_marker_path,
           "%s/%s/%s/.booting",
-          android_data_dir.path,
+          android_data_dir.c_str(),
           DALVIK_CACHE,
           instruction_set);
 
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 6f7ab6b..6a7d845 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -41,6 +41,7 @@
 #include <system/thread_defs.h>
 
 #include "dexopt.h"
+#include "globals.h"
 #include "installd_deps.h"
 #include "otapreopt_utils.h"
 #include "utils.h"
@@ -156,7 +157,7 @@
   int count = 0;
   char buf[kPropertyValueMax];
 
-  strncpy(buf, str, sizeof(buf));
+  strlcpy(buf, str, sizeof(buf));
   char *pBuf = buf;
 
   while(strtok_r(pBuf, " ", &ctx) != NULL) {
@@ -333,7 +334,8 @@
 
     bool have_dex2oat_compiler_filter_flag = false;
     if (skip_compilation) {
-        strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=extract");
+        strlcpy(dex2oat_compiler_filter_arg, "--compiler-filter=extract",
+                sizeof(dex2oat_compiler_filter_arg));
         have_dex2oat_compiler_filter_flag = true;
         have_dex2oat_relocation_skip_flag = true;
     } else if (compiler_filter != nullptr) {
@@ -955,14 +957,6 @@
     return replace_file_extension(oat_path, ".vdex");
 }
 
-static bool add_extension_to_file_name(char* file_name, const char* extension) {
-    if (strlen(file_name) + strlen(extension) + 1 > PKG_PATH_MAX) {
-        return false;
-    }
-    strcat(file_name, extension);
-    return true;
-}
-
 static int open_output_file(const char* file_name, bool recreate, int permissions) {
     int flags = O_RDWR | O_CREAT;
     if (recreate) {
@@ -1198,21 +1192,16 @@
     if (!ShouldUseSwapFileForDexopt()) {
         return invalid_unique_fd();
     }
-    // Make sure there really is enough space.
-    char swap_file_name[PKG_PATH_MAX];
-    strcpy(swap_file_name, out_oat_path);
-    if (!add_extension_to_file_name(swap_file_name, ".swap")) {
-        return invalid_unique_fd();
-    }
+    auto swap_file_name = std::string(out_oat_path) + ".swap";
     unique_fd swap_fd(open_output_file(
-            swap_file_name, /*recreate*/true, /*permissions*/0600));
+            swap_file_name.c_str(), /*recreate*/true, /*permissions*/0600));
     if (swap_fd.get() < 0) {
         // Could not create swap file. Optimistically go on and hope that we can compile
         // without it.
-        ALOGE("installd could not create '%s' for swap during dexopt\n", swap_file_name);
+        ALOGE("installd could not create '%s' for swap during dexopt\n", swap_file_name.c_str());
     } else {
         // Immediately unlink. We don't really want to hit flash.
-        if (unlink(swap_file_name) < 0) {
+        if (unlink(swap_file_name.c_str()) < 0) {
             PLOG(ERROR) << "Couldn't unlink swap file " << swap_file_name;
         }
     }
@@ -2040,5 +2029,98 @@
     return return_value_oat && return_value_art && return_value_vdex;
 }
 
+static bool is_absolute_path(const std::string& path) {
+    if (path.find('/') != 0 || path.find("..") != std::string::npos) {
+        LOG(ERROR) << "Invalid absolute path " << path;
+        return false;
+    } else {
+        return true;
+    }
+}
+
+static bool is_valid_instruction_set(const std::string& instruction_set) {
+    // TODO: add explicit whitelisting of instruction sets
+    if (instruction_set.find('/') != std::string::npos) {
+        LOG(ERROR) << "Invalid instruction set " << instruction_set;
+        return false;
+    } else {
+        return true;
+    }
+}
+
+bool calculate_oat_file_path_default(char path[PKG_PATH_MAX], const char *oat_dir,
+        const char *apk_path, const char *instruction_set) {
+    std::string oat_dir_ = oat_dir;
+    std::string apk_path_ = apk_path;
+    std::string instruction_set_ = instruction_set;
+
+    if (!is_absolute_path(oat_dir_)) return false;
+    if (!is_absolute_path(apk_path_)) return false;
+    if (!is_valid_instruction_set(instruction_set_)) return false;
+
+    std::string::size_type end = apk_path_.rfind('.');
+    std::string::size_type start = apk_path_.rfind('/', end);
+    if (end == std::string::npos || start == std::string::npos) {
+        LOG(ERROR) << "Invalid apk_path " << apk_path_;
+        return false;
+    }
+
+    std::string res_ = oat_dir_ + '/' + instruction_set + '/'
+            + apk_path_.substr(start + 1, end - start - 1) + ".odex";
+    const char* res = res_.c_str();
+    if (strlen(res) >= PKG_PATH_MAX) {
+        LOG(ERROR) << "Result too large";
+        return false;
+    } else {
+        strlcpy(path, res, PKG_PATH_MAX);
+        return true;
+    }
+}
+
+bool calculate_odex_file_path_default(char path[PKG_PATH_MAX], const char *apk_path,
+        const char *instruction_set) {
+    std::string apk_path_ = apk_path;
+    std::string instruction_set_ = instruction_set;
+
+    if (!is_absolute_path(apk_path_)) return false;
+    if (!is_valid_instruction_set(instruction_set_)) return false;
+
+    std::string::size_type end = apk_path_.rfind('.');
+    std::string::size_type start = apk_path_.rfind('/', end);
+    if (end == std::string::npos || start == std::string::npos) {
+        LOG(ERROR) << "Invalid apk_path " << apk_path_;
+        return false;
+    }
+
+    std::string oat_dir = apk_path_.substr(0, start + 1) + "oat";
+    return calculate_oat_file_path_default(path, oat_dir.c_str(), apk_path, instruction_set);
+}
+
+bool create_cache_path_default(char path[PKG_PATH_MAX], const char *src,
+        const char *instruction_set) {
+    std::string src_ = src;
+    std::string instruction_set_ = instruction_set;
+
+    if (!is_absolute_path(src_)) return false;
+    if (!is_valid_instruction_set(instruction_set_)) return false;
+
+    for (auto it = src_.begin() + 1; it < src_.end(); ++it) {
+        if (*it == '/') {
+            *it = '@';
+        }
+    }
+
+    std::string res_ = android_data_dir + DALVIK_CACHE + '/' + instruction_set_ + src_
+            + DALVIK_CACHE_POSTFIX;
+    const char* res = res_.c_str();
+    if (strlen(res) >= PKG_PATH_MAX) {
+        LOG(ERROR) << "Result too large";
+        return false;
+    } else {
+        strlcpy(path, res, PKG_PATH_MAX);
+        return true;
+    }
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 23446da..1f41e67 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -17,6 +17,8 @@
 #ifndef DEXOPT_H_
 #define DEXOPT_H_
 
+#include "installd_constants.h"
+
 #include <sys/types.h>
 
 #include <cutils/multiuser.h>
@@ -66,6 +68,15 @@
         const char* volume_uuid, const char* class_loader_context, const char* se_info,
         bool downgrade);
 
+bool calculate_oat_file_path_default(char path[PKG_PATH_MAX], const char *oat_dir,
+        const char *apk_path, const char *instruction_set);
+
+bool calculate_odex_file_path_default(char path[PKG_PATH_MAX], const char *apk_path,
+        const char *instruction_set);
+
+bool create_cache_path_default(char path[PKG_PATH_MAX], const char *src,
+        const char *instruction_set);
+
 }  // namespace installd
 }  // namespace android
 
diff --git a/cmds/installd/globals.cpp b/cmds/installd/globals.cpp
index edcdb6a..b3a6daf 100644
--- a/cmds/installd/globals.cpp
+++ b/cmds/installd/globals.cpp
@@ -16,15 +16,15 @@
 
 #define LOG_TAG "installd"
 
-#include <stdlib.h>
-#include <string.h>
-
-#include <log/log.h>              // TODO: Move everything to base::logging.
-
 #include <globals.h>
 #include <installd_constants.h>
 #include <utils.h>
 
+#include <android-base/logging.h>
+
+#include <stdlib.h>
+#include <string.h>
+
 namespace android {
 namespace installd {
 
@@ -44,106 +44,78 @@
 static constexpr const char* PRIVATE_APP_SUBDIR = "app-private/"; // sub-directory under
                                                                   // ANDROID_DATA
 
-/* Directory records that are used in execution of commands. */
-dir_rec_t android_app_dir;
-dir_rec_t android_app_ephemeral_dir;
-dir_rec_t android_app_lib_dir;
-dir_rec_t android_app_private_dir;
-dir_rec_t android_asec_dir;
-dir_rec_t android_data_dir;
-dir_rec_t android_media_dir;
-dir_rec_t android_mnt_expand_dir;
-dir_rec_t android_profiles_dir;
+std::string android_app_dir;
+std::string android_app_ephemeral_dir;
+std::string android_app_lib_dir;
+std::string android_app_private_dir;
+std::string android_asec_dir;
+std::string android_data_dir;
+std::string android_media_dir;
+std::string android_mnt_expand_dir;
+std::string android_profiles_dir;
+std::string android_root_dir;
 
-dir_rec_array_t android_system_dirs;
+std::vector<std::string> android_system_dirs;
 
-/**
- * Initialize all the global variables that are used elsewhere. Returns 0 upon
- * success and -1 on error.
- */
-void free_globals() {
-    size_t i;
-
-    for (i = 0; i < android_system_dirs.count; i++) {
-        if (android_system_dirs.dirs[i].path != NULL) {
-            free(android_system_dirs.dirs[i].path);
-        }
+bool init_globals_from_data_and_root() {
+    const char* data_path = getenv("ANDROID_DATA");
+    if (data_path == nullptr) {
+        LOG(ERROR) << "Could not find ANDROID_DATA";
+        return false;
     }
+    const char* root_path = getenv("ANDROID_ROOT");
+    if (root_path == nullptr) {
+        LOG(ERROR) << "Could not find ANDROID_ROOT";
+        return false;
+    }
+    return init_globals_from_data_and_root(data_path, root_path);
+}
 
-    free(android_system_dirs.dirs);
+static std::string ensure_trailing_slash(const std::string& path) {
+    if (path.rfind('/') != path.size() - 1) {
+        return path + '/';
+    } else {
+        return path;
+    }
 }
 
 bool init_globals_from_data_and_root(const char* data, const char* root) {
     // Get the android data directory.
-    if (get_path_from_string(&android_data_dir, data) < 0) {
-        return false;
-    }
+    android_data_dir = ensure_trailing_slash(data);
+
+    // Get the android root directory.
+    android_root_dir = ensure_trailing_slash(root);
 
     // Get the android app directory.
-    if (copy_and_append(&android_app_dir, &android_data_dir, APP_SUBDIR) < 0) {
-        return false;
-    }
+    android_app_dir = android_data_dir + APP_SUBDIR;
 
     // Get the android protected app directory.
-    if (copy_and_append(&android_app_private_dir, &android_data_dir, PRIVATE_APP_SUBDIR) < 0) {
-        return false;
-    }
+    android_app_private_dir = android_data_dir + PRIVATE_APP_SUBDIR;
 
     // Get the android ephemeral app directory.
-    if (copy_and_append(&android_app_ephemeral_dir, &android_data_dir, EPHEMERAL_APP_SUBDIR) < 0) {
-        return false;
-    }
+    android_app_ephemeral_dir = android_data_dir + EPHEMERAL_APP_SUBDIR;
 
     // Get the android app native library directory.
-    if (copy_and_append(&android_app_lib_dir, &android_data_dir, APP_LIB_SUBDIR) < 0) {
-        return false;
-    }
+    android_app_lib_dir = android_data_dir + APP_LIB_SUBDIR;
 
     // Get the sd-card ASEC mount point.
-    if (get_path_from_env(&android_asec_dir, ASEC_MOUNTPOINT_ENV_NAME) < 0) {
-        return false;
-    }
+    android_asec_dir = ensure_trailing_slash(getenv(ASEC_MOUNTPOINT_ENV_NAME));
 
     // Get the android media directory.
-    if (copy_and_append(&android_media_dir, &android_data_dir, MEDIA_SUBDIR) < 0) {
-        return false;
-    }
+    android_media_dir = android_data_dir + MEDIA_SUBDIR;
 
     // Get the android external app directory.
-    if (get_path_from_string(&android_mnt_expand_dir, "/mnt/expand/") < 0) {
-        return false;
-    }
+    android_mnt_expand_dir = "/mnt/expand/";
 
     // Get the android profiles directory.
-    if (copy_and_append(&android_profiles_dir, &android_data_dir, PROFILES_SUBDIR) < 0) {
-        return false;
-    }
+    android_profiles_dir = android_data_dir + PROFILES_SUBDIR;
 
     // Take note of the system and vendor directories.
-    android_system_dirs.count = 4;
-
-    android_system_dirs.dirs = (dir_rec_t*) calloc(android_system_dirs.count, sizeof(dir_rec_t));
-    if (android_system_dirs.dirs == NULL) {
-        ALOGE("Couldn't allocate array for dirs; aborting\n");
-        return false;
-    }
-
-    dir_rec_t android_root_dir;
-    if (get_path_from_string(&android_root_dir, root) < 0) {
-        return false;
-    }
-
-    android_system_dirs.dirs[0].path = build_string2(android_root_dir.path, APP_SUBDIR);
-    android_system_dirs.dirs[0].len = strlen(android_system_dirs.dirs[0].path);
-
-    android_system_dirs.dirs[1].path = build_string2(android_root_dir.path, PRIV_APP_SUBDIR);
-    android_system_dirs.dirs[1].len = strlen(android_system_dirs.dirs[1].path);
-
-    android_system_dirs.dirs[2].path = strdup("/vendor/app/");
-    android_system_dirs.dirs[2].len = strlen(android_system_dirs.dirs[2].path);
-
-    android_system_dirs.dirs[3].path = strdup("/oem/app/");
-    android_system_dirs.dirs[3].len = strlen(android_system_dirs.dirs[3].path);
+    android_system_dirs.clear();
+    android_system_dirs.push_back(android_root_dir + APP_SUBDIR);
+    android_system_dirs.push_back(android_root_dir + PRIV_APP_SUBDIR);
+    android_system_dirs.push_back("/vendor/app/");
+    android_system_dirs.push_back("/oem/app/");
 
     return true;
 }
diff --git a/cmds/installd/globals.h b/cmds/installd/globals.h
index c90beec..633e33b 100644
--- a/cmds/installd/globals.h
+++ b/cmds/installd/globals.h
@@ -19,40 +19,29 @@
 #define GLOBALS_H_
 
 #include <inttypes.h>
+#include <string>
+#include <vector>
 
 namespace android {
 namespace installd {
 
-/* constants */
-
 // Name of the environment variable that contains the asec mountpoint.
 static constexpr const char* ASEC_MOUNTPOINT_ENV_NAME = "ASEC_MOUNTPOINT";
 
-/* data structures */
+extern std::string android_app_dir;
+extern std::string android_app_ephemeral_dir;
+extern std::string android_app_lib_dir;
+extern std::string android_app_private_dir;
+extern std::string android_asec_dir;
+extern std::string android_data_dir;
+extern std::string android_media_dir;
+extern std::string android_mnt_expand_dir;
+extern std::string android_profiles_dir;
+extern std::string android_root_dir;
 
-struct dir_rec_t {
-    char* path;
-    size_t len;
-};
+extern std::vector<std::string> android_system_dirs;
 
-struct dir_rec_array_t {
-    size_t count;
-    dir_rec_t* dirs;
-};
-
-extern dir_rec_t android_app_dir;
-extern dir_rec_t android_app_ephemeral_dir;
-extern dir_rec_t android_app_lib_dir;
-extern dir_rec_t android_app_private_dir;
-extern dir_rec_t android_asec_dir;
-extern dir_rec_t android_data_dir;
-extern dir_rec_t android_media_dir;
-extern dir_rec_t android_mnt_expand_dir;
-extern dir_rec_t android_profiles_dir;
-
-extern dir_rec_array_t android_system_dirs;
-
-void free_globals();
+bool init_globals_from_data_and_root();
 bool init_globals_from_data_and_root(const char* data, const char* root);
 
 }  // namespace installd
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index 35936a2..95ed2ff 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -30,6 +30,7 @@
 #include <private/android_filesystem_config.h>
 
 #include "InstalldNativeService.h"
+#include "dexopt.h"
 #include "globals.h"
 #include "installd_constants.h"
 #include "installd_deps.h"  // Need to fill in requirements of commands.
@@ -50,133 +51,22 @@
     return property_get(key, value, default_value);
 }
 
-// Compute the output path of
-bool calculate_oat_file_path(char path[PKG_PATH_MAX],
-                             const char *oat_dir,
-                             const char *apk_path,
-                             const char *instruction_set) {
-    const char *file_name_start;
-    const char *file_name_end;
-
-    file_name_start = strrchr(apk_path, '/');
-    if (file_name_start == NULL) {
-        SLOGE("apk_path '%s' has no '/'s in it\n", apk_path);
-        return false;
-    }
-    file_name_end = strrchr(apk_path, '.');
-    if (file_name_end < file_name_start) {
-        SLOGE("apk_path '%s' has no extension\n", apk_path);
-        return false;
-    }
-
-    // Calculate file_name
-    int file_name_len = file_name_end - file_name_start - 1;
-    char file_name[file_name_len + 1];
-    memcpy(file_name, file_name_start + 1, file_name_len);
-    file_name[file_name_len] = '\0';
-
-    // <apk_parent_dir>/oat/<isa>/<file_name>.odex
-    snprintf(path, PKG_PATH_MAX, "%s/%s/%s.odex", oat_dir, instruction_set, file_name);
-    return true;
+bool calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
+        const char *instruction_set) {
+    return calculate_oat_file_path_default(path, oat_dir, apk_path, instruction_set);
 }
 
-/*
- * Computes the odex file for the given apk_path and instruction_set.
- * /system/framework/whatever.jar -> /system/framework/oat/<isa>/whatever.odex
- *
- * Returns false if it failed to determine the odex file path.
- */
-bool calculate_odex_file_path(char path[PKG_PATH_MAX],
-                              const char *apk_path,
-                              const char *instruction_set) {
-    if (strlen(apk_path) + strlen("oat/") + strlen(instruction_set)
-            + strlen("/") + strlen("odex") + 1 > PKG_PATH_MAX) {
-        SLOGE("apk_path '%s' may be too long to form odex file path.\n", apk_path);
-        return false;
-    }
-
-    strcpy(path, apk_path);
-    char *end = strrchr(path, '/');
-    if (end == NULL) {
-        SLOGE("apk_path '%s' has no '/'s in it?!\n", apk_path);
-        return false;
-    }
-    const char *apk_end = apk_path + (end - path); // strrchr(apk_path, '/');
-
-    strcpy(end + 1, "oat/");       // path = /system/framework/oat/\0
-    strcat(path, instruction_set); // path = /system/framework/oat/<isa>\0
-    strcat(path, apk_end);         // path = /system/framework/oat/<isa>/whatever.jar\0
-    end = strrchr(path, '.');
-    if (end == NULL) {
-        SLOGE("apk_path '%s' has no extension.\n", apk_path);
-        return false;
-    }
-    strcpy(end + 1, "odex");
-    return true;
+bool calculate_odex_file_path(char path[PKG_PATH_MAX], const char *apk_path,
+        const char *instruction_set) {
+    return calculate_odex_file_path_default(path, apk_path, instruction_set);
 }
 
-bool create_cache_path(char path[PKG_PATH_MAX],
-                       const char *src,
-                       const char *instruction_set) {
-    /* demand that we are an absolute path */
-    if ((src == nullptr) || (src[0] != '/') || strstr(src,"..")) {
-        return false;
-    }
-
-    size_t srclen = strlen(src);
-
-    if (srclen > PKG_PATH_MAX) {        // XXX: PKG_NAME_MAX?
-        return false;
-    }
-
-    size_t dstlen =
-        android_data_dir.len +
-        strlen(DALVIK_CACHE) +
-        1 +
-        strlen(instruction_set) +
-        srclen +
-        strlen(DALVIK_CACHE_POSTFIX) + 2;
-
-    if (dstlen > PKG_PATH_MAX) {
-        return false;
-    }
-
-    sprintf(path,"%s%s/%s/%s",
-            android_data_dir.path,
-            DALVIK_CACHE,
-            instruction_set,
-            src + 1 /* skip the leading / */);
-
-    char* tmp =
-            path +
-            android_data_dir.len +
-            strlen(DALVIK_CACHE) +
-            1 +
-            strlen(instruction_set) + 1;
-
-    for(; *tmp; tmp++) {
-        if (*tmp == '/') {
-            *tmp = '@';
-        }
-    }
-
-    strcat(path, DALVIK_CACHE_POSTFIX);
-    return true;
+bool create_cache_path(char path[PKG_PATH_MAX], const char *src, const char *instruction_set) {
+    return create_cache_path_default(path, src, instruction_set);
 }
 
 static bool initialize_globals() {
-    const char* data_path = getenv("ANDROID_DATA");
-    if (data_path == nullptr) {
-        SLOGE("Could not find ANDROID_DATA");
-        return false;
-    }
-    const char* root_path = getenv("ANDROID_ROOT");
-    if (root_path == nullptr) {
-        SLOGE("Could not find ANDROID_ROOT");
-        return false;
-    }
-
-    return init_globals_from_data_and_root(data_path, root_path);
+    return init_globals_from_data_and_root();
 }
 
 static int initialize_directories() {
@@ -184,7 +74,7 @@
 
     // Read current filesystem layout version to handle upgrade paths
     char version_path[PATH_MAX];
-    snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.path);
+    snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.c_str());
 
     int oldVersion;
     if (fs_read_atomic_int(version_path, &oldVersion) == -1) {
@@ -206,7 +96,7 @@
         SLOGD("Upgrading to /data/misc/user directories");
 
         char misc_dir[PATH_MAX];
-        snprintf(misc_dir, PATH_MAX, "%smisc", android_data_dir.path);
+        snprintf(misc_dir, PATH_MAX, "%smisc", android_data_dir.c_str());
 
         char keychain_added_dir[PATH_MAX];
         snprintf(keychain_added_dir, PATH_MAX, "%s/keychain/cacerts-added", misc_dir);
@@ -227,7 +117,7 @@
                     if ((name[1] == '.') && (name[2] == 0)) continue;
                 }
 
-                uint32_t user_id = atoi(name);
+                uint32_t user_id = std::stoi(name);
 
                 // /data/misc/user/<user_id>
                 if (ensure_config_user_dirs(user_id) == -1) {
@@ -281,7 +171,7 @@
     return res;
 }
 
-static int log_callback(int type, const char *fmt, ...) {
+static int log_callback(int type, const char *fmt, ...) { // NOLINT
     va_list ap;
     int priority;
 
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 09e1a00..a58ba41 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -146,12 +146,12 @@
                 return 0;
             }
             // Copy in the default value.
-            strncpy(value, default_value, kPropertyValueMax - 1);
+            strlcpy(value, default_value, kPropertyValueMax - 1);
             value[kPropertyValueMax - 1] = 0;
             return strlen(default_value);// TODO: Need to truncate?
         }
         size_t size = std::min(kPropertyValueMax - 1, prop_value->length());
-        strncpy(value, prop_value->data(), size);
+        strlcpy(value, prop_value->data(), size);
         value[size] = 0;
         return static_cast<int>(size);
     }
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index 34818f6..ca812bd 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -25,6 +25,7 @@
 #include <gtest/gtest.h>
 
 #include "InstalldNativeService.h"
+#include "dexopt.h"
 #include "globals.h"
 #include "utils.h"
 
@@ -41,25 +42,18 @@
     return property_get(key, value, default_value);
 }
 
-bool calculate_oat_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
-        const char *oat_dir ATTRIBUTE_UNUSED,
-        const char *apk_path ATTRIBUTE_UNUSED,
-        const char *instruction_set ATTRIBUTE_UNUSED) {
-    return false;
-}
-
-bool calculate_odex_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
-        const char *apk_path ATTRIBUTE_UNUSED,
-        const char *instruction_set ATTRIBUTE_UNUSED) {
-    return false;
-}
-
-bool create_cache_path(char path[PKG_PATH_MAX],
-        const char *src,
+bool calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
         const char *instruction_set) {
-    // Not really a valid path but it's good enough for testing.
-    sprintf(path,"/data/dalvik-cache/%s/%s", instruction_set, src);
-    return true;
+    return calculate_oat_file_path_default(path, oat_dir, apk_path, instruction_set);
+}
+
+bool calculate_odex_file_path(char path[PKG_PATH_MAX], const char *apk_path,
+        const char *instruction_set) {
+    return calculate_odex_file_path_default(path, apk_path, instruction_set);
+}
+
+bool create_cache_path(char path[PKG_PATH_MAX], const char *src, const char *instruction_set) {
+    return create_cache_path_default(path, src, instruction_set);
 }
 
 static void mkdir(const char* path, uid_t owner, gid_t group, mode_t mode) {
@@ -102,6 +96,8 @@
         testUuid = std::make_unique<std::string>();
         *testUuid = std::string(kTestUuid);
         system("mkdir -p /data/local/tmp/user/0");
+
+        init_globals_from_data_and_root();
     }
 
     virtual void TearDown() {
@@ -153,12 +149,28 @@
     EXPECT_EQ(10000, stat_gid("com.example/bar/file"));
 }
 
-TEST_F(ServiceTest, RmDexNoDalvikCache) {
-    LOG(INFO) << "RmDexNoDalvikCache";
+TEST_F(ServiceTest, CalculateOat) {
+    char buf[PKG_PATH_MAX];
 
-    // Try to remove a non existing dalvik cache dex. The call should be
-    // successful because there's nothing to remove.
-    EXPECT_TRUE(service->rmdex("com.example", "arm").isOk());
+    EXPECT_TRUE(calculate_oat_file_path(buf, "/path/to/oat", "/path/to/file.apk", "isa"));
+    EXPECT_EQ("/path/to/oat/isa/file.odex", std::string(buf));
+
+    EXPECT_FALSE(calculate_oat_file_path(buf, "/path/to/oat", "/path/to/file", "isa"));
+    EXPECT_FALSE(calculate_oat_file_path(buf, "/path/to/oat", "file", "isa"));
+}
+
+TEST_F(ServiceTest, CalculateOdex) {
+    char buf[PKG_PATH_MAX];
+
+    EXPECT_TRUE(calculate_odex_file_path(buf, "/path/to/file.apk", "isa"));
+    EXPECT_EQ("/path/to/oat/isa/file.odex", std::string(buf));
+}
+
+TEST_F(ServiceTest, CalculateCache) {
+    char buf[PKG_PATH_MAX];
+
+    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));
 }
 
 }  // namespace installd
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 46ed85f..09dd25a 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -17,6 +17,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <android-base/logging.h>
 #include <gtest/gtest.h>
 
 #include "InstalldNativeService.h"
@@ -27,6 +28,7 @@
 #define LOG_TAG "utils_test"
 
 #define TEST_DATA_DIR "/data/"
+#define TEST_ROOT_DIR "/system/"
 #define TEST_APP_DIR "/data/app/"
 #define TEST_APP_PRIVATE_DIR "/data/app-private/"
 #define TEST_APP_EPHEMERAL_DIR "/data/app-ephemeral/"
@@ -44,39 +46,13 @@
 class UtilsTest : public testing::Test {
 protected:
     virtual void SetUp() {
-        android_app_dir.path = (char*) TEST_APP_DIR;
-        android_app_dir.len = strlen(TEST_APP_DIR);
+        setenv("ANDROID_LOG_TAGS", "*:v", 1);
+        android::base::InitLogging(nullptr);
 
-        android_app_private_dir.path = (char*) TEST_APP_PRIVATE_DIR;
-        android_app_private_dir.len = strlen(TEST_APP_PRIVATE_DIR);
-
-        android_app_ephemeral_dir.path = (char*) TEST_APP_EPHEMERAL_DIR;
-        android_app_ephemeral_dir.len = strlen(TEST_APP_EPHEMERAL_DIR);
-
-        android_data_dir.path = (char*) TEST_DATA_DIR;
-        android_data_dir.len = strlen(TEST_DATA_DIR);
-
-        android_asec_dir.path = (char*) TEST_ASEC_DIR;
-        android_asec_dir.len = strlen(TEST_ASEC_DIR);
-
-        android_mnt_expand_dir.path = (char*) TEST_EXPAND_DIR;
-        android_mnt_expand_dir.len = strlen(TEST_EXPAND_DIR);
-
-        android_system_dirs.count = 2;
-
-        android_system_dirs.dirs = (dir_rec_t*) calloc(android_system_dirs.count, sizeof(dir_rec_t));
-        android_system_dirs.dirs[0].path = (char*) TEST_SYSTEM_DIR1;
-        android_system_dirs.dirs[0].len = strlen(TEST_SYSTEM_DIR1);
-
-        android_system_dirs.dirs[1].path = (char*) TEST_SYSTEM_DIR2;
-        android_system_dirs.dirs[1].len = strlen(TEST_SYSTEM_DIR2);
-
-        android_profiles_dir.path = (char*) TEST_PROFILE_DIR;
-        android_profiles_dir.len = strlen(TEST_PROFILE_DIR);
+        init_globals_from_data_and_root(TEST_DATA_DIR, TEST_ROOT_DIR);
     }
 
     virtual void TearDown() {
-        free(android_system_dirs.dirs);
     }
 
     std::string create_too_long_path(const std::string& seed) {
@@ -276,184 +252,6 @@
             << badapp2 << " should be rejected not a system path";
 }
 
-TEST_F(UtilsTest, GetPathFromString_NullPathFail) {
-    dir_rec_t test1;
-    EXPECT_EQ(-1, get_path_from_string(&test1, (const char *) NULL))
-            << "Should not allow NULL as a path.";
-}
-
-TEST_F(UtilsTest, GetPathFromString_EmptyPathFail) {
-    dir_rec_t test1;
-    EXPECT_EQ(-1, get_path_from_string(&test1, ""))
-            << "Should not allow empty paths.";
-}
-
-TEST_F(UtilsTest, GetPathFromString_RelativePathFail) {
-    dir_rec_t test1;
-    EXPECT_EQ(-1, get_path_from_string(&test1, "mnt/asec"))
-            << "Should not allow relative paths.";
-}
-
-TEST_F(UtilsTest, GetPathFromString_NonCanonical) {
-    dir_rec_t test1;
-
-    EXPECT_EQ(0, get_path_from_string(&test1, "/mnt/asec"))
-            << "Should be able to canonicalize directory /mnt/asec";
-    EXPECT_STREQ("/mnt/asec/", test1.path)
-            << "/mnt/asec should be canonicalized to /mnt/asec/";
-    EXPECT_EQ(10, (ssize_t) test1.len)
-            << "path len should be equal to the length of /mnt/asec/ (10)";
-    free(test1.path);
-}
-
-TEST_F(UtilsTest, GetPathFromString_CanonicalPath) {
-    dir_rec_t test3;
-    EXPECT_EQ(0, get_path_from_string(&test3, "/data/app/"))
-            << "Should be able to canonicalize directory /data/app/";
-    EXPECT_STREQ("/data/app/", test3.path)
-            << "/data/app/ should be canonicalized to /data/app/";
-    EXPECT_EQ(10, (ssize_t) test3.len)
-            << "path len should be equal to the length of /data/app/ (10)";
-    free(test3.path);
-}
-
-TEST_F(UtilsTest, CreatePkgPath_LongPkgNameSuccess) {
-    char path[PKG_PATH_MAX];
-
-    // Create long packagename of "aaaaa..."
-    size_t pkgnameSize = PKG_NAME_MAX;
-    char pkgname[pkgnameSize + 1];
-    memset(pkgname, 'a', pkgnameSize);
-    pkgname[1] = '.';
-    pkgname[pkgnameSize] = '\0';
-
-    EXPECT_EQ(0, create_pkg_path(path, pkgname, "", 0))
-            << "Should successfully be able to create package name.";
-
-    std::string prefix = std::string(TEST_DATA_DIR) + PRIMARY_USER_PREFIX;
-    size_t offset = prefix.length();
-
-    EXPECT_STREQ(pkgname, path + offset)
-             << "Package path should be a really long string of a's";
-}
-
-TEST_F(UtilsTest, CreatePkgPath_LongPostfixFail) {
-    char path[PKG_PATH_MAX];
-
-    // Create long packagename of "aaaaa..."
-    size_t postfixSize = PKG_PATH_MAX;
-    char postfix[postfixSize + 1];
-    memset(postfix, 'a', postfixSize);
-    postfix[postfixSize] = '\0';
-
-    EXPECT_EQ(-1, create_pkg_path(path, "com.example.package", postfix, 0))
-            << "Should return error because postfix is too long.";
-}
-
-TEST_F(UtilsTest, CreatePkgPath_PrimaryUser) {
-    char path[PKG_PATH_MAX];
-
-    EXPECT_EQ(0, create_pkg_path(path, "com.example.package", "", 0))
-            << "Should return error because postfix is too long.";
-
-    std::string p = std::string(TEST_DATA_DIR)
-                    + PRIMARY_USER_PREFIX
-                    + "com.example.package";
-    EXPECT_STREQ(p.c_str(), path)
-            << "Package path should be in /data/data/";
-}
-
-TEST_F(UtilsTest, CreatePkgPath_SecondaryUser) {
-    char path[PKG_PATH_MAX];
-
-    EXPECT_EQ(0, create_pkg_path(path, "com.example.package", "", 1))
-            << "Should successfully create package path.";
-
-    std::string p = std::string(TEST_DATA_DIR)
-                    + SECONDARY_USER_PREFIX
-                    + "1/com.example.package";
-    EXPECT_STREQ(p.c_str(), path)
-            << "Package path should be in /data/user/";
-}
-
-TEST_F(UtilsTest, CreateMovePath_Primary) {
-    char path[PKG_PATH_MAX];
-
-    EXPECT_EQ(0, create_move_path(path, "com.android.test", "shared_prefs", 0))
-            << "Should be able to create move path for primary user";
-
-    EXPECT_STREQ("/data/data/com.android.test/shared_prefs", path)
-            << "Primary user package directory should be created correctly";
-}
-
-
-TEST_F(UtilsTest, CreateMovePath_Fail_AppTooLong) {
-    char path[PKG_PATH_MAX];
-    std::string really_long_app_name = create_too_long_path("com.example");
-    EXPECT_EQ(-1, create_move_path(path, really_long_app_name.c_str(), "shared_prefs", 0))
-            << "Should fail to create move path for primary user";
-}
-
-TEST_F(UtilsTest, CreateMovePath_Fail_LeafTooLong) {
-    char path[PKG_PATH_MAX];
-    std::string really_long_leaf_name = create_too_long_path("leaf_");
-    EXPECT_EQ(-1, create_move_path(path, "com.android.test", really_long_leaf_name.c_str(), 0))
-            << "Should fail to create move path for primary user";
-}
-
-TEST_F(UtilsTest, CopyAndAppend_Normal) {
-    //int copy_and_append(dir_rec_t* dst, dir_rec_t* src, char* suffix)
-    dir_rec_t dst;
-    dir_rec_t src;
-
-    src.path = (char*) "/data/";
-    src.len = strlen(src.path);
-
-    EXPECT_EQ(0, copy_and_append(&dst, &src, "app/"))
-            << "Should return error because postfix is too long.";
-
-    EXPECT_STREQ("/data/app/", dst.path)
-            << "Appended path should be correct";
-
-    EXPECT_EQ(10, (ssize_t) dst.len)
-            << "Appended path should be length of '/data/app/' (10)";
-}
-
-TEST_F(UtilsTest, AppendAndIncrement_Normal) {
-    size_t dst_size = 10;
-    char dst[dst_size];
-    char *dstp = dst;
-    const char* src = "FOO";
-
-    EXPECT_EQ(0, append_and_increment(&dstp, src, &dst_size))
-            << "String should append successfully";
-
-    EXPECT_STREQ("FOO", dst)
-            << "String should append correctly";
-
-    EXPECT_EQ(0, append_and_increment(&dstp, src, &dst_size))
-            << "String should append successfully again";
-
-    EXPECT_STREQ("FOOFOO", dst)
-            << "String should append correctly again";
-}
-
-TEST_F(UtilsTest, AppendAndIncrement_TooBig) {
-    size_t dst_size = 5;
-    char dst[dst_size];
-    char *dstp = dst;
-    const char* src = "FOO";
-
-    EXPECT_EQ(0, append_and_increment(&dstp, src, &dst_size))
-            << "String should append successfully";
-
-    EXPECT_STREQ("FOO", dst)
-            << "String should append correctly";
-
-    EXPECT_EQ(-1, append_and_increment(&dstp, src, &dst_size))
-            << "String should fail because it's too large to fit";
-}
-
 TEST_F(UtilsTest, CreateDataPath) {
     EXPECT_EQ("/data", create_data_path(nullptr));
     EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b",
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 7a562ca..c21fae5 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -129,24 +129,6 @@
             create_data_user_de_path(volume_uuid, user).c_str(), package_name);
 }
 
-int create_pkg_path(char path[PKG_PATH_MAX], const char *pkgname,
-        const char *postfix, userid_t userid) {
-    if (!is_valid_package_name(pkgname)) {
-        path[0] = '\0';
-        return -1;
-    }
-
-    std::string _tmp(create_data_user_ce_package_path(nullptr, userid, pkgname) + postfix);
-    const char* tmp = _tmp.c_str();
-    if (strlen(tmp) >= PKG_PATH_MAX) {
-        path[0] = '\0';
-        return -1;
-    } else {
-        strcpy(path, tmp);
-        return 0;
-    }
-}
-
 std::string create_data_path(const char* volume_uuid) {
     if (volume_uuid == nullptr) {
         return "/data";
@@ -213,7 +195,7 @@
 }
 
 std::string create_primary_cur_profile_dir_path(userid_t userid) {
-    return StringPrintf("%s/cur/%u", android_profiles_dir.path, userid);
+    return StringPrintf("%s/cur/%u", android_profiles_dir.c_str(), userid);
 }
 
 std::string create_primary_current_profile_package_dir_path(userid_t user,
@@ -224,12 +206,12 @@
 }
 
 std::string create_primary_ref_profile_dir_path() {
-    return StringPrintf("%s/ref", android_profiles_dir.path);
+    return StringPrintf("%s/ref", android_profiles_dir.c_str());
 }
 
 std::string create_primary_reference_profile_package_dir_path(const std::string& package_name) {
     check_package_name(package_name.c_str());
-    return StringPrintf("%s/ref/%s", android_profiles_dir.path, package_name.c_str());
+    return StringPrintf("%s/ref/%s", android_profiles_dir.c_str(), package_name.c_str());
 }
 
 std::string create_data_dalvik_cache_path() {
@@ -378,20 +360,6 @@
     return 0;
 }
 
-int create_move_path(char path[PKG_PATH_MAX],
-    const char* pkgname,
-    const char* leaf,
-    userid_t userid ATTRIBUTE_UNUSED)
-{
-    if ((android_data_dir.len + strlen(PRIMARY_USER_PREFIX) + strlen(pkgname) + strlen(leaf) + 1)
-            >= PKG_PATH_MAX) {
-        return -1;
-    }
-
-    sprintf(path, "%s%s%s/%s", android_data_dir.path, PRIMARY_USER_PREFIX, pkgname, leaf);
-    return 0;
-}
-
 /**
  * Checks whether the package name is valid. Returns -1 on error and
  * 0 on success.
@@ -767,22 +735,33 @@
  * The path is allowed to have at most one subdirectory and no indirections
  * to top level directories (i.e. have "..").
  */
-static int validate_path(const dir_rec_t* dir, const char* path, int maxSubdirs) {
-    size_t dir_len = dir->len;
-    const char* subdir = strchr(path + dir_len, '/');
-
-    // Only allow the path to have at most one subdirectory.
-    if (subdir != NULL) {
-        ++subdir;
-        if ((--maxSubdirs == 0) && strchr(subdir, '/') != NULL) {
-            ALOGE("invalid apk path '%s' (subdir?)\n", path);
-            return -1;
-        }
+static int validate_path(const std::string& dir, const std::string& path, int maxSubdirs) {
+    // Argument sanity checking
+    if (dir.find('/') != 0 || dir.rfind('/') != dir.size() - 1
+            || dir.find("..") != std::string::npos) {
+        LOG(ERROR) << "Invalid directory " << dir;
+        return -1;
+    }
+    if (path.find("..") != std::string::npos) {
+        LOG(ERROR) << "Invalid path " << path;
+        return -1;
     }
 
-    // Directories can't have a period directly after the directory markers to prevent "..".
-    if ((path[dir_len] == '.') || ((subdir != NULL) && (*subdir == '.'))) {
-        ALOGE("invalid apk path '%s' (trickery)\n", path);
+    if (path.compare(0, dir.size(), dir) != 0) {
+        // Common case, path isn't under directory
+        return -1;
+    }
+
+    // Count number of subdirectories
+    auto pos = path.find('/', dir.size());
+    int count = 0;
+    while (pos != std::string::npos) {
+        pos = path.find('/', pos + 1);
+        count++;
+    }
+
+    if (count > maxSubdirs) {
+        LOG(ERROR) << "Invalid path depth " << path << " when tested against " << dir;
         return -1;
     }
 
@@ -794,15 +773,12 @@
  * if it is a system app or -1 if it is not.
  */
 int validate_system_app_path(const char* path) {
-    size_t i;
-
-    for (i = 0; i < android_system_dirs.count; i++) {
-        const size_t dir_len = android_system_dirs.dirs[i].len;
-        if (!strncmp(path, android_system_dirs.dirs[i].path, dir_len)) {
-            return validate_path(android_system_dirs.dirs + i, path, 1);
+    std::string path_ = path;
+    for (const auto& dir : android_system_dirs) {
+        if (validate_path(dir, path, 1) == 0) {
+            return 0;
         }
     }
-
     return -1;
 }
 
@@ -840,116 +816,26 @@
 }
 
 /**
- * Get the contents of a environment variable that contains a path. Caller
- * owns the string that is inserted into the directory record. Returns
- * 0 on success and -1 on error.
- */
-int get_path_from_env(dir_rec_t* rec, const char* var) {
-    const char* path = getenv(var);
-    int ret = get_path_from_string(rec, path);
-    if (ret < 0) {
-        ALOGW("Problem finding value for environment variable %s\n", var);
-    }
-    return ret;
-}
-
-/**
- * Puts the string into the record as a directory. Appends '/' to the end
- * of all paths. Caller owns the string that is inserted into the directory
- * record. A null value will result in an error.
- *
- * Returns 0 on success and -1 on error.
- */
-int get_path_from_string(dir_rec_t* rec, const char* path) {
-    if (path == NULL) {
-        return -1;
-    } else {
-        const size_t path_len = strlen(path);
-        if (path_len <= 0) {
-            return -1;
-        }
-
-        // Make sure path is absolute.
-        if (path[0] != '/') {
-            return -1;
-        }
-
-        if (path[path_len - 1] == '/') {
-            // Path ends with a forward slash. Make our own copy.
-
-            rec->path = strdup(path);
-            if (rec->path == NULL) {
-                return -1;
-            }
-
-            rec->len = path_len;
-        } else {
-            // Path does not end with a slash. Generate a new string.
-            char *dst;
-
-            // Add space for slash and terminating null.
-            size_t dst_size = path_len + 2;
-
-            rec->path = (char*) malloc(dst_size);
-            if (rec->path == NULL) {
-                return -1;
-            }
-
-            dst = rec->path;
-
-            if (append_and_increment(&dst, path, &dst_size) < 0
-                    || append_and_increment(&dst, "/", &dst_size)) {
-                ALOGE("Error canonicalizing path");
-                return -1;
-            }
-
-            rec->len = dst - rec->path;
-        }
-    }
-    return 0;
-}
-
-int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix) {
-    dst->len = src->len + strlen(suffix);
-    const size_t dstSize = dst->len + 1;
-    dst->path = (char*) malloc(dstSize);
-
-    if (dst->path == NULL
-            || snprintf(dst->path, dstSize, "%s%s", src->path, suffix)
-                    != (ssize_t) dst->len) {
-        ALOGE("Could not allocate memory to hold appended path; aborting\n");
-        return -1;
-    }
-
-    return 0;
-}
-
-/**
  * Check whether path points to a valid path for an APK file. The path must
  * begin with a whitelisted prefix path and must be no deeper than |maxSubdirs| within
  * that path. Returns -1 when an invalid path is encountered and 0 when a valid path
  * is encountered.
  */
 static int validate_apk_path_internal(const char *path, int maxSubdirs) {
-    const dir_rec_t* dir = NULL;
-    if (!strncmp(path, android_app_dir.path, android_app_dir.len)) {
-        dir = &android_app_dir;
-    } else if (!strncmp(path, android_app_private_dir.path, android_app_private_dir.len)) {
-        dir = &android_app_private_dir;
-    } else if (!strncmp(path, android_app_ephemeral_dir.path, android_app_ephemeral_dir.len)) {
-        dir = &android_app_ephemeral_dir;
-    } else if (!strncmp(path, android_asec_dir.path, android_asec_dir.len)) {
-        dir = &android_asec_dir;
-    } else if (!strncmp(path, android_mnt_expand_dir.path, android_mnt_expand_dir.len)) {
-        dir = &android_mnt_expand_dir;
-        if (maxSubdirs < 2) {
-            maxSubdirs = 2;
-        }
+    std::string path_ = path;
+    if (validate_path(android_app_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) {
+        return 0;
+    } else if (validate_path(android_asec_dir, path_, maxSubdirs) == 0) {
+        return 0;
+    } else if (validate_path(android_mnt_expand_dir, path_, std::max(maxSubdirs, 2)) == 0) {
+        return 0;
     } else {
         return -1;
     }
-
-    return validate_path(dir, path, maxSubdirs);
 }
 
 int validate_apk_path(const char* path) {
@@ -960,48 +846,6 @@
     return validate_apk_path_internal(path, 3 /* maxSubdirs */);
 }
 
-int append_and_increment(char** dst, const char* src, size_t* dst_size) {
-    ssize_t ret = strlcpy(*dst, src, *dst_size);
-    if (ret < 0 || (size_t) ret >= *dst_size) {
-        return -1;
-    }
-    *dst += ret;
-    *dst_size -= ret;
-    return 0;
-}
-
-char *build_string2(const char *s1, const char *s2) {
-    if (s1 == NULL || s2 == NULL) return NULL;
-
-    int len_s1 = strlen(s1);
-    int len_s2 = strlen(s2);
-    int len = len_s1 + len_s2 + 1;
-    char *result = (char *) malloc(len);
-    if (result == NULL) return NULL;
-
-    strcpy(result, s1);
-    strcpy(result + len_s1, s2);
-
-    return result;
-}
-
-char *build_string3(const char *s1, const char *s2, const char *s3) {
-    if (s1 == NULL || s2 == NULL || s3 == NULL) return NULL;
-
-    int len_s1 = strlen(s1);
-    int len_s2 = strlen(s2);
-    int len_s3 = strlen(s3);
-    int len = len_s1 + len_s2 + len_s3 + 1;
-    char *result = (char *) malloc(len);
-    if (result == NULL) return NULL;
-
-    strcpy(result, s1);
-    strcpy(result + len_s1, s2);
-    strcpy(result + len_s1 + len_s2, s3);
-
-    return result;
-}
-
 int ensure_config_user_dirs(userid_t userid) {
     // writable by system, readable by any app within the same user
     const int uid = multiuser_get_uid(userid, AID_SYSTEM);
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index a1d8443..3e04af9 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -41,18 +41,11 @@
 namespace android {
 namespace installd {
 
-struct dir_rec_t;
-
 constexpr const char* kXattrInodeCache = "user.inode_cache";
 constexpr const char* kXattrInodeCodeCache = "user.inode_code_cache";
 constexpr const char* kXattrCacheGroup = "user.cache_group";
 constexpr const char* kXattrCacheTombstone = "user.cache_tombstone";
 
-int create_pkg_path(char path[PKG_PATH_MAX],
-                    const char *pkgname,
-                    const char *postfix,
-                    userid_t userid);
-
 std::string create_data_path(const char* volume_uuid);
 
 std::string create_data_app_path(const char* volume_uuid);
@@ -96,11 +89,6 @@
 
 int create_user_config_path(char path[PKG_PATH_MAX], userid_t userid);
 
-int create_move_path(char path[PKG_PATH_MAX],
-                     const char* pkgname,
-                     const char* leaf,
-                     userid_t userid);
-
 bool is_valid_filename(const std::string& name);
 bool is_valid_package_name(const std::string& packageName);
 
@@ -128,20 +116,9 @@
 bool validate_secondary_dex_path(const std::string& pkgname, const std::string& dex_path,
         const char* volume_uuid, int uid, int storage_flag, bool validate_package_path = true);
 
-int get_path_from_env(dir_rec_t* rec, const char* var);
-
-int get_path_from_string(dir_rec_t* rec, const char* path);
-
-int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix);
-
 int validate_apk_path(const char *path);
 int validate_apk_path_subdirs(const char *path);
 
-int append_and_increment(char** dst, const char* src, size_t* dst_size);
-
-char *build_string2(const char *s1, const char *s2);
-char *build_string3(const char *s1, const char *s2, const char *s3);
-
 int ensure_config_user_dirs(userid_t userid);
 
 int wait_child(pid_t pid);