Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ca3872ce authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Fully implement "install" and "install-write" in PackageManagerShellCommand.

We can use the new mechanism to ask the calling shell to open
a file in order to implement the rest of these commands, allowing
you to give the path to an apk to install.  That API is thus
extended to allow you to open readable files, not just opening
file for writing.

Doing this however means we no longer can pass a file path to
AssetManager for the apk to parse, we only have an already open
fd for that.  Extending AssetManager to allow adding apks from
fds is not that hard, however, since the underlying zip library
already supports this.

This main thing this changes is in AssetManager.cpp where we
retrieve the open zip file for a particular apk that has been
added.  This used to look up the zip file by path every time
it was needed, but that won't work anymore now that we can have
things added by fd.  Instead, we keep track of each opened zip
in the AssetManager, so we can just directly retrieve it from
the asset_path representing the item that was added.  As a
side-effect, this means for normal paths we no longer need to
look up by name, but just have the opened zip file directly
accessible.  (This is probably good, but it does mean that we
no longer run the logic of seeing if the zip file's timestamp
has changed and re-opening it if it has.  We probably shouldn't
be relying on that for an active AssetManager anyway, and maybe
it is even good that we don't allow the zip file to change
under it?)

A follow-up change will finally remove the Pm.java implementation
and turn the pm "command" into a simple shell script that runs
cmd package.

Test: manual

Change-Id: Ie103e3bdaa5b706796cc329254f2638151a3924f
parent 362e983a
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -98,7 +98,8 @@ public class Am extends BaseCommand {
    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;
+2 −1
Original line number Diff line number Diff line
@@ -157,7 +157,8 @@ public final class Pm {
    }

    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 {
+23 −2
Original line number Diff line number Diff line
@@ -102,6 +102,7 @@ import org.xmlpull.v1.XmlPullParser;
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 class PackageParser {
     */
    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);
+30 −3
Original line number Diff line number Diff line
@@ -28,8 +28,7 @@ import android.util.Log;
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,6 +693,34 @@ public final class AssetManager implements AutoCloseable {

    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.
     *
+14 −9
Original line number Diff line number Diff line
@@ -35,8 +35,9 @@ public class ShellCallback implements Parcelable {
    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 @@ public class ShellCallback implements Parcelable {
    }

    /**
     * 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 @@ public class ShellCallback implements Parcelable {
        return null;
    }

    public ParcelFileDescriptor onOpenOutputFile(String path, String seLinuxContext) {
    public ParcelFileDescriptor onOpenFile(String path, String seLinuxContext, String mode) {
        return null;
    }

Loading