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;
}