The pm command is no more.

It is now just a shell of itself. :)

Also brings in a few fixes to never try to open files from the system
process.

Test: manual
Change-Id: Ia8187196af597046fd2e7092dbf19ce1dc1ea457
diff --git a/cmds/pm/Android.mk b/cmds/pm/Android.mk
index 6a03def..960c805 100644
--- a/cmds/pm/Android.mk
+++ b/cmds/pm/Android.mk
@@ -3,14 +3,8 @@
 LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_MODULE := pmlib
-LOCAL_MODULE_STEM := pm
-include $(BUILD_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
 LOCAL_MODULE := pm
-LOCAL_MODULE_CLASS := EXECUTABLES
 LOCAL_SRC_FILES := pm
-LOCAL_REQUIRED_MODULES := pmlib
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_TAGS := optional
 include $(BUILD_PREBUILT)
diff --git a/cmds/pm/pm b/cmds/pm/pm
index 53f85b2..4d1f945 100755
--- a/cmds/pm/pm
+++ b/cmds/pm/pm
@@ -1,8 +1,2 @@
 #!/system/bin/sh
-# Script to start "pm" on the device, which has a very rudimentary
-# shell.
-#
-base=/system
-export CLASSPATH=$base/framework/pm.jar
-exec app_process $base/bin com.android.commands.pm.Pm "$@"
-
+cmd package "$@"
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
deleted file mode 100644
index 9490880..0000000
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ /dev/null
@@ -1,822 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.commands.pm;
-
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
-
-import android.accounts.IAccountManager;
-import android.app.ActivityManager;
-import android.app.PackageInstallObserver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.IIntentReceiver;
-import android.content.IIntentSender;
-import android.content.Intent;
-import android.content.IntentSender;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageDataObserver;
-import android.content.pm.IPackageInstaller;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageInstaller;
-import android.content.pm.PackageInstaller.SessionInfo;
-import android.content.pm.PackageInstaller.SessionParams;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.ApkLite;
-import android.content.pm.PackageParser.PackageLite;
-import android.content.pm.PackageParser.PackageParserException;
-import android.content.pm.UserInfo;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.IUserManager;
-import android.os.ParcelFileDescriptor;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.os.SELinux;
-import android.os.ServiceManager;
-import android.os.ShellCallback;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.os.storage.StorageManager;
-import android.text.TextUtils;
-import android.text.format.DateUtils;
-import android.util.Log;
-import android.util.Pair;
-
-import com.android.internal.content.PackageHelper;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.SizedInputStream;
-
-import libcore.io.IoUtils;
-
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.concurrent.SynchronousQueue;
-import java.util.concurrent.TimeUnit;
-
-public final class Pm {
-    private static final String TAG = "Pm";
-    private static final String STDIN_PATH = "-";
-
-    IPackageManager mPm;
-    IPackageInstaller mInstaller;
-    IUserManager mUm;
-    IAccountManager mAm;
-
-    private String[] mArgs;
-    private int mNextArg;
-    private String mCurArgData;
-
-    private static final String PM_NOT_RUNNING_ERR =
-        "Error: Could not access the Package Manager.  Is the system running?";
-
-    public static void main(String[] args) {
-        int exitCode = 1;
-        try {
-            exitCode = new Pm().run(args);
-        } catch (Exception e) {
-            Log.e(TAG, "Error", e);
-            System.err.println("Error: " + e);
-            if (e instanceof RemoteException) {
-                System.err.println(PM_NOT_RUNNING_ERR);
-            }
-        }
-        System.exit(exitCode);
-    }
-
-    public int run(String[] args) throws RemoteException {
-        if (args.length < 1) {
-            return runShellCommand("package", mArgs);
-        }
-        mAm = IAccountManager.Stub.asInterface(ServiceManager.getService(Context.ACCOUNT_SERVICE));
-        mUm = IUserManager.Stub.asInterface(ServiceManager.getService(Context.USER_SERVICE));
-        mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
-
-        if (mPm == null) {
-            System.err.println(PM_NOT_RUNNING_ERR);
-            return 1;
-        }
-        mInstaller = mPm.getPackageInstaller();
-
-        mArgs = args;
-        String op = args[0];
-        mNextArg = 1;
-
-        if ("install".equals(op)) {
-            return runInstall();
-        }
-
-        if ("install-create".equals(op)) {
-            return runInstallCreate();
-        }
-
-        if ("install-write".equals(op)) {
-            return runInstallWrite();
-        }
-
-        if ("install-commit".equals(op)) {
-            return runInstallCommit();
-        }
-
-        if ("install-abandon".equals(op) || "install-destroy".equals(op)) {
-            return runInstallAbandon();
-        }
-
-        return runShellCommand("package", mArgs);
-    }
-
-    static final class MyShellCallback extends ShellCallback {
-        @Override public ParcelFileDescriptor onOpenFile(String path, String seLinuxContext,
-                String mode) {
-            File file = new File(path);
-            final ParcelFileDescriptor fd;
-            try {
-                fd = ParcelFileDescriptor.open(file,
-                            ParcelFileDescriptor.MODE_CREATE |
-                            ParcelFileDescriptor.MODE_TRUNCATE |
-                            ParcelFileDescriptor.MODE_WRITE_ONLY);
-            } catch (FileNotFoundException e) {
-                String msg = "Unable to open file " + path + ": " + e;
-                System.err.println(msg);
-                throw new IllegalArgumentException(msg);
-            }
-            if (seLinuxContext != null) {
-                final String tcon = SELinux.getFileContext(file.getAbsolutePath());
-                if (!SELinux.checkSELinuxAccess(seLinuxContext, tcon, "file", "write")) {
-                    try {
-                        fd.close();
-                    } catch (IOException e) {
-                    }
-                    String msg = "System server has no access to file context " + tcon;
-                    System.err.println(msg + " (from path " + file.getAbsolutePath()
-                            + ", context " + seLinuxContext + ")");
-                    throw new IllegalArgumentException(msg);
-                }
-            }
-            return fd;
-        }
-    }
-
-    private int runShellCommand(String serviceName, String[] args) {
-        final HandlerThread handlerThread = new HandlerThread("results");
-        handlerThread.start();
-        try {
-            ServiceManager.getService(serviceName).shellCommand(
-                    FileDescriptor.in, FileDescriptor.out, FileDescriptor.err,
-                    args, new MyShellCallback(),
-                    new ResultReceiver(new Handler(handlerThread.getLooper())));
-            return 0;
-        } catch (RemoteException e) {
-            e.printStackTrace();
-        } finally {
-            handlerThread.quitSafely();
-        }
-        return -1;
-    }
-
-    private static class LocalIntentReceiver {
-        private final SynchronousQueue<Intent> mResult = new SynchronousQueue<>();
-
-        private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
-            @Override
-            public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
-                    IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
-                try {
-                    mResult.offer(intent, 5, TimeUnit.SECONDS);
-                } catch (InterruptedException e) {
-                    throw new RuntimeException(e);
-                }
-            }
-        };
-
-        public IntentSender getIntentSender() {
-            return new IntentSender((IIntentSender) mLocalSender);
-        }
-
-        public Intent getResult() {
-            try {
-                return mResult.take();
-            } catch (InterruptedException e) {
-                throw new RuntimeException(e);
-            }
-        }
-    }
-
-    private int translateUserId(int userId, String logContext) {
-        return ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
-                userId, true, true, logContext, "pm command");
-    }
-
-    private static String checkAbiArgument(String abi) {
-        if (TextUtils.isEmpty(abi)) {
-            throw new IllegalArgumentException("Missing ABI argument");
-        }
-        if ("-".equals(abi)) {
-            return abi;
-        }
-        final String[] supportedAbis = Build.SUPPORTED_ABIS;
-        for (String supportedAbi : supportedAbis) {
-            if (supportedAbi.equals(abi)) {
-                return abi;
-            }
-        }
-        throw new IllegalArgumentException("ABI " + abi + " not supported on this device");
-    }
-
-    /*
-     * Keep this around to support existing users of the "pm install" command that may not be
-     * able to be updated [or, at least informed the API has changed] such as ddmlib.
-     *
-     * Moving the implementation of "pm install" to "cmd package install" changes the executing
-     * context. Instead of being a stand alone process, "cmd package install" runs in the
-     * system_server process. Due to SELinux rules, system_server cannot access many directories;
-     * one of which being the package install staging directory [/data/local/tmp].
-     *
-     * The use of "adb install" or "cmd package install" over "pm install" is highly encouraged.
-     */
-    private int runInstall() throws RemoteException {
-        long startedTime = SystemClock.elapsedRealtime();
-        final InstallParams params = makeInstallParams();
-        final String inPath = nextArg();
-        if (params.sessionParams.sizeBytes == -1 && !STDIN_PATH.equals(inPath)) {
-            File file = new File(inPath);
-            if (file.isFile()) {
-                try {
-                    ApkLite baseApk = PackageParser.parseApkLite(file, 0);
-                    PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
-                            null, null);
-                    params.sessionParams.setSize(
-                            PackageHelper.calculateInstalledSize(pkgLite,
-                            params.sessionParams.abiOverride));
-                } catch (PackageParserException | IOException e) {
-                    System.err.println("Error: Failed to parse APK file: " + e);
-                    return 1;
-                }
-            } else {
-                System.err.println("Error: Can't open non-file: " + inPath);
-                return 1;
-            }
-        }
-
-        final int sessionId = doCreateSession(params.sessionParams,
-                params.installerPackageName, params.userId);
-
-        try {
-            if (inPath == null && params.sessionParams.sizeBytes == -1) {
-                System.err.println("Error: must either specify a package size or an APK file");
-                return 1;
-            }
-            if (doWriteSession(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
-                    false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
-                return 1;
-            }
-            Pair<String, Integer> status = doCommitSession(sessionId, false /*logSuccess*/);
-            if (status.second != PackageInstaller.STATUS_SUCCESS) {
-                return 1;
-            }
-            Log.i(TAG, "Package " + status.first + " installed in " + (SystemClock.elapsedRealtime()
-                    - startedTime) + " ms");
-            System.out.println("Success");
-            return 0;
-        } finally {
-            try {
-                mInstaller.abandonSession(sessionId);
-            } catch (Exception ignore) {
-            }
-        }
-    }
-
-    private int runInstallAbandon() throws RemoteException {
-        final int sessionId = Integer.parseInt(nextArg());
-        return doAbandonSession(sessionId, true /*logSuccess*/);
-    }
-
-    private int runInstallCommit() throws RemoteException {
-        final int sessionId = Integer.parseInt(nextArg());
-        return doCommitSession(sessionId, true /*logSuccess*/).second;
-    }
-
-    private int runInstallCreate() throws RemoteException {
-        final InstallParams installParams = makeInstallParams();
-        final int sessionId = doCreateSession(installParams.sessionParams,
-                installParams.installerPackageName, installParams.userId);
-
-        // NOTE: adb depends on parsing this string
-        System.out.println("Success: created install session [" + sessionId + "]");
-        return PackageInstaller.STATUS_SUCCESS;
-    }
-
-    private int runInstallWrite() throws RemoteException {
-        long sizeBytes = -1;
-
-        String opt;
-        while ((opt = nextOption()) != null) {
-            if (opt.equals("-S")) {
-                sizeBytes = Long.parseLong(nextArg());
-            } else {
-                throw new IllegalArgumentException("Unknown option: " + opt);
-            }
-        }
-
-        final int sessionId = Integer.parseInt(nextArg());
-        final String splitName = nextArg();
-        final String path = nextArg();
-        return doWriteSession(sessionId, path, sizeBytes, splitName, true /*logSuccess*/);
-    }
-
-    private static class InstallParams {
-        SessionParams sessionParams;
-        String installerPackageName;
-        int userId = UserHandle.USER_ALL;
-    }
-
-    private InstallParams makeInstallParams() {
-        final SessionParams sessionParams = new SessionParams(SessionParams.MODE_FULL_INSTALL);
-        final InstallParams params = new InstallParams();
-        params.sessionParams = sessionParams;
-        String opt;
-        while ((opt = nextOption()) != null) {
-            switch (opt) {
-                case "-l":
-                    sessionParams.installFlags |= PackageManager.INSTALL_FORWARD_LOCK;
-                    break;
-                case "-r":
-                    sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
-                    break;
-                case "-i":
-                    params.installerPackageName = nextArg();
-                    if (params.installerPackageName == null) {
-                        throw new IllegalArgumentException("Missing installer package");
-                    }
-                    break;
-                case "-t":
-                    sessionParams.installFlags |= PackageManager.INSTALL_ALLOW_TEST;
-                    break;
-                case "-s":
-                    sessionParams.installFlags |= PackageManager.INSTALL_EXTERNAL;
-                    break;
-                case "-f":
-                    sessionParams.installFlags |= PackageManager.INSTALL_INTERNAL;
-                    break;
-                case "-d":
-                    sessionParams.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
-                    break;
-                case "-g":
-                    sessionParams.installFlags |= PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS;
-                    break;
-                case "--dont-kill":
-                    sessionParams.installFlags |= PackageManager.INSTALL_DONT_KILL_APP;
-                    break;
-                case "--originating-uri":
-                    sessionParams.originatingUri = Uri.parse(nextOptionData());
-                    break;
-                case "--referrer":
-                    sessionParams.referrerUri = Uri.parse(nextOptionData());
-                    break;
-                case "-p":
-                    sessionParams.mode = SessionParams.MODE_INHERIT_EXISTING;
-                    sessionParams.appPackageName = nextOptionData();
-                    if (sessionParams.appPackageName == null) {
-                        throw new IllegalArgumentException("Missing inherit package name");
-                    }
-                    break;
-                case "--pkg":
-                    sessionParams.appPackageName = nextOptionData();
-                    if (sessionParams.appPackageName == null) {
-                        throw new IllegalArgumentException("Missing package name");
-                    }
-                    break;
-                case "-S":
-                    final long sizeBytes = Long.parseLong(nextOptionData());
-                    if (sizeBytes <= 0) {
-                        throw new IllegalArgumentException("Size must be positive");
-                    }
-                    sessionParams.setSize(sizeBytes);
-                    break;
-                case "--abi":
-                    sessionParams.abiOverride = checkAbiArgument(nextOptionData());
-                    break;
-                case "--ephemeral":
-                case "--instant":
-                    sessionParams.setInstallAsInstantApp(true /*isInstantApp*/);
-                    break;
-                case "--full":
-                    sessionParams.setInstallAsInstantApp(false /*isInstantApp*/);
-                    break;
-                case "--user":
-                    params.userId = UserHandle.parseUserArg(nextOptionData());
-                    break;
-                case "--install-location":
-                    sessionParams.installLocation = Integer.parseInt(nextOptionData());
-                    break;
-                case "--force-uuid":
-                    sessionParams.installFlags |= PackageManager.INSTALL_FORCE_VOLUME_UUID;
-                    sessionParams.volumeUuid = nextOptionData();
-                    if ("internal".equals(sessionParams.volumeUuid)) {
-                        sessionParams.volumeUuid = null;
-                    }
-                    break;
-                case "--force-sdk":
-                    sessionParams.installFlags |= PackageManager.INSTALL_FORCE_SDK;
-                    break;
-                default:
-                    throw new IllegalArgumentException("Unknown option " + opt);
-            }
-        }
-        return params;
-    }
-
-    private int doCreateSession(SessionParams params, String installerPackageName, int userId)
-            throws RemoteException {
-        userId = translateUserId(userId, "runInstallCreate");
-        if (userId == UserHandle.USER_ALL) {
-            userId = UserHandle.USER_SYSTEM;
-            params.installFlags |= PackageManager.INSTALL_ALL_USERS;
-        }
-
-        final int sessionId = mInstaller.createSession(params, installerPackageName, userId);
-        return sessionId;
-    }
-
-    private int doWriteSession(int sessionId, String inPath, long sizeBytes, String splitName,
-            boolean logSuccess) throws RemoteException {
-        if (STDIN_PATH.equals(inPath)) {
-            inPath = null;
-        } else if (inPath != null) {
-            final File file = new File(inPath);
-            if (file.isFile()) {
-                sizeBytes = file.length();
-            }
-        }
-
-        final SessionInfo info = mInstaller.getSessionInfo(sessionId);
-
-        PackageInstaller.Session session = null;
-        InputStream in = null;
-        OutputStream out = null;
-        try {
-            session = new PackageInstaller.Session(
-                    mInstaller.openSession(sessionId));
-
-            if (inPath != null) {
-                in = new FileInputStream(inPath);
-            } else {
-                in = new SizedInputStream(System.in, sizeBytes);
-            }
-            out = session.openWrite(splitName, 0, sizeBytes);
-
-            int total = 0;
-            byte[] buffer = new byte[1024 * 1024];
-            int c;
-            while ((c = in.read(buffer)) != -1) {
-                total += c;
-                out.write(buffer, 0, c);
-
-                if (info.sizeBytes > 0) {
-                    final float fraction = ((float) c / (float) info.sizeBytes);
-                    session.addProgress(fraction);
-                }
-            }
-            session.fsync(out);
-
-            if (logSuccess) {
-                System.out.println("Success: streamed " + total + " bytes");
-            }
-            return PackageInstaller.STATUS_SUCCESS;
-        } catch (IOException e) {
-            System.err.println("Error: failed to write; " + e.getMessage());
-            return PackageInstaller.STATUS_FAILURE;
-        } finally {
-            IoUtils.closeQuietly(out);
-            IoUtils.closeQuietly(in);
-            IoUtils.closeQuietly(session);
-        }
-    }
-
-    private Pair<String, Integer> doCommitSession(int sessionId, boolean logSuccess)
-            throws RemoteException {
-        PackageInstaller.Session session = null;
-        try {
-            session = new PackageInstaller.Session(
-                    mInstaller.openSession(sessionId));
-
-            final LocalIntentReceiver receiver = new LocalIntentReceiver();
-            session.commit(receiver.getIntentSender());
-
-            final Intent result = receiver.getResult();
-            final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
-                    PackageInstaller.STATUS_FAILURE);
-            if (status == PackageInstaller.STATUS_SUCCESS) {
-                if (logSuccess) {
-                    System.out.println("Success");
-                }
-            } else {
-                System.err.println("Failure ["
-                        + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
-            }
-            return new Pair<>(result.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME), status);
-        } finally {
-            IoUtils.closeQuietly(session);
-        }
-    }
-
-    private int doAbandonSession(int sessionId, boolean logSuccess) throws RemoteException {
-        PackageInstaller.Session session = null;
-        try {
-            session = new PackageInstaller.Session(mInstaller.openSession(sessionId));
-            session.abandon();
-            if (logSuccess) {
-                System.out.println("Success");
-            }
-            return PackageInstaller.STATUS_SUCCESS;
-        } finally {
-            IoUtils.closeQuietly(session);
-        }
-    }
-
-    class LocalPackageInstallObserver extends PackageInstallObserver {
-        boolean finished;
-        int result;
-        String extraPermission;
-        String extraPackage;
-
-        @Override
-        public void onPackageInstalled(String name, int status, String msg, Bundle extras) {
-            synchronized (this) {
-                finished = true;
-                result = status;
-                if (status == PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION) {
-                    extraPermission = extras.getString(
-                            PackageManager.EXTRA_FAILURE_EXISTING_PERMISSION);
-                    extraPackage = extras.getString(
-                            PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
-                }
-                notifyAll();
-            }
-        }
-    }
-
-    private static boolean isNumber(String s) {
-        try {
-            Integer.parseInt(s);
-        } catch (NumberFormatException nfe) {
-            return false;
-        }
-        return true;
-    }
-
-    static class ClearCacheObserver extends IPackageDataObserver.Stub {
-        boolean finished;
-        boolean result;
-
-        @Override
-        public void onRemoveCompleted(String packageName, boolean succeeded) throws RemoteException {
-            synchronized (this) {
-                finished = true;
-                result = succeeded;
-                notifyAll();
-            }
-        }
-
-    }
-
-    static class ClearDataObserver extends IPackageDataObserver.Stub {
-        boolean finished;
-        boolean result;
-
-        @Override
-        public void onRemoveCompleted(String packageName, boolean succeeded) throws RemoteException {
-            synchronized (this) {
-                finished = true;
-                result = succeeded;
-                notifyAll();
-            }
-        }
-    }
-
-    /**
-     * Displays the package file for a package.
-     * @param pckg
-     */
-    private int displayPackageFilePath(String pckg, int userId) {
-        try {
-            PackageInfo info = mPm.getPackageInfo(pckg, 0, userId);
-            if (info != null && info.applicationInfo != null) {
-                System.out.print("package:");
-                System.out.println(info.applicationInfo.sourceDir);
-                if (!ArrayUtils.isEmpty(info.applicationInfo.splitSourceDirs)) {
-                    for (String splitSourceDir : info.applicationInfo.splitSourceDirs) {
-                        System.out.print("package:");
-                        System.out.println(splitSourceDir);
-                    }
-                }
-                return 0;
-            }
-        } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(PM_NOT_RUNNING_ERR);
-        }
-        return 1;
-    }
-
-    private String nextOption() {
-        if (mNextArg >= mArgs.length) {
-            return null;
-        }
-        String arg = mArgs[mNextArg];
-        if (!arg.startsWith("-")) {
-            return null;
-        }
-        mNextArg++;
-        if (arg.equals("--")) {
-            return null;
-        }
-        if (arg.length() > 1 && arg.charAt(1) != '-') {
-            if (arg.length() > 2) {
-                mCurArgData = arg.substring(2);
-                return arg.substring(0, 2);
-            } else {
-                mCurArgData = null;
-                return arg;
-            }
-        }
-        mCurArgData = null;
-        return arg;
-    }
-
-    private String nextOptionData() {
-        if (mCurArgData != null) {
-            return mCurArgData;
-        }
-        if (mNextArg >= mArgs.length) {
-            return null;
-        }
-        String data = mArgs[mNextArg];
-        mNextArg++;
-        return data;
-    }
-
-    private String nextArg() {
-        if (mNextArg >= mArgs.length) {
-            return null;
-        }
-        String arg = mArgs[mNextArg];
-        mNextArg++;
-        return arg;
-    }
-
-    private static int showUsage() {
-        System.err.println("usage: pm path [--user USER_ID] PACKAGE");
-        System.err.println("       pm dump PACKAGE");
-        System.err.println("       pm install [-lrtsfdg] [-i PACKAGE] [--user USER_ID]");
-        System.err.println("               [-p INHERIT_PACKAGE] [--install-location 0/1/2]");
-        System.err.println("               [--originating-uri URI] [---referrer URI]");
-        System.err.println("               [--abi ABI_NAME] [--force-sdk]");
-        System.err.println("               [--preload] [--instantapp] [--full] [--dont-kill]");
-        System.err.println("               [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES] [PATH|-]");
-        System.err.println("       pm install-create [-lrtsfdg] [-i PACKAGE] [--user USER_ID]");
-        System.err.println("               [-p INHERIT_PACKAGE] [--install-location 0/1/2]");
-        System.err.println("               [--originating-uri URI] [---referrer URI]");
-        System.err.println("               [--abi ABI_NAME] [--force-sdk]");
-        System.err.println("               [--preload] [--instantapp] [--full] [--dont-kill]");
-        System.err.println("               [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES]");
-        System.err.println("       pm install-write [-S BYTES] SESSION_ID SPLIT_NAME [PATH|-]");
-        System.err.println("       pm install-commit SESSION_ID");
-        System.err.println("       pm install-abandon SESSION_ID");
-        System.err.println("       pm uninstall [-k] [--user USER_ID] [--versionCode VERSION_CODE] PACKAGE");
-        System.err.println("       pm set-installer PACKAGE INSTALLER");
-        System.err.println("       pm move-package PACKAGE [internal|UUID]");
-        System.err.println("       pm move-primary-storage [internal|UUID]");
-        System.err.println("       pm clear [--user USER_ID] PACKAGE");
-        System.err.println("       pm enable [--user USER_ID] PACKAGE_OR_COMPONENT");
-        System.err.println("       pm disable [--user USER_ID] PACKAGE_OR_COMPONENT");
-        System.err.println("       pm disable-user [--user USER_ID] PACKAGE_OR_COMPONENT");
-        System.err.println("       pm disable-until-used [--user USER_ID] PACKAGE_OR_COMPONENT");
-        System.err.println("       pm default-state [--user USER_ID] PACKAGE_OR_COMPONENT");
-        System.err.println("       pm set-user-restriction [--user USER_ID] RESTRICTION VALUE");
-        System.err.println("       pm hide [--user USER_ID] PACKAGE_OR_COMPONENT");
-        System.err.println("       pm unhide [--user USER_ID] PACKAGE_OR_COMPONENT");
-        System.err.println("       pm grant [--user USER_ID] PACKAGE PERMISSION");
-        System.err.println("       pm revoke [--user USER_ID] PACKAGE PERMISSION");
-        System.err.println("       pm reset-permissions");
-        System.err.println("       pm set-app-link [--user USER_ID] PACKAGE {always|ask|never|undefined}");
-        System.err.println("       pm get-app-link [--user USER_ID] PACKAGE");
-        System.err.println("       pm set-install-location [0/auto] [1/internal] [2/external]");
-        System.err.println("       pm get-install-location");
-        System.err.println("       pm set-permission-enforced PERMISSION [true|false]");
-        System.err.println("       pm trim-caches DESIRED_FREE_SPACE [internal|UUID]");
-        System.err.println("       pm create-user [--profileOf USER_ID] [--managed] [--restricted] [--ephemeral] [--guest] USER_NAME");
-        System.err.println("       pm remove-user USER_ID");
-        System.err.println("       pm get-max-users");
-        System.err.println("");
-        System.err.println("NOTE: 'pm list' commands have moved! Run 'adb shell cmd package'");
-        System.err.println("  to display the new commands.");
-        System.err.println("");
-        System.err.println("pm path: print the path to the .apk of the given PACKAGE.");
-        System.err.println("");
-        System.err.println("pm dump: print system state associated with the given PACKAGE.");
-        System.err.println("");
-        System.err.println("pm install: install a single legacy package");
-        System.err.println("pm install-create: create an install session");
-        System.err.println("    -l: forward lock application");
-        System.err.println("    -r: allow replacement of existing application");
-        System.err.println("    -t: allow test packages");
-        System.err.println("    -i: specify package name of installer owning the app");
-        System.err.println("    -s: install application on sdcard");
-        System.err.println("    -f: install application on internal flash");
-        System.err.println("    -d: allow version code downgrade (debuggable packages only)");
-        System.err.println("    -p: partial application install (new split on top of existing pkg)");
-        System.err.println("    -g: grant all runtime permissions");
-        System.err.println("    -S: size in bytes of entire session");
-        System.err.println("    --dont-kill: installing a new feature split, don't kill running app");
-        System.err.println("    --originating-uri: set URI where app was downloaded from");
-        System.err.println("    --referrer: set URI that instigated the install of the app");
-        System.err.println("    --pkg: specify expected package name of app being installed");
-        System.err.println("    --abi: override the default ABI of the platform");
-        System.err.println("    --instantapp: cause the app to be installed as an ephemeral install app");
-        System.err.println("    --full: cause the app to be installed as a non-ephemeral full app");
-        System.err.println("    --install-location: force the install location:");
-        System.err.println("        0=auto, 1=internal only, 2=prefer external");
-        System.err.println("    --force-uuid: force install on to disk volume with given UUID");
-        System.err.println("    --force-sdk: allow install even when existing app targets platform");
-        System.err.println("        codename but new one targets a final API level");
-        System.err.println("");
-        System.err.println("pm install-write: write a package into existing session; path may");
-        System.err.println("  be '-' to read from stdin");
-        System.err.println("    -S: size in bytes of package, required for stdin");
-        System.err.println("");
-        System.err.println("pm install-commit: perform install of fully staged session");
-        System.err.println("pm install-abandon: abandon session");
-        System.err.println("");
-        System.err.println("pm set-installer: set installer package name");
-        System.err.println("");
-        System.err.println("pm uninstall: removes a package from the system. Options:");
-        System.err.println("    -k: keep the data and cache directories around after package removal.");
-        System.err.println("");
-        System.err.println("pm clear: deletes all data associated with a package.");
-        System.err.println("");
-        System.err.println("pm enable, disable, disable-user, disable-until-used, default-state:");
-        System.err.println("  these commands change the enabled state of a given package or");
-        System.err.println("  component (written as \"package/class\").");
-        System.err.println("");
-        System.err.println("pm grant, revoke: these commands either grant or revoke permissions");
-        System.err.println("    to apps. The permissions must be declared as used in the app's");
-        System.err.println("    manifest, be runtime permissions (protection level dangerous),");
-        System.err.println("    and the app targeting SDK greater than Lollipop MR1.");
-        System.err.println("");
-        System.err.println("pm reset-permissions: revert all runtime permissions to their default state.");
-        System.err.println("");
-        System.err.println("pm get-install-location: returns the current install location.");
-        System.err.println("    0 [auto]: Let system decide the best location");
-        System.err.println("    1 [internal]: Install on internal device storage");
-        System.err.println("    2 [external]: Install on external media");
-        System.err.println("");
-        System.err.println("pm set-install-location: changes the default install location.");
-        System.err.println("  NOTE: this is only intended for debugging; using this can cause");
-        System.err.println("  applications to break and other undersireable behavior.");
-        System.err.println("    0 [auto]: Let system decide the best location");
-        System.err.println("    1 [internal]: Install on internal device storage");
-        System.err.println("    2 [external]: Install on external media");
-        System.err.println("");
-        System.err.println("pm trim-caches: trim cache files to reach the given free space.");
-        System.err.println("");
-        System.err.println("pm create-user: create a new user with the given USER_NAME,");
-        System.err.println("  printing the new user identifier of the user.");
-        System.err.println("");
-        System.err.println("pm remove-user: remove the user with the given USER_IDENTIFIER,");
-        System.err.println("  deleting all data associated with that user");
-        System.err.println("");
-        return 1;
-    }
-}
diff --git a/core/java/android/os/ShellCallback.java b/core/java/android/os/ShellCallback.java
index ad9fbfb..6a62424 100644
--- a/core/java/android/os/ShellCallback.java
+++ b/core/java/android/os/ShellCallback.java
@@ -105,6 +105,9 @@
     ShellCallback(Parcel in) {
         mLocal = false;
         mShellCallback = IShellCallback.Stub.asInterface(in.readStrongBinder());
+        if (mShellCallback != null) {
+            Binder.allowBlocking(mShellCallback.asBinder());
+        }
     }
 
     public static final Parcelable.Creator<ShellCallback> CREATOR
diff --git a/core/java/android/os/ShellCommand.java b/core/java/android/os/ShellCommand.java
index d75219f..fa05a5e 100644
--- a/core/java/android/os/ShellCommand.java
+++ b/core/java/android/os/ShellCommand.java
@@ -91,7 +91,13 @@
         mCmd = cmd;
         mResultReceiver = resultReceiver;
 
-        if (DEBUG) Slog.d(TAG, "Starting command " + mCmd + " on " + mTarget);
+        if (DEBUG) {
+            RuntimeException here = new RuntimeException("here");
+            here.fillInStackTrace();
+            Slog.d(TAG, "Starting command " + mCmd + " on " + mTarget, here);
+            Slog.d(TAG, "Calling uid=" + Binder.getCallingUid()
+                    + " pid=" + Binder.getCallingPid() + " ShellCallback=" + getShellCallback());
+        }
         int res = -1;
         try {
             res = onCommand(mCmd);
@@ -227,15 +233,19 @@
      * @hide
      */
     public ParcelFileDescriptor openFileForSystem(String path, String mode) {
+        if (DEBUG) Slog.d(TAG, "openFileForSystem: " + path + " mode=" + mode);
         try {
             ParcelFileDescriptor pfd = getShellCallback().openFile(path,
                     "u:r:system_server:s0", mode);
             if (pfd != null) {
+                if (DEBUG) Slog.d(TAG, "Got file: " + pfd);
                 return pfd;
             }
         } catch (RuntimeException e) {
+            if (DEBUG) Slog.d(TAG, "Failure opening file: " + e.getMessage());
             getErrPrintWriter().println("Failure opening file: " + e.getMessage());
         }
+        if (DEBUG) Slog.d(TAG, "Error: Unable to open file: " + path);
         getErrPrintWriter().println("Error: Unable to open file: " + path);
         getErrPrintWriter().println("Consider using a file under /data/local/tmp/");
         return null;
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index 83b7d2f..a1e6fd8 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -43,6 +43,7 @@
 
 import java.io.Closeable;
 import java.io.File;
+import java.io.FileDescriptor;
 import java.io.IOException;
 import java.util.List;
 
@@ -118,6 +119,17 @@
             return new Handle(apkHandles, multiArch, extractNativeLibs, debuggable);
         }
 
+        public static Handle createFd(PackageLite lite, FileDescriptor fd) throws IOException {
+            final long[] apkHandles = new long[1];
+            final String path = lite.baseCodePath;
+            apkHandles[0] = nativeOpenApkFd(fd, path);
+            if (apkHandles[0] == 0) {
+                throw new IOException("Unable to open APK " + path + " from fd " + fd);
+            }
+
+            return new Handle(apkHandles, lite.multiArch, lite.extractNativeLibs, lite.debuggable);
+        }
+
         Handle(long[] apkHandles, boolean multiArch, boolean extractNativeLibs,
                 boolean debuggable) {
             this.apkHandles = apkHandles;
@@ -152,6 +164,7 @@
     }
 
     private static native long nativeOpenApk(String path);
+    private static native long nativeOpenApkFd(FileDescriptor fd, String debugPath);
     private static native void nativeClose(long handle);
 
     private static native long nativeSumNativeBinaries(long handle, String cpuAbi,
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index 59a7995..e765ab1 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -42,6 +42,7 @@
 import libcore.io.IoUtils;
 
 import java.io.File;
+import java.io.FileDescriptor;
 import java.io.IOException;
 import java.util.Objects;
 import java.util.UUID;
@@ -383,9 +384,15 @@
 
     public static long calculateInstalledSize(PackageLite pkg, String abiOverride)
             throws IOException {
+        return calculateInstalledSize(pkg, abiOverride, null);
+    }
+
+    public static long calculateInstalledSize(PackageLite pkg, String abiOverride,
+            FileDescriptor fd) throws IOException {
         NativeLibraryHelper.Handle handle = null;
         try {
-            handle = NativeLibraryHelper.Handle.create(pkg);
+            handle = fd != null ? NativeLibraryHelper.Handle.createFd(pkg, fd)
+                    : NativeLibraryHelper.Handle.create(pkg);
             return calculateInstalledSize(pkg, handle, abiOverride);
         } finally {
             IoUtils.closeQuietly(handle);
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index fce5dd5..17b98da 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -557,6 +557,23 @@
     return reinterpret_cast<jlong>(zipFile);
 }
 
+static jlong
+com_android_internal_content_NativeLibraryHelper_openApkFd(JNIEnv *env, jclass,
+        jobject fileDescriptor, jstring debugPathName)
+{
+    ScopedUtfChars debugFilePath(env, debugPathName);
+
+    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+    if (fd < 0) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "Bad FileDescriptor");
+        return 0;
+    }
+
+    ZipFileRO* zipFile = ZipFileRO::openFd(fd, debugFilePath.c_str());
+
+    return reinterpret_cast<jlong>(zipFile);
+}
+
 static void
 com_android_internal_content_NativeLibraryHelper_close(JNIEnv *env, jclass, jlong apkHandle)
 {
@@ -567,6 +584,9 @@
     {"nativeOpenApk",
             "(Ljava/lang/String;)J",
             (void *)com_android_internal_content_NativeLibraryHelper_openApk},
+    {"nativeOpenApkFd",
+            "(Ljava/io/FileDescriptor;Ljava/lang/String;)J",
+            (void *)com_android_internal_content_NativeLibraryHelper_openApkFd},
     {"nativeClose",
             "(J)V",
             (void *)com_android_internal_content_NativeLibraryHelper_close},
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 3c8736e..0485625 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -148,11 +148,15 @@
     int count = android_atomic_dec(&gCount);
     if (kIsDebug) {
         ALOGI("Destroying AssetManager in %p #%d\n", this, count);
+    } else {
+        ALOGV("Destroying AssetManager in %p #%d\n", this, count);
     }
 
     // Manually close any fd paths for which we have not yet opened their zip (which
     // will take ownership of the fd and close it when done).
     for (size_t i=0; i<mAssetPaths.size(); i++) {
+        ALOGV("Cleaning path #%d: fd=%d, zip=%p", (int)i, mAssetPaths[i].rawFd,
+                mAssetPaths[i].zip.get());
         if (mAssetPaths[i].rawFd >= 0 && mAssetPaths[i].zip == NULL) {
             close(mAssetPaths[i].rawFd);
         }
@@ -202,7 +206,7 @@
          ap.type == kFileTypeDirectory ? "dir" : "zip", ap.path.string());
 
     ap.isSystemAsset = isSystemAsset;
-    mAssetPaths.add(ap);
+    ssize_t apPos = mAssetPaths.add(ap);
 
     // new paths are always added at the end
     if (cookie) {
@@ -219,7 +223,7 @@
 #endif
 
     if (mResources != NULL) {
-        appendPathToResTable(ap, appAsLib);
+        appendPathToResTable(mAssetPaths.editItemAt(apPos), appAsLib);
     }
 
     return true;
@@ -304,7 +308,7 @@
 
     ALOGV("In %p Asset fd %d name: %s", this, fd, ap.path.string());
 
-    mAssetPaths.add(ap);
+    ssize_t apPos = mAssetPaths.add(ap);
 
     // new paths are always added at the end
     if (cookie) {
@@ -312,7 +316,7 @@
     }
 
     if (mResources != NULL) {
-        appendPathToResTable(ap, appAsLib);
+        appendPathToResTable(mAssetPaths.editItemAt(apPos), appAsLib);
     }
 
     return true;
@@ -442,7 +446,8 @@
         i--;
         ALOGV("Looking for asset '%s' in '%s'\n",
                 assetName.string(), mAssetPaths.itemAt(i).path.string());
-        Asset* pAsset = openNonAssetInPathLocked(assetName.string(), mode, mAssetPaths.itemAt(i));
+        Asset* pAsset = openNonAssetInPathLocked(assetName.string(), mode,
+                mAssetPaths.editItemAt(i));
         if (pAsset != NULL) {
             return pAsset != kExcludedAsset ? pAsset : NULL;
         }
@@ -471,7 +476,7 @@
         i--;
         ALOGV("Looking for non-asset '%s' in '%s'\n", fileName, mAssetPaths.itemAt(i).path.string());
         Asset* pAsset = openNonAssetInPathLocked(
-            fileName, mode, mAssetPaths.itemAt(i));
+            fileName, mode, mAssetPaths.editItemAt(i));
         if (pAsset != NULL) {
             if (outCookie != NULL) *outCookie = static_cast<int32_t>(i + 1);
             return pAsset != kExcludedAsset ? pAsset : NULL;
@@ -493,7 +498,7 @@
         ALOGV("Looking for non-asset '%s' in '%s'\n", fileName,
                 mAssetPaths.itemAt(which).path.string());
         Asset* pAsset = openNonAssetInPathLocked(
-            fileName, mode, mAssetPaths.itemAt(which));
+            fileName, mode, mAssetPaths.editItemAt(which));
         if (pAsset != NULL) {
             return pAsset != kExcludedAsset ? pAsset : NULL;
         }
@@ -527,7 +532,7 @@
     }
 }
 
-bool AssetManager::appendPathToResTable(const asset_path& ap, bool appAsLib) const {
+bool AssetManager::appendPathToResTable(asset_path& ap, bool appAsLib) const {
     // skip those ap's that correspond to system overlays
     if (ap.isSystemOverlay) {
         return true;
@@ -645,7 +650,8 @@
     bool onlyEmptyResources = true;
     const size_t N = mAssetPaths.size();
     for (size_t i=0; i<N; i++) {
-        bool empty = appendPathToResTable(mAssetPaths.itemAt(i));
+        bool empty = appendPathToResTable(
+                const_cast<AssetManager*>(this)->mAssetPaths.editItemAt(i));
         onlyEmptyResources = onlyEmptyResources && empty;
     }
 
@@ -770,7 +776,7 @@
  * be used.
  */
 Asset* AssetManager::openNonAssetInPathLocked(const char* fileName, AccessMode mode,
-    const asset_path& ap)
+    asset_path& ap)
 {
     Asset* pAsset = NULL;
 
@@ -851,17 +857,19 @@
  * Return a pointer to one of our open Zip archives.  Returns NULL if no
  * matching Zip file exists.
  */
-ZipFileRO* AssetManager::getZipFileLocked(const asset_path& ap)
+ZipFileRO* AssetManager::getZipFileLocked(asset_path& ap)
 {
-    ALOGV("getZipFileLocked() in %p\n", this);
+    ALOGV("getZipFileLocked() in %p: ap=%p zip=%p", this, &ap, ap.zip.get());
 
     if (ap.zip != NULL) {
         return ap.zip->getZip();
     }
 
     if (ap.rawFd < 0) {
+        ALOGV("getZipFileLocked: Creating new zip from path %s", ap.path.string());
         ap.zip = mZipSet.getSharedZip(ap.path);
     } else {
+        ALOGV("getZipFileLocked: Creating new zip from fd %d", ap.rawFd);
         ap.zip = SharedZip::create(ap.rawFd, ap.path);
 
     }
diff --git a/libs/androidfw/include/androidfw/AssetManager.h b/libs/androidfw/include/androidfw/AssetManager.h
index 4254614..ecc5dc1 100644
--- a/libs/androidfw/include/androidfw/AssetManager.h
+++ b/libs/androidfw/include/androidfw/AssetManager.h
@@ -222,16 +222,16 @@
         bool isSystemOverlay;
         bool isSystemAsset;
         bool assumeOwnership;
-        mutable sp<SharedZip> zip;
+        sp<SharedZip> zip;
     };
 
     Asset* openNonAssetInPathLocked(const char* fileName, AccessMode mode,
-        const asset_path& path);
+        asset_path& path);
     String8 createPathNameLocked(const asset_path& path, const char* rootDir);
     String8 createZipSourceNameLocked(const String8& zipFileName,
         const String8& dirName, const String8& fileName);
 
-    ZipFileRO* getZipFileLocked(const asset_path& path);
+    ZipFileRO* getZipFileLocked(asset_path& path);
     Asset* openAssetFromFileLocked(const String8& fileName, AccessMode mode);
     Asset* openAssetFromZipLocked(const ZipFileRO* pZipFile,
         const ZipEntryRO entry, AccessMode mode, const String8& entryName);
@@ -247,7 +247,7 @@
     const ResTable* getResTable(bool required = true) const;
     void setLocaleLocked(const char* locale);
     void updateResourceParamsLocked() const;
-    bool appendPathToResTable(const asset_path& ap, bool appAsLib=false) const;
+    bool appendPathToResTable(asset_path& ap, bool appAsLib=false) const;
 
     Asset* openIdmapLocked(const struct asset_path& ap) const;
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 807eb1a..0b9514a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -264,7 +264,7 @@
                 PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
                         null, null);
                 params.sessionParams.setSize(PackageHelper.calculateInstalledSize(
-                        pkgLite, params.sessionParams.abiOverride));
+                        pkgLite, params.sessionParams.abiOverride, fd.getFileDescriptor()));
             } catch (PackageParserException | IOException e) {
                 getErrPrintWriter().println("Error: Failed to parse APK file: " + inPath);
                 throw new IllegalArgumentException(