Merge "Fully implement "install" and "install-write" in PackageManagerShellCommand."
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index ab075ee..79e7fac 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -98,7 +98,8 @@
     static final class MyShellCallback extends ShellCallback {
         boolean mActive = true;
 
-        @Override public ParcelFileDescriptor onOpenOutputFile(String path, String seLinuxContext) {
+        @Override public ParcelFileDescriptor onOpenFile(String path, String seLinuxContext,
+                String mode) {
             if (!mActive) {
                 System.err.println("Open attempt after active for: " + path);
                 return null;
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 29433f3..9490880 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -157,7 +157,8 @@
     }
 
     static final class MyShellCallback extends ShellCallback {
-        @Override public ParcelFileDescriptor onOpenOutputFile(String path, String seLinuxContext) {
+        @Override public ParcelFileDescriptor onOpenFile(String path, String seLinuxContext,
+                String mode) {
             File file = new File(path);
             final ParcelFileDescriptor fd;
             try {
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index b48829c..1c5cf15 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -102,6 +102,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.File;
+import java.io.FileDescriptor;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -1708,13 +1709,33 @@
      */
     public static ApkLite parseApkLite(File apkFile, int flags)
             throws PackageParserException {
-        final String apkPath = apkFile.getAbsolutePath();
+        return parseApkLiteInner(apkFile, null, null, flags);
+    }
+
+    /**
+     * Utility method that retrieves lightweight details about a single APK
+     * file, including package name, split name, and install location.
+     *
+     * @param fd already open file descriptor of an apk file
+     * @param debugPathName arbitrary text name for this file, for debug output
+     * @param flags optional parse flags, such as
+     *            {@link #PARSE_COLLECT_CERTIFICATES}
+     */
+    public static ApkLite parseApkLite(FileDescriptor fd, String debugPathName, int flags)
+            throws PackageParserException {
+        return parseApkLiteInner(null, fd, debugPathName, flags);
+    }
+
+    private static ApkLite parseApkLiteInner(File apkFile, FileDescriptor fd, String debugPathName,
+            int flags) throws PackageParserException {
+        final String apkPath = fd != null ? debugPathName : apkFile.getAbsolutePath();
 
         AssetManager assets = null;
         XmlResourceParser parser = null;
         try {
             assets = newConfiguredAssetManager();
-            int cookie = assets.addAssetPath(apkPath);
+            int cookie = fd != null
+                    ? assets.addAssetFd(fd, debugPathName) : assets.addAssetPath(apkPath);
             if (cookie == 0) {
                 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
                         "Failed to parse " + apkPath);
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index f0adcd6..7866560 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -28,8 +28,7 @@
 import android.util.SparseArray;
 import android.util.TypedValue;
 
-import dalvik.annotation.optimization.FastNative;
-
+import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
@@ -694,7 +693,35 @@
 
     private native final int addAssetPathNative(String path, boolean appAsLib);
 
-     /**
+    /**
+     * Add an additional set of assets to the asset manager from an already open
+     * FileDescriptor.  Not for use by applications.
+     * This does not give full AssetManager functionality for these assets,
+     * since the origin of the file is not known for purposes of sharing,
+     * overlay resolution, and other features.  However it does allow you
+     * to do simple access to the contents of the given fd as an apk file.
+     * Performs a dup of the underlying fd, so you must take care of still closing
+     * the FileDescriptor yourself (and can do that whenever you want).
+     * Returns the cookie of the added asset, or 0 on failure.
+     * {@hide}
+     */
+    public int addAssetFd(FileDescriptor fd, String debugPathName) {
+        return addAssetFdInternal(fd, debugPathName, false);
+    }
+
+    private int addAssetFdInternal(FileDescriptor fd, String debugPathName,
+            boolean appAsLib) {
+        synchronized (this) {
+            int res = addAssetFdNative(fd, debugPathName, appAsLib);
+            makeStringBlocks(mStringBlocks);
+            return res;
+        }
+    }
+
+    private native int addAssetFdNative(FileDescriptor fd, String debugPathName,
+            boolean appAsLib);
+
+    /**
      * Add a set of assets to overlay an already added set of assets.
      *
      * This is only intended for application resources. System wide resources
diff --git a/core/java/android/os/ShellCallback.java b/core/java/android/os/ShellCallback.java
index e7fe697..ad9fbfb 100644
--- a/core/java/android/os/ShellCallback.java
+++ b/core/java/android/os/ShellCallback.java
@@ -35,8 +35,9 @@
     IShellCallback mShellCallback;
 
     class MyShellCallback extends IShellCallback.Stub {
-        public ParcelFileDescriptor openOutputFile(String path, String seLinuxContext) {
-            return onOpenOutputFile(path, seLinuxContext);
+        public ParcelFileDescriptor openFile(String path, String seLinuxContext,
+                String mode) {
+            return onOpenFile(path, seLinuxContext, mode);
         }
     }
 
@@ -48,23 +49,27 @@
     }
 
     /**
-     * Ask the shell to open a file for writing.  This will truncate the file if it
-     * already exists.  It will create the file if it doesn't exist.
+     * Ask the shell to open a file.  If opening for writing, will truncate the file if it
+     * already exists and will create the file if it doesn't exist.
      * @param path Path of the file to be opened/created.
      * @param seLinuxContext Optional SELinux context that must be allowed to have
      * access to the file; if null, nothing is required.
+     * @param mode Mode to open file in: "r" for input/reading an existing file,
+     * "r+" for reading/writing an existing file, "w" for output/writing a new file (either
+     * creating or truncating an existing one), "w+" for reading/writing a new file (either
+     * creating or truncating an existing one).
      */
-    public ParcelFileDescriptor openOutputFile(String path, String seLinuxContext) {
-        if (DEBUG) Log.d(TAG, "openOutputFile " + this + ": mLocal=" + mLocal
+    public ParcelFileDescriptor openFile(String path, String seLinuxContext, String mode) {
+        if (DEBUG) Log.d(TAG, "openFile " + this + " mode=" + mode + ": mLocal=" + mLocal
                 + " mShellCallback=" + mShellCallback);
 
         if (mLocal) {
-            return onOpenOutputFile(path, seLinuxContext);
+            return onOpenFile(path, seLinuxContext, mode);
         }
 
         if (mShellCallback != null) {
             try {
-                return mShellCallback.openOutputFile(path, seLinuxContext);
+                return mShellCallback.openFile(path, seLinuxContext, mode);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failure opening " + path, e);
             }
@@ -72,7 +77,7 @@
         return null;
     }
 
-    public ParcelFileDescriptor onOpenOutputFile(String path, String seLinuxContext) {
+    public ParcelFileDescriptor onOpenFile(String path, String seLinuxContext, String mode) {
         return null;
     }
 
diff --git a/core/java/android/os/ShellCommand.java b/core/java/android/os/ShellCommand.java
index 6223235..d75219f 100644
--- a/core/java/android/os/ShellCommand.java
+++ b/core/java/android/os/ShellCommand.java
@@ -226,10 +226,10 @@
      * Helper for just system services to ask the shell to open an output file.
      * @hide
      */
-    public ParcelFileDescriptor openOutputFileForSystem(String path) {
+    public ParcelFileDescriptor openFileForSystem(String path, String mode) {
         try {
-            ParcelFileDescriptor pfd = getShellCallback().openOutputFile(path,
-                    "u:r:system_server:s0");
+            ParcelFileDescriptor pfd = getShellCallback().openFile(path,
+                    "u:r:system_server:s0", mode);
             if (pfd != null) {
                 return pfd;
             }
diff --git a/core/java/com/android/internal/os/IShellCallback.aidl b/core/java/com/android/internal/os/IShellCallback.aidl
index 57d6789..5704342 100644
--- a/core/java/com/android/internal/os/IShellCallback.aidl
+++ b/core/java/com/android/internal/os/IShellCallback.aidl
@@ -20,5 +20,5 @@
 
 /** @hide */
 interface IShellCallback {
-    ParcelFileDescriptor openOutputFile(String path, String seLinuxContext);
+    ParcelFileDescriptor openFile(String path, String seLinuxContext, String mode);
 }
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index b137da3..c6828c4 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -568,6 +568,35 @@
     return (res) ? (jint)cookie : 0;
 }
 
+static jint android_content_AssetManager_addAssetFd(JNIEnv* env, jobject clazz,
+                                                    jobject fileDescriptor, jstring debugPathName,
+                                                    jboolean appAsLib)
+{
+    ScopedUtfChars debugPathName8(env, debugPathName);
+
+    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+    if (fd < 0) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "Bad FileDescriptor");
+        return 0;
+    }
+
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+
+    int dupfd = ::dup(fd);
+    if (dupfd < 0) {
+        jniThrowIOException(env, errno);
+        return 0;
+    }
+
+    int32_t cookie;
+    bool res = am->addAssetFd(dupfd, String8(debugPathName8.c_str()), &cookie, appAsLib);
+
+    return (res) ? static_cast<jint>(cookie) : 0;
+}
+
 static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject clazz)
 {
     AssetManager* am = assetManagerForJavaObject(env, clazz);
@@ -1673,6 +1702,8 @@
         (void*) android_content_AssetManager_getAssetRemainingLength },
     { "addAssetPathNative", "(Ljava/lang/String;Z)I",
         (void*) android_content_AssetManager_addAssetPath },
+    { "addAssetFdNative", "(Ljava/io/FileDescriptor;Ljava/lang/String;Z)I",
+        (void*) android_content_AssetManager_addAssetFd },
     { "addOverlayPathNative",   "(Ljava/lang/String;)I",
         (void*) android_content_AssetManager_addOverlayPath },
     { "isUpToDate",     "()Z",
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 5603508..3c8736e 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -150,6 +150,14 @@
         ALOGI("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++) {
+        if (mAssetPaths[i].rawFd >= 0 && mAssetPaths[i].zip == NULL) {
+            close(mAssetPaths[i].rawFd);
+        }
+    }
+
     delete mConfig;
     delete mResources;
 
@@ -280,7 +288,35 @@
     }
 
     return true;
- }
+}
+
+bool AssetManager::addAssetFd(
+        int fd, const String8& debugPathName, int32_t* cookie, bool appAsLib,
+        bool assume_ownership) {
+    AutoMutex _l(mLock);
+
+    asset_path ap;
+
+    ap.path = debugPathName;
+    ap.rawFd = fd;
+    ap.type = kFileTypeRegular;
+    ap.assumeOwnership = assume_ownership;
+
+    ALOGV("In %p Asset fd %d name: %s", this, fd, ap.path.string());
+
+    mAssetPaths.add(ap);
+
+    // new paths are always added at the end
+    if (cookie) {
+        *cookie = static_cast<int32_t>(mAssetPaths.size());
+    }
+
+    if (mResources != NULL) {
+        appendPathToResTable(ap, appAsLib);
+    }
+
+    return true;
+}
 
 bool AssetManager::createIdmap(const char* targetApkPath, const char* overlayApkPath,
         uint32_t targetCrc, uint32_t overlayCrc, uint32_t** outData, size_t* outSize)
@@ -505,7 +541,7 @@
     Asset* idmap = openIdmapLocked(ap);
     size_t nextEntryIdx = mResources->getTableCount();
     ALOGV("Looking for resource asset in '%s'\n", ap.path.string());
-    if (ap.type != kFileTypeDirectory) {
+    if (ap.type != kFileTypeDirectory && ap.rawFd < 0) {
         if (nextEntryIdx == 0) {
             // The first item is typically the framework resources,
             // which we want to avoid parsing every time.
@@ -738,6 +774,8 @@
 {
     Asset* pAsset = NULL;
 
+    ALOGV("openNonAssetInPath: name=%s type=%d fd=%d", fileName, ap.type, ap.rawFd);
+
     /* look at the filesystem on disk */
     if (ap.type == kFileTypeDirectory) {
         String8 path(ap.path);
@@ -752,7 +790,7 @@
         }
 
         if (pAsset != NULL) {
-            //printf("FOUND NA '%s' on disk\n", fileName);
+            ALOGV("FOUND NA '%s' on disk", fileName);
             pAsset->setAssetSource(path);
         }
 
@@ -763,10 +801,10 @@
         /* check the appropriate Zip file */
         ZipFileRO* pZip = getZipFileLocked(ap);
         if (pZip != NULL) {
-            //printf("GOT zip, checking NA '%s'\n", (const char*) path);
+            ALOGV("GOT zip, checking NA '%s'", (const char*) path);
             ZipEntryRO entry = pZip->findEntryByName(path.string());
             if (entry != NULL) {
-                //printf("FOUND NA in Zip file for %s\n", appName ? appName : kAppCommon);
+                ALOGV("FOUND NA in Zip file for %s", (const char*) path);
                 pAsset = openAssetFromZipLocked(pZip, entry, mode, path);
                 pZip->releaseEntry(entry);
             }
@@ -817,7 +855,17 @@
 {
     ALOGV("getZipFileLocked() in %p\n", this);
 
-    return mZipSet.getZip(ap.path);
+    if (ap.zip != NULL) {
+        return ap.zip->getZip();
+    }
+
+    if (ap.rawFd < 0) {
+        ap.zip = mZipSet.getSharedZip(ap.path);
+    } else {
+        ap.zip = SharedZip::create(ap.rawFd, ap.path);
+
+    }
+    return ap.zip != NULL ? ap.zip->getZip() : NULL;
 }
 
 /*
@@ -1374,6 +1422,21 @@
     }
 }
 
+AssetManager::SharedZip::SharedZip(int fd, const String8& path)
+    : mPath(path), mZipFile(NULL), mModWhen(0),
+      mResourceTableAsset(NULL), mResourceTable(NULL)
+{
+    if (kIsDebug) {
+        ALOGI("Creating SharedZip %p fd=%d %s\n", this, fd, (const char*)mPath);
+    }
+    ALOGV("+++ opening zip fd=%d '%s'\n", fd, mPath.string());
+    mZipFile = ZipFileRO::openFd(fd, mPath.string());
+    if (mZipFile == NULL) {
+        ::close(fd);
+        ALOGD("failed to open Zip archive fd=%d '%s'\n", fd, mPath.string());
+    }
+}
+
 sp<AssetManager::SharedZip> AssetManager::SharedZip::get(const String8& path,
         bool createIfNotPresent)
 {
@@ -1389,7 +1452,11 @@
     zip = new SharedZip(path, modWhen);
     gOpen.add(path, zip);
     return zip;
+}
 
+sp<AssetManager::SharedZip> AssetManager::SharedZip::create(int fd, const String8& path)
+{
+    return new SharedZip(fd, path);
 }
 
 ZipFileRO* AssetManager::SharedZip::getZip()
@@ -1500,19 +1567,23 @@
     mZipFile.editItemAt(idx) = NULL;
 }
 
-
 /*
  * Retrieve the appropriate Zip file from the set.
  */
 ZipFileRO* AssetManager::ZipSet::getZip(const String8& path)
 {
+    return getSharedZip(path)->getZip();
+}
+
+const sp<AssetManager::SharedZip> AssetManager::ZipSet::getSharedZip(const String8& path)
+{
     int idx = getIndex(path);
     sp<SharedZip> zip = mZipFile[idx];
     if (zip == NULL) {
         zip = SharedZip::get(path);
         mZipFile.editItemAt(idx) = zip;
     }
-    return zip->getZip();
+    return zip;
 }
 
 Asset* AssetManager::ZipSet::getZipResourceTableAsset(const String8& path)
diff --git a/libs/androidfw/ZipFileRO.cpp b/libs/androidfw/ZipFileRO.cpp
index 49fe8a2..6e2ca60c 100644
--- a/libs/androidfw/ZipFileRO.cpp
+++ b/libs/androidfw/ZipFileRO.cpp
@@ -55,7 +55,9 @@
 
 ZipFileRO::~ZipFileRO() {
     CloseArchive(mHandle);
-    free(mFileName);
+    if (mFileName != NULL) {
+        free(mFileName);
+    }
 }
 
 /*
@@ -76,6 +78,20 @@
 }
 
 
+/* static */ ZipFileRO* ZipFileRO::openFd(int fd, const char* debugFileName,
+        bool assume_ownership)
+{
+    ZipArchiveHandle handle;
+    const int32_t error = OpenArchiveFd(fd, debugFileName, &handle, assume_ownership);
+    if (error) {
+        ALOGW("Error opening archive fd %d %s: %s", fd, debugFileName, ErrorCodeString(error));
+        CloseArchive(handle);
+        return NULL;
+    }
+
+    return new ZipFileRO(handle, strdup(debugFileName));
+}
+
 ZipEntryRO ZipFileRO::findEntryByName(const char* entryName) const
 {
     _ZipEntryRO* data = new _ZipEntryRO;
@@ -139,7 +155,8 @@
                                    prefix ? &pe : NULL,
                                    suffix ? &se : NULL);
     if (error) {
-        ALOGW("Could not start iteration over %s: %s", mFileName, ErrorCodeString(error));
+        ALOGW("Could not start iteration over %s: %s", mFileName != NULL ? mFileName : "<null>",
+                ErrorCodeString(error));
         delete ze;
         return false;
     }
@@ -154,7 +171,8 @@
     int32_t error = Next(ze->cookie, &(ze->entry), &(ze->name));
     if (error) {
         if (error != -1) {
-            ALOGW("Error iteration over %s: %s", mFileName, ErrorCodeString(error));
+            ALOGW("Error iteration over %s: %s", mFileName != NULL ? mFileName : "<null>",
+                    ErrorCodeString(error));
         }
         return NULL;
     }
diff --git a/libs/androidfw/include/androidfw/AssetManager.h b/libs/androidfw/include/androidfw/AssetManager.h
index 0441b9d..4254614 100644
--- a/libs/androidfw/include/androidfw/AssetManager.h
+++ b/libs/androidfw/include/androidfw/AssetManager.h
@@ -92,6 +92,20 @@
     bool addOverlayPath(const String8& path, int32_t* cookie);
 
     /*
+     * Add a new source for assets from an already open file descriptor.
+     * This does not give full AssetManager functionality for these assets,
+     * since the origin of the file is not known for purposes of sharing,
+     * overlay resolution, and other features.  However it does allow you
+     * to do simple access to the contents of the given fd as an apk file.
+     *
+     * Returns "true" on success, "false" on failure.  If 'cookie' is non-NULL,
+     * then on success, *cookie is set to the value corresponding to the
+     * newly-added asset source.
+     */
+    bool addAssetFd(int fd, const String8& debugPathName, int32_t* cookie,
+        bool appAsLib=false, bool assume_ownership=true);
+
+    /*
      * Convenience for adding the standard system assets.  Uses the
      * ANDROID_ROOT environment variable to find them.
      */
@@ -195,15 +209,20 @@
         uint32_t targetCrc, uint32_t overlayCrc, uint32_t** outData, size_t* outSize);
 
 private:
+    class SharedZip;
+
     struct asset_path
     {
-        asset_path() : path(""), type(kFileTypeRegular), idmap(""),
-                       isSystemOverlay(false), isSystemAsset(false) {}
+        asset_path() : path(""), rawFd(-1), type(kFileTypeRegular), idmap(""),
+                       isSystemOverlay(false), isSystemAsset(false), assumeOwnership(false) {}
         String8 path;
+        int rawFd;
         FileType type;
         String8 idmap;
         bool isSystemOverlay;
         bool isSystemAsset;
+        bool assumeOwnership;
+        mutable sp<SharedZip> zip;
     };
 
     Asset* openNonAssetInPathLocked(const char* fileName, AccessMode mode,
@@ -238,6 +257,7 @@
     class SharedZip : public RefBase {
     public:
         static sp<SharedZip> get(const String8& path, bool createIfNotPresent = true);
+        static sp<SharedZip> create(int fd, const String8& path);
 
         ZipFileRO* getZip();
 
@@ -257,6 +277,7 @@
 
     private:
         SharedZip(const String8& path, time_t modWhen);
+        SharedZip(int fd, const String8& path);
         SharedZip(); // <-- not implemented
 
         String8 mPath;
@@ -290,6 +311,8 @@
          */
         ZipFileRO* getZip(const String8& path);
 
+        const sp<SharedZip> getSharedZip(const String8& path);
+
         Asset* getZipResourceTableAsset(const String8& path);
         Asset* setZipResourceTableAsset(const String8& path, Asset* asset);
 
diff --git a/libs/androidfw/include/androidfw/ZipFileRO.h b/libs/androidfw/include/androidfw/ZipFileRO.h
index 7680342..03154d0 100644
--- a/libs/androidfw/include/androidfw/ZipFileRO.h
+++ b/libs/androidfw/include/androidfw/ZipFileRO.h
@@ -80,6 +80,12 @@
     static ZipFileRO* open(const char* zipFileName);
 
     /*
+     * Open an archive from an already open file descriptor.
+     */
+    static ZipFileRO* openFd(int fd, const char* debugFileName,
+        bool assume_ownership = true);
+
+    /*
      * Find an entry, by name.  Returns the entry identifier, or NULL if
      * not found.
      */
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index f942265..d6bd2b31 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -373,7 +373,7 @@
             if (mProfileFile != null || mAgent != null) {
                 ParcelFileDescriptor fd = null;
                 if (mProfileFile != null) {
-                    fd = openOutputFileForSystem(mProfileFile);
+                    fd = openFileForSystem(mProfileFile, "w");
                     if (fd == null) {
                         return 1;
                     }
@@ -668,7 +668,7 @@
 
         File file = new File(filename);
         file.delete();
-        ParcelFileDescriptor fd = openOutputFileForSystem(filename);
+        ParcelFileDescriptor fd = openFileForSystem(filename, "w");
         if (fd == null) {
             return -1;
         }
@@ -756,7 +756,7 @@
 
         if (start) {
             profileFile = getNextArgRequired();
-            fd = openOutputFileForSystem(profileFile);
+            fd = openFileForSystem(profileFile, "w");
             if (fd == null) {
                 return -1;
             }
@@ -820,7 +820,7 @@
 
         File file = new File(heapFile);
         file.delete();
-        ParcelFileDescriptor fd = openOutputFileForSystem(heapFile);
+        ParcelFileDescriptor fd = openFileForSystem(heapFile, "w");
         if (fd == null) {
             return -1;
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index a2099e6..807eb1a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -54,6 +54,7 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.IUserManager;
+import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -78,7 +79,6 @@
 import libcore.io.IoUtils;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -102,8 +102,6 @@
 class PackageManagerShellCommand extends ShellCommand {
     /** Path for streaming APK content */
     private static final String STDIN_PATH = "-";
-    /** Whether or not APK content must be streamed from stdin */
-    private static final boolean FORCE_STREAM_INSTALL = true;
 
     final IPackageManager mInterface;
     final private WeakHashMap<String, Resources> mResourceCache =
@@ -255,30 +253,27 @@
     }
 
     private void setParamsSize(InstallParams params, String inPath) {
-        // If we're forced to stream the package, the params size
-        // must be set via command-line argument. There's nothing
-        // to do here.
-        if (FORCE_STREAM_INSTALL) {
-            return;
-        }
-        final PrintWriter pw = getOutPrintWriter();
         if (params.sessionParams.sizeBytes == -1 && !STDIN_PATH.equals(inPath)) {
-            File file = new File(inPath);
-            if (file.isFile()) {
+            final ParcelFileDescriptor fd = openFileForSystem(inPath, "r");
+            if (fd == null) {
+                getErrPrintWriter().println("Error: Can't open file: " + inPath);
+                throw new IllegalArgumentException("Error: Can't open file: " + inPath);
+            }
+            try {
+                ApkLite baseApk = PackageParser.parseApkLite(fd.getFileDescriptor(), inPath, 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) {
+                getErrPrintWriter().println("Error: Failed to parse APK file: " + inPath);
+                throw new IllegalArgumentException(
+                        "Error: Failed to parse APK file: " + inPath, e);
+            } finally {
                 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) {
-                    pw.println("Error: Failed to parse APK file: " + file);
-                    throw new IllegalArgumentException(
-                            "Error: Failed to parse APK file: " + file, e);
+                    fd.close();
+                } catch (IOException e) {
                 }
-            } else {
-                pw.println("Error: Can't open non-file: " + inPath);
-                throw new IllegalArgumentException("Error: Can't open non-file: " + inPath);
             }
         }
     }
@@ -1914,6 +1909,12 @@
                         throw new IllegalArgumentException("Missing inherit package name");
                     }
                     break;
+                case "--pkg":
+                    sessionParams.appPackageName = getNextArg();
+                    if (sessionParams.appPackageName == null) {
+                        throw new IllegalArgumentException("Missing package name");
+                    }
+                    break;
                 case "-S":
                     final long sizeBytes = Long.parseLong(getNextArg());
                     if (sizeBytes <= 0) {
@@ -1925,6 +1926,7 @@
                     sessionParams.abiOverride = checkAbiArgument(getNextArg());
                     break;
                 case "--ephemeral":
+                case "--instant":
                 case "--instantapp":
                     sessionParams.setInstallAsInstantApp(true /*isInstantApp*/);
                     break;
@@ -2092,20 +2094,24 @@
     private int doWriteSplit(int sessionId, String inPath, long sizeBytes, String splitName,
             boolean logSuccess) throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
-        if (FORCE_STREAM_INSTALL && inPath != null && !STDIN_PATH.equals(inPath)) {
-            pw.println("Error: APK content must be streamed");
-            return 1;
-        }
+        final ParcelFileDescriptor fd;
         if (STDIN_PATH.equals(inPath)) {
-            inPath = null;
+            fd = null;
         } else if (inPath != null) {
-            final File file = new File(inPath);
-            if (file.isFile()) {
-                sizeBytes = file.length();
+            fd = openFileForSystem(inPath, "r");
+            if (fd == null) {
+                return -1;
             }
+            sizeBytes = fd.getStatSize();
+            if (sizeBytes < 0) {
+                getErrPrintWriter().println("Unable to get size of: " + inPath);
+                return -1;
+            }
+        } else {
+            fd = null;
         }
         if (sizeBytes <= 0) {
-            pw.println("Error: must specify a APK size");
+            getErrPrintWriter().println("Error: must specify a APK size");
             return 1;
         }
 
@@ -2118,8 +2124,8 @@
             session = new PackageInstaller.Session(
                     mInterface.getPackageInstaller().openSession(sessionId));
 
-            if (inPath != null) {
-                in = new FileInputStream(inPath);
+            if (fd != null) {
+                in = new ParcelFileDescriptor.AutoCloseInputStream(fd);
             } else {
                 in = new SizedInputStream(getRawInputStream(), sizeBytes);
             }
@@ -2144,7 +2150,7 @@
             }
             return 0;
         } catch (IOException e) {
-            pw.println("Error: failed to write; " + e.getMessage());
+            getErrPrintWriter().println("Error: failed to write; " + e.getMessage());
             return 1;
         } finally {
             IoUtils.closeQuietly(out);
diff --git a/services/coverage/java/com/android/server/coverage/CoverageService.java b/services/coverage/java/com/android/server/coverage/CoverageService.java
index d600aa8..ed8d24a 100644
--- a/services/coverage/java/com/android/server/coverage/CoverageService.java
+++ b/services/coverage/java/com/android/server/coverage/CoverageService.java
@@ -112,7 +112,7 @@
             }
 
             // Try to open the destination file
-            ParcelFileDescriptor fd = openOutputFileForSystem(dest);
+            ParcelFileDescriptor fd = openFileForSystem(dest, "w");
             if (fd == null) {
                 return -1;
             }