From f1977b4500e82b72ea6aa5c46d97406a20017caf Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Mon, 24 Mar 2014 16:25:51 -0700 Subject: Expand install observer semantics ...and now fail conservatively when two apps both attempt to define the same permission. Apps signed with the same certificate are permitted to redefine permissions. We also finally have a (hidden) interface class for observing package installation so that we can now rev the interface without breaking existing callers. Bug 13551375 Change-Id: Ifa4e59154dcccbb286ee46a35a6f25e4ad0f0f01 --- .../android/app/ApplicationPackageManager.java | 49 ++++++- core/java/android/app/PackageInstallObserver.java | 49 +++++++ .../content/pm/IPackageInstallObserver2.aidl | 45 +++++++ core/java/android/content/pm/IPackageManager.aidl | 16 +++ core/java/android/content/pm/PackageManager.java | 143 +++++++++++++++++++-- core/java/android/content/pm/PackageParser.java | 1 - 6 files changed, 288 insertions(+), 15 deletions(-) create mode 100644 core/java/android/app/PackageInstallObserver.java create mode 100644 core/java/android/content/pm/IPackageInstallObserver2.aidl (limited to 'core/java/android') diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 0615bd9..6ca5244 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -29,6 +29,7 @@ import android.content.pm.FeatureInfo; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageDeleteObserver; import android.content.pm.IPackageInstallObserver; +import android.content.pm.IPackageInstallObserver2; import android.content.pm.IPackageManager; import android.content.pm.IPackageMoveObserver; import android.content.pm.IPackageStatsObserver; @@ -1073,7 +1074,7 @@ final class ApplicationPackageManager extends PackageManager { public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags, String installerPackageName) { try { - mPM.installPackage(packageURI, observer, flags, installerPackageName); + mPM.installPackageEtc(packageURI, observer, null, flags, installerPackageName); } catch (RemoteException e) { // Should never happen! } @@ -1084,8 +1085,8 @@ final class ApplicationPackageManager extends PackageManager { int flags, String installerPackageName, Uri verificationURI, ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) { try { - mPM.installPackageWithVerification(packageURI, observer, flags, installerPackageName, - verificationURI, manifestDigest, encryptionParams); + mPM.installPackageWithVerificationEtc(packageURI, observer, null, flags, + installerPackageName, verificationURI, manifestDigest, encryptionParams); } catch (RemoteException e) { // Should never happen! } @@ -1096,8 +1097,46 @@ final class ApplicationPackageManager extends PackageManager { IPackageInstallObserver observer, int flags, String installerPackageName, VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) { try { - mPM.installPackageWithVerificationAndEncryption(packageURI, observer, flags, - installerPackageName, verificationParams, encryptionParams); + mPM.installPackageWithVerificationAndEncryptionEtc(packageURI, observer, null, + flags, installerPackageName, verificationParams, encryptionParams); + } catch (RemoteException e) { + // Should never happen! + } + } + + // Expanded observer-API versions + @Override + public void installPackage(Uri packageURI, PackageInstallObserver observer, + int flags, String installerPackageName) { + try { + mPM.installPackageEtc(packageURI, null, observer.mObserver, + flags, installerPackageName); + } catch (RemoteException e) { + // Should never happen! + } + } + + @Override + public void installPackageWithVerification(Uri packageURI, + PackageInstallObserver observer, int flags, String installerPackageName, + Uri verificationURI, ManifestDigest manifestDigest, + ContainerEncryptionParams encryptionParams) { + try { + mPM.installPackageWithVerificationEtc(packageURI, null, observer.mObserver, flags, + installerPackageName, verificationURI, manifestDigest, encryptionParams); + } catch (RemoteException e) { + // Should never happen! + } + } + + @Override + public void installPackageWithVerificationAndEncryption(Uri packageURI, + PackageInstallObserver observer, int flags, String installerPackageName, + VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) { + try { + mPM.installPackageWithVerificationAndEncryptionEtc(packageURI, null, + observer.mObserver, flags, installerPackageName, verificationParams, + encryptionParams); } catch (RemoteException e) { // Should never happen! } diff --git a/core/java/android/app/PackageInstallObserver.java b/core/java/android/app/PackageInstallObserver.java new file mode 100644 index 0000000..dacffb4 --- /dev/null +++ b/core/java/android/app/PackageInstallObserver.java @@ -0,0 +1,49 @@ +/* + * 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 android.app; + +import android.content.pm.IPackageInstallObserver2; +import android.os.Bundle; +import android.os.RemoteException; + +/** + * @hide + * + * New-style observer for package installers to use. + */ +public class PackageInstallObserver { + IPackageInstallObserver2.Stub mObserver = new IPackageInstallObserver2.Stub() { + @Override + public void packageInstalled(String pkgName, Bundle extras, int result) + throws RemoteException { + PackageInstallObserver.this.packageInstalled(pkgName, extras, result); + } + }; + + /** + * This method will be called to report the result of the package installation attempt. + * + * @param pkgName Name of the package whose installation was attempted + * @param extras If non-null, this Bundle contains extras providing additional information + * about an install failure. See {@link android.content.pm.PackageManager} for + * documentation about which extras apply to various failures; in particular the + * strings named EXTRA_FAILURE_*. + * @param result The numeric success or failure code indicating the basic outcome + */ + public void packageInstalled(String pkgName, Bundle extras, int result) { + } +} diff --git a/core/java/android/content/pm/IPackageInstallObserver2.aidl b/core/java/android/content/pm/IPackageInstallObserver2.aidl new file mode 100644 index 0000000..2602ab5 --- /dev/null +++ b/core/java/android/content/pm/IPackageInstallObserver2.aidl @@ -0,0 +1,45 @@ +/* +** +** Copyright 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 android.content.pm; + +import android.os.Bundle; + +/** + * API for installation callbacks from the Package Manager. In certain result cases + * additional information will be provided. + * @hide + */ +oneway interface IPackageInstallObserver2 { + /** + * The install operation has completed. {@code returnCode} holds a numeric code + * indicating success or failure. In certain cases the {@code extras} Bundle will + * contain additional details: + * + *

+ * + * + * + * + *
INSTALL_FAILED_DUPLICATE_PERMISSIONTwo strings are provided in the extras bundle: EXTRA_EXISTING_PERMISSION + * is the name of the permission that the app is attempting to define, and + * EXTRA_EXISTING_PACKAGE is the package name of the app which has already + * defined the permission.
+ */ + void packageInstalled(in String packageName, in Bundle extras, int returnCode); +} + diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index c9fb530..ae0899f 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -25,6 +25,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.ContainerEncryptionParams; import android.content.pm.FeatureInfo; import android.content.pm.IPackageInstallObserver; +import android.content.pm.IPackageInstallObserver2; import android.content.pm.IPackageDeleteObserver; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageMoveObserver; @@ -406,6 +407,21 @@ interface IPackageManager { in VerificationParams verificationParams, in ContainerEncryptionParams encryptionParams); + /** Expanded observer versions */ + void installPackageEtc(in Uri packageURI, IPackageInstallObserver observer, + IPackageInstallObserver2 observer2, int flags, in String installerPackageName); + + void installPackageWithVerificationEtc(in Uri packageURI, + in IPackageInstallObserver observer, IPackageInstallObserver2 observer2, + int flags, in String installerPackageName, in Uri verificationURI, + in ManifestDigest manifestDigest, in ContainerEncryptionParams encryptionParams); + + void installPackageWithVerificationAndEncryptionEtc(in Uri packageURI, + in IPackageInstallObserver observer, in IPackageInstallObserver2 observer2, + int flags, in String installerPackageName, + in VerificationParams verificationParams, + in ContainerEncryptionParams encryptionParams); + int installExistingPackageAsUser(String packageName, int userId); void verifyPendingInstall(int id, int verificationCode); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index e86833b..ceb7764 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -19,6 +19,7 @@ package android.content.pm; import android.annotation.IntDef; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.app.PackageInstallObserver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -683,6 +684,20 @@ public abstract class PackageManager { public static final int INSTALL_FAILED_USER_RESTRICTED = -111; /** + * Installation failed return code: this is passed to the {@link IPackageInstallObserver} by + * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} + * if the system failed to install the package because it is attempting to define a + * permission that is already defined by some existing package. + * + *

The package name of the app which has already defined the permission is passed to + * a {@link IPackageInstallObserver2}, if any, as the {@link #EXTRA_EXISTING_PACKAGE} + * string extra; and the name of the permission being redefined is passed in the + * {@link #EXTRA_EXISTING_PERMISSION} string extra. + * @hide + */ + public static final int INSTALL_FAILED_DUPLICATE_PERMISSION = -112; + + /** * Flag parameter for {@link #deletePackage} to indicate that you don't want to delete the * package's data directory. * @@ -1390,6 +1405,24 @@ public abstract class PackageManager { = "android.content.pm.extra.PERMISSION_LIST"; /** + * String extra for {@link IPackageInstallObserver2} in the 'extras' Bundle in case of + * {@link #INSTALL_FAILED_DUPLICATE_PERMISSION}. This extra names the package which provides + * the existing definition for the permission. + * @hide + */ + public static final String EXTRA_FAILURE_EXISTING_PACKAGE + = "android.content.pm.extra.FAILURE_EXISTING_PACKAGE"; + + /** + * String extra for {@link IPackageInstallObserver2} in the 'extras' Bundle in case of + * {@link #INSTALL_FAILED_DUPLICATE_PERMISSION}. This extra names the permission that is + * being redundantly defined by the package being installed. + * @hide + */ + public static final String EXTRA_FAILURE_EXISTING_PERMISSION + = "android.content.pm.extra.FAILURE_EXISTING_PERMISSION"; + + /** * Retrieve overall information about an application package that is * installed on the system. *

@@ -2752,11 +2785,14 @@ public abstract class PackageManager { * 'content:' URI. * @param observer An observer callback to get notified when the package installation is * complete. {@link IPackageInstallObserver#packageInstalled(String, int)} will be - * called when that happens. observer may be null to indicate that no callback is desired. + * called when that happens. This parameter must not be null. * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK}, * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}. * @param installerPackageName Optional package name of the application that is performing the * installation. This identifies which market the package came from. + * @deprecated Use {@link #installPackage(Uri, IPackageInstallObserver2, int, String)} + * instead. This method will continue to be supported but the older observer interface + * will not get additional failure details. */ public abstract void installPackage( Uri packageURI, IPackageInstallObserver observer, int flags, @@ -2772,11 +2808,9 @@ public abstract class PackageManager { * @param observer An observer callback to get notified when the package * installation is complete. * {@link IPackageInstallObserver#packageInstalled(String, int)} - * will be called when that happens. observer may be null to - * indicate that no callback is desired. + * will be called when that happens. This parameter must not be null. * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK}, - * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST} - * . + * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}. * @param installerPackageName Optional package name of the application that * is performing the installation. This identifies which market * the package came from. @@ -2789,6 +2823,10 @@ public abstract class PackageManager { * these parameters describing the encryption and authentication * used. May be {@code null}. * @hide + * @deprecated Use {@link #installPackageWithVerification(Uri, IPackageInstallObserver2, + * int, String, Uri, ManifestDigest, ContainerEncryptionParams)} instead. This method will + * continue to be supported but the older observer interface will not get additional failure + * details. */ public abstract void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer, int flags, String installerPackageName, @@ -2805,11 +2843,9 @@ public abstract class PackageManager { * @param observer An observer callback to get notified when the package * installation is complete. * {@link IPackageInstallObserver#packageInstalled(String, int)} - * will be called when that happens. observer may be null to - * indicate that no callback is desired. + * will be called when that happens. This parameter must not be null. * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK}, - * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST} - * . + * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}. * @param installerPackageName Optional package name of the application that * is performing the installation. This identifies which market * the package came from. @@ -2820,12 +2856,101 @@ public abstract class PackageManager { * used. May be {@code null}. * * @hide + * @deprecated Use {@link #installPackageWithVerificationAndEncryption(Uri, + * IPackageInstallObserver2, int, String, VerificationParams, + * ContainerEncryptionParams)} instead. This method will continue to be + * supported but the older observer interface will not get additional failure details. */ + @Deprecated public abstract void installPackageWithVerificationAndEncryption(Uri packageURI, IPackageInstallObserver observer, int flags, String installerPackageName, VerificationParams verificationParams, ContainerEncryptionParams encryptionParams); + // Package-install variants that take the new, expanded form of observer interface. + // Note that these *also* take the original observer type and will redundantly + // report the same information to that observer if supplied; but it is not required. + + /** + * @hide + * + * Install a package. Since this may take a little while, the result will + * be posted back to the given observer. An installation will fail if the calling context + * lacks the {@link android.Manifest.permission#INSTALL_PACKAGES} permission, if the + * package named in the package file's manifest is already installed, or if there's no space + * available on the device. + * + * @param packageURI The location of the package file to install. This can be a 'file:' or a + * 'content:' URI. + * @param observer An observer callback to get notified when the package installation is + * complete. {@link PackageInstallObserver#packageInstalled(String, Bundle, int)} will be + * called when that happens. This parameter must not be null. + * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK}, + * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}. + * @param installerPackageName Optional package name of the application that is performing the + * installation. This identifies which market the package came from. + */ + public abstract void installPackage( + Uri packageURI, PackageInstallObserver observer, + int flags, String installerPackageName); + + /** + * Similar to + * {@link #installPackage(Uri, IPackageInstallObserver, int, String)} but + * with an extra verification file provided. + * + * @param packageURI The location of the package file to install. This can + * be a 'file:' or a 'content:' URI. + * @param observer An observer callback to get notified when the package installation is + * complete. {@link PackageInstallObserver#packageInstalled(String, Bundle, int)} will be + * called when that happens. This parameter must not be null. + * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK}, + * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}. + * @param installerPackageName Optional package name of the application that + * is performing the installation. This identifies which market + * the package came from. + * @param verificationURI The location of the supplementary verification + * file. This can be a 'file:' or a 'content:' URI. May be + * {@code null}. + * @param manifestDigest an object that holds the digest of the package + * which can be used to verify ownership. May be {@code null}. + * @param encryptionParams if the package to be installed is encrypted, + * these parameters describing the encryption and authentication + * used. May be {@code null}. + * @hide + */ + public abstract void installPackageWithVerification(Uri packageURI, + PackageInstallObserver observer, int flags, String installerPackageName, + Uri verificationURI, ManifestDigest manifestDigest, + ContainerEncryptionParams encryptionParams); + + /** + * Similar to + * {@link #installPackage(Uri, IPackageInstallObserver, int, String)} but + * with an extra verification information provided. + * + * @param packageURI The location of the package file to install. This can + * be a 'file:' or a 'content:' URI. + * @param observer An observer callback to get notified when the package installation is + * complete. {@link PackageInstallObserver#packageInstalled(String, Bundle, int)} will be + * called when that happens. This parameter must not be null. + * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK}, + * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}. + * @param installerPackageName Optional package name of the application that + * is performing the installation. This identifies which market + * the package came from. + * @param verificationParams an object that holds signal information to + * assist verification. May be {@code null}. + * @param encryptionParams if the package to be installed is encrypted, + * these parameters describing the encryption and authentication + * used. May be {@code null}. + * + * @hide + */ + public abstract void installPackageWithVerificationAndEncryption(Uri packageURI, + PackageInstallObserver observer, int flags, String installerPackageName, + VerificationParams verificationParams, ContainerEncryptionParams encryptionParams); + /** * If there is already an application with the given package name installed * on the system for other users, also install it for the calling user. diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index cf44ad8..8898beb 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -1105,7 +1105,6 @@ public class PackageParser { if (!parseUsesPermission(pkg, res, parser, attrs, outError)) { return null; } - } else if (tagName.equals("uses-configuration")) { ConfigurationInfo cPref = new ConfigurationInfo(); sa = res.obtainAttributes(attrs, -- cgit v1.1