diff options
author | Christopher Tate <ctate@google.com> | 2014-03-24 16:25:51 -0700 |
---|---|---|
committer | Christopher Tate <ctate@google.com> | 2014-03-27 12:37:47 -0700 |
commit | f1977b4500e82b72ea6aa5c46d97406a20017caf (patch) | |
tree | 9d6b4e63bc4b4c70eb9fbd5eb2cff9587ba45485 | |
parent | 9ad8a5331ca5eb6390c702ec57952043b56170bf (diff) | |
download | frameworks_base-f1977b4500e82b72ea6aa5c46d97406a20017caf.zip frameworks_base-f1977b4500e82b72ea6aa5c46d97406a20017caf.tar.gz frameworks_base-f1977b4500e82b72ea6aa5c46d97406a20017caf.tar.bz2 |
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
12 files changed, 485 insertions, 47 deletions
@@ -120,6 +120,7 @@ LOCAL_SRC_FILES += \ core/java/android/content/pm/IPackageDataObserver.aidl \ core/java/android/content/pm/IPackageDeleteObserver.aidl \ core/java/android/content/pm/IPackageInstallObserver.aidl \ + core/java/android/content/pm/IPackageInstallObserver2.aidl \ core/java/android/content/pm/IPackageManager.aidl \ core/java/android/content/pm/IPackageMoveObserver.aidl \ core/java/android/content/pm/IPackageStatsObserver.aidl \ diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index d513a10..f415c85 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -25,7 +25,7 @@ import android.content.pm.ContainerEncryptionParams; 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.InstrumentationInfo; import android.content.pm.PackageInfo; @@ -39,6 +39,7 @@ import android.content.pm.VerificationParams; import android.content.res.AssetManager; import android.content.res.Resources; import android.net.Uri; +import android.os.Bundle; import android.os.IUserManager; import android.os.Process; import android.os.RemoteException; @@ -700,14 +701,23 @@ public final class Pm { ActivityManager.dumpPackageStateStatic(FileDescriptor.out, pkg); } - class PackageInstallObserver extends IPackageInstallObserver.Stub { + class PackageInstallObserver extends IPackageInstallObserver2.Stub { boolean finished; int result; + String extraPermission; + String extraPackage; - public void packageInstalled(String name, int status) { + @Override + public void packageInstalled(String name, Bundle extras, int status) { synchronized( this) { finished = true; result = status; + if (status == PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION) { + extraPermission = extras.getString( + PackageManager.EXTRA_FAILURE_EXISTING_PERMISSION); + extraPackage = extras.getString( + PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE); + } notifyAll(); } } @@ -717,7 +727,8 @@ public final class Pm { * Converts a failure code into a string by using reflection to find a matching constant * in PackageManager. */ - private String installFailureToString(int result) { + private String installFailureToString(PackageInstallObserver obs) { + final int result = obs.result; Field[] fields = PackageManager.class.getFields(); for (Field f: fields) { if (f.getType() == int.class) { @@ -732,7 +743,16 @@ public final class Pm { // get the int value and compare it to result. try { if (result == f.getInt(null)) { - return fieldName; + StringBuilder sb = new StringBuilder(64); + sb.append(fieldName); + if (obs.extraPermission != null) { + sb.append(" perm="); + sb.append(obs.extraPermission); + } + if (obs.extraPackage != null) { + sb.append(" pkg=" + obs.extraPackage); + } + return sb.toString(); } } catch (IllegalAccessException e) { // this shouldn't happen since we only look for public static fields. @@ -956,7 +976,7 @@ public final class Pm { VerificationParams verificationParams = new VerificationParams(verificationURI, originatingURI, referrerURI, VerificationParams.NO_UID, null); - mPm.installPackageWithVerificationAndEncryption(apkURI, obs, installFlags, + mPm.installPackageWithVerificationAndEncryptionEtc(apkURI, null, obs, installFlags, installerPackageName, verificationParams, encryptionParams); synchronized (obs) { @@ -970,7 +990,7 @@ public final class Pm { System.out.println("Success"); } else { System.err.println("Failure [" - + installFailureToString(obs.result) + + installFailureToString(obs) + "]"); } } 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: + * + * <p><table> + * <tr> + * <td>INSTALL_FAILED_DUPLICATE_PERMISSION</td> + * <td>Two 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.</td> + * </tr> + * </table> + */ + 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. + * + * <p>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. * <p> @@ -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, diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java index 04f8009..e77564f 100644 --- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java +++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java @@ -21,6 +21,7 @@ import static libcore.io.OsConstants.*; import com.android.frameworks.coretests.R; import com.android.internal.content.PackageHelper; +import android.app.PackageInstallObserver; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -31,6 +32,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.content.res.Resources.NotFoundException; import android.net.Uri; +import android.os.Bundle; import android.os.Environment; import android.os.FileUtils; import android.os.IBinder; @@ -117,12 +119,12 @@ public class PackageManagerTests extends AndroidTestCase { super.tearDown(); } - private class PackageInstallObserver extends IPackageInstallObserver.Stub { + private class TestInstallObserver extends PackageInstallObserver { public int returnCode; private boolean doneFlag = false; - public void packageInstalled(String packageName, int returnCode) { + public void packageInstalled(String packageName, Bundle extras, int returnCode) { synchronized (this) { this.returnCode = returnCode; doneFlag = true; @@ -203,7 +205,7 @@ public class PackageManagerTests extends AndroidTestCase { public void invokeInstallPackage(Uri packageURI, int flags, GenericReceiver receiver, boolean shouldSucceed) { - PackageInstallObserver observer = new PackageInstallObserver(); + TestInstallObserver observer = new TestInstallObserver(); mContext.registerReceiver(receiver, receiver.filter); try { // Wait on observer @@ -261,7 +263,7 @@ public class PackageManagerTests extends AndroidTestCase { } public void invokeInstallPackageFail(Uri packageURI, int flags, int expectedResult) { - PackageInstallObserver observer = new PackageInstallObserver(); + TestInstallObserver observer = new TestInstallObserver(); try { // Wait on observer synchronized (observer) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index a01c586..a07ad5a 100755 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -69,6 +69,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; @@ -340,7 +341,7 @@ public class PackageManagerService extends IPackageManager.Stub { // Lock for state used when installing and doing other long running // operations. Methods that must be called with this lock held have - // the prefix "LI". + // the suffix "LI". final Object mInstallLock = new Object(); // These are the directories in the 3rd party applications installed dir @@ -916,6 +917,14 @@ public class PackageManagerService extends IPackageManager.Stub { Slog.i(TAG, "Observer no longer exists."); } } + if (args.observer2 != null) { + try { + Bundle extras = extrasForInstallResult(res); + args.observer2.packageInstalled(res.name, extras, res.returnCode); + } catch (RemoteException e) { + Slog.i(TAG, "Observer no longer exists."); + } + } } else { Slog.e(TAG, "Bogus post-install token " + msg.arg1); } @@ -1044,6 +1053,21 @@ public class PackageManagerService extends IPackageManager.Stub { } } + Bundle extrasForInstallResult(PackageInstalledInfo res) { + Bundle extras = null; + switch (res.returnCode) { + case PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION: { + extras = new Bundle(); + extras.putString(PackageManager.EXTRA_FAILURE_EXISTING_PERMISSION, + res.origPermission); + extras.putString(PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE, + res.origPackage); + break; + } + } + return extras; + } + void scheduleWriteSettingsLocked() { if (!mHandler.hasMessages(WRITE_SETTINGS)) { mHandler.sendEmptyMessageDelayed(WRITE_SETTINGS, WRITE_SETTINGS_DELAY); @@ -6772,18 +6796,24 @@ public class PackageManagerService extends IPackageManager.Stub { private final boolean mIsPrivileged; } + /* + * The old-style observer methods all just trampoline to the newer signature with + * expanded install observer API. The older API continues to work but does not + * supply the additional details of the Observer2 API. + */ + /* Called when a downloaded package installation has been confirmed by the user */ public void installPackage( final Uri packageURI, final IPackageInstallObserver observer, final int flags) { - installPackage(packageURI, observer, flags, null); + installPackageEtc(packageURI, observer, null, flags, null); } /* Called when a downloaded package installation has been confirmed by the user */ public void installPackage( final Uri packageURI, final IPackageInstallObserver observer, final int flags, final String installerPackageName) { - installPackageWithVerification(packageURI, observer, flags, installerPackageName, null, - null, null); + installPackageWithVerificationEtc(packageURI, observer, null, flags, + installerPackageName, null, null, null); } @Override @@ -6792,20 +6822,67 @@ public class PackageManagerService extends IPackageManager.Stub { ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) { VerificationParams verificationParams = new VerificationParams(verificationURI, null, null, VerificationParams.NO_UID, manifestDigest); - installPackageWithVerificationAndEncryption(packageURI, observer, flags, + installPackageWithVerificationAndEncryptionEtc(packageURI, observer, null, flags, installerPackageName, verificationParams, encryptionParams); } public void installPackageWithVerificationAndEncryption(Uri packageURI, IPackageInstallObserver observer, int flags, String installerPackageName, VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) { + installPackageWithVerificationAndEncryptionEtc(packageURI, observer, null, flags, + installerPackageName, verificationParams, encryptionParams); + } + + /* + * And here are the "live" versions that take both observer arguments + */ + public void installPackageEtc( + final Uri packageURI, final IPackageInstallObserver observer, + IPackageInstallObserver2 observer2, final int flags) { + installPackageEtc(packageURI, observer, observer2, flags, null); + } + + public void installPackageEtc( + final Uri packageURI, final IPackageInstallObserver observer, + final IPackageInstallObserver2 observer2, final int flags, + final String installerPackageName) { + installPackageWithVerificationEtc(packageURI, observer, observer2, flags, + installerPackageName, null, null, null); + } + + @Override + public void installPackageWithVerificationEtc(Uri packageURI, IPackageInstallObserver observer, + IPackageInstallObserver2 observer2, + int flags, String installerPackageName, Uri verificationURI, + ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) { + VerificationParams verificationParams = new VerificationParams(verificationURI, null, null, + VerificationParams.NO_UID, manifestDigest); + installPackageWithVerificationAndEncryptionEtc(packageURI, observer, observer2, flags, + installerPackageName, verificationParams, encryptionParams); + } + + /* + * All of the installPackage...*() methods redirect to this one for the master implementation + */ + public void installPackageWithVerificationAndEncryptionEtc(Uri packageURI, + IPackageInstallObserver observer, IPackageInstallObserver2 observer2, + int flags, String installerPackageName, + VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) { + if (observer == null && observer2 == null) { + throw new IllegalArgumentException("No install observer supplied"); + } mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null); final int uid = Binder.getCallingUid(); if (isUserRestricted(UserHandle.getUserId(uid), UserManager.DISALLOW_INSTALL_APPS)) { try { - observer.packageInstalled("", PackageManager.INSTALL_FAILED_USER_RESTRICTED); + if (observer != null) { + observer.packageInstalled("", PackageManager.INSTALL_FAILED_USER_RESTRICTED); + } + if (observer2 != null) { + observer2.packageInstalled("", null, PackageManager.INSTALL_FAILED_USER_RESTRICTED); + } } catch (RemoteException re) { } return; @@ -6832,8 +6909,8 @@ public class PackageManagerService extends IPackageManager.Stub { verificationParams.setInstallerUid(uid); final Message msg = mHandler.obtainMessage(INIT_COPY); - msg.obj = new InstallParams(packageURI, observer, filteredFlags, installerPackageName, - verificationParams, encryptionParams, user); + msg.obj = new InstallParams(packageURI, observer, observer2, filteredFlags, + installerPackageName, verificationParams, encryptionParams, user); mHandler.sendMessage(msg); } @@ -7522,6 +7599,7 @@ public class PackageManagerService extends IPackageManager.Stub { class InstallParams extends HandlerParams { final IPackageInstallObserver observer; + final IPackageInstallObserver2 observer2; int flags; private final Uri mPackageURI; @@ -7533,13 +7611,14 @@ public class PackageManagerService extends IPackageManager.Stub { final ContainerEncryptionParams encryptionParams; InstallParams(Uri packageURI, - IPackageInstallObserver observer, int flags, - String installerPackageName, VerificationParams verificationParams, + IPackageInstallObserver observer, IPackageInstallObserver2 observer2, + int flags, String installerPackageName, VerificationParams verificationParams, ContainerEncryptionParams encryptionParams, UserHandle user) { super(user); this.mPackageURI = packageURI; this.flags = flags; this.observer = observer; + this.observer2 = observer2; this.installerPackageName = installerPackageName; this.verificationParams = verificationParams; this.encryptionParams = encryptionParams; @@ -8109,6 +8188,7 @@ public class PackageManagerService extends IPackageManager.Stub { static abstract class InstallArgs { final IPackageInstallObserver observer; + final IPackageInstallObserver2 observer2; // Always refers to PackageManager flags only final int flags; final Uri packageURI; @@ -8116,12 +8196,14 @@ public class PackageManagerService extends IPackageManager.Stub { final ManifestDigest manifestDigest; final UserHandle user; - InstallArgs(Uri packageURI, IPackageInstallObserver observer, int flags, - String installerPackageName, ManifestDigest manifestDigest, + InstallArgs(Uri packageURI, + IPackageInstallObserver observer, IPackageInstallObserver2 observer2, + int flags, String installerPackageName, ManifestDigest manifestDigest, UserHandle user) { this.packageURI = packageURI; this.flags = flags; this.observer = observer; + this.observer2 = observer2; this.installerPackageName = installerPackageName; this.manifestDigest = manifestDigest; this.user = user; @@ -8178,13 +8260,13 @@ public class PackageManagerService extends IPackageManager.Stub { boolean created = false; FileInstallArgs(InstallParams params) { - super(params.getPackageUri(), params.observer, params.flags, + super(params.getPackageUri(), params.observer, params.observer2, params.flags, params.installerPackageName, params.getManifestDigest(), params.getUser()); } FileInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath) { - super(null, null, 0, null, null, null); + super(null, null, null, 0, null, null, null); File codeFile = new File(fullCodePath); installDir = codeFile.getParentFile(); codeFileName = fullCodePath; @@ -8193,7 +8275,7 @@ public class PackageManagerService extends IPackageManager.Stub { } FileInstallArgs(Uri packageURI, String pkgName, String dataDir) { - super(packageURI, null, 0, null, null, null); + super(packageURI, null, null, 0, null, null, null); installDir = isFwdLocked() ? mDrmAppPrivateInstallDir : mAppInstallDir; String apkName = getNextCodePath(null, pkgName, ".apk"); codeFileName = new File(installDir, apkName + ".apk").getPath(); @@ -8514,14 +8596,14 @@ public class PackageManagerService extends IPackageManager.Stub { String libraryPath; AsecInstallArgs(InstallParams params) { - super(params.getPackageUri(), params.observer, params.flags, + super(params.getPackageUri(), params.observer, params.observer2, params.flags, params.installerPackageName, params.getManifestDigest(), params.getUser()); } AsecInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath, boolean isExternal, boolean isForwardLocked) { - super(null, null, (isExternal ? PackageManager.INSTALL_EXTERNAL : 0) + super(null, null, null, (isExternal ? PackageManager.INSTALL_EXTERNAL : 0) | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0), null, null, null); // Extract cid from fullCodePath @@ -8533,7 +8615,7 @@ public class PackageManagerService extends IPackageManager.Stub { } AsecInstallArgs(String cid, boolean isForwardLocked) { - super(null, null, (isAsecExternal(cid) ? PackageManager.INSTALL_EXTERNAL : 0) + super(null, null, null, (isAsecExternal(cid) ? PackageManager.INSTALL_EXTERNAL : 0) | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0), null, null, null); this.cid = cid; @@ -8541,7 +8623,7 @@ public class PackageManagerService extends IPackageManager.Stub { } AsecInstallArgs(Uri packageURI, String cid, boolean isExternal, boolean isForwardLocked) { - super(packageURI, null, (isExternal ? PackageManager.INSTALL_EXTERNAL : 0) + super(packageURI, null, null, (isExternal ? PackageManager.INSTALL_EXTERNAL : 0) | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0), null, null, null); this.cid = cid; @@ -8875,6 +8957,10 @@ public class PackageManagerService extends IPackageManager.Stub { PackageParser.Package pkg; int returnCode; PackageRemovedInfo removedInfo; + + // In some error cases we want to convey more info back to the observer + String origPackage; + String origPermission; } /* @@ -9299,6 +9385,27 @@ public class PackageManagerService extends IPackageManager.Stub { String oldCodePath = null; boolean systemApp = false; synchronized (mPackages) { + // Check whether the newly-scanned package wants to define an already-defined perm + int N = pkg.permissions.size(); + for (int i = 0; i < N; i++) { + PackageParser.Permission perm = pkg.permissions.get(i); + BasePermission bp = mSettings.mPermissions.get(perm.info.name); + if (bp != null) { + // If the defining package is signed with our cert, it's okay. This + // also includes the "updating the same package" case, of course. + if (compareSignatures(bp.packageSetting.signatures.mSignatures, + pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) { + Slog.w(TAG, "Package " + pkg.packageName + + " attempting to redeclare permission " + perm.info.name + + " already owned by " + bp.sourcePackage); + res.returnCode = PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION; + res.origPermission = perm.info.name; + res.origPackage = bp.sourcePackage; + return; + } + } + } + // Check if installing already existing package if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0) { String oldName = mSettings.mRenamedPackages.get(pkgName); diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index 118cba4..daef37a 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -16,6 +16,7 @@ package android.test.mock; +import android.app.PackageInstallObserver; import android.content.ComponentName; import android.content.Intent; import android.content.IntentFilter; @@ -664,4 +665,34 @@ public class MockPackageManager extends PackageManager { public VerifierDeviceIdentity getVerifierDeviceIdentity() { throw new UnsupportedOperationException(); } + + /** + * @hide + */ + @Override + public void installPackage(Uri packageURI, PackageInstallObserver observer, + int flags, String installerPackageName) { + throw new UnsupportedOperationException(); + } + + /** + * @hide + */ + @Override + public void installPackageWithVerification(Uri packageURI, + PackageInstallObserver observer, int flags, String installerPackageName, + Uri verificationURI, ManifestDigest manifestDigest, + ContainerEncryptionParams encryptionParams) { + throw new UnsupportedOperationException(); + } + + /** + * @hide + */ + @Override + public void installPackageWithVerificationAndEncryption(Uri packageURI, + PackageInstallObserver observer, int flags, String installerPackageName, + VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) { + throw new UnsupportedOperationException(); + } } diff --git a/tests/permission/src/com/android/framework/permission/tests/PmPermissionsTests.java b/tests/permission/src/com/android/framework/permission/tests/PmPermissionsTests.java index b690c45..93aa555 100644 --- a/tests/permission/src/com/android/framework/permission/tests/PmPermissionsTests.java +++ b/tests/permission/src/com/android/framework/permission/tests/PmPermissionsTests.java @@ -16,7 +16,7 @@ package com.android.framework.permission.tests; -import junit.framework.TestCase; +import android.app.PackageInstallObserver; import android.content.pm.PackageManager; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; @@ -68,10 +68,14 @@ public class PmPermissionsTests extends AndroidTestCase { * This test verifies that PackageManger.installPackage enforces permission * android.permission.INSTALL_PACKAGES */ + private class TestInstallObserver extends PackageInstallObserver { + } + @SmallTest public void testInstallPackage() { + TestInstallObserver observer = new TestInstallObserver(); try { - mPm.installPackage(null, null, 0, null); + mPm.installPackage(null, observer, 0, null); fail("PackageManager.installPackage" + "did not throw SecurityException as expected"); } catch (SecurityException e) { |