Follow installd changes, throw exceptions.

Start by passing down flags to work on both CE and DE storage areas;
a future change will refine this further.

Force consistent argument checking and null handling for all
installd callers.  Throw explicit exceptions instead of returning int
values that can accidentally be ignored.

Bug: 26466827
Change-Id: Iddb591f6b3c7786d210d3f132ff7f9886a97b749
diff --git a/core/java/com/android/internal/os/InstallerConnection.java b/core/java/com/android/internal/os/InstallerConnection.java
index 830da79..b3222f0 100644
--- a/core/java/com/android/internal/os/InstallerConnection.java
+++ b/core/java/com/android/internal/os/InstallerConnection.java
@@ -19,6 +19,7 @@
 import android.net.LocalSocket;
 import android.net.LocalSocketAddress;
 import android.os.SystemClock;
+import android.text.TextUtils;
 import android.util.Slog;
 
 import com.android.internal.util.Preconditions;
@@ -29,6 +30,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.Arrays;
 
 /**
  * Represents a connection to {@code installd}. Allows multiple connect and
@@ -61,6 +63,11 @@
     }
 
     public synchronized String transact(String cmd) {
+        if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
+            Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
+                    + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable());
+        }
+
         if (!connect()) {
             Slog.e(TAG, "connection failed");
             return "-1";
@@ -96,44 +103,50 @@
         }
     }
 
-    public int execute(String cmd) {
-        if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
-            Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
-                    + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable());
-        }
-
-        String res = transact(cmd);
+    public void execute(String cmd, Object... args) throws InstallerException {
+        final String resRaw = executeForResult(cmd, args);
+        int res = -1;
         try {
-            return Integer.parseInt(res);
-        } catch (NumberFormatException ex) {
-            return -1;
+            res = Integer.parseInt(resRaw);
+        } catch (NumberFormatException ignored) {
+        }
+        if (res != 0) {
+            throw new InstallerException(
+                    "Failed to execute " + cmd + " " + Arrays.toString(args) + ": " + res);
         }
     }
 
-    public int dexopt(String apkPath, int uid, String instructionSet,
-            int dexoptNeeded, int dexFlags) {
-        return dexopt(apkPath, uid, "*", instructionSet, dexoptNeeded,
-                null /*outputPath*/, dexFlags);
+    public String executeForResult(String cmd, Object... args)
+            throws InstallerException {
+        final StringBuilder builder = new StringBuilder(cmd);
+        for (Object arg : args) {
+            String escaped;
+            if (arg == null) {
+                escaped = "";
+            } else {
+                escaped = String.valueOf(arg);
+            }
+            if (escaped.indexOf('\0') != -1 || escaped.indexOf(' ') != -1 || "!".equals(escaped)) {
+                throw new InstallerException(
+                        "Invalid argument while executing " + cmd + " " + Arrays.toString(args));
+            }
+            if (TextUtils.isEmpty(escaped)) {
+                escaped = "!";
+            }
+            builder.append(' ').append(escaped);
+        }
+        return transact(builder.toString());
     }
 
-    public int dexopt(String apkPath, int uid, String pkgName, String instructionSet,
-            int dexoptNeeded, String outputPath, int dexFlags) {
-        StringBuilder builder = new StringBuilder("dexopt");
-        builder.append(' ');
-        builder.append(apkPath);
-        builder.append(' ');
-        builder.append(uid);
-        builder.append(' ');
-        builder.append(pkgName);
-        builder.append(' ');
-        builder.append(instructionSet);
-        builder.append(' ');
-        builder.append(dexoptNeeded);
-        builder.append(' ');
-        builder.append(outputPath != null ? outputPath : "!");
-        builder.append(' ');
-        builder.append(dexFlags);
-        return execute(builder.toString());
+    public void dexopt(String apkPath, int uid, String instructionSet, int dexoptNeeded,
+            int dexFlags) throws InstallerException {
+        dexopt(apkPath, uid, "*", instructionSet, dexoptNeeded, null /* outputPath */, dexFlags);
+    }
+
+    public void dexopt(String apkPath, int uid, String pkgName, String instructionSet,
+            int dexoptNeeded, String outputPath, int dexFlags) throws InstallerException {
+        execute("dexopt", apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath,
+                dexFlags);
     }
 
     private boolean connect() {
@@ -227,11 +240,19 @@
 
     public void waitForConnection() {
         for (;;) {
-            if (execute("ping") >= 0) {
+            try {
+                execute("ping");
                 return;
+            } catch (InstallerException ignored) {
             }
             Slog.w(TAG, "installd not ready");
             SystemClock.sleep(1000);
         }
     }
+
+    public static class InstallerException extends Exception {
+        public InstallerException(String detailMessage) {
+            super(detailMessage);
+        }
+    }
 }
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 4a1f7f4..eecc0ee 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -37,6 +37,8 @@
 import android.util.Log;
 import android.webkit.WebViewFactory;
 
+import com.android.internal.os.InstallerConnection.InstallerException;
+
 import dalvik.system.DexFile;
 import dalvik.system.PathClassLoader;
 import dalvik.system.VMRuntime;
@@ -502,8 +504,8 @@
                             dexoptNeeded, 0 /*dexFlags*/);
                 }
             }
-        } catch (IOException ioe) {
-            throw new RuntimeException("Error starting system_server", ioe);
+        } catch (IOException | InstallerException e) {
+            throw new RuntimeException("Error starting system_server", e);
         } finally {
             installer.disconnect();
         }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e8d831f..4cb64a1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -35,6 +35,7 @@
 import com.android.internal.os.ProcessCpuTracker;
 import com.android.internal.os.TransferPipe;
 import com.android.internal.os.Zygote;
+import com.android.internal.os.InstallerConnection.InstallerException;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.FastXmlSerializer;
@@ -6590,8 +6591,10 @@
             Process.establishZygoteConnectionForAbi(abi);
             final String instructionSet = VMRuntime.getInstructionSet(abi);
             if (!completedIsas.contains(instructionSet)) {
-                if (mInstaller.markBootComplete(VMRuntime.getInstructionSet(abi)) != 0) {
-                    Slog.e(TAG, "Unable to mark boot complete for abi: " + abi);
+                try {
+                    mInstaller.markBootComplete(VMRuntime.getInstructionSet(abi));
+                } catch (InstallerException e) {
+                    Slog.e(TAG, "Unable to mark boot complete for abi: " + abi, e);
                 }
                 completedIsas.add(instructionSet);
             }
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 99a051a..190eca6 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -20,14 +20,14 @@
 import android.content.Context;
 import android.content.pm.PackageStats;
 import android.os.Build;
-import android.text.TextUtils;
 import android.util.Slog;
 
-import dalvik.system.VMRuntime;
-
 import com.android.internal.os.InstallerConnection;
+import com.android.internal.os.InstallerConnection.InstallerException;
 import com.android.server.SystemService;
 
+import dalvik.system.VMRuntime;
+
 public final class Installer extends SystemService {
     private static final String TAG = "Installer";
 
@@ -46,6 +46,11 @@
     /** Run the application with the JIT compiler */
     public static final int DEXOPT_USEJIT       = 1 << 5;
 
+    public static final int FLAG_DE_STORAGE = 1 << 0;
+    public static final int FLAG_CE_STORAGE = 1 << 1;
+    public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 2;
+    public static final int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 3;
+
     private final InstallerConnection mInstaller;
 
     public Installer(Context context) {
@@ -67,423 +72,137 @@
         mInstaller.waitForConnection();
     }
 
-    private static String escapeNull(String arg) {
-        if (TextUtils.isEmpty(arg)) {
-            return "!";
-        } else {
-            if (arg.indexOf('\0') != -1 || arg.indexOf(' ') != -1) {
-                throw new IllegalArgumentException(arg);
-            }
-            return arg;
-        }
+    public void createAppData(String uuid, String pkgname, int userid, int flags, int appid,
+            String seinfo) throws InstallerException {
+        mInstaller.execute("create_app_data", uuid, pkgname, userid, flags, appid, seinfo);
     }
 
-    @Deprecated
-    public int install(String name, int uid, int gid, String seinfo) {
-        return install(null, name, uid, gid, seinfo);
+    public void restoreconAppData(String uuid, String pkgname, int userid, int flags, int appid,
+            String seinfo) throws InstallerException {
+        mInstaller.execute("restorecon_app_data", uuid, pkgname, userid, flags, appid,
+                seinfo);
     }
 
-    public int install(String uuid, String name, int uid, int gid, String seinfo) {
-        StringBuilder builder = new StringBuilder("install");
-        builder.append(' ');
-        builder.append(escapeNull(uuid));
-        builder.append(' ');
-        builder.append(name);
-        builder.append(' ');
-        builder.append(uid);
-        builder.append(' ');
-        builder.append(gid);
-        builder.append(' ');
-        builder.append(seinfo != null ? seinfo : "!");
-        return mInstaller.execute(builder.toString());
+    public void clearAppData(String uuid, String pkgname, int userid, int flags)
+            throws InstallerException {
+        mInstaller.execute("clear_app_data", uuid, pkgname, userid, flags);
     }
 
-    public int dexopt(String apkPath, int uid, String instructionSet,
-            int dexoptNeeded, int dexFlags) {
-        if (!isValidInstructionSet(instructionSet)) {
-            Slog.e(TAG, "Invalid instruction set: " + instructionSet);
-            return -1;
-        }
-
-        return mInstaller.dexopt(apkPath, uid, instructionSet, dexoptNeeded, dexFlags);
+    public void destroyAppData(String uuid, String pkgname, int userid, int flags)
+            throws InstallerException {
+        mInstaller.execute("destroy_app_data", uuid, pkgname, userid, flags);
     }
 
-    public int dexopt(String apkPath, int uid, String pkgName, String instructionSet,
-            int dexoptNeeded, @Nullable String outputPath, int dexFlags) {
-        if (!isValidInstructionSet(instructionSet)) {
-            Slog.e(TAG, "Invalid instruction set: " + instructionSet);
-            return -1;
-        }
-        return mInstaller.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded,
-                outputPath, dexFlags);
+    public void moveCompleteApp(String from_uuid, String to_uuid, String package_name,
+            String data_app_name, int appid, String seinfo) throws InstallerException {
+        mInstaller.execute("move_complete_app", from_uuid, to_uuid, package_name,
+                data_app_name, appid, seinfo);
     }
 
-    public int idmap(String targetApkPath, String overlayApkPath, int uid) {
-        StringBuilder builder = new StringBuilder("idmap");
-        builder.append(' ');
-        builder.append(targetApkPath);
-        builder.append(' ');
-        builder.append(overlayApkPath);
-        builder.append(' ');
-        builder.append(uid);
-        return mInstaller.execute(builder.toString());
-    }
-
-    public int movedex(String srcPath, String dstPath, String instructionSet) {
-        if (!isValidInstructionSet(instructionSet)) {
-            Slog.e(TAG, "Invalid instruction set: " + instructionSet);
-            return -1;
-        }
-
-        StringBuilder builder = new StringBuilder("movedex");
-        builder.append(' ');
-        builder.append(srcPath);
-        builder.append(' ');
-        builder.append(dstPath);
-        builder.append(' ');
-        builder.append(instructionSet);
-        return mInstaller.execute(builder.toString());
-    }
-
-    public int rmdex(String codePath, String instructionSet) {
-        if (!isValidInstructionSet(instructionSet)) {
-            Slog.e(TAG, "Invalid instruction set: " + instructionSet);
-            return -1;
-        }
-
-        StringBuilder builder = new StringBuilder("rmdex");
-        builder.append(' ');
-        builder.append(codePath);
-        builder.append(' ');
-        builder.append(instructionSet);
-        return mInstaller.execute(builder.toString());
-    }
-
-    /**
-     * Removes packageDir or its subdirectory
-     */
-    public int rmPackageDir(String packageDir) {
-        StringBuilder builder = new StringBuilder("rmpackagedir");
-        builder.append(' ');
-        builder.append(packageDir);
-        return mInstaller.execute(builder.toString());
-    }
-
-    @Deprecated
-    public int remove(String name, int userId) {
-        return remove(null, name, userId);
-    }
-
-    public int remove(String uuid, String name, int userId) {
-        StringBuilder builder = new StringBuilder("remove");
-        builder.append(' ');
-        builder.append(escapeNull(uuid));
-        builder.append(' ');
-        builder.append(name);
-        builder.append(' ');
-        builder.append(userId);
-        return mInstaller.execute(builder.toString());
-    }
-
-    @Deprecated
-    public int fixUid(String name, int uid, int gid) {
-        return fixUid(null, name, uid, gid);
-    }
-
-    public int fixUid(String uuid, String name, int uid, int gid) {
-        StringBuilder builder = new StringBuilder("fixuid");
-        builder.append(' ');
-        builder.append(escapeNull(uuid));
-        builder.append(' ');
-        builder.append(name);
-        builder.append(' ');
-        builder.append(uid);
-        builder.append(' ');
-        builder.append(gid);
-        return mInstaller.execute(builder.toString());
-    }
-
-    @Deprecated
-    public int deleteCacheFiles(String name, int userId) {
-        return deleteCacheFiles(null, name, userId);
-    }
-
-    public int deleteCacheFiles(String uuid, String name, int userId) {
-        StringBuilder builder = new StringBuilder("rmcache");
-        builder.append(' ');
-        builder.append(escapeNull(uuid));
-        builder.append(' ');
-        builder.append(name);
-        builder.append(' ');
-        builder.append(userId);
-        return mInstaller.execute(builder.toString());
-    }
-
-    @Deprecated
-    public int deleteCodeCacheFiles(String name, int userId) {
-        return deleteCodeCacheFiles(null, name, userId);
-    }
-
-    public int deleteCodeCacheFiles(String uuid, String name, int userId) {
-        StringBuilder builder = new StringBuilder("rmcodecache");
-        builder.append(' ');
-        builder.append(escapeNull(uuid));
-        builder.append(' ');
-        builder.append(name);
-        builder.append(' ');
-        builder.append(userId);
-        return mInstaller.execute(builder.toString());
-    }
-
-    @Deprecated
-    public int createUserData(String name, int uid, int userId, String seinfo) {
-        return createUserData(null, name, uid, userId, seinfo);
-    }
-
-    public int createUserData(String uuid, String name, int uid, int userId, String seinfo) {
-        StringBuilder builder = new StringBuilder("mkuserdata");
-        builder.append(' ');
-        builder.append(escapeNull(uuid));
-        builder.append(' ');
-        builder.append(name);
-        builder.append(' ');
-        builder.append(uid);
-        builder.append(' ');
-        builder.append(userId);
-        builder.append(' ');
-        builder.append(seinfo != null ? seinfo : "!");
-        return mInstaller.execute(builder.toString());
-    }
-
-    public int createUserConfig(int userId) {
-        StringBuilder builder = new StringBuilder("mkuserconfig");
-        builder.append(' ');
-        builder.append(userId);
-        return mInstaller.execute(builder.toString());
-    }
-
-    @Deprecated
-    public int removeUserDataDirs(int userId) {
-        return removeUserDataDirs(null, userId);
-    }
-
-    public int removeUserDataDirs(String uuid, int userId) {
-        StringBuilder builder = new StringBuilder("rmuser");
-        builder.append(' ');
-        builder.append(escapeNull(uuid));
-        builder.append(' ');
-        builder.append(userId);
-        return mInstaller.execute(builder.toString());
-    }
-
-    public int copyCompleteApp(String fromUuid, String toUuid, String packageName,
-            String dataAppName, int appId, String seinfo) {
-        StringBuilder builder = new StringBuilder("cpcompleteapp");
-        builder.append(' ');
-        builder.append(escapeNull(fromUuid));
-        builder.append(' ');
-        builder.append(escapeNull(toUuid));
-        builder.append(' ');
-        builder.append(packageName);
-        builder.append(' ');
-        builder.append(dataAppName);
-        builder.append(' ');
-        builder.append(appId);
-        builder.append(' ');
-        builder.append(seinfo);
-        return mInstaller.execute(builder.toString());
-    }
-
-    @Deprecated
-    public int clearUserData(String name, int userId) {
-        return clearUserData(null, name, userId);
-    }
-
-    public int clearUserData(String uuid, String name, int userId) {
-        StringBuilder builder = new StringBuilder("rmuserdata");
-        builder.append(' ');
-        builder.append(escapeNull(uuid));
-        builder.append(' ');
-        builder.append(name);
-        builder.append(' ');
-        builder.append(userId);
-        return mInstaller.execute(builder.toString());
-    }
-
-    public int markBootComplete(String instructionSet) {
-        if (!isValidInstructionSet(instructionSet)) {
-            Slog.e(TAG, "Invalid instruction set: " + instructionSet);
-            return -1;
-        }
-
-        StringBuilder builder = new StringBuilder("markbootcomplete");
-        builder.append(' ');
-        builder.append(instructionSet);
-        return mInstaller.execute(builder.toString());
-    }
-
-    @Deprecated
-    public int freeCache(long freeStorageSize) {
-        return freeCache(null, freeStorageSize);
-    }
-
-    public int freeCache(String uuid, long freeStorageSize) {
-        StringBuilder builder = new StringBuilder("freecache");
-        builder.append(' ');
-        builder.append(escapeNull(uuid));
-        builder.append(' ');
-        builder.append(String.valueOf(freeStorageSize));
-        return mInstaller.execute(builder.toString());
-    }
-
-    @Deprecated
-    public int getSizeInfo(String pkgName, int persona, String apkPath, String libDirPath,
-            String fwdLockApkPath, String asecPath, String[] instructionSets, PackageStats pStats) {
-        return getSizeInfo(null, pkgName, persona, apkPath, libDirPath, fwdLockApkPath, asecPath,
-                instructionSets, pStats);
-    }
-
-    public int getSizeInfo(String uuid, String pkgName, int persona, String apkPath,
+    public void getAppSize(String uuid, String pkgname, int userid, int flags, String apkPath,
             String libDirPath, String fwdLockApkPath, String asecPath, String[] instructionSets,
-            PackageStats pStats) {
+            PackageStats pStats) throws InstallerException {
         for (String instructionSet : instructionSets) {
-            if (!isValidInstructionSet(instructionSet)) {
-                Slog.e(TAG, "Invalid instruction set: " + instructionSet);
-                return -1;
-            }
+            assertValidInstructionSet(instructionSet);
         }
 
-        StringBuilder builder = new StringBuilder("getsize");
-        builder.append(' ');
-        builder.append(escapeNull(uuid));
-        builder.append(' ');
-        builder.append(pkgName);
-        builder.append(' ');
-        builder.append(persona);
-        builder.append(' ');
-        builder.append(apkPath);
-        builder.append(' ');
         // TODO: Extend getSizeInfo to look at the full subdirectory tree,
         // not just the first level.
-        builder.append(libDirPath != null ? libDirPath : "!");
-        builder.append(' ');
-        builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!");
-        builder.append(' ');
-        builder.append(asecPath != null ? asecPath : "!");
-        builder.append(' ');
         // TODO: Extend getSizeInfo to look at *all* instrution sets, not
         // just the primary.
-        builder.append(instructionSets[0]);
-
-        String s = mInstaller.transact(builder.toString());
-        String res[] = s.split(" ");
+        final String rawRes = mInstaller.executeForResult("get_app_size", uuid, pkgname, userid,
+                flags, apkPath, libDirPath, fwdLockApkPath, asecPath, instructionSets[0]);
+        final String res[] = rawRes.split(" ");
 
         if ((res == null) || (res.length != 5)) {
-            return -1;
+            throw new InstallerException("Invalid size result: " + rawRes);
         }
         try {
             pStats.codeSize = Long.parseLong(res[1]);
             pStats.dataSize = Long.parseLong(res[2]);
             pStats.cacheSize = Long.parseLong(res[3]);
             pStats.externalCodeSize = Long.parseLong(res[4]);
-            return Integer.parseInt(res[0]);
         } catch (NumberFormatException e) {
-            return -1;
+            throw new InstallerException("Invalid size result: " + rawRes);
         }
     }
 
-    public int moveFiles() {
-        return mInstaller.execute("movefiles");
+    public void dexopt(String apkPath, int uid, String instructionSet, int dexoptNeeded,
+            int dexFlags) throws InstallerException {
+        assertValidInstructionSet(instructionSet);
+        mInstaller.dexopt(apkPath, uid, instructionSet, dexoptNeeded, dexFlags);
     }
 
-    @Deprecated
-    public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath32, int userId) {
-        return linkNativeLibraryDirectory(null, dataPath, nativeLibPath32, userId);
+    public void dexopt(String apkPath, int uid, String pkgName, String instructionSet,
+            int dexoptNeeded, @Nullable String outputPath, int dexFlags)
+                    throws InstallerException {
+        assertValidInstructionSet(instructionSet);
+        mInstaller.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded,
+                outputPath, dexFlags);
+    }
+
+    public void idmap(String targetApkPath, String overlayApkPath, int uid)
+            throws InstallerException {
+        mInstaller.execute("idmap", targetApkPath, overlayApkPath, uid);
+    }
+
+    public void rmdex(String codePath, String instructionSet) throws InstallerException {
+        assertValidInstructionSet(instructionSet);
+        mInstaller.execute("rmdex", codePath, instructionSet);
+    }
+
+    public void rmPackageDir(String packageDir) throws InstallerException {
+        mInstaller.execute("rmpackagedir", packageDir);
+    }
+
+    public void createUserConfig(int userid) throws InstallerException {
+        mInstaller.execute("mkuserconfig", userid);
+    }
+
+    public void removeUserDataDirs(String uuid, int userid) throws InstallerException {
+        mInstaller.execute("rmuser", uuid, userid);
+    }
+
+    public void markBootComplete(String instructionSet) throws InstallerException {
+        assertValidInstructionSet(instructionSet);
+        mInstaller.execute("markbootcomplete", instructionSet);
+    }
+
+    public void freeCache(String uuid, long freeStorageSize) throws InstallerException {
+        mInstaller.execute("freecache", uuid, freeStorageSize);
+    }
+
+    public void moveFiles() throws InstallerException {
+        mInstaller.execute("movefiles");
     }
 
     /**
-     * Links the 32 bit native library directory in an application's data directory to the
-     * real location for backward compatibility. Note that no such symlink is created for
-     * 64 bit shared libraries.
-     *
-     * @return -1 on error
+     * Links the 32 bit native library directory in an application's data
+     * directory to the real location for backward compatibility. Note that no
+     * such symlink is created for 64 bit shared libraries.
      */
-    public int linkNativeLibraryDirectory(String uuid, String dataPath, String nativeLibPath32,
-            int userId) {
-        if (dataPath == null) {
-            Slog.e(TAG, "linkNativeLibraryDirectory dataPath is null");
-            return -1;
-        } else if (nativeLibPath32 == null) {
-            Slog.e(TAG, "linkNativeLibraryDirectory nativeLibPath is null");
-            return -1;
-        }
-
-        StringBuilder builder = new StringBuilder("linklib");
-        builder.append(' ');
-        builder.append(escapeNull(uuid));
-        builder.append(' ');
-        builder.append(dataPath);
-        builder.append(' ');
-        builder.append(nativeLibPath32);
-        builder.append(' ');
-        builder.append(userId);
-
-        return mInstaller.execute(builder.toString());
+    public void linkNativeLibraryDirectory(String uuid, String dataPath, String nativeLibPath32,
+            int userId) throws InstallerException {
+        mInstaller.execute("linklib", uuid, dataPath, nativeLibPath32, userId);
     }
 
-    @Deprecated
-    public boolean restoreconData(String pkgName, String seinfo, int uid) {
-        return restoreconData(null, pkgName, seinfo, uid);
+    public void createOatDir(String oatDir, String dexInstructionSet)
+            throws InstallerException {
+        mInstaller.execute("createoatdir", oatDir, dexInstructionSet);
     }
 
-    public boolean restoreconData(String uuid, String pkgName, String seinfo, int uid) {
-        StringBuilder builder = new StringBuilder("restorecondata");
-        builder.append(' ');
-        builder.append(escapeNull(uuid));
-        builder.append(' ');
-        builder.append(pkgName);
-        builder.append(' ');
-        builder.append(seinfo != null ? seinfo : "!");
-        builder.append(' ');
-        builder.append(uid);
-        return (mInstaller.execute(builder.toString()) == 0);
+    public void linkFile(String relativePath, String fromBase, String toBase)
+            throws InstallerException {
+        mInstaller.execute("linkfile", relativePath, fromBase, toBase);
     }
 
-    public int createOatDir(String oatDir, String dexInstructionSet) {
-        StringBuilder builder = new StringBuilder("createoatdir");
-        builder.append(' ');
-        builder.append(oatDir);
-        builder.append(' ');
-        builder.append(dexInstructionSet);
-        return mInstaller.execute(builder.toString());
-    }
-
-
-    public int linkFile(String relativePath, String fromBase, String toBase) {
-        StringBuilder builder = new StringBuilder("linkfile");
-        builder.append(' ');
-        builder.append(relativePath);
-        builder.append(' ');
-        builder.append(fromBase);
-        builder.append(' ');
-        builder.append(toBase);
-        return mInstaller.execute(builder.toString());
-    }
-
-    /**
-     * Returns true iff. {@code instructionSet} is a valid instruction set.
-     */
-    private static boolean isValidInstructionSet(String instructionSet) {
-        if (instructionSet == null) {
-            return false;
-        }
-
+    private static void assertValidInstructionSet(String instructionSet)
+            throws InstallerException {
         for (String abi : Build.SUPPORTED_ABIS) {
-            if (instructionSet.equals(VMRuntime.getInstructionSet(abi))) {
-                return true;
+            if (VMRuntime.getInstructionSet(abi).equals(instructionSet)) {
+                return;
             }
         }
-
-        return false;
+        throw new InstallerException("Invalid instruction set: " + instructionSet);
     }
 }
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index d29a623..b45a922 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -27,6 +27,8 @@
 import android.util.Log;
 import android.util.Slog;
 
+import com.android.internal.os.InstallerConnection.InstallerException;
+
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -166,12 +168,13 @@
                             | (vmSafeMode ? DEXOPT_SAFEMODE : 0)
                             | (debuggable ? DEXOPT_DEBUGGABLE : 0)
                             | DEXOPT_BOOTCOMPLETE;
-                    final int ret = mPackageManagerService.mInstaller.dexopt(path, sharedGid,
-                            pkg.packageName, dexCodeInstructionSet, dexoptNeeded, oatDir, dexFlags);
-
-                    // Dex2oat might fail due to compiler / verifier errors.
-                    if (ret == 0) {
+                    try {
+                        mPackageManagerService.mInstaller.dexopt(path, sharedGid,
+                                pkg.packageName, dexCodeInstructionSet, dexoptNeeded, oatDir,
+                                dexFlags);
                         performedDexOpt = true;
+                    } catch (InstallerException e) {
+                        Slog.w(TAG, "Failed to dexopt", e);
                     }
                 }
             }
@@ -210,8 +213,13 @@
         File codePath = new File(pkg.codePath);
         if (codePath.isDirectory()) {
             File oatDir = getOatDir(codePath);
-            mPackageManagerService.mInstaller.createOatDir(oatDir.getAbsolutePath(),
-                    dexInstructionSet);
+            try {
+                mPackageManagerService.mInstaller.createOatDir(oatDir.getAbsolutePath(),
+                        dexInstructionSet);
+            } catch (InstallerException e) {
+                Slog.w(TAG, "Failed to create oat dir", e);
+                return null;
+            }
             return oatDir.getAbsolutePath();
         }
         return null;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 55b8bf2..23a58d0 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -258,11 +258,7 @@
         for (File stage : unclaimedStages) {
             Slog.w(TAG, "Deleting orphan stage " + stage);
             synchronized (mPm.mInstallLock) {
-                if (stage.isDirectory()) {
-                    mPm.mInstaller.rmPackageDir(stage.getAbsolutePath());
-                } else {
-                    stage.delete();
-                }
+                mPm.removeCodePathLI(stage);
             }
         }
     }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 1655cb6..b84ffa3 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -69,6 +69,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.NativeLibraryHelper;
 import com.android.internal.content.PackageHelper;
+import com.android.internal.os.InstallerConnection.InstallerException;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
@@ -832,9 +833,14 @@
         throw new IOException("File: " + pathStr + " outside base: " + baseStr);
     }
 
-    private void createOatDirs(List<String> instructionSets, File fromDir) {
+    private void createOatDirs(List<String> instructionSets, File fromDir)
+            throws PackageManagerException {
         for (String instructionSet : instructionSets) {
-            mPm.mInstaller.createOatDir(fromDir.getAbsolutePath(), instructionSet);
+            try {
+                mPm.mInstaller.createOatDir(fromDir.getAbsolutePath(), instructionSet);
+            } catch (InstallerException e) {
+                throw PackageManagerException.from(e);
+            }
         }
     }
 
@@ -842,13 +848,12 @@
             throws IOException {
         for (File fromFile : fromFiles) {
             final String relativePath = getRelativePath(fromFile, fromDir);
-            final int ret = mPm.mInstaller.linkFile(relativePath, fromDir.getAbsolutePath(),
-                    toDir.getAbsolutePath());
-
-            if (ret < 0) {
-                // installd will log failure details.
+            try {
+                mPm.mInstaller.linkFile(relativePath, fromDir.getAbsolutePath(),
+                        toDir.getAbsolutePath());
+            } catch (InstallerException e) {
                 throw new IOException("failed linkOrCreateDir(" + relativePath + ", "
-                        + fromDir + ", " + toDir + ")");
+                        + fromDir + ", " + toDir + ")", e);
             }
         }
 
@@ -1041,7 +1046,10 @@
             }
         }
         if (stageDir != null) {
-            mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
+            try {
+                mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
+            } catch (InstallerException ignored) {
+            }
         }
         if (stageCid != null) {
             PackageHelper.destroySdDir(stageCid);
diff --git a/services/core/java/com/android/server/pm/PackageManagerException.java b/services/core/java/com/android/server/pm/PackageManagerException.java
index a41636e..d04eedc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerException.java
+++ b/services/core/java/com/android/server/pm/PackageManagerException.java
@@ -16,8 +16,11 @@
 
 package com.android.server.pm;
 
+import android.content.pm.PackageManager;
 import android.content.pm.PackageParser.PackageParserException;
 
+import com.android.internal.os.InstallerConnection.InstallerException;
+
 /** {@hide} */
 public class PackageManagerException extends Exception {
     public final int error;
@@ -36,4 +39,10 @@
             throws PackageManagerException {
         throw new PackageManagerException(e.error, e.getMessage(), e.getCause());
     }
+
+    public static PackageManagerException from(InstallerException e)
+            throws PackageManagerException {
+        throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
+                e.getMessage(), e.getCause());
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e3ed0c1..f777faf 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -219,6 +219,7 @@
 import com.android.internal.content.NativeLibraryHelper;
 import com.android.internal.content.PackageHelper;
 import com.android.internal.os.IParcelFileDescriptorFactory;
+import com.android.internal.os.InstallerConnection.InstallerException;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.os.Zygote;
 import com.android.internal.util.ArrayUtils;
@@ -2067,7 +2068,7 @@
                             }
                         } catch (FileNotFoundException e) {
                             Slog.w(TAG, "Library not found: " + lib);
-                        } catch (IOException e) {
+                        } catch (IOException | InstallerException e) {
                             Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "
                                     + e.getMessage());
                         }
@@ -2136,7 +2137,11 @@
                     | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
 
             if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
-            mInstaller.moveFiles();
+            try {
+                mInstaller.moveFiles();
+            } catch (InstallerException e) {
+                logCriticalInfo(Log.WARN, "Update commands failed: " + e);
+            }
 
             // Prune any system packages that no longer exist.
             final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();
@@ -2710,11 +2715,7 @@
 
         removeDataDirsLI(ps.volumeUuid, ps.name);
         if (ps.codePath != null) {
-            if (ps.codePath.isDirectory()) {
-                mInstaller.rmPackageDir(ps.codePath.getAbsolutePath());
-            } else {
-                ps.codePath.delete();
-            }
+            removeCodePathLI(ps.codePath);
         }
         if (ps.resourcePath != null && !ps.resourcePath.equals(ps.codePath)) {
             if (ps.resourcePath.isDirectory()) {
@@ -3038,16 +3039,18 @@
         mHandler.post(new Runnable() {
             public void run() {
                 mHandler.removeCallbacks(this);
-                int retCode = -1;
+                boolean success = true;
                 synchronized (mInstallLock) {
-                    retCode = mInstaller.freeCache(volumeUuid, freeStorageSize);
-                    if (retCode < 0) {
-                        Slog.w(TAG, "Couldn't clear application caches");
+                    try {
+                        mInstaller.freeCache(volumeUuid, freeStorageSize);
+                    } catch (InstallerException e) {
+                        Slog.w(TAG, "Couldn't clear application caches: " + e);
+                        success = false;
                     }
                 }
                 if (observer != null) {
                     try {
-                        observer.onRemoveCompleted(null, (retCode >= 0));
+                        observer.onRemoveCompleted(null, success);
                     } catch (RemoteException e) {
                         Slog.w(TAG, "RemoveException when invoking call back");
                     }
@@ -3065,17 +3068,19 @@
         mHandler.post(new Runnable() {
             public void run() {
                 mHandler.removeCallbacks(this);
-                int retCode = -1;
+                boolean success = true;
                 synchronized (mInstallLock) {
-                    retCode = mInstaller.freeCache(volumeUuid, freeStorageSize);
-                    if (retCode < 0) {
-                        Slog.w(TAG, "Couldn't clear application caches");
+                    try {
+                        mInstaller.freeCache(volumeUuid, freeStorageSize);
+                    } catch (InstallerException e) {
+                        Slog.w(TAG, "Couldn't clear application caches: " + e);
+                        success = false;
                     }
                 }
                 if(pi != null) {
                     try {
                         // Callback via pending intent
-                        int code = (retCode >= 0) ? 1 : 0;
+                        int code = success ? 1 : 0;
                         pi.sendIntent(null, code, null,
                                 null, null);
                     } catch (SendIntentException e1) {
@@ -3088,8 +3093,10 @@
 
     void freeStorage(String volumeUuid, long freeStorageSize) throws IOException {
         synchronized (mInstallLock) {
-            if (mInstaller.freeCache(volumeUuid, freeStorageSize) < 0) {
-                throw new IOException("Failed to free enough space");
+            try {
+                mInstaller.freeCache(volumeUuid, freeStorageSize);
+            } catch (InstallerException e) {
+                throw new IOException("Failed to free enough space", e);
             }
         }
     }
@@ -6086,7 +6093,9 @@
         }
         final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
         // TODO: generate idmap for split APKs
-        if (mInstaller.idmap(pkg.baseCodePath, opkg.baseCodePath, sharedGid) != 0) {
+        try {
+            mInstaller.idmap(pkg.baseCodePath, opkg.baseCodePath, sharedGid);
+        } catch (InstallerException e) {
             Slog.e(TAG, "Failed to generate idmap for " + pkg.baseCodePath + " and "
                     + opkg.baseCodePath);
             return false;
@@ -6146,11 +6155,7 @@
                 if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
                         e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
                     logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);
-                    if (file.isDirectory()) {
-                        mInstaller.rmPackageDir(file.getAbsolutePath());
-                    } else {
-                        file.delete();
-                    }
+                    removeCodePathLI(file);
                 }
             }
         }
@@ -6716,50 +6721,65 @@
 
     private void createDataDirsLI(String volumeUuid, String packageName, int uid, String seinfo)
             throws PackageManagerException {
-        int res = mInstaller.install(volumeUuid, packageName, uid, uid, seinfo);
-        if (res != 0) {
+        // TODO: triage flags as part of 26466827
+        final int appId = UserHandle.getAppId(uid);
+        final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+
+        try {
+            final int[] users = sUserManager.getUserIds();
+            for (int user : users) {
+                mInstaller.createAppData(volumeUuid, packageName, user, flags, appId, seinfo);
+            }
+        } catch (InstallerException e) {
             throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
-                    "Failed to install " + packageName + ": " + res);
+                    "Failed to prepare data directory", e);
         }
+    }
+
+    private boolean removeDataDirsLI(String volumeUuid, String packageName) {
+        // TODO: triage flags as part of 26466827
+        final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+
+        boolean res = true;
+        final int[] users = sUserManager.getUserIds();
+        for (int user : users) {
+            try {
+                mInstaller.destroyAppData(volumeUuid, packageName, user, flags);
+            } catch (InstallerException e) {
+                Slog.w(TAG, "Failed to delete data directory", e);
+                res = false;
+            }
+        }
+        return res;
+    }
+
+    void removeCodePathLI(File codePath) {
+        if (codePath.isDirectory()) {
+            try {
+                mInstaller.rmPackageDir(codePath.getAbsolutePath());
+            } catch (InstallerException e) {
+                Slog.w(TAG, "Failed to remove code path", e);
+            }
+        } else {
+            codePath.delete();
+        }
+    }
+
+    private void deleteCodeCacheDirsLI(String volumeUuid, String packageName) {
+        // TODO: triage flags as part of 26466827
+        final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
 
         final int[] users = sUserManager.getUserIds();
         for (int user : users) {
-            if (user != 0) {
-                res = mInstaller.createUserData(volumeUuid, packageName,
-                        UserHandle.getUid(user, uid), user, seinfo);
-                if (res != 0) {
-                    throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
-                            "Failed to createUserData " + packageName + ": " + res);
-                }
+            try {
+                mInstaller.clearAppData(volumeUuid, packageName, user,
+                        flags | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
+            } catch (InstallerException e) {
+                Slog.w(TAG, "Failed to delete code cache directory", e);
             }
         }
     }
 
-    private int removeDataDirsLI(String volumeUuid, String packageName) {
-        int[] users = sUserManager.getUserIds();
-        int res = 0;
-        for (int user : users) {
-            int resInner = mInstaller.remove(volumeUuid, packageName, user);
-            if (resInner < 0) {
-                res = resInner;
-            }
-        }
-
-        return res;
-    }
-
-    private int deleteCodeCacheDirsLI(String volumeUuid, String packageName) {
-        int[] users = sUserManager.getUserIds();
-        int res = 0;
-        for (int user : users) {
-            int resInner = mInstaller.deleteCodeCacheFiles(volumeUuid, packageName, user);
-            if (resInner < 0) {
-                res = resInner;
-            }
-        }
-        return res;
-    }
-
     private void addSharedLibraryLPw(ArraySet<String> usesLibraryFiles, SharedLibraryEntry file,
             PackageParser.Package changingLib) {
         if (file.path != null) {
@@ -7258,6 +7278,8 @@
             final File dataPath = Environment.getDataUserCredentialEncryptedPackageDirectory(
                     pkg.volumeUuid, UserHandle.USER_SYSTEM, pkg.packageName);
 
+            // TOOD: switch to ensure various directories
+
             boolean uidError = false;
             if (dataPath.exists()) {
                 int currentUid = 0;
@@ -7271,27 +7293,12 @@
                 // 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(pkg.volumeUuid, 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
-                            || (scanFlags&SCAN_BOOTING) != 0)) {
+                    if (((parseFlags & PackageParser.PARSE_IS_SYSTEM) != 0
+                            || (scanFlags & 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(pkg.volumeUuid, pkgName);
-                        if (ret >= 0) {
+                        boolean res = removeDataDirsLI(pkg.volumeUuid, pkgName);
+                        if (res) {
                             // TODO: Kill the processes first
                             // Old data gone!
                             String prefix = (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0
@@ -7306,11 +7313,12 @@
                         if (!recovered) {
                             mHasSystemUidErrors = true;
                         }
-                    } else if (!recovered) {
+                    } else {
                         // If we allow this install to proceed, we will be broken.
                         // Abort, abort!
                         throw new PackageManagerException(INSTALL_FAILED_UID_CHANGED,
-                                "scanPackageLI");
+                                "Expected data to be owned by UID " + pkg.applicationInfo.uid
+                                        + " but found " + currentUid);
                     }
                     if (!recovered) {
                         pkg.applicationInfo.dataDir = "/mismatched_uid/settings_"
@@ -7340,8 +7348,16 @@
 
                 if (mShouldRestoreconData) {
                     Slog.i(TAG, "SELinux relabeling of " + pkg.packageName + " issued.");
-                    mInstaller.restoreconData(pkg.volumeUuid, pkg.packageName,
-                            pkg.applicationInfo.seinfo, pkg.applicationInfo.uid);
+                    // TODO: extend this to restorecon over all users
+                    final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);
+                    // TODO: triage flags as part of 26466827
+                    final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+                    try {
+                        mInstaller.restoreconAppData(pkg.volumeUuid, pkg.packageName,
+                                UserHandle.USER_SYSTEM, flags, appId, pkg.applicationInfo.seinfo);
+                    } catch (InstallerException e) {
+                        Slog.w(TAG, "Failed to restorecon " + pkg.packageName, e);
+                    }
                 }
             } else {
                 if (DEBUG_PACKAGE_SCANNING) {
@@ -7397,9 +7413,15 @@
             if (!TextUtils.isEmpty(pkg.volumeUuid)) {
                 for (int userId : userIds) {
                     if (userId != UserHandle.USER_SYSTEM) {
-                        mInstaller.createUserData(pkg.volumeUuid, pkg.packageName,
-                                UserHandle.getUid(userId, pkg.applicationInfo.uid), userId,
-                                pkg.applicationInfo.seinfo);
+                        // TODO: triage flags as part of 26466827
+                        final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+                        final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);
+                        try {
+                            mInstaller.createAppData(pkg.volumeUuid, pkg.packageName, userId,
+                                    flags, appId, pkg.applicationInfo.seinfo);
+                        } catch (InstallerException e) {
+                            throw PackageManagerException.from(e);
+                        }
                     }
                 }
             }
@@ -7413,10 +7435,11 @@
                 try {
                     final String nativeLibPath = pkg.applicationInfo.nativeLibraryDir;
                     for (int userId : userIds) {
-                        if (mInstaller.linkNativeLibraryDirectory(pkg.volumeUuid, pkg.packageName,
-                                nativeLibPath, userId) < 0) {
-                            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
-                                    "Failed linking native library dir (user=" + userId + ")");
+                        try {
+                            mInstaller.linkNativeLibraryDirectory(pkg.volumeUuid, pkg.packageName,
+                                    nativeLibPath, userId);
+                        } catch (InstallerException e) {
+                            throw PackageManagerException.from(e);
                         }
                     }
                 } finally {
@@ -8149,8 +8172,11 @@
                     if (ps.pkg != null && ps.pkg.applicationInfo != null) {
                         ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
                         Slog.i(TAG, "Adjusting ABI for " + ps.name + " to " + adjustedAbi);
-                        mInstaller.rmdex(ps.codePathString,
-                                getDexCodeInstructionSet(getPreferredInstructionSet()));
+                        try {
+                            mInstaller.rmdex(ps.codePathString,
+                                    getDexCodeInstructionSet(getPreferredInstructionSet()));
+                        } catch (InstallerException ignored) {
+                        }
                     }
                 }
             }
@@ -11133,9 +11159,12 @@
                     final long sizeBytes = mContainerService.calculateInstalledSize(
                             origin.resolvedPath, isForwardLocked(), packageAbiOverride);
 
-                    if (mInstaller.freeCache(null, sizeBytes + lowThreshold) >= 0) {
+                    try {
+                        mInstaller.freeCache(null, sizeBytes + lowThreshold);
                         pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath,
                                 installFlags, packageAbiOverride);
+                    } catch (InstallerException e) {
+                        Slog.w(TAG, "Failed to free cache", e);
                     }
 
                     /*
@@ -11533,11 +11562,9 @@
             String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
             for (String codePath : allCodePaths) {
                 for (String dexCodeInstructionSet : dexCodeInstructionSets) {
-                    int retCode = mInstaller.rmdex(codePath, dexCodeInstructionSet);
-                    if (retCode < 0) {
-                        Slog.w(TAG, "Couldn't remove dex file for package at location " + codePath
-                                + ", retcode=" + retCode);
-                        // we don't consider this to be a failure of the core package deletion
+                    try {
+                        mInstaller.rmdex(codePath, dexCodeInstructionSet);
+                    } catch (InstallerException ignored) {
                     }
                 }
             }
@@ -11723,11 +11750,7 @@
                 return false;
             }
 
-            if (codeFile.isDirectory()) {
-                mInstaller.rmPackageDir(codeFile.getAbsolutePath());
-            } else {
-                codeFile.delete();
-            }
+            removeCodePathLI(codeFile);
 
             if (resourceFile != null && !FileUtils.contains(codeFile, resourceFile)) {
                 resourceFile.delete();
@@ -12104,8 +12127,11 @@
             if (DEBUG_INSTALL) Slog.d(TAG, "Moving " + move.packageName + " from "
                     + move.fromUuid + " to " + move.toUuid);
             synchronized (mInstaller) {
-                if (mInstaller.copyCompleteApp(move.fromUuid, move.toUuid, move.packageName,
-                        move.dataAppName, move.appId, move.seinfo) != 0) {
+                try {
+                    mInstaller.moveCompleteApp(move.fromUuid, move.toUuid, move.packageName,
+                            move.dataAppName, move.appId, move.seinfo);
+                } catch (InstallerException e) {
+                    Slog.w(TAG, "Failed to move app", e);
                     return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
                 }
             }
@@ -12168,11 +12194,7 @@
             synchronized (mInstallLock) {
                 // Clean up both app data and code
                 removeDataDirsLI(volumeUuid, move.packageName);
-                if (codeFile.isDirectory()) {
-                    mInstaller.rmPackageDir(codeFile.getAbsolutePath());
-                } else {
-                    codeFile.delete();
-                }
+                removeCodePathLI(codeFile);
             }
             return true;
         }
@@ -13853,7 +13875,13 @@
                 outInfo.removedAppId = appId;
                 outInfo.removedUsers = new int[] {removeUser};
             }
-            mInstaller.clearUserData(ps.volumeUuid, packageName, removeUser);
+            // TODO: triage flags as part of 26466827
+            final int installerFlags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+            try {
+                mInstaller.destroyAppData(ps.volumeUuid, packageName, removeUser, installerFlags);
+            } catch (InstallerException e) {
+                Slog.w(TAG, "Failed to delete app data", e);
+            }
             removeKeystoreDataIfNeeded(removeUser, appId);
             schedulePackageCleaning(packageName, removeUser, false);
             synchronized (mPackages) {
@@ -14027,13 +14055,16 @@
         // Always delete data directories for package, even if we found no other
         // record of app. This helps users recover from UID mismatches without
         // resorting to a full data wipe.
-        int retCode = mInstaller.clearUserData(pkg.volumeUuid, packageName, userId);
-        if (retCode < 0) {
-            Slog.w(TAG, "Couldn't remove cache files for package " + packageName);
+        // TODO: triage flags as part of 26466827
+        final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+        try {
+            mInstaller.clearAppData(pkg.volumeUuid, packageName, userId, flags);
+        } catch (InstallerException e) {
+            Slog.w(TAG, "Couldn't remove cache files for package " + packageName, e);
             return false;
         }
 
-        final int appId = pkg.applicationInfo.uid;
+        final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);
         removeKeystoreDataIfNeeded(userId, appId);
 
         // Create a native library symlink only if we have native libraries
@@ -14042,9 +14073,11 @@
         if (pkg.applicationInfo.primaryCpuAbi != null &&
                 !VMRuntime.is64BitAbi(pkg.applicationInfo.primaryCpuAbi)) {
             final String nativeLibPath = pkg.applicationInfo.nativeLibraryDir;
-            if (mInstaller.linkNativeLibraryDirectory(pkg.volumeUuid, pkg.packageName,
-                    nativeLibPath, userId) < 0) {
-                Slog.w(TAG, "Failed linking native library dir");
+            try {
+                mInstaller.linkNativeLibraryDirectory(pkg.volumeUuid, pkg.packageName,
+                        nativeLibPath, userId);
+            } catch (InstallerException e) {
+                Slog.w(TAG, "Failed linking native library dir", e);
                 return false;
             }
         }
@@ -14257,10 +14290,14 @@
             Slog.w(TAG, "Package " + packageName + " has no applicationInfo.");
             return false;
         }
-        int retCode = mInstaller.deleteCacheFiles(p.volumeUuid, packageName, userId);
-        if (retCode < 0) {
+        // TODO: triage flags as part of 26466827
+        final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+        try {
+            mInstaller.clearAppData(p.volumeUuid, packageName, userId,
+                    flags | Installer.FLAG_CLEAR_CACHE_ONLY);
+        } catch (InstallerException e) {
             Slog.w(TAG, "Couldn't remove cache files for package "
-                       + packageName + " u" + userId);
+                    + packageName + " u" + userId, e);
             return false;
         }
         return true;
@@ -14354,9 +14391,12 @@
             apkPath = p.baseCodePath;
         }
 
-        int res = mInstaller.getSizeInfo(p.volumeUuid, packageName, userHandle, apkPath,
-                libDirRoot, publicSrcDir, asecPath, dexCodeInstructionSets, pStats);
-        if (res < 0) {
+        // TODO: triage flags as part of 26466827
+        final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+        try {
+            mInstaller.getAppSize(p.volumeUuid, packageName, userHandle, flags, apkPath,
+                    libDirRoot, publicSrcDir, asecPath, dexCodeInstructionSets, pStats);
+        } catch (InstallerException e) {
             return false;
         }
 
@@ -16571,7 +16611,11 @@
 
             if (destroyUser) {
                 synchronized (mInstallLock) {
-                    mInstaller.removeUserDataDirs(volumeUuid, userId);
+                    try {
+                        mInstaller.removeUserDataDirs(volumeUuid, userId);
+                    } catch (InstallerException e) {
+                        Slog.w(TAG, "Failed to clean up user dirs", e);
+                    }
                 }
             }
         }
@@ -16637,11 +16681,7 @@
                     if (packageName != null) {
                         removeDataDirsLI(volumeUuid, packageName);
                     }
-                    if (file.isDirectory()) {
-                        mInstaller.rmPackageDir(file.getAbsolutePath());
-                    } else {
-                        file.delete();
-                    }
+                    removeCodePathLI(file);
                 }
             }
         }
@@ -16977,7 +17017,11 @@
             for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
                 final String volumeUuid = vol.getFsUuid();
                 if (DEBUG_INSTALL) Slog.d(TAG, "Removing user data on volume " + volumeUuid);
-                mInstaller.removeUserDataDirs(volumeUuid, userHandle);
+                try {
+                    mInstaller.removeUserDataDirs(volumeUuid, userHandle);
+                } catch (InstallerException e) {
+                    Slog.w(TAG, "Failed to remove user data", e);
+                }
             }
             synchronized (mPackages) {
                 removeUnusedPackagesLILPw(userManager, userHandle);
@@ -17040,7 +17084,11 @@
     /** Called by UserManagerService */
     void createNewUser(int userHandle) {
         synchronized (mInstallLock) {
-            mInstaller.createUserConfig(userHandle);
+            try {
+                mInstaller.createUserConfig(userHandle);
+            } catch (InstallerException e) {
+                Slog.w(TAG, "Failed to create user config", e);
+            }
             mSettings.createNewUserLI(this, mInstaller, userHandle);
         }
         synchronized (mPackages) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 1a79d3c3..9fef515 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -81,6 +81,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.BackgroundThread;
+import com.android.internal.os.InstallerConnection.InstallerException;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
@@ -3668,7 +3669,7 @@
             int userHandle) {
         String[] volumeUuids;
         String[] names;
-        int[] uids;
+        int[] appIds;
         String[] seinfos;
         int packagesCount;
         synchronized (mPackages) {
@@ -3676,7 +3677,7 @@
             packagesCount = packages.size();
             volumeUuids = new String[packagesCount];
             names = new String[packagesCount];
-            uids = new int[packagesCount];
+            appIds = new int[packagesCount];
             seinfos = new String[packagesCount];
             Iterator<PackageSetting> packagesIterator = packages.iterator();
             for (int i = 0; i < packagesCount; i++) {
@@ -3690,7 +3691,7 @@
                 // required args and call the installer after mPackages lock has been released
                 volumeUuids[i] = ps.volumeUuid;
                 names[i] = ps.name;
-                uids[i] = UserHandle.getUid(userHandle, ps.appId);
+                appIds[i] = ps.appId;
                 seinfos[i] = ps.pkg.applicationInfo.seinfo;
             }
         }
@@ -3698,7 +3699,14 @@
             if (names[i] == null) {
                 continue;
             }
-            installer.createUserData(volumeUuids[i], names[i], uids[i], userHandle, seinfos[i]);
+            // TODO: triage flags!
+            final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+            try {
+                installer.createAppData(volumeUuids[i], names[i], userHandle, flags, appIds[i],
+                        seinfos[i]);
+            } catch (InstallerException e) {
+                Slog.w(TAG, "Failed to prepare app data", e);
+            }
         }
         synchronized (mPackages) {
             applyDefaultPreferredAppsLPw(service, userHandle);