summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java267
-rw-r--r--core/java/android/app/ApplicationPackageManager.java4
-rw-r--r--core/java/android/content/pm/IPackageInstaller.aidl8
-rw-r--r--core/java/android/content/pm/PackageInstaller.java18
-rw-r--r--core/java/android/content/pm/PackageInstallerParams.java24
-rw-r--r--core/java/android/content/pm/PackageParser.java11
-rw-r--r--core/java/android/content/pm/Signature.java3
-rw-r--r--core/java/android/os/FileBridge.java29
-rw-r--r--core/java/com/android/internal/util/SizedInputStream.java66
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java93
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java44
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java189
12 files changed, 522 insertions, 234 deletions
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index a435fba..92e9290 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -19,15 +19,18 @@ package com.android.commands.pm;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
+import android.app.PackageInstallObserver;
import android.content.ComponentName;
import android.content.pm.ApplicationInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver;
-import android.content.pm.IPackageInstallObserver2;
+import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageManager;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageInstallerParams;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
@@ -46,12 +49,21 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
+import android.util.Log;
import com.android.internal.content.PackageHelper;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.SizedInputStream;
+
+import libcore.io.IoUtils;
+import libcore.io.Streams;
import java.io.File;
import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
@@ -61,7 +73,10 @@ import java.util.List;
import java.util.WeakHashMap;
public final class Pm {
+ private static final String TAG = "Pm";
+
IPackageManager mPm;
+ IPackageInstaller mInstaller;
IUserManager mUm;
private WeakHashMap<String, Resources> mResourceCache
@@ -75,10 +90,18 @@ public final class Pm {
"Error: Could not access the Package Manager. Is the system running?";
public static void main(String[] args) {
- new Pm().run(args);
+ try {
+ new Pm().run(args);
+ } catch (Exception e) {
+ Log.e(TAG, "Error", e);
+ System.err.println("Error: " + e);
+ if (e instanceof RemoteException) {
+ System.err.println(PM_NOT_RUNNING_ERR);
+ }
+ }
}
- public void run(String[] args) {
+ public void run(String[] args) throws IOException, RemoteException {
boolean validCommand = false;
if (args.length < 1) {
showUsage();
@@ -91,6 +114,7 @@ public final class Pm {
System.err.println(PM_NOT_RUNNING_ERR);
return;
}
+ mInstaller = mPm.getPackageInstaller();
mArgs = args;
String op = args[0];
@@ -116,6 +140,31 @@ public final class Pm {
return;
}
+ if ("install-create".equals(op)) {
+ runInstallCreate();
+ return;
+ }
+
+ if ("install-write".equals(op)) {
+ runInstallWrite();
+ return;
+ }
+
+ if ("install-commit".equals(op)) {
+ runInstallCommit();
+ return;
+ }
+
+ if ("install-destroy".equals(op)) {
+ runInstallDestroy();
+ return;
+ }
+
+ if ("set-installer".equals(op)) {
+ runSetInstaller();
+ return;
+ }
+
if ("uninstall".equals(op)) {
runUninstall();
return;
@@ -697,7 +746,7 @@ public final class Pm {
ActivityManager.dumpPackageStateStatic(FileDescriptor.out, pkg);
}
- class PackageInstallObserver extends IPackageInstallObserver2.Stub {
+ class LocalPackageInstallObserver extends PackageInstallObserver {
boolean finished;
int result;
String extraPermission;
@@ -705,7 +754,7 @@ public final class Pm {
@Override
public void packageInstalled(String name, Bundle extras, int status) {
- synchronized( this) {
+ synchronized (this) {
finished = true;
result = status;
if (status == PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION) {
@@ -723,7 +772,7 @@ public final class Pm {
* Converts a failure code into a string by using reflection to find a matching constant
* in PackageManager.
*/
- private String installFailureToString(PackageInstallObserver obs) {
+ private String installFailureToString(LocalPackageInstallObserver obs) {
final int result = obs.result;
Field[] fields = PackageManager.class.getFields();
for (Field f: fields) {
@@ -908,12 +957,12 @@ public final class Pm {
verificationURI = null;
}
- PackageInstallObserver obs = new PackageInstallObserver();
+ LocalPackageInstallObserver obs = new LocalPackageInstallObserver();
try {
VerificationParams verificationParams = new VerificationParams(verificationURI,
originatingURI, referrerURI, VerificationParams.NO_UID, null);
- mPm.installPackage(apkFilePath, obs, installFlags, installerPackageName,
+ mPm.installPackage(apkFilePath, obs.getBinder(), installFlags, installerPackageName,
verificationParams, abi);
synchronized (obs) {
@@ -937,35 +986,149 @@ public final class Pm {
}
}
- /**
- * Convert a string containing hex-encoded bytes to a byte array.
- *
- * @param input String containing hex-encoded bytes
- * @return input as an array of bytes
- */
- private byte[] hexToBytes(String input) {
- if (input == null) {
- return null;
+ private void runInstallCreate() throws RemoteException {
+ String installerPackageName = null;
+
+ final PackageInstallerParams params = new PackageInstallerParams();
+ params.installFlags = PackageManager.INSTALL_ALL_USERS;
+ params.fullInstall = true;
+
+ String opt;
+ while ((opt = nextOption()) != null) {
+ if (opt.equals("-l")) {
+ params.installFlags |= PackageManager.INSTALL_FORWARD_LOCK;
+ } else if (opt.equals("-r")) {
+ params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
+ } else if (opt.equals("-i")) {
+ installerPackageName = nextArg();
+ if (installerPackageName == null) {
+ throw new IllegalArgumentException("Missing installer package");
+ }
+ } else if (opt.equals("-t")) {
+ params.installFlags |= PackageManager.INSTALL_ALLOW_TEST;
+ } else if (opt.equals("-s")) {
+ params.installFlags |= PackageManager.INSTALL_EXTERNAL;
+ } else if (opt.equals("-f")) {
+ params.installFlags |= PackageManager.INSTALL_INTERNAL;
+ } else if (opt.equals("-d")) {
+ params.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
+ } else if (opt.equals("-p")) {
+ params.fullInstall = false;
+ } else if (opt.equals("-S")) {
+ params.deltaSize = Long.parseLong(nextOptionData());
+ } else {
+ throw new IllegalArgumentException("Unknown option " + opt);
+ }
}
- final int inputLength = input.length();
- if ((inputLength % 2) != 0) {
- System.err.print("Invalid length; must be multiple of 2");
- return null;
+ final int sessionId = mInstaller.createSession(installerPackageName, params,
+ UserHandle.USER_OWNER);
+
+ // NOTE: adb depends on parsing this string
+ System.out.println("Success: created install session [" + sessionId + "]");
+ }
+
+ private void runInstallWrite() throws IOException, RemoteException {
+ long sizeBytes = -1;
+
+ String opt;
+ while ((opt = nextOption()) != null) {
+ if (opt.equals("-S")) {
+ sizeBytes = Long.parseLong(nextOptionData());
+ } else {
+ throw new IllegalArgumentException("Unknown option: " + opt);
+ }
}
- final int byteLength = inputLength / 2;
- final byte[] output = new byte[byteLength];
+ final int sessionId = Integer.parseInt(nextArg());
+ final String splitName = nextArg();
- int inputIndex = 0;
- int byteIndex = 0;
- while (inputIndex < inputLength) {
- output[byteIndex++] = (byte) Integer.parseInt(
- input.substring(inputIndex, inputIndex + 2), 16);
- inputIndex += 2;
+ String path = nextArg();
+ if ("-".equals(path)) {
+ path = null;
+ } else if (path != null) {
+ final File file = new File(path);
+ if (file.isFile()) {
+ sizeBytes = file.length();
+ }
}
- return output;
+ PackageInstaller.Session session = null;
+ InputStream in = null;
+ OutputStream out = null;
+ try {
+ session = new PackageInstaller.Session(mInstaller.openSession(sessionId));
+
+ if (path != null) {
+ in = new FileInputStream(path);
+ } else {
+ in = new SizedInputStream(System.in, sizeBytes);
+ }
+ out = session.openWrite(splitName, 0, sizeBytes);
+
+ final int n = Streams.copy(in, out);
+ out.flush();
+
+ System.out.println("Success: streamed " + n + " bytes");
+ } finally {
+ IoUtils.closeQuietly(out);
+ IoUtils.closeQuietly(in);
+ IoUtils.closeQuietly(session);
+ }
+ }
+
+ private void runInstallCommit() throws RemoteException {
+ final int sessionId = Integer.parseInt(nextArg());
+
+ PackageInstaller.Session session = null;
+ try {
+ session = new PackageInstaller.Session(mInstaller.openSession(sessionId));
+
+ final LocalPackageInstallObserver observer = new LocalPackageInstallObserver();
+ session.install(observer);
+
+ synchronized (observer) {
+ while (!observer.finished) {
+ try {
+ observer.wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ if (observer.result != PackageManager.INSTALL_SUCCEEDED) {
+ throw new IllegalStateException(
+ "Failure [" + installFailureToString(observer) + "]");
+ }
+ }
+ System.out.println("Success");
+ } finally {
+ IoUtils.closeQuietly(session);
+ }
+ }
+
+ private void runInstallDestroy() throws RemoteException {
+ final int sessionId = Integer.parseInt(nextArg());
+
+ PackageInstaller.Session session = null;
+ try {
+ session = new PackageInstaller.Session(mInstaller.openSession(sessionId));
+ session.destroy();
+ System.out.println("Success");
+ } finally {
+ IoUtils.closeQuietly(session);
+ }
+ }
+
+ private void runSetInstaller() throws RemoteException {
+ final String targetPackage = nextArg();
+ final String installerPackageName = nextArg();
+
+ if (targetPackage == null || installerPackageName == null) {
+ throw new IllegalArgumentException(
+ "must provide both target and installer package names");
+ }
+
+ mPm.setInstallerPackageName(targetPackage, installerPackageName);
+ System.out.println("Success");
}
public void runCreateUser() {
@@ -1146,10 +1309,10 @@ public final class Pm {
}
}
- private boolean deletePackage(String pkg, int unInstallFlags, int userId) {
+ private boolean deletePackage(String packageName, int flags, int userId) {
PackageDeleteObserver obs = new PackageDeleteObserver();
try {
- mPm.deletePackageAsUser(pkg, obs, userId, unInstallFlags);
+ mInstaller.uninstall(packageName, flags, obs, userId);
synchronized (obs) {
while (!obs.finished) {
@@ -1548,10 +1711,13 @@ public final class Pm {
System.err.println(" pm list users");
System.err.println(" pm path PACKAGE");
System.err.println(" pm dump PACKAGE");
- System.err.println(" pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f]");
- System.err.println(" [--algo <algorithm name> --key <key-in-hex> --iv <IV-in-hex>]");
- System.err.println(" [--originating-uri <URI>] [--referrer <URI>] PATH");
+ System.err.println(" pm install [-lrtsfd] [-i PACKAGE] [PATH]");
+ System.err.println(" pm install-create [-lrtsfdp] [-i PACKAGE] [-S BYTES]");
+ System.err.println(" pm install-write [-S BYTES] SESSION_ID SPLIT_NAME [PATH]");
+ System.err.println(" pm install-commit SESSION_ID");
+ System.err.println(" pm install-destroy SESSION_ID");
System.err.println(" pm uninstall [-k] [--user USER_ID] PACKAGE");
+ System.err.println(" pm set-installer PACKAGE INSTALLER");
System.err.println(" pm clear [--user USER_ID] PACKAGE");
System.err.println(" pm enable [--user USER_ID] PACKAGE_OR_COMPONENT");
System.err.println(" pm disable [--user USER_ID] PACKAGE_OR_COMPONENT");
@@ -1600,16 +1766,28 @@ public final class Pm {
System.err.println("");
System.err.println("pm path: print the path to the .apk of the given PACKAGE.");
System.err.println("");
- System.err.println("pm dump: print system state associated w ith the given PACKAGE.");
+ System.err.println("pm dump: print system state associated with the given PACKAGE.");
+ System.err.println("");
+ System.err.println("pm install: install a single legacy package");
+ System.err.println("pm install-create: create an install session");
+ System.err.println(" -l: forward lock application");
+ System.err.println(" -r: replace existing application");
+ System.err.println(" -t: allow test packages");
+ System.err.println(" -i: specify the installer package name");
+ System.err.println(" -s: install application on sdcard");
+ System.err.println(" -f: install application on internal flash");
+ System.err.println(" -d: allow version code downgrade");
+ System.err.println(" -p: partial application install");
+ System.err.println(" -S: size in bytes of entire session");
+ System.err.println("");
+ System.err.println("pm install-write: write a package into existing session; path may");
+ System.err.println(" be '-' to read from stdin");
+ System.err.println(" -S: size in bytes of package, required for stdin");
System.err.println("");
- System.err.println("pm install: installs a package to the system. Options:");
- System.err.println(" -l: install the package with FORWARD_LOCK.");
- System.err.println(" -r: reinstall an exisiting app, keeping its data.");
- System.err.println(" -t: allow test .apks to be installed.");
- System.err.println(" -i: specify the installer package name.");
- System.err.println(" -s: install package on sdcard.");
- System.err.println(" -f: install package on internal flash.");
- System.err.println(" -d: allow version code downgrade.");
+ System.err.println("pm install-commit: perform install of fully staged session");
+ System.err.println("pm install-destroy: destroy session");
+ System.err.println("");
+ System.err.println("pm set-installer: set installer package name");
System.err.println("");
System.err.println("pm uninstall: removes a package from the system. Options:");
System.err.println(" -k: keep the data and cache directories around after package removal.");
@@ -1643,5 +1821,6 @@ public final class Pm {
System.err.println("");
System.err.println("pm remove-user: remove the user with the given USER_IDENTIFIER,");
System.err.println(" deleting all data associated with that user");
+ System.err.println("");
}
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 97f1e50..2935b8e 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1463,8 +1463,8 @@ final class ApplicationPackageManager extends PackageManager {
@Override
public PackageInstaller getPackageInstaller() {
try {
- return new PackageInstaller(this, mPM.getPackageInstaller(), mContext.getUserId(),
- mContext.getPackageName());
+ return new PackageInstaller(this, mPM.getPackageInstaller(), mContext.getPackageName(),
+ mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl
index 68c019b..4d6ee64 100644
--- a/core/java/android/content/pm/IPackageInstaller.aidl
+++ b/core/java/android/content/pm/IPackageInstaller.aidl
@@ -23,11 +23,11 @@ import android.os.ParcelFileDescriptor;
/** {@hide} */
interface IPackageInstaller {
- int createSession(int userId, String installerPackageName, in PackageInstallerParams params);
+ int createSession(String installerPackageName, in PackageInstallerParams params, int userId);
IPackageInstallerSession openSession(int sessionId);
- int[] getSessions(int userId, String installerPackageName);
+ int[] getSessions(String installerPackageName, int userId);
- void uninstall(int userId, String basePackageName, in IPackageDeleteObserver observer);
- void uninstallSplit(int userId, String basePackageName, String splitName, in IPackageDeleteObserver observer);
+ void uninstall(String basePackageName, int flags, in IPackageDeleteObserver observer, int userId);
+ void uninstallSplit(String basePackageName, String splitName, int flags, in IPackageDeleteObserver observer, int userId);
}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 4672015..a60a2fe 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -23,6 +23,7 @@ import android.os.FileBridge;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
+import java.io.Closeable;
import java.io.OutputStream;
/** {@hide} */
@@ -33,12 +34,12 @@ public class PackageInstaller {
private final String mInstallerPackageName;
/** {@hide} */
- public PackageInstaller(PackageManager pm, IPackageInstaller installer, int userId,
- String installerPackageName) {
+ public PackageInstaller(PackageManager pm, IPackageInstaller installer,
+ String installerPackageName, int userId) {
mPm = pm;
mInstaller = installer;
- mUserId = userId;
mInstallerPackageName = installerPackageName;
+ mUserId = userId;
}
public boolean isPackageAvailable(String basePackageName) {
@@ -63,7 +64,7 @@ public class PackageInstaller {
public int createSession(PackageInstallerParams params) {
try {
- return mInstaller.createSession(mUserId, mInstallerPackageName, params);
+ return mInstaller.createSession(mInstallerPackageName, params, mUserId);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -79,7 +80,7 @@ public class PackageInstaller {
public int[] getSessions() {
try {
- return mInstaller.getSessions(mUserId, mInstallerPackageName);
+ return mInstaller.getSessions(mInstallerPackageName, mUserId);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -87,7 +88,7 @@ public class PackageInstaller {
public void uninstall(String basePackageName, PackageUninstallObserver observer) {
try {
- mInstaller.uninstall(mUserId, basePackageName, observer.getBinder());
+ mInstaller.uninstall(basePackageName, 0, observer.getBinder(), mUserId);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -96,7 +97,7 @@ public class PackageInstaller {
public void uninstall(String basePackageName, String splitName,
PackageUninstallObserver observer) {
try {
- mInstaller.uninstallSplit(mUserId, basePackageName, splitName, observer.getBinder());
+ mInstaller.uninstallSplit(basePackageName, splitName, 0, observer.getBinder(), mUserId);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -114,7 +115,7 @@ public class PackageInstaller {
* installation (for example, the same split name), the package in this
* session will replace the existing package.
*/
- public class Session {
+ public static class Session implements Closeable {
private IPackageInstallerSession mSession;
/** {@hide} */
@@ -154,6 +155,7 @@ public class PackageInstaller {
}
}
+ @Override
public void close() {
// No resources to release at the moment
}
diff --git a/core/java/android/content/pm/PackageInstallerParams.java b/core/java/android/content/pm/PackageInstallerParams.java
index 67cf276..527edee 100644
--- a/core/java/android/content/pm/PackageInstallerParams.java
+++ b/core/java/android/content/pm/PackageInstallerParams.java
@@ -41,6 +41,8 @@ public class PackageInstallerParams implements Parcelable {
/** {@hide} */
public long deltaSize = -1;
/** {@hide} */
+ public String basePackageName;
+ /** {@hide} */
public Bitmap icon;
/** {@hide} */
public String title;
@@ -48,23 +50,27 @@ public class PackageInstallerParams implements Parcelable {
public Uri originatingUri;
/** {@hide} */
public Uri referrerUri;
+ /** {@hide} */
+ public String abiOverride;
public PackageInstallerParams() {
}
/** {@hide} */
public PackageInstallerParams(Parcel source) {
- this.fullInstall = source.readInt() != 0;
- this.installFlags = source.readInt();
- this.installLocation = source.readInt();
- this.signatures = (Signature[]) source.readParcelableArray(null);
+ fullInstall = source.readInt() != 0;
+ installFlags = source.readInt();
+ installLocation = source.readInt();
+ signatures = (Signature[]) source.readParcelableArray(null);
deltaSize = source.readLong();
+ basePackageName = source.readString();
if (source.readInt() != 0) {
icon = Bitmap.CREATOR.createFromParcel(source);
}
title = source.readString();
- originatingUri = Uri.CREATOR.createFromParcel(source);
- referrerUri = Uri.CREATOR.createFromParcel(source);
+ originatingUri = source.readParcelable(null);
+ referrerUri = source.readParcelable(null);
+ abiOverride = source.readString();
}
public void setFullInstall(boolean fullInstall) {
@@ -87,6 +93,10 @@ public class PackageInstallerParams implements Parcelable {
this.deltaSize = deltaSize;
}
+ public void setBasePackageName(String basePackageName) {
+ this.basePackageName = basePackageName;
+ }
+
public void setIcon(Bitmap icon) {
this.icon = icon;
}
@@ -115,6 +125,7 @@ public class PackageInstallerParams implements Parcelable {
dest.writeInt(installLocation);
dest.writeParcelableArray(signatures, flags);
dest.writeLong(deltaSize);
+ dest.writeString(basePackageName);
if (icon != null) {
dest.writeInt(1);
icon.writeToParcel(dest, flags);
@@ -124,6 +135,7 @@ public class PackageInstallerParams implements Parcelable {
dest.writeString(title);
dest.writeParcelable(originatingUri, flags);
dest.writeParcelable(referrerUri, flags);
+ dest.writeString(abiOverride);
}
public static final Parcelable.Creator<PackageInstallerParams>
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 3b118c0..ab0bf25 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -71,7 +71,6 @@ import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
@@ -923,19 +922,17 @@ public class PackageParser {
"Package " + apkPath + " has no certificates at entry "
+ entry.getName());
}
+ final Signature[] entrySignatures = convertToSignatures(entryCerts);
if (pkg.mCertificates == null) {
pkg.mCertificates = entryCerts;
- pkg.mSignatures = convertToSignatures(entryCerts);
+ pkg.mSignatures = entrySignatures;
pkg.mSigningKeys = new ArraySet<PublicKey>();
for (int i=0; i < entryCerts.length; i++) {
pkg.mSigningKeys.add(entryCerts[i][0].getPublicKey());
}
} else {
- final boolean certsMatch = (pkg.mCertificates.length == entryCerts.length)
- && ArrayUtils.containsAll(pkg.mCertificates, entryCerts)
- && ArrayUtils.containsAll(entryCerts, pkg.mCertificates);
- if (!certsMatch) {
+ if (!Signature.areExactMatch(pkg.mSignatures, entrySignatures)) {
throw new PackageParserException(
INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, "Package " + apkPath
+ " has mismatched certificates at entry "
@@ -1097,7 +1094,7 @@ public class PackageParser {
if (splitName.length() == 0) {
splitName = null;
} else {
- final String error = validateName(splitName, true);
+ final String error = validateName(splitName, false);
if (error != null) {
throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
"Invalid manifest split: " + error);
diff --git a/core/java/android/content/pm/Signature.java b/core/java/android/content/pm/Signature.java
index 96aa083..7edf4b9 100644
--- a/core/java/android/content/pm/Signature.java
+++ b/core/java/android/content/pm/Signature.java
@@ -249,6 +249,7 @@ public class Signature implements Parcelable {
* @hide
*/
public static boolean areExactMatch(Signature[] a, Signature[] b) {
- return ArrayUtils.containsAll(a, b) && ArrayUtils.containsAll(b, a);
+ return (a.length == b.length) && ArrayUtils.containsAll(a, b)
+ && ArrayUtils.containsAll(b, a);
}
}
diff --git a/core/java/android/os/FileBridge.java b/core/java/android/os/FileBridge.java
index 7f8bc9f..691afdd 100644
--- a/core/java/android/os/FileBridge.java
+++ b/core/java/android/os/FileBridge.java
@@ -54,6 +54,8 @@ public class FileBridge extends Thread {
private static final int CMD_WRITE = 1;
/** CMD_FSYNC */
private static final int CMD_FSYNC = 2;
+ /** CMD_CLOSE */
+ private static final int CMD_CLOSE = 3;
private FileDescriptor mTarget;
@@ -102,12 +104,17 @@ public class FileBridge extends Thread {
// Sync and echo back to confirm
Os.fsync(mTarget);
IoBridge.write(mServer, temp, 0, MSG_LENGTH);
+
+ } else if (cmd == CMD_CLOSE) {
+ // Close and echo back to confirm
+ Os.fsync(mTarget);
+ Os.close(mTarget);
+ mClosed = true;
+ IoBridge.write(mServer, temp, 0, MSG_LENGTH);
+ break;
}
}
- // Client was closed; one last fsync
- Os.fsync(mTarget);
-
} catch (ErrnoException e) {
Log.e(TAG, "Failed during bridge: ", e);
} catch (IOException e) {
@@ -130,22 +137,30 @@ public class FileBridge extends Thread {
@Override
public void close() throws IOException {
- IoBridge.closeAndSignalBlockedThreads(mClient);
+ try {
+ writeCommandAndBlock(CMD_CLOSE, "close()");
+ } finally {
+ IoBridge.closeAndSignalBlockedThreads(mClient);
+ }
}
@Override
public void flush() throws IOException {
- Memory.pokeInt(mTemp, 0, CMD_FSYNC, ByteOrder.BIG_ENDIAN);
+ writeCommandAndBlock(CMD_FSYNC, "fsync()");
+ }
+
+ private void writeCommandAndBlock(int cmd, String cmdString) throws IOException {
+ Memory.pokeInt(mTemp, 0, cmd, ByteOrder.BIG_ENDIAN);
IoBridge.write(mClient, mTemp, 0, MSG_LENGTH);
// Wait for server to ack
if (IoBridge.read(mClient, mTemp, 0, MSG_LENGTH) == MSG_LENGTH) {
- if (Memory.peekInt(mTemp, 0, ByteOrder.BIG_ENDIAN) == CMD_FSYNC) {
+ if (Memory.peekInt(mTemp, 0, ByteOrder.BIG_ENDIAN) == cmd) {
return;
}
}
- throw new SyncFailedException("Failed to fsync() across bridge");
+ throw new IOException("Failed to execute " + cmdString + " across bridge");
}
@Override
diff --git a/core/java/com/android/internal/util/SizedInputStream.java b/core/java/com/android/internal/util/SizedInputStream.java
new file mode 100644
index 0000000..00a729d
--- /dev/null
+++ b/core/java/com/android/internal/util/SizedInputStream.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import libcore.io.Streams;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Reads exact number of bytes from wrapped stream, returning EOF once those
+ * bytes have been read.
+ */
+public class SizedInputStream extends InputStream {
+ private final InputStream mWrapped;
+ private long mLength;
+
+ public SizedInputStream(InputStream wrapped, long length) {
+ mWrapped = wrapped;
+ mLength = length;
+ }
+
+ @Override
+ public void close() throws IOException {
+ super.close();
+ mWrapped.close();
+ }
+
+ @Override
+ public int read() throws IOException {
+ return Streams.readSingleByte(this);
+ }
+
+ @Override
+ public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
+ if (mLength <= 0) {
+ return -1;
+ } else if (byteCount > mLength) {
+ byteCount = (int) mLength;
+ }
+
+ final int n = mWrapped.read(buffer, byteOffset, byteCount);
+ if (n == -1) {
+ if (mLength > 0) {
+ throw new IOException("Unexpected EOF; expected " + mLength + " more bytes");
+ }
+ } else {
+ mLength -= n;
+ }
+ return n;
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 5fdfce4..682a38d 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -30,8 +30,11 @@ import android.os.Binder;
import android.os.FileUtils;
import android.os.HandlerThread;
import android.os.Process;
+import android.os.SELinux;
import android.os.UserHandle;
import android.os.UserManager;
+import android.system.ErrnoException;
+import android.system.Os;
import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
@@ -42,6 +45,8 @@ import com.android.server.IoThread;
import com.google.android.collect.Sets;
import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
public class PackageInstallerService extends IPackageInstaller.Stub {
private static final String TAG = "PackageInstaller";
@@ -54,8 +59,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
private final AppOpsManager mAppOps;
private final File mStagingDir;
+ private final HandlerThread mInstallThread;
- private final HandlerThread mInstallThread = new HandlerThread(TAG);
private final Callback mCallback = new Callback();
@GuardedBy("mSessions")
@@ -63,27 +68,50 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
@GuardedBy("mSessions")
private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();
+ private static final FilenameFilter sStageFilter = new FilenameFilter() {
+ @Override
+ public boolean accept(File dir, String name) {
+ return name.startsWith("vmdl") && name.endsWith(".tmp");
+ }
+ };
+
public PackageInstallerService(Context context, PackageManagerService pm, File stagingDir) {
mContext = context;
mPm = pm;
mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
mStagingDir = stagingDir;
- mStagingDir.mkdirs();
+
+ mInstallThread = new HandlerThread(TAG);
+ mInstallThread.start();
synchronized (mSessions) {
readSessionsLocked();
// Clean up orphaned staging directories
- final ArraySet<String> dirs = Sets.newArraySet(mStagingDir.list());
+ final ArraySet<File> stages = Sets.newArraySet(mStagingDir.listFiles(sStageFilter));
for (int i = 0; i < mSessions.size(); i++) {
- dirs.remove(Integer.toString(mSessions.keyAt(i)));
+ final PackageInstallerSession session = mSessions.valueAt(i);
+ stages.remove(session.sessionStageDir);
+ }
+ for (File stage : stages) {
+ Slog.w(TAG, "Deleting orphan stage " + stage);
+ if (stage.isDirectory()) {
+ FileUtils.deleteContents(stage);
+ }
+ stage.delete();
}
- for (String dirName : dirs) {
- Slog.w(TAG, "Deleting orphan session " + dirName);
- final File dir = new File(mStagingDir, dirName);
- FileUtils.deleteContents(dir);
- dir.delete();
+ }
+ }
+
+ @Deprecated
+ public File allocateSessionDir() throws IOException {
+ synchronized (mSessions) {
+ try {
+ final int sessionId = allocateSessionIdLocked();
+ return prepareSessionStageDir(sessionId);
+ } catch (IllegalStateException e) {
+ throw new IOException(e);
}
}
}
@@ -110,11 +138,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
}
@Override
- public int createSession(int userId, String installerPackageName,
- PackageInstallerParams params) {
+ public int createSession(String installerPackageName, PackageInstallerParams params,
+ int userId) {
final int callingUid = Binder.getCallingUid();
mPm.enforceCrossUserPermission(callingUid, userId, false, TAG);
- mAppOps.checkPackage(callingUid, installerPackageName);
if (mPm.isUserRestricted(UserHandle.getUserId(callingUid),
UserManager.DISALLOW_INSTALL_APPS)) {
@@ -124,20 +151,21 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
if ((callingUid == Process.SHELL_UID) || (callingUid == 0)) {
params.installFlags |= INSTALL_FROM_ADB;
} else {
+ mAppOps.checkPackage(callingUid, installerPackageName);
+
params.installFlags &= ~INSTALL_FROM_ADB;
params.installFlags &= ~INSTALL_ALL_USERS;
params.installFlags |= INSTALL_REPLACE_EXISTING;
}
synchronized (mSessions) {
- final int sessionId = allocateSessionIdLocked();
final long createdMillis = System.currentTimeMillis();
- final File sessionDir = new File(mStagingDir, Integer.toString(sessionId));
- sessionDir.mkdirs();
+ final int sessionId = allocateSessionIdLocked();
+ final File sessionStageDir = prepareSessionStageDir(sessionId);
final PackageInstallerSession session = new PackageInstallerSession(mCallback, mPm,
sessionId, userId, installerPackageName, callingUid, params, createdMillis,
- sessionDir, mInstallThread.getLooper());
+ sessionStageDir, mInstallThread.getLooper());
mSessions.put(sessionId, session);
writeSessionsAsync();
@@ -166,8 +194,30 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
return mNextSessionId++;
}
+ private File prepareSessionStageDir(int sessionId) {
+ final File file = new File(mStagingDir, "vmdl" + sessionId + ".tmp");
+
+ if (file.exists()) {
+ throw new IllegalStateException();
+ }
+
+ try {
+ Os.mkdir(file.getAbsolutePath(), 0755);
+ Os.chmod(file.getAbsolutePath(), 0755);
+ } catch (ErrnoException e) {
+ // This purposefully throws if directory already exists
+ throw new IllegalStateException("Failed to prepare session dir", e);
+ }
+
+ if (!SELinux.restorecon(file)) {
+ throw new IllegalStateException("Failed to prepare session dir");
+ }
+
+ return file;
+ }
+
@Override
- public int[] getSessions(int userId, String installerPackageName) {
+ public int[] getSessions(String installerPackageName, int userId) {
final int callingUid = Binder.getCallingUid();
mPm.enforceCrossUserPermission(callingUid, userId, false, TAG);
mAppOps.checkPackage(callingUid, installerPackageName);
@@ -187,13 +237,14 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
}
@Override
- public void uninstall(int userId, String basePackageName, IPackageDeleteObserver observer) {
- mPm.deletePackageAsUser(basePackageName, observer, userId, 0);
+ public void uninstall(String basePackageName, int flags, IPackageDeleteObserver observer,
+ int userId) {
+ mPm.deletePackageAsUser(basePackageName, observer, userId, flags);
}
@Override
- public void uninstallSplit(int userId, String basePackageName, String overlayName,
- IPackageDeleteObserver observer) {
+ public void uninstallSplit(String basePackageName, String overlayName, int flags,
+ IPackageDeleteObserver observer, int userId) {
// TODO: flesh out once PM has split support
throw new UnsupportedOperationException();
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 8067bd9..3448803 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -20,6 +20,8 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
+import static android.system.OsConstants.O_CREAT;
+import static android.system.OsConstants.O_WRONLY;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageInstallObserver2;
@@ -37,9 +39,11 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
+import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.system.ErrnoException;
+import android.system.Os;
import android.system.OsConstants;
import android.system.StructStat;
import android.util.ArraySet;
@@ -58,6 +62,10 @@ import java.util.ArrayList;
public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private static final String TAG = "PackageInstaller";
+ // TODO: enforce INSTALL_ALLOW_TEST
+ // TODO: enforce INSTALL_ALLOW_DOWNGRADE
+ // TODO: handle INSTALL_EXTERNAL, INSTALL_INTERNAL
+
private final PackageInstallerService.Callback mCallback;
private final PackageManagerService mPm;
private final Handler mHandler;
@@ -69,7 +77,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
public final int installerUid;
public final PackageInstallerParams params;
public final long createdMillis;
- public final File sessionDir;
+ public final File sessionStageDir;
private static final int MSG_INSTALL = 0;
@@ -85,6 +93,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
installLocked();
} catch (InstallFailedException e) {
Slog.e(TAG, "Install failed: " + e);
+ destroy();
try {
mRemoteObserver.packageInstalled(mPackageName, null, e.error);
} catch (RemoteException ignored) {
@@ -114,7 +123,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
public PackageInstallerSession(PackageInstallerService.Callback callback,
PackageManagerService pm, int sessionId, int userId, String installerPackageName,
- int installerUid, PackageInstallerParams params, long createdMillis, File sessionDir,
+ int installerUid, PackageInstallerParams params, long createdMillis, File sessionStageDir,
Looper looper) {
mCallback = callback;
mPm = pm;
@@ -126,7 +135,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
this.installerUid = installerUid;
this.params = params;
this.createdMillis = createdMillis;
- this.sessionDir = sessionDir;
+ this.sessionStageDir = sessionStageDir;
// Check against any explicitly provided signatures
mSignatures = params.signatures;
@@ -138,6 +147,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
== PackageManager.PERMISSION_GRANTED) {
mPermissionsConfirmed = true;
}
+ if (installerUid == Process.SHELL_UID || installerUid == 0) {
+ mPermissionsConfirmed = true;
+ }
}
@Override
@@ -168,10 +180,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
if (!FileUtils.isValidExtFilename(name)) {
throw new IllegalArgumentException("Invalid name: " + name);
}
- final File target = new File(sessionDir, name);
+ final File target = new File(sessionStageDir, name);
final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(),
- OsConstants.O_CREAT | OsConstants.O_WRONLY, 00700);
+ O_CREAT | O_WRONLY, 0644);
+ Os.chmod(target.getAbsolutePath(), 0644);
// If caller specified a total length, allocate it for them. Free up
// cache space to grow, if needed.
@@ -235,7 +248,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
if (!mPermissionsConfirmed) {
// TODO: async confirm permissions with user
// when they confirm, we'll kick off another install() pass
- mPermissionsConfirmed = true;
+ throw new SecurityException("Caller must hold INSTALL permission");
}
// Inherit any packages and native libraries from existing install that
@@ -258,7 +271,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
};
- mPm.installStage(mPackageName, this.sessionDir, localObserver, params, installerPackageName,
+ mPm.installStage(mPackageName, this.sessionStageDir, localObserver, params, installerPackageName,
installerUid, new UserHandle(userId));
}
@@ -271,9 +284,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private void validateInstallLocked() throws InstallFailedException {
mPackageName = null;
mVersionCode = -1;
- mSignatures = null;
- final File[] files = sessionDir.listFiles();
+ final File[] files = sessionStageDir.listFiles();
if (ArrayUtils.isEmpty(files)) {
throw new InstallFailedException(INSTALL_FAILED_INVALID_APK, "No packages staged");
}
@@ -296,11 +308,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
// Use first package to define unknown values
- if (mPackageName != null) {
+ if (mPackageName == null) {
mPackageName = info.packageName;
mVersionCode = info.versionCode;
}
- if (mSignatures != null) {
+ if (mSignatures == null) {
mSignatures = info.signatures;
}
@@ -310,9 +322,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// Take this opportunity to enforce uniform naming
final String name;
if (info.splitName == null) {
- name = info.packageName + ".apk";
+ name = "base.apk";
} else {
- name = info.packageName + "-" + info.splitName + ".apk";
+ name = "split_" + info.splitName + ".apk";
}
if (!FileUtils.isValidExtFilename(name)) {
throw new InstallFailedException(INSTALL_FAILED_INVALID_APK,
@@ -382,7 +394,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
final File existingDir = new File(app.getBaseCodePath());
try {
- linkTreeIgnoringExisting(existingDir, sessionDir);
+ linkTreeIgnoringExisting(existingDir, sessionStageDir);
} catch (ErrnoException e) {
throw new InstallFailedException(INSTALL_FAILED_INTERNAL_ERROR,
"Failed to splice into stage");
@@ -416,8 +428,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
synchronized (mLock) {
mInvalid = true;
}
- FileUtils.deleteContents(sessionDir);
- sessionDir.delete();
+ FileUtils.deleteContents(sessionStageDir);
+ sessionStageDir.delete();
} finally {
mCallback.onSessionInvalid(this);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 0a201f9..fe9ce8f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -377,11 +377,6 @@ public class PackageManagerService extends IPackageManager.Stub {
// apps.
final File mDrmAppPrivateInstallDir;
- /** Directory where third-party apps are staged before install */
- final File mAppStagingDir;
-
- private final Random mTempFileRandom = new Random();
-
// ----------------------------------------------------------------
// Lock for state used when installing and doing other long running
@@ -1363,7 +1358,6 @@ public class PackageManagerService extends IPackageManager.Stub {
mAsecInternalPath = new File(dataDir, "app-asec").getPath();
mUserAppDataDir = new File(dataDir, "user");
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
- mAppStagingDir = new File(dataDir, "app-staging");
sUserManager = new UserManagerService(context, this,
mInstallLock, mPackages);
@@ -1767,7 +1761,7 @@ public class PackageManagerService extends IPackageManager.Stub {
} // synchronized (mPackages)
} // synchronized (mInstallLock)
- mInstallerService = new PackageInstallerService(context, this, mAppStagingDir);
+ mInstallerService = new PackageInstallerService(context, this, mAppInstallDir);
// Now after opening every single application zip, make sure they
// are all flushed. Not really needed, but keeps things nice and
@@ -4172,6 +4166,7 @@ public class PackageManagerService extends IPackageManager.Stub {
pp.collectCertificates(pkg, parseFlags);
pp.collectManifestDigest(pkg);
} catch (PackageParserException e) {
+ Slog.e(TAG, "Failed during collect: " + e);
mLastScanError = e.error;
return false;
}
@@ -4200,6 +4195,7 @@ public class PackageManagerService extends IPackageManager.Stub {
try {
pkg = pp.parsePackage(scanFile, parseFlags);
} catch (PackageParserException e) {
+ Slog.e(TAG, "Failed during scan: " + e);
mLastScanError = e.error;
return null;
}
@@ -7652,8 +7648,20 @@ public class PackageManagerService extends IPackageManager.Stub {
verificationParams.setInstallerUid(uid);
final Message msg = mHandler.obtainMessage(INIT_COPY);
- msg.obj = new InstallParams(originFile, observer, filteredFlags, installerPackageName,
- verificationParams, user, packageAbiOverride);
+ msg.obj = new InstallParams(originFile, false, observer, filteredFlags,
+ installerPackageName, verificationParams, user, packageAbiOverride);
+ mHandler.sendMessage(msg);
+ }
+
+ void installStage(String packageName, File stageDir, IPackageInstallObserver2 observer,
+ PackageInstallerParams params, String installerPackageName, int installerUid,
+ UserHandle user) {
+ final VerificationParams verifParams = new VerificationParams(null, params.originatingUri,
+ params.referrerUri, installerUid, null);
+
+ final Message msg = mHandler.obtainMessage(INIT_COPY);
+ msg.obj = new InstallParams(stageDir, true, observer, params.installFlags,
+ installerPackageName, verifParams, user, params.abiOverride);
mHandler.sendMessage(msg);
}
@@ -7769,17 +7777,6 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- void installStage(String packageName, File stageDir, IPackageInstallObserver2 observer2,
- PackageInstallerParams params, String installerPackageName, int installerUid,
- UserHandle user) {
- Slog.e(TAG, "TODO: install stage!");
- try {
- observer2.packageInstalled(packageName, null,
- PackageManager.INSTALL_FAILED_INTERNAL_ERROR);
- } catch (RemoteException ignored) {
- }
- }
-
/**
* @hide
*/
@@ -8365,10 +8362,10 @@ public class PackageManagerService extends IPackageManager.Stub {
final File originFile;
/**
- * Flag indicating that {@link #originFile} lives in a trusted location,
+ * Flag indicating that {@link #originFile} has already been staged,
* meaning downstream users don't need to defensively copy the contents.
*/
- boolean originTrusted;
+ boolean originStaged;
final IPackageInstallObserver2 observer;
int flags;
@@ -8379,12 +8376,12 @@ public class PackageManagerService extends IPackageManager.Stub {
final String packageAbiOverride;
final String packageInstructionSetOverride;
- InstallParams(File originFile, IPackageInstallObserver2 observer, int flags,
- String installerPackageName, VerificationParams verificationParams, UserHandle user,
- String packageAbiOverride) {
+ InstallParams(File originFile, boolean originStaged, IPackageInstallObserver2 observer,
+ int flags, String installerPackageName, VerificationParams verificationParams,
+ UserHandle user, String packageAbiOverride) {
super(user);
this.originFile = Preconditions.checkNotNull(originFile);
- this.originTrusted = false;
+ this.originStaged = originStaged;
this.observer = observer;
this.flags = flags;
this.installerPackageName = installerPackageName;
@@ -8912,8 +8909,8 @@ public class PackageManagerService extends IPackageManager.Stub {
static abstract class InstallArgs {
/** @see InstallParams#originFile */
final File originFile;
- /** @see InstallParams#originTrusted */
- final boolean originTrusted;
+ /** @see InstallParams#originStaged */
+ final boolean originStaged;
// TODO: define inherit location
@@ -8926,11 +8923,11 @@ public class PackageManagerService extends IPackageManager.Stub {
final String instructionSet;
final String abiOverride;
- InstallArgs(File originFile, boolean originTrusted, IPackageInstallObserver2 observer,
+ InstallArgs(File originFile, boolean originStaged, IPackageInstallObserver2 observer,
int flags, String installerPackageName, ManifestDigest manifestDigest,
UserHandle user, String instructionSet, String abiOverride) {
this.originFile = originFile;
- this.originTrusted = originTrusted;
+ this.originStaged = originStaged;
this.flags = flags;
this.observer = observer;
this.installerPackageName = installerPackageName;
@@ -9009,7 +9006,7 @@ public class PackageManagerService extends IPackageManager.Stub {
/** New install */
FileInstallArgs(InstallParams params) {
- super(params.originFile, params.originTrusted, params.observer, params.flags,
+ super(params.originFile, params.originStaged, params.observer, params.flags,
params.installerPackageName, params.getManifestDigest(), params.getUser(),
params.packageInstructionSetOverride, params.packageAbiOverride);
if (isFwdLocked()) {
@@ -9028,7 +9025,7 @@ public class PackageManagerService extends IPackageManager.Stub {
/** New install from existing */
FileInstallArgs(File originFile, String instructionSet) {
- super(originFile, true, null, 0, null, null, null, instructionSet, null);
+ super(originFile, false, null, 0, null, null, null, instructionSet, null);
}
boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
@@ -9053,37 +9050,45 @@ public class PackageManagerService extends IPackageManager.Stub {
}
int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
- try {
- final File tempDir = createTempPackageDir(mAppInstallDir);
- codeFile = tempDir;
- resourceFile = tempDir;
- } catch (IOException e) {
- Slog.w(TAG, "Failed to create copy file: " + e);
- return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- }
+ int ret = PackageManager.INSTALL_SUCCEEDED;
- final IParcelFileDescriptorFactory target = new IParcelFileDescriptorFactory.Stub() {
- @Override
- public ParcelFileDescriptor open(String name, int mode) throws RemoteException {
- if (!FileUtils.isValidExtFilename(name)) {
- throw new IllegalArgumentException("Invalid filename: " + name);
- }
- try {
- final File file = new File(codeFile, name);
- final FileDescriptor fd = Os.open(file.getAbsolutePath(),
- O_RDWR | O_CREAT, 0644);
- Os.chmod(file.getAbsolutePath(), 0644);
- return new ParcelFileDescriptor(fd);
- } catch (ErrnoException e) {
- throw new RemoteException("Failed to open: " + e.getMessage());
- }
+ if (originStaged) {
+ Slog.d(TAG, originFile + " already staged; skipping copy");
+ codeFile = originFile;
+ resourceFile = originFile;
+ } else {
+ try {
+ final File tempDir = mInstallerService.allocateSessionDir();
+ codeFile = tempDir;
+ resourceFile = tempDir;
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to create copy file: " + e);
+ return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
- };
- int ret = imcs.copyPackage(originFile.getAbsolutePath(), target);
- if (ret != PackageManager.INSTALL_SUCCEEDED) {
- Slog.e(TAG, "Failed to copy package");
- return ret;
+ final IParcelFileDescriptorFactory target = new IParcelFileDescriptorFactory.Stub() {
+ @Override
+ public ParcelFileDescriptor open(String name, int mode) throws RemoteException {
+ if (!FileUtils.isValidExtFilename(name)) {
+ throw new IllegalArgumentException("Invalid filename: " + name);
+ }
+ try {
+ final File file = new File(codeFile, name);
+ final FileDescriptor fd = Os.open(file.getAbsolutePath(),
+ O_RDWR | O_CREAT, 0644);
+ Os.chmod(file.getAbsolutePath(), 0644);
+ return new ParcelFileDescriptor(fd);
+ } catch (ErrnoException e) {
+ throw new RemoteException("Failed to open: " + e.getMessage());
+ }
+ }
+ };
+
+ ret = imcs.copyPackage(originFile.getAbsolutePath(), target);
+ if (ret != PackageManager.INSTALL_SUCCEEDED) {
+ Slog.e(TAG, "Failed to copy package");
+ return ret;
+ }
}
String[] abiList = (abiOverride != null) ?
@@ -9288,7 +9293,7 @@ public class PackageManagerService extends IPackageManager.Stub {
/** New install */
AsecInstallArgs(InstallParams params) {
- super(params.originFile, params.originTrusted, params.observer, params.flags,
+ super(params.originFile, params.originStaged, params.observer, params.flags,
params.installerPackageName, params.getManifestDigest(), params.getUser(),
params.packageInstructionSetOverride, params.packageAbiOverride);
}
@@ -9318,7 +9323,7 @@ public class PackageManagerService extends IPackageManager.Stub {
/** New install from existing */
AsecInstallArgs(File originPackageFile, String cid, String instructionSet,
boolean isExternal, boolean isForwardLocked) {
- super(originPackageFile, true, null, (isExternal ? INSTALL_EXTERNAL : 0)
+ super(originPackageFile, false, null, (isExternal ? INSTALL_EXTERNAL : 0)
| (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
instructionSet, null);
this.cid = cid;
@@ -10082,6 +10087,7 @@ public class PackageManagerService extends IPackageManager.Stub {
try {
pkg = pp.parsePackage(tmpPackageFile, parseFlags);
} catch (PackageParserException e) {
+ Slog.e(TAG, "Failed during install: " + e);
res.returnCode = e.error;
return;
}
@@ -10098,6 +10104,7 @@ public class PackageManagerService extends IPackageManager.Stub {
pp.collectCertificates(pkg, parseFlags);
pp.collectManifestDigest(pkg);
} catch (PackageParserException e) {
+ Slog.e(TAG, "Failed during install: " + e);
res.returnCode = e.error;
return;
}
@@ -10276,63 +10283,9 @@ public class PackageManagerService extends IPackageManager.Stub {
return name.startsWith("vmdl") && name.endsWith(".tmp");
}
};
- deleteTempPackageFilesInDirectory(mAppInstallDir, filter);
- deleteTempPackageFilesInDirectory(mDrmAppPrivateInstallDir, filter);
- }
-
- private static final void deleteTempPackageFilesInDirectory(File directory,
- FilenameFilter filter) {
- final File[] files = directory.listFiles(filter);
- if (!ArrayUtils.isEmpty(files)) {
- for (File file : files) {
- if (file.isDirectory()) {
- FileUtils.deleteContents(file);
- file.delete();
- } else if (file.isFile()) {
- file.delete();
- }
- }
- }
- }
-
- private File createTempPackageDir(File installDir) throws IOException {
- int n = 0;
- while (n++ < 32) {
- final File file = new File(installDir, "vmdl" + mTempFileRandom.nextInt() + ".tmp");
- try {
- Os.mkdir(file.getAbsolutePath(), 0755);
- Os.chmod(file.getAbsolutePath(), 0755);
- if (!SELinux.restorecon(file)) {
- throw new IOException("Failed to restorecon");
- }
- return file;
- } catch (ErrnoException e) {
- if (e.errno == EEXIST) continue;
- throw e.rethrowAsIOException();
- }
- }
- throw new IOException("Failed to create temp directory");
- }
-
- private File createTempPackageFile(File installDir) throws IOException {
- int n = 0;
- while (n++ < 32) {
- final File file = new File(installDir, "vmdl" + mTempFileRandom.nextInt() + ".tmp");
- try {
- final FileDescriptor fd = Os.open(file.getAbsolutePath(),
- O_RDWR | O_CREAT | O_EXCL, 0644);
- IoUtils.closeQuietly(fd);
- Os.chmod(file.getAbsolutePath(), 0644);
- if (!SELinux.restorecon(file)) {
- throw new IOException("Failed to restorecon");
- }
- return file;
- } catch (ErrnoException e) {
- if (e.errno == EEXIST) continue;
- throw e.rethrowAsIOException();
- }
+ for (File file : mDrmAppPrivateInstallDir.listFiles(filter)) {
+ file.delete();
}
- throw new IOException("Failed to create temp file");
}
@Override