am da2509c4: Merge "Check non-primary user dirs during package scan" into jb-mr1-dev

* commit 'da2509c434ebb2a5a0da1bc270cae7f007cbb0f9':
  Check non-primary user dirs during package scan
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 387f33d..1e6398f 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -141,39 +141,54 @@
     return 0;
 }
 
-int fix_uid(const char *pkgname, uid_t uid, gid_t gid)
+int fix_uid(const char *pkgname, uid_t uid, uid_t userId)
 {
     char pkgdir[PKG_PATH_MAX];
     struct stat s;
     int rc = 0;
 
-    if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
-        ALOGE("invalid uid/gid: %d %d\n", uid, gid);
+    if (uid < AID_SYSTEM) {
+        ALOGE("invalid uid: %d\n", uid);
         return -1;
     }
 
-    if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {
+    if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userId)) {
         ALOGE("cannot create package path\n");
         return -1;
     }
 
     if (stat(pkgdir, &s) < 0) return -1;
 
-    if (s.st_uid != 0 || s.st_gid != 0) {
-        ALOGE("fixing uid of non-root pkg: %s %lu %lu\n", pkgdir, s.st_uid, s.st_gid);
+    if (((s.st_uid != 0) && (s.st_uid != AID_INSTALL))
+            || ((s.st_gid != 0) && (s.st_gid != AID_INSTALL))) {
+        ALOGE("fixing uid of pkg not owned by install or root: %s %lu %lu\n", pkgdir, s.st_uid,
+                s.st_gid);
+        return -1;
+    }
+
+    if (chown(pkgdir, AID_INSTALL, AID_INSTALL) < 0) {
+        ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
+        unlink(pkgdir);
         return -1;
     }
 
     if (chmod(pkgdir, 0751) < 0) {
         ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
         unlink(pkgdir);
-        return -errno;
+        return -1;
     }
-    if (chown(pkgdir, uid, gid) < 0) {
+    if (chown(pkgdir, uid, uid) < 0) {
         ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
         unlink(pkgdir);
-        return -errno;
+        return -1;
     }
+#ifdef HAVE_SELINUX
+    if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
+        ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
+        unlink(pkgdir);
+        return -1;
+    }
+#endif
 
     return 0;
 }
diff --git a/services/java/com/android/server/pm/Installer.java b/services/java/com/android/server/pm/Installer.java
index 71a6a01..0247911 100644
--- a/services/java/com/android/server/pm/Installer.java
+++ b/services/java/com/android/server/pm/Installer.java
@@ -243,14 +243,14 @@
         return execute(builder.toString());
     }
 
-    public int fixUid(String name, int uid, int gid) {
+    public int fixUid(String name, int uid, int userId) {
         StringBuilder builder = new StringBuilder("fixuid");
         builder.append(' ');
         builder.append(name);
         builder.append(' ');
         builder.append(uid);
         builder.append(' ');
-        builder.append(gid);
+        builder.append(userId);
         return execute(builder.toString());
     }
 
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 4c6f589..66d2f24 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -1008,6 +1008,8 @@
             mHandler = new PackageHandler(mHandlerThread.getLooper());
 
             File dataDir = Environment.getDataDirectory();
+            mAppInstallDir = new File(dataDir, "app");
+            mAppLibInstallDir = new File(dataDir, "app-lib");
             mAppDataDir = new File(dataDir, "data");
             mAsecInternalPath = new File(dataDir, "app-asec").getPath();
             mUserAppDataDir = new File(dataDir, "user");
@@ -1218,8 +1220,6 @@
                 }
             }
 
-            mAppInstallDir = new File(dataDir, "app");
-            mAppLibInstallDir = new File(dataDir, "app-lib");
             //look for any incomplete package installations
             ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
             //clean up list
@@ -3576,22 +3576,22 @@
         }
     }
 
-    private int createDataDirsLI(String packageName, int uid) {
-        int[] users = sUserManager.getUserIds();
-        int res = mInstaller.install(packageName, uid, uid);
-        if (res < 0) {
-            return res;
+    private int createDataDirForUserLI(String packageName, int uid, int userId) {
+        if (userId == 0) {
+            return mInstaller.install(packageName, uid, uid);
+        } else {
+            return mInstaller.createUserData(packageName, UserHandle.getUid(userId, uid), userId);
         }
-        for (int user : users) {
-            if (user != 0) {
-                res = mInstaller.createUserData(packageName,
-                        UserHandle.getUid(user, uid), user);
-                if (res < 0) {
-                    return res;
-                }
+    }
+
+    private int createDataDirsLI(String packageName, int uid) {
+        for (int userId : sUserManager.getUserIds()) {
+            int res = createDataDirForUserLI(packageName, uid, userId);
+            if (res < 0) {
+                return res;
             }
         }
-        return res;
+        return 0;
     }
 
     private int removeDataDirsLI(String packageName) {
@@ -3930,134 +3930,49 @@
             pkg.applicationInfo.dataDir = dataPath.getPath();
         } else {
             // This is a normal package, need to make its data directory.
-            dataPath = getDataPathForPackage(pkg.packageName, 0);
+            dataPath = getDataPathForPackage(pkg.packageName, UserHandle.USER_OWNER);
 
-            boolean uidError = false;
-
-            if (dataPath.exists()) {
-                int currentUid = 0;
-                try {
-                    StructStat stat = Libcore.os.stat(dataPath.getPath());
-                    currentUid = stat.st_uid;
-                } catch (ErrnoException e) {
-                    Slog.e(TAG, "Couldn't stat path " + dataPath.getPath(), e);
-                }
-
-                // If we have mismatched owners for the data path, we have a problem.
-                if (currentUid != pkg.applicationInfo.uid) {
-                    boolean recovered = false;
-                    if (currentUid == 0) {
-                        // The directory somehow became owned by root.  Wow.
-                        // This is probably because the system was stopped while
-                        // installd was in the middle of messing with its libs
-                        // directory.  Ask installd to fix that.
-                        int ret = mInstaller.fixUid(pkgName, pkg.applicationInfo.uid,
-                                pkg.applicationInfo.uid);
-                        if (ret >= 0) {
-                            recovered = true;
-                            String msg = "Package " + pkg.packageName
-                                    + " unexpectedly changed to uid 0; recovered to " +
-                                    + pkg.applicationInfo.uid;
-                            reportSettingsProblem(Log.WARN, msg);
-                        }
-                    }
-                    if (!recovered && ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0
-                            || (scanMode&SCAN_BOOTING) != 0)) {
-                        // If this is a system app, we can at least delete its
-                        // current data so the application will still work.
-                        int ret = removeDataDirsLI(pkgName);
-                        if (ret >= 0) {
-                            // TODO: Kill the processes first
-                            // Old data gone!
-                            String prefix = (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0
-                                    ? "System package " : "Third party package ";
-                            String msg = prefix + pkg.packageName
-                                    + " has changed from uid: "
-                                    + currentUid + " to "
-                                    + pkg.applicationInfo.uid + "; old data erased";
-                            reportSettingsProblem(Log.WARN, msg);
-                            recovered = true;
-
-                            // And now re-install the app.
-                            ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid);
-                            if (ret == -1) {
-                                // Ack should not happen!
-                                msg = prefix + pkg.packageName
-                                        + " could not have data directory re-created after delete.";
-                                reportSettingsProblem(Log.WARN, msg);
-                                mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-                                return null;
-                            }
-                        }
-                        if (!recovered) {
-                            mHasSystemUidErrors = true;
-                        }
-                    } else if (!recovered) {
-                        // If we allow this install to proceed, we will be broken.
-                        // Abort, abort!
-                        mLastScanError = PackageManager.INSTALL_FAILED_UID_CHANGED;
-                        return null;
-                    }
-                    if (!recovered) {
-                        pkg.applicationInfo.dataDir = "/mismatched_uid/settings_"
-                            + pkg.applicationInfo.uid + "/fs_"
-                            + currentUid;
-                        pkg.applicationInfo.nativeLibraryDir = pkg.applicationInfo.dataDir;
-                        String msg = "Package " + pkg.packageName
-                                + " has mismatched uid: "
-                                + currentUid + " on disk, "
-                                + pkg.applicationInfo.uid + " in settings";
-                        // writer
-                        synchronized (mPackages) {
-                            mSettings.mReadMessages.append(msg);
-                            mSettings.mReadMessages.append('\n');
-                            uidError = true;
-                            if (!pkgSetting.uidError) {
-                                reportSettingsProblem(Log.ERROR, msg);
-                            }
-                        }
-                    }
-                }
-                pkg.applicationInfo.dataDir = dataPath.getPath();
-            } else {
+            if (!ensureDataDirExistsForAllUsers(pkg.packageName, pkg.applicationInfo.uid)) {
                 if (DEBUG_PACKAGE_SCANNING) {
-                    if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
+                    if ((parseFlags & PackageParser.PARSE_CHATTY) != 0) {
                         Log.v(TAG, "Want this data dir: " + dataPath);
-                }
-                //invoke installer to do the actual installation
-                int ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid);
-                if (ret < 0) {
-                    // Error from installer
-                    mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-                    return null;
+                    }
                 }
 
-                if (dataPath.exists()) {
-                    pkg.applicationInfo.dataDir = dataPath.getPath();
-                } else {
-                    Slog.w(TAG, "Unable to create data directory: " + dataPath);
-                    pkg.applicationInfo.dataDir = null;
-                }
+                // Error from installer
+                mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+                return null;
+            } else {
+                pkg.applicationInfo.dataDir = dataPath.getPath();
             }
 
+            final boolean isSystemApp = (parseFlags & PackageParser.PARSE_IS_SYSTEM) != 0;
+            final boolean isBootScan = (scanMode & SCAN_BOOTING) != 0;
+
+            final boolean uidCorrect = ensureDataDirUidIsCorrectForAllUsers(pkg.packageName,
+                    pkg.applicationInfo.uid, isSystemApp, isBootScan);
+            if (!uidCorrect) {
+                pkg.applicationInfo.dataDir = "/mismatched_uid/settings_" + pkg.applicationInfo.uid
+                        + "/fs_mismatched";
+                pkg.applicationInfo.nativeLibraryDir = pkg.applicationInfo.dataDir;
+            }
+
+            pkgSetting.uidError = !uidCorrect;
+
             /*
-             * Set the data dir to the default "/data/data/<package name>/lib"
-             * if we got here without anyone telling us different (e.g., apps
-             * stored on SD card have their native libraries stored in the ASEC
-             * container with the APK).
-             *
-             * This happens during an upgrade from a package settings file that
-             * doesn't have a native library path attribute at all.
+             * Set the native library dir to the default if we got here without
+             * anyone telling us different (e.g., apps stored on SD card have
+             * their native libraries stored in the ASEC container with the
+             * APK). This happens during an upgrade from a package settings file
+             * that doesn't have a native library path attribute at all.
              */
-            if (pkg.applicationInfo.nativeLibraryDir == null && pkg.applicationInfo.dataDir != null) {
+            if (pkg.applicationInfo.nativeLibraryDir == null) {
                 if (pkgSetting.nativeLibraryPathString == null) {
                     setInternalAppNativeLibraryPath(pkg, pkgSetting);
                 } else {
                     pkg.applicationInfo.nativeLibraryDir = pkgSetting.nativeLibraryPathString;
                 }
             }
-
-            pkgSetting.uidError = uidError;
         }
 
         String path = scanFile.getPath();
@@ -4446,6 +4361,100 @@
         return pkg;
     }
 
+    /**
+     * Checks to see whether a package data directory is owned by the correct
+     * user. If it isn't, it will attempt to fix it if it's a system application
+     * or if this is the boot scan.
+     *
+     * @return {@code true} if successful, {@code false} if recovery failed
+     */
+    private boolean ensureDataDirUidIsCorrectForAllUsers(String packageName, int appUid,
+            boolean isSystemApp, boolean isBootScan) {
+        boolean mismatch = false;
+
+        for (int userId : sUserManager.getUserIds()) {
+            final File dataPath = getDataPathForPackage(packageName, userId);
+
+            int currentUid = 0;
+            try {
+                final StructStat stat = Libcore.os.stat(dataPath.getPath());
+                currentUid = stat.st_uid;
+            } catch (ErrnoException e) {
+                Slog.e(TAG, "Couldn't stat path " + dataPath.getPath(), e);
+            }
+
+            final int expectedUid = UserHandle.getUid(userId, appUid);
+
+            // If we have mismatched owners for the data path, we have a
+            // problem.
+            if (currentUid != expectedUid) {
+                if (currentUid == 0) {
+                    // The directory somehow became owned by root. Wow.
+                    // This is probably because the system was stopped while
+                    // installd was in the middle of messing with its libs
+                    // directory. Ask installd to fix that.
+                    final int ret;
+                    synchronized (mInstaller) {
+                        ret = mInstaller.fixUid(packageName, expectedUid, userId);
+                    }
+                    if (ret >= 0) {
+                        String msg = "Package " + packageName
+                                + " unexpectedly changed to uid 0; recovered to " + expectedUid;
+                        reportSettingsProblem(Log.WARN, msg);
+                    } else {
+                        mismatch = true;
+                        String prefix = isSystemApp ? "System package " : "Third party package ";
+                        String msg = prefix + packageName + " has changed from uid: " + currentUid
+                                + " to " + expectedUid;
+                        reportSettingsProblem(Log.WARN, msg);
+                    }
+                }
+            }
+        }
+
+        if (mismatch) {
+            if (isSystemApp || isBootScan) {
+                // If this is a system app, we can at least delete its
+                // current data so the application will still work.
+                int ret;
+                synchronized (mInstallLock) {
+                    ret = removeDataDirsLI(packageName);
+                }
+                if (ret >= 0) {
+                    // TODO: Kill the processes first
+                    // Old data gone!
+                    String prefix = isSystemApp
+                            ? "System package " : "Third party package ";
+                    String msg = prefix + packageName + " old data erased";
+                    reportSettingsProblem(Log.WARN, msg);
+
+                    // And now re-install the app.
+                    synchronized (mInstallLock) {
+                        ret = createDataDirsLI(packageName, appUid);
+                    }
+                    if (ret == -1) {
+                        // Ack should not happen!
+                        msg = prefix + packageName
+                                + " could not have data directory re-created after delete.";
+                        reportSettingsProblem(Log.WARN, msg);
+                        mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+                        return false;
+                    }
+                } else {
+                    mHasSystemUidErrors = true;
+                    return false;
+                }
+            } else {
+                // If we allow this install to proceed, we will be broken.
+                // Abort, abort!
+                mLastScanError = PackageManager.INSTALL_FAILED_UID_CHANGED;
+                return false;
+            }
+        }
+
+        return true;
+    }
+
     private void setInternalAppNativeLibraryPath(PackageParser.Package pkg,
             PackageSetting pkgSetting) {
         final String apkLibPath = getApkName(pkgSetting.codePathString);
@@ -7502,6 +7511,22 @@
         PackageRemovedInfo removedInfo;
     }
 
+    private boolean ensureDataDirExistsForAllUsers(String packageName, int uid) {
+        boolean exists = true;
+        for (int userId : sUserManager.getUserIds()) {
+            final File dataPath = getDataPathForPackage(packageName, userId);
+            if (!dataPath.exists()) {
+                synchronized (mInstallLock) {
+                    if (createDataDirForUserLI(packageName, uid, userId) < 0) {
+                        Slog.e(TAG, "Couldn't create data path " + dataPath.getPath());
+                    }
+                }
+                exists &= dataPath.exists();
+            }
+        }
+        return exists;
+    }
+
     /*
      * Install a non-existing package.
      */
@@ -7511,7 +7536,8 @@
         // Remember this for later, in case we need to rollback this install
         String pkgName = pkg.packageName;
 
-        boolean dataDirExists = getDataPathForPackage(pkg.packageName, 0).exists();
+        boolean dataDirExists = ensureDataDirExistsForAllUsers(pkg.packageName,
+                pkg.applicationInfo.uid);
         synchronized(mPackages) {
             if (mSettings.mRenamedPackages.containsKey(pkgName)) {
                 // A package with the same name is already installed, though