Infrastructure to support package verifier

Allow a package verifier to approve or disapprove of a package being
installed.

Change-Id: Ibfea0f2b1aaa4ab1589a4e59f96144702b9bf94b
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 4cff12f..4b2a8d2 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -41,11 +41,11 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.UserInfo;
+import android.content.pm.ManifestDigest;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
-import android.os.Parcel;
 import android.os.Process;
 import android.os.RemoteException;
 import android.util.Log;
@@ -941,6 +941,27 @@
     }
 
     @Override
+    public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
+            int flags, String installerPackageName, Uri verificationURI,
+            ManifestDigest manifestDigest) {
+        try {
+            mPM.installPackageWithVerification(packageURI, observer, flags, installerPackageName,
+                    verificationURI, manifestDigest);
+        } catch (RemoteException e) {
+            // Should never happen!
+        }
+    }
+
+    @Override
+    public void verifyPendingInstall(int id, boolean verified, String failureMessage) {
+        try {
+            mPM.verifyPendingInstall(id, verified, failureMessage);
+        } catch (RemoteException e) {
+            // Should never happen!
+        }
+    }
+
+    @Override
     public void setInstallerPackageName(String targetPackage,
             String installerPackageName) {
         try {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 2579ced..8d6cee1 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1530,6 +1530,18 @@
     public static final String ACTION_PACKAGE_FIRST_LAUNCH = "android.intent.action.PACKAGE_FIRST_LAUNCH";
 
     /**
+     * Broadcast Action: Sent to the system package verifier when a package
+     * needs to be verified. The data contains the package URI.
+     * <p class="note">
+     * This is a protected intent that can only be sent by the system.
+     * </p>
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_PACKAGE_NEEDS_VERIFICATION = "android.intent.action.PACKAGE_NEEDS_VERIFICATION";
+
+    /**
      * Broadcast Action: Resources for a set of packages (which were
      * previously unavailable) are currently
      * available since the media on which they exist is available.
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 37b6822..d7607e3 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -30,6 +30,7 @@
 import android.content.pm.IPackageStatsObserver;
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.PackageInfo;
+import android.content.pm.ManifestDigest;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ProviderInfo;
 import android.content.pm.PermissionGroupInfo;
@@ -346,4 +347,10 @@
 
     UserInfo createUser(in String name, int flags);
     boolean removeUser(int userId);
+
+    void installPackageWithVerification(in Uri packageURI, in IPackageInstallObserver observer,
+            int flags, in String installerPackageName, in Uri verificationURI,
+            in ManifestDigest manifestDigest);
+
+    void verifyPendingInstall(int id, boolean verified, in String message);
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index dd684cd..5c641f1 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -23,6 +23,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentSender;
+import android.content.pm.ManifestDigest;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
@@ -289,11 +290,19 @@
     public static final int INSTALL_EXTERNAL = 0x00000008;
 
     /**
-    * Flag parameter for {@link #installPackage} to indicate that this
-    * package has to be installed on the sdcard.
-    * @hide
-    */
-   public static final int INSTALL_INTERNAL = 0x00000010;
+     * Flag parameter for {@link #installPackage} to indicate that this package
+     * has to be installed on the sdcard.
+     * @hide
+     */
+    public static final int INSTALL_INTERNAL = 0x00000010;
+
+    /**
+     * Flag parameter for {@link #installPackage} to indicate that this install
+     * was initiated via ADB.
+     *
+     * @hide
+     */
+    public static final int INSTALL_FROM_ADB = 0x00000020;
 
     /**
      * Flag parameter for
@@ -483,6 +492,30 @@
     public static final int INSTALL_FAILED_MEDIA_UNAVAILABLE = -20;
 
     /**
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
+     * the new package couldn't be installed because the verification timed out.
+     * @hide
+     */
+    public static final int INSTALL_FAILED_VERIFICATION_TIMEOUT = -21;
+
+    /**
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
+     * the new package couldn't be installed because the verification did not succeed.
+     * @hide
+     */
+    public static final int INSTALL_FAILED_VERIFICATION_FAILURE = -22;
+
+    /**
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
+     * the package changed from what the calling program expected.
+     * @hide
+     */
+    public static final int INSTALL_FAILED_PACKAGE_CHANGED = -23;
+
+    /**
      * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
      * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
      * if the parser was given a path that is not a file, or does not end with the expected
@@ -995,35 +1028,63 @@
             = "android.content.pm.CLEAN_EXTERNAL_STORAGE";
 
     /**
+     * Extra field name for the URI to a verification file. Passed to a package
+     * verifier.
+     *
+     * @hide
+     */
+    public static final String EXTRA_VERIFICATION_URI = "android.content.pm.extra.VERIFICATION_URI";
+
+    /**
+     * Extra field name for the ID of a package pending verification. Passed to
+     * a package verifier and is used to call back to
+     * {@link PackageManager#verifyPendingInstall(int, boolean)}
+     *
+     * @hide
+     */
+    public static final String EXTRA_VERIFICATION_ID = "android.content.pm.extra.VERIFICATION_ID";
+
+    /**
+     * Extra field name for the package identifier which is trying to install
+     * the package.
+     *
+     * @hide
+     */
+    public static final String EXTRA_VERIFICATION_INSTALLER_PACKAGE
+            = "android.content.pm.extra.VERIFICATION_INSTALLER_PACKAGE";
+
+    /**
+     * Extra field name for the requested install flags for a package pending
+     * verification. Passed to a package verifier.
+     *
+     * @hide
+     */
+    public static final String EXTRA_VERIFICATION_INSTALL_FLAGS
+            = "android.content.pm.extra.VERIFICATION_INSTALL_FLAGS";
+
+    /**
      * Retrieve overall information about an application package that is
      * installed on the system.
-     *
-     * <p>Throws {@link NameNotFoundException} if a package with the given
-     * name can not be found on the system.
+     * <p>
+     * Throws {@link NameNotFoundException} if a package with the given name can
+     * not be found on the system.
      *
      * @param packageName The full name (i.e. com.google.apps.contacts) of the
-     *                    desired package.
-
+     *            desired package.
      * @param flags Additional option flags. Use any combination of
-     * {@link #GET_ACTIVITIES},
-     * {@link #GET_GIDS},
-     * {@link #GET_CONFIGURATIONS},
-     * {@link #GET_INSTRUMENTATION},
-     * {@link #GET_PERMISSIONS},
-     * {@link #GET_PROVIDERS},
-     * {@link #GET_RECEIVERS},
-     * {@link #GET_SERVICES},
-     * {@link #GET_SIGNATURES},
-     * {@link #GET_UNINSTALLED_PACKAGES} to modify the data returned.
-     *
-     * @return Returns a PackageInfo object containing information about the package.
-     *         If flag GET_UNINSTALLED_PACKAGES is set and  if the package is not
-     *         found in the list of installed applications, the package information is
-     *         retrieved from the list of uninstalled applications(which includes
-     *         installed applications as well as applications
-     *         with data directory ie applications which had been
+     *            {@link #GET_ACTIVITIES}, {@link #GET_GIDS},
+     *            {@link #GET_CONFIGURATIONS}, {@link #GET_INSTRUMENTATION},
+     *            {@link #GET_PERMISSIONS}, {@link #GET_PROVIDERS},
+     *            {@link #GET_RECEIVERS}, {@link #GET_SERVICES},
+     *            {@link #GET_SIGNATURES}, {@link #GET_UNINSTALLED_PACKAGES} to
+     *            modify the data returned.
+     * @return Returns a PackageInfo object containing information about the
+     *         package. If flag GET_UNINSTALLED_PACKAGES is set and if the
+     *         package is not found in the list of installed applications, the
+     *         package information is retrieved from the list of uninstalled
+     *         applications(which includes installed applications as well as
+     *         applications with data directory ie applications which had been
      *         deleted with DONT_DELTE_DATA flag set).
-     *
      * @see #GET_ACTIVITIES
      * @see #GET_GIDS
      * @see #GET_CONFIGURATIONS
@@ -1034,7 +1095,6 @@
      * @see #GET_SERVICES
      * @see #GET_SIGNATURES
      * @see #GET_UNINSTALLED_PACKAGES
-     *
      */
     public abstract PackageInfo getPackageInfo(String packageName, int flags)
             throws NameNotFoundException;
@@ -2061,6 +2121,46 @@
             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 IPackageInstallObserver#packageInstalled(String, int)}
+     *            will be called when that happens. observer may be null to
+     *            indicate that no callback is desired.
+     * @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.
+     * @hide
+     */
+    public abstract void installPackageWithVerification(Uri packageURI,
+            IPackageInstallObserver observer, int flags, String installerPackageName,
+            Uri verificationURI, ManifestDigest manifestDigest);
+
+    /**
+     * Allows a package listening to the
+     * {@link Intent#ACTION_PACKAGE_NEEDS_VERIFICATION package verification
+     * broadcast} to respond to the package manager.
+     *
+     * @param id pending package identifier as passed via the
+     *            {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra
+     * @param verified whether the package was verified as valid
+     * @param failureMessage if verification was false, this is the error
+     *            message that may be shown to the user
+     * @hide
+     */
+    public abstract void verifyPendingInstall(int id, boolean verified, String failureMessage);
+
+    /**
      * Change the installer associated with a given package.  There are limitations
      * on how the installer package can be changed; in particular:
      * <ul>
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f8702b9..de06f20 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3960,6 +3960,12 @@
         public static final String WEB_AUTOFILL_QUERY_URL =
             "web_autofill_query_url";
 
+        /** Whether package verification is enabled. {@hide} */
+        public static final String PACKAGE_VERIFIER_ENABLE = "verifier_enable";
+
+        /** Timeout for package verification. {@hide} */
+        public static final String PACKAGE_VERIFIER_TIMEOUT = "verifier_timeout";
+
         /**
          * @hide
          */
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b9868db..2dbb0b2 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -42,6 +42,7 @@
     <protected-broadcast android:name="android.intent.action.PACKAGE_RESTARTED" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_DATA_CLEARED" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_FIRST_LAUNCH" />
+    <protected-broadcast android:name="android.intent.action.PACKAGE_NEEDS_VERIFICATION" />
     <protected-broadcast android:name="android.intent.action.UID_REMOVED" />
     <protected-broadcast android:name="android.intent.action.CONFIGURATION_CHANGED" />
     <protected-broadcast android:name="android.intent.action.LOCALE_CHANGED" />
@@ -1429,6 +1430,24 @@
           android:protectionLevel="signature" />
     <uses-permission android:name="android.intent.category.MASTER_CLEAR.permission.C2D_MESSAGE"/>
 
+    <!-- Package verifier needs to have this permission before the PackageManager will
+         trust it to verify packages.
+         @hide
+    -->
+    <permission android:name="android.permission.PACKAGE_VERIFICATION_AGENT"
+        android:label="@string/permlab_packageVerificationAgent"
+        android:description="@string/permdesc_packageVerificationAgent"
+        android:protectionLevel="signatureOrSystem" />
+
+    <!-- Must be required by package verifier receiver, to ensure that only the
+         system can interact with it.
+         @hide
+    -->
+    <permission android:name="android.permission.BIND_PACKAGE_VERIFIER"
+        android:label="@string/permlab_bindPackageVerifier"
+        android:description="@string/permdesc_bindPackageVerifier"
+        android:protectionLevel="signature" />
+
     <!-- The system process is explicitly the only one allowed to launch the
          confirmation UI for full backup/restore -->
     <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 7d6d25c..c70e3d2 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2181,6 +2181,22 @@
         Browser\'s geolocation permissions. Malicious applications
         can use this to allow sending location information to arbitrary web sites.</string>
 
+    <!-- Title of an application permission which allows the application to verify whether
+         a different package is able to be installed by some internal logic. [CHAR LIMIT=40] -->
+    <string name="permlab_packageVerificationAgent">verify packages</string>
+    <!-- Description of an application permission which allows the application to verify whether
+         a different package is able to be installed by some internal heuristic. [CHAR LIMIT=NONE] -->
+    <string name="permdesc_packageVerificationAgent">Allows the application to verify a package is
+        installable.</string>
+
+    <!-- Title of an application permission which allows the application to verify whether
+         a different package is able to be installed by some internal heuristic. [CHAR LIMIT=40] -->
+    <string name="permlab_bindPackageVerifier">bind to a package verifier</string>
+    <!-- Description of an application permission which allows the application to verify whether
+         a different package is able to be installed by some internal heuristic. [CHAR LIMIT=NONE] -->
+    <string name="permdesc_bindPackageVerifier">Allows the holder to make requests of
+        package verifiers. Should never be needed for normal applications.</string>
+
     <!-- If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. Text in the save password dialog, asking if the browser should remember a password. -->
     <string name="save_password_message">Do you want the browser to remember this password?</string>
     <!-- If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. Button in the save password dialog, saying not to remember this password. -->