Merge "Valid APK paths now include expanded storage."
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 58e7efe..5f72ae4 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -30,6 +30,7 @@
 dir_rec_t android_app_private_dir;
 dir_rec_t android_app_lib_dir;
 dir_rec_t android_media_dir;
+dir_rec_t android_mnt_expand_dir;
 dir_rec_array_t android_system_dirs;
 
 int install(const char *pkgname, uid_t uid, gid_t gid, const char *seinfo)
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index 5b71175..930ba2f 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -352,6 +352,11 @@
         return -1;
     }
 
+    // Get the android external app directory.
+    if (get_path_from_string(&android_mnt_expand_dir, "/mnt/expand") < 0) {
+        return -1;
+    }
+
     // Take note of the system and vendor directories.
     android_system_dirs.count = 4;
 
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index 9c30a35..7c52b78 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -101,6 +101,7 @@
 extern dir_rec_t android_data_dir;
 extern dir_rec_t android_asec_dir;
 extern dir_rec_t android_media_dir;
+extern dir_rec_t android_mnt_expand_dir;
 extern dir_rec_array_t android_system_dirs;
 
 typedef struct cache_dir_struct {
@@ -230,4 +231,4 @@
 int create_oat_dir(const char* oat_dir, const char *instruction_set);
 int rm_package_dir(const char* apk_path);
 int calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
-                            const char *instruction_set);
\ No newline at end of file
+                            const char *instruction_set);
diff --git a/cmds/installd/utils.c b/cmds/installd/utils.c
index 8f366a0..54f90ab 100644
--- a/cmds/installd/utils.c
+++ b/cmds/installd/utils.c
@@ -910,14 +910,14 @@
  * 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) {
+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 (strchr(subdir, '/') != NULL) {
+        if ((--maxSubdirs == 0) && strchr(subdir, '/') != NULL) {
             ALOGE("invalid apk path '%s' (subdir?)\n", path);
             return -1;
         }
@@ -942,7 +942,7 @@
     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);
+            return validate_path(android_system_dirs.dirs + i, path, 1);
         }
     }
 
@@ -1042,6 +1042,7 @@
 int validate_apk_path(const char *path)
 {
     const dir_rec_t* dir = NULL;
+    int maxSubdirs = 1;
 
     if (!strncmp(path, android_app_dir.path, android_app_dir.len)) {
         dir = &android_app_dir;
@@ -1049,11 +1050,14 @@
         dir = &android_app_private_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;
+        maxSubdirs = 2;
     } else {
         return -1;
     }
 
-    return validate_path(dir, path);
+    return validate_path(dir, path, maxSubdirs);
 }
 
 int append_and_increment(char** dst, const char* src, size_t* dst_size) {