Merge "Fix attribute extraction, use color attrs in Quantum drawables"
diff --git a/Android.mk b/Android.mk
index 33e64d0..eeec9458 100644
--- a/Android.mk
+++ b/Android.mk
@@ -120,6 +120,7 @@
 	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..f92bed2 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.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.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,21 @@
         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_EXISTING_PERMISSION);
+                    extraPackage = extras.getString(PackageManager.EXTRA_EXISTING_PACKAGE);
+                }
                 notifyAll();
             }
         }
@@ -717,7 +725,8 @@
      * 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 +741,16 @@
                         // 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 +974,7 @@
             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 +988,7 @@
                     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.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 @@
     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 @@
             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 @@
             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..78c2ec9
--- /dev/null
+++ b/core/java/android/app/PackageInstallObserver.java
@@ -0,0 +1,48 @@
+/*
+ * 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.IBinder;
+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 the install result
+     * @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..eff7bfe
--- /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.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 @@
             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..ca66bae 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -19,6 +19,7 @@
 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 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 @@
             = "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_EXISTING_PACKAGE
+            = "android.content.pm.extra.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_EXISTING_PERMISSION
+            = "android.content.pm.extra.EXISTING_PERMISSION";
+
+    /**
      * Retrieve overall information about an application package that is
      * installed on the system.
      * <p>
@@ -2752,11 +2785,14 @@
      * '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,8 +2808,104 @@
      * @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}
+     *            .
+     * @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
+     * @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,
+            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 IPackageInstallObserver#packageInstalled(String, 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
+     * @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}
      *            .
@@ -2791,7 +2923,7 @@
      * @hide
      */
     public abstract void installPackageWithVerification(Uri packageURI,
-            IPackageInstallObserver observer, int flags, String installerPackageName,
+            PackageInstallObserver observer, int flags, String installerPackageName,
             Uri verificationURI, ManifestDigest manifestDigest,
             ContainerEncryptionParams encryptionParams);
 
@@ -2802,11 +2934,9 @@
      *
      * @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 IPackageInstallObserver#packageInstalled(String, int)}
-     *            will be called when that happens. observer may be null to
-     *            indicate that no callback is desired.
+     * @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}
      *            .
@@ -2822,9 +2952,8 @@
      * @hide
      */
     public abstract void installPackageWithVerificationAndEncryption(Uri packageURI,
-            IPackageInstallObserver observer, int flags, String installerPackageName,
-            VerificationParams verificationParams,
-            ContainerEncryptionParams encryptionParams);
+            PackageInstallObserver observer, int flags, String installerPackageName,
+            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams);
 
     /**
      * If there is already an application with the given package name installed
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 @@
                 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 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.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 @@
         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 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 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..ed54e47c 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.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 @@
 
     // 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 @@
                                 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,19 @@
         }
     }
 
+    Bundle extrasForInstallResult(PackageInstalledInfo res) {
+        Bundle extras = null;
+        switch (res.returnCode) {
+            case PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION: {
+                extras = new Bundle();
+                extras.putString(PackageManager.EXTRA_EXISTING_PERMISSION, res.origPermission);
+                extras.putString(PackageManager.EXTRA_EXISTING_PACKAGE, res.origPackage);
+                break;
+            }
+        }
+        return extras;
+    }
+
     void scheduleWriteSettingsLocked() {
         if (!mHandler.hasMessages(WRITE_SETTINGS)) {
             mHandler.sendEmptyMessageDelayed(WRITE_SETTINGS, WRITE_SETTINGS_DELAY);
@@ -6772,18 +6794,24 @@
         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 +6820,67 @@
             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 +6907,8 @@
         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 +7597,7 @@
 
     class InstallParams extends HandlerParams {
         final IPackageInstallObserver observer;
+        final IPackageInstallObserver2 observer2;
         int flags;
 
         private final Uri mPackageURI;
@@ -7533,13 +7609,14 @@
         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 +8186,7 @@
 
     static abstract class InstallArgs {
         final IPackageInstallObserver observer;
+        final IPackageInstallObserver2 observer2;
         // Always refers to PackageManager flags only
         final int flags;
         final Uri packageURI;
@@ -8116,12 +8194,14 @@
         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 +8258,13 @@
         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 +8273,7 @@
         }
 
         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 +8594,14 @@
         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 +8613,7 @@
         }
 
         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 +8621,7 @@
         }
 
         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 +8955,10 @@
         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 +9383,22 @@
         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) {
+                    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 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();
+    }
 }