diff options
author | Dianne Hackborn <hackbod@google.com> | 2017-10-30 14:19:32 -0700 |
---|---|---|
committer | Dianne Hackborn <hackbod@google.com> | 2017-10-31 10:54:31 -0700 |
commit | ca3872ce36c94090ae18519dc7fe0cf39d834c4a (patch) | |
tree | 26361b8a308121902da16e035851489e11af38c9 | |
parent | 362e983accb269b07a95ef563fe37ed325145035 (diff) |
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
-rw-r--r-- | cmds/am/src/com/android/commands/am/Am.java | 3 | ||||
-rw-r--r-- | cmds/pm/src/com/android/commands/pm/Pm.java | 3 | ||||
-rw-r--r-- | core/java/android/content/pm/PackageParser.java | 25 | ||||
-rw-r--r-- | core/java/android/content/res/AssetManager.java | 33 | ||||
-rw-r--r-- | core/java/android/os/ShellCallback.java | 23 | ||||
-rw-r--r-- | core/java/android/os/ShellCommand.java | 6 | ||||
-rw-r--r-- | core/java/com/android/internal/os/IShellCallback.aidl | 2 | ||||
-rw-r--r-- | core/jni/android_util_AssetManager.cpp | 31 | ||||
-rw-r--r-- | libs/androidfw/AssetManager.cpp | 87 | ||||
-rw-r--r-- | libs/androidfw/ZipFileRO.cpp | 24 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/AssetManager.h | 27 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/ZipFileRO.h | 6 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ActivityManagerShellCommand.java | 8 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/PackageManagerShellCommand.java | 78 | ||||
-rw-r--r-- | services/coverage/java/com/android/server/coverage/CoverageService.java | 2 |
15 files changed, 284 insertions, 74 deletions
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index ab075ee0e9f2..79e7fac11bb1 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 @@ 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; diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index 29433f3fc14f..9490880afe0f 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 @@ 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 { diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index b48829cfc87d..1c5cf15da062 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.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); diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index f0adcd6cfb3e..78665609bdd4 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -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,7 +693,35 @@ 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. * * 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 e7fe697f9c54..ad9fbfbfae40 100644 --- a/core/java/android/os/ShellCallback.java +++ b/core/java/android/os/ShellCallback.java @@ -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; } diff --git a/core/java/android/os/ShellCommand.java b/core/java/android/os/ShellCommand.java index 6223235e628f..d75219fdfd11 100644 --- a/core/java/android/os/ShellCommand.java +++ b/core/java/android/os/ShellCommand.java @@ -226,10 +226,10 @@ public abstract class ShellCommand { * 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 57d67890d840..57043424fc47 100644 --- a/core/java/com/android/internal/os/IShellCallback.aidl +++ b/core/java/com/android/internal/os/IShellCallback.aidl @@ -20,5 +20,5 @@ import android.os.ParcelFileDescriptor; /** @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 b137da3ef792..c6828c4f60de 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -568,6 +568,35 @@ static jint android_content_AssetManager_addOverlayPath(JNIEnv* env, jobject cla 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 @@ static const JNINativeMethod gAssetManagerMethods[] = { (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 5603508eaf09..3c8736ea0c4c 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -150,6 +150,14 @@ AssetManager::~AssetManager() { 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 @@ bool AssetManager::addOverlayPath(const String8& packagePath, int32_t* cookie) } 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 @@ bool AssetManager::appendPathToResTable(const asset_path& ap, bool appAsLib) con 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* AssetManager::openNonAssetInPathLocked(const char* fileName, AccessMode m { 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 @@ Asset* AssetManager::openNonAssetInPathLocked(const char* fileName, AccessMode m } 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 @@ Asset* AssetManager::openNonAssetInPathLocked(const char* fileName, AccessMode m /* 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 @@ ZipFileRO* AssetManager::getZipFileLocked(const asset_path& ap) { 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(const String8& path, time_t modWhen) } } +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 @@ sp<AssetManager::SharedZip> AssetManager::SharedZip::get(const String8& path, 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 @@ void AssetManager::ZipSet::closeZip(int idx) 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 49fe8a261178..6e2ca60cc3d3 100644 --- a/libs/androidfw/ZipFileRO.cpp +++ b/libs/androidfw/ZipFileRO.cpp @@ -55,7 +55,9 @@ private: ZipFileRO::~ZipFileRO() { CloseArchive(mHandle); - free(mFileName); + if (mFileName != NULL) { + free(mFileName); + } } /* @@ -76,6 +78,20 @@ ZipFileRO::~ZipFileRO() { } +/* 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 @@ bool ZipFileRO::startIteration(void** cookie, const char* prefix, const char* su 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 @@ ZipEntryRO ZipFileRO::nextEntry(void* cookie) 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 0441b9d789e2..4254614c8448 100644 --- a/libs/androidfw/include/androidfw/AssetManager.h +++ b/libs/androidfw/include/androidfw/AssetManager.h @@ -92,6 +92,20 @@ public: 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 @@ public: 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 @@ private: 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: private: SharedZip(const String8& path, time_t modWhen); + SharedZip(int fd, const String8& path); SharedZip(); // <-- not implemented String8 mPath; @@ -290,6 +311,8 @@ private: */ 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 768034287afa..03154d04def1 100644 --- a/libs/androidfw/include/androidfw/ZipFileRO.h +++ b/libs/androidfw/include/androidfw/ZipFileRO.h @@ -80,6 +80,12 @@ public: 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 f9422656c7db..d6bd2b317a97 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 @@ final class ActivityManagerShellCommand extends ShellCommand { 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 @@ final class ActivityManagerShellCommand extends ShellCommand { 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 @@ final class ActivityManagerShellCommand extends ShellCommand { if (start) { profileFile = getNextArgRequired(); - fd = openOutputFileForSystem(profileFile); + fd = openFileForSystem(profileFile, "w"); if (fd == null) { return -1; } @@ -820,7 +820,7 @@ final class ActivityManagerShellCommand extends ShellCommand { 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 a2099e6080e5..807eb1a8aac4 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.Build; 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 dalvik.system.DexFile; 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 @@ import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATIO 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 @@ class PackageManagerShellCommand extends ShellCommand { } 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 @@ class PackageManagerShellCommand extends ShellCommand { 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 @@ class PackageManagerShellCommand extends ShellCommand { sessionParams.abiOverride = checkAbiArgument(getNextArg()); break; case "--ephemeral": + case "--instant": case "--instantapp": sessionParams.setInstallAsInstantApp(true /*isInstantApp*/); break; @@ -2092,20 +2094,24 @@ class PackageManagerShellCommand extends ShellCommand { 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 @@ class PackageManagerShellCommand extends ShellCommand { 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 @@ class PackageManagerShellCommand extends ShellCommand { } 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 d600aa8c4276..ed8d24aa3b8f 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 @@ public class CoverageService extends Binder { } // Try to open the destination file - ParcelFileDescriptor fd = openOutputFileForSystem(dest); + ParcelFileDescriptor fd = openFileForSystem(dest, "w"); if (fd == null) { return -1; } |