diff options
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) { |