diff options
-rw-r--r-- | cmds/pm/src/com/android/commands/pm/Pm.java | 23 | ||||
-rw-r--r-- | core/java/android/app/ApplicationPackageManager.java | 23 | ||||
-rw-r--r-- | core/java/android/content/Intent.java | 12 | ||||
-rw-r--r-- | core/java/android/content/pm/IPackageManager.aidl | 7 | ||||
-rw-r--r-- | core/java/android/content/pm/PackageManager.java | 158 | ||||
-rw-r--r-- | core/java/android/provider/Settings.java | 6 | ||||
-rw-r--r-- | core/res/AndroidManifest.xml | 19 | ||||
-rwxr-xr-x | core/res/res/values/strings.xml | 16 | ||||
-rw-r--r-- | services/java/com/android/server/pm/PackageManagerService.java | 298 | ||||
-rw-r--r-- | test-runner/src/android/test/mock/MockPackageManager.java | 19 |
10 files changed, 506 insertions, 75 deletions
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index c980715..0ec007c 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -772,18 +772,33 @@ public final class Pm { } } - String apkFilePath = nextArg(); + final Uri apkURI; + final Uri verificationURI; + + // Populate apkURI, must be present + final String apkFilePath = nextArg(); System.err.println("\tpkg: " + apkFilePath); - if (apkFilePath == null) { + if (apkFilePath != null) { + apkURI = Uri.fromFile(new File(apkFilePath)); + } else { System.err.println("Error: no package specified"); showUsage(); return; } + // Populate verificationURI, optionally present + final String verificationFilePath = nextArg(); + if (verificationFilePath != null) { + System.err.println("\tver: " + verificationFilePath); + verificationURI = Uri.fromFile(new File(verificationFilePath)); + } else { + verificationURI = null; + } + PackageInstallObserver obs = new PackageInstallObserver(); try { - mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags, - installerPackageName); + mPm.installPackageWithVerification(apkURI, obs, installFlags, installerPackageName, + verificationURI, null); synchronized (obs) { while (!obs.finished) { 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.ProviderInfo; 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 @@ final class ApplicationPackageManager extends PackageManager { } @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 class Intent implements Parcelable, Cloneable { 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.IPackageMoveObserver; 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 @@ interface IPackageManager { 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.Context; 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 abstract class PackageManager { 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 abstract class PackageManager { 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 @@ public abstract class PackageManager { = "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 @@ public abstract class PackageManager { * @see #GET_SERVICES * @see #GET_SIGNATURES * @see #GET_UNINSTALLED_PACKAGES - * */ public abstract PackageInfo getPackageInfo(String packageName, int flags) throws NameNotFoundException; @@ -2061,6 +2121,46 @@ public abstract class PackageManager { 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 final class Settings { 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. --> diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 177cf41..abb62de 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -38,6 +38,7 @@ import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.app.admin.IDevicePolicyManager; import android.app.backup.IBackupManager; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.IIntentReceiver; @@ -69,6 +70,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.Signature; import android.content.pm.UserInfo; +import android.content.pm.ManifestDigest; import android.net.Uri; import android.os.Binder; import android.os.Build; @@ -188,6 +190,17 @@ public class PackageManagerService extends IPackageManager.Stub { static final int REMOVE_CHATTY = 1<<16; + /** + * Whether verification is enabled by default. + */ + private static final boolean DEFAULT_VERIFY_ENABLE = true; + + /** + * The default maximum time to wait for the verification agent to return in + * milliseconds. + */ + private static final long DEFAULT_VERIFICATION_TIMEOUT = 60 * 1000; + static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer"; static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName( @@ -333,6 +346,12 @@ public class PackageManagerService extends IPackageManager.Stub { // Broadcast actions that are only available to the system. final HashSet<String> mProtectedBroadcasts = new HashSet<String>(); + /** List of packages waiting for verification. */ + final SparseArray<InstallArgs> mPendingVerification = new SparseArray<InstallArgs>(); + + /** Token for keys in mPendingVerification. */ + private int mPendingVerificationToken = 0; + boolean mSystemReady; boolean mSafeMode; boolean mHasSystemUidErrors; @@ -364,6 +383,8 @@ public class PackageManagerService extends IPackageManager.Stub { static final int UPDATED_MEDIA_STATUS = 12; static final int WRITE_SETTINGS = 13; static final int WRITE_STOPPED_PACKAGES = 14; + static final int PACKAGE_VERIFIED = 15; + static final int CHECK_PENDING_VERIFICATION = 16; static final int WRITE_SETTINGS_DELAY = 10*1000; // 10 seconds @@ -444,10 +465,10 @@ public class PackageManagerService extends IPackageManager.Stub { void doHandleMessage(Message msg) { switch (msg.what) { case INIT_COPY: { - if (DEBUG_SD_INSTALL) Log.i(TAG, "init_copy"); + if (DEBUG_INSTALL) Slog.i(TAG, "init_copy"); HandlerParams params = (HandlerParams) msg.obj; int idx = mPendingInstalls.size(); - if (DEBUG_SD_INSTALL) Log.i(TAG, "idx=" + idx); + if (DEBUG_INSTALL) Slog.i(TAG, "idx=" + idx); // If a bind was already initiated we dont really // need to do anything. The pending install // will be processed later on. @@ -474,7 +495,7 @@ public class PackageManagerService extends IPackageManager.Stub { break; } case MCS_BOUND: { - if (DEBUG_SD_INSTALL) Log.i(TAG, "mcs_bound"); + if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound"); if (msg.obj != null) { mContainerService = (IMediaContainerService) msg.obj; } @@ -525,8 +546,8 @@ public class PackageManagerService extends IPackageManager.Stub { } break; } - case MCS_RECONNECT : { - if (DEBUG_SD_INSTALL) Log.i(TAG, "mcs_reconnect"); + case MCS_RECONNECT: { + if (DEBUG_INSTALL) Slog.i(TAG, "mcs_reconnect"); if (mPendingInstalls.size() > 0) { if (mBound) { disconnectService(); @@ -543,27 +564,31 @@ public class PackageManagerService extends IPackageManager.Stub { } break; } - case MCS_UNBIND : { + case MCS_UNBIND: { // If there is no actual work left, then time to unbind. - if (DEBUG_SD_INSTALL) Log.i(TAG, "mcs_unbind"); - if (mPendingInstalls.size() == 0) { + if (DEBUG_INSTALL) Slog.i(TAG, "mcs_unbind"); + + if (mPendingInstalls.size() == 0 && mPendingVerification.size() == 0) { if (mBound) { + if (DEBUG_INSTALL) Slog.i(TAG, "calling disconnectService()"); + disconnectService(); } - } else { + } else if (mPendingInstalls.size() > 0) { // There are more pending requests in queue. // Just post MCS_BOUND message to trigger processing // of next pending install. mHandler.sendEmptyMessage(MCS_BOUND); } + break; } case MCS_GIVE_UP: { - if (DEBUG_SD_INSTALL) Log.i(TAG, "mcs_giveup too many retries"); + if (DEBUG_INSTALL) Slog.i(TAG, "mcs_giveup too many retries"); mPendingInstalls.remove(0); break; } - case SEND_PENDING_BROADCAST : { + case SEND_PENDING_BROADCAST: { String packages[]; ArrayList<String> components[]; int size = 0; @@ -707,6 +732,52 @@ public class PackageManagerService extends IPackageManager.Stub { } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); } break; + case CHECK_PENDING_VERIFICATION: { + final int verificationId = msg.arg1; + final InstallArgs args = mPendingVerification.get(verificationId); + + if (args != null) { + Slog.i(TAG, "Validation timed out for " + args.packageURI.toString()); + mPendingVerification.remove(verificationId); + + int ret = PackageManager.INSTALL_FAILED_VERIFICATION_TIMEOUT; + processPendingInstall(args, ret); + + mHandler.sendEmptyMessage(MCS_UNBIND); + } + + break; + } + case PACKAGE_VERIFIED: { + final int verificationId = msg.arg1; + final boolean verified = msg.arg2 == 1 ? true : false; + + final InstallArgs args = mPendingVerification.get(verificationId); + if (args == null) { + Slog.w(TAG, "Invalid validation token " + verificationId + " received"); + break; + } + + mPendingVerification.remove(verificationId); + + int ret; + if (verified) { + ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; + try { + ret = args.copyApk(mContainerService, true); + } catch (RemoteException e) { + Slog.e(TAG, "Could not contact the ContainerService"); + } + } else { + ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE; + } + + processPendingInstall(args, ret); + + mHandler.sendEmptyMessage(MCS_UNBIND); + + break; + } } } } @@ -4693,12 +4764,45 @@ public class PackageManagerService extends IPackageManager.Stub { public void installPackage( final Uri packageURI, final IPackageInstallObserver observer, final int flags, final String installerPackageName) { + installPackageWithVerification(packageURI, observer, flags, installerPackageName, null, + null); + } + + @Override + public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer, + int flags, String installerPackageName, Uri verificationURI, + ManifestDigest manifestDigest) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null); + + final int uid = Binder.getCallingUid(); + + final int filteredFlags; + + if (uid == Process.SHELL_UID || uid == 0) { + if (DEBUG_INSTALL) { + Slog.v(TAG, "Install from ADB"); + } + filteredFlags = flags | PackageManager.INSTALL_FROM_ADB; + } else { + filteredFlags = flags & ~PackageManager.INSTALL_FROM_ADB; + } + + final Message msg = mHandler.obtainMessage(INIT_COPY); + msg.obj = new InstallParams(packageURI, observer, filteredFlags, installerPackageName, + verificationURI, manifestDigest); + mHandler.sendMessage(msg); + } + + @Override + public void verifyPendingInstall(int id, boolean verified, String message) + throws RemoteException { mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.INSTALL_PACKAGES, null); + android.Manifest.permission.PACKAGE_VERIFICATION_AGENT, null); - Message msg = mHandler.obtainMessage(INIT_COPY); - msg.obj = new InstallParams(packageURI, observer, flags, - installerPackageName); + final Message msg = mHandler.obtainMessage(PACKAGE_VERIFIED); + msg.arg1 = id; + msg.arg2 = verified ? 1 : 0; + msg.obj = message; mHandler.sendMessage(msg); } @@ -4713,6 +4817,28 @@ public class PackageManagerService extends IPackageManager.Stub { mHandler.sendMessage(msg); } + /** + * Get the verification agent timeout. + * + * @return verification timeout in milliseconds + */ + private long getVerificationTimeout() { + return android.provider.Settings.Secure.getLong(mContext.getContentResolver(), + android.provider.Settings.Secure.PACKAGE_VERIFIER_TIMEOUT, + DEFAULT_VERIFICATION_TIMEOUT); + } + + /** + * Check whether or not package verification has been enabled. + * + * @return true if verification should be performed + */ + private boolean isVerificationEnabled() { + return android.provider.Settings.Secure.getInt(mContext.getContentResolver(), + android.provider.Settings.Secure.PACKAGE_VERIFIER_ENABLE, + DEFAULT_VERIFY_ENABLE ? 1 : 0) == 1 ? true : false; + } + public void setInstallerPackageName(String targetPackage, String installerPackageName) { final int uid = Binder.getCallingUid(); // writer @@ -4856,15 +4982,21 @@ public class PackageManagerService extends IPackageManager.Stub { }); } - abstract class HandlerParams { - final static int MAX_RETRIES = 4; - int retry = 0; + private abstract class HandlerParams { + private static final int MAX_RETRIES = 4; + + /** + * Number of times startCopy() has been attempted and had a non-fatal + * error. + */ + private int mRetries = 0; + final boolean startCopy() { boolean res; try { - if (DEBUG_SD_INSTALL) Log.i(TAG, "startCopy"); - retry++; - if (retry > MAX_RETRIES) { + if (DEBUG_INSTALL) Slog.i(TAG, "startCopy"); + + if (++mRetries > MAX_RETRIES) { Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up"); mHandler.sendEmptyMessage(MCS_GIVE_UP); handleServiceError(); @@ -4874,7 +5006,7 @@ public class PackageManagerService extends IPackageManager.Stub { res = true; } } catch (RemoteException e) { - if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting install MCS_RECONNECT"); + if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT"); mHandler.sendEmptyMessage(MCS_RECONNECT); res = false; } @@ -4883,10 +5015,11 @@ public class PackageManagerService extends IPackageManager.Stub { } final void serviceError() { - if (DEBUG_SD_INSTALL) Log.i(TAG, "serviceError"); + if (DEBUG_INSTALL) Slog.i(TAG, "serviceError"); handleServiceError(); handleReturnCode(); } + abstract void handleStartCopy() throws RemoteException; abstract void handleServiceError(); abstract void handleReturnCode(); @@ -4969,15 +5102,20 @@ public class PackageManagerService extends IPackageManager.Stub { int flags; final Uri packageURI; final String installerPackageName; + final Uri verificationURI; + final ManifestDigest manifestDigest; private InstallArgs mArgs; private int mRet; + InstallParams(Uri packageURI, IPackageInstallObserver observer, int flags, - String installerPackageName) { + String installerPackageName, Uri verificationURI, ManifestDigest manifestDigest) { this.packageURI = packageURI; this.flags = flags; this.observer = observer; this.installerPackageName = installerPackageName; + this.verificationURI = verificationURI; + this.manifestDigest = manifestDigest; } private int installLocationPolicy(PackageInfoLite pkgLite, int flags) { @@ -5102,13 +5240,70 @@ public class PackageManagerService extends IPackageManager.Stub { } } } - // Create the file args now. - mArgs = createInstallArgs(this); + + final InstallArgs args = createInstallArgs(this); if (ret == PackageManager.INSTALL_SUCCEEDED) { - // Create copy only if we are not in an erroneous state. - // Remote call to initiate copy using temporary file - ret = mArgs.copyApk(mContainerService, true); + /* + * Determine if we have any installed package verifiers. If we + * do, then we'll defer to them to verify the packages. + */ + final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION, + packageURI); + verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + + final List<ResolveInfo> receivers = queryIntentReceivers(verification, null, + PackageManager.GET_DISABLED_COMPONENTS); + if (isVerificationEnabled() && receivers.size() > 0) { + if (DEBUG_INSTALL) { + Slog.d(TAG, "Found " + receivers.size() + " verifiers for intent " + + verification.toString()); + } + + final int verificationId = mPendingVerificationToken++; + + verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId); + + verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE, + installerPackageName); + + verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS, flags); + + if (verificationURI != null) { + verification.putExtra(PackageManager.EXTRA_VERIFICATION_URI, + verificationURI); + } + + mPendingVerification.append(verificationId, args); + + /* + * Send the intent to the registered verification agents, + * but only start the verification timeout after the target + * BroadcastReceivers have run. + */ + mContext.sendOrderedBroadcast(verification, + android.Manifest.permission.PACKAGE_VERIFICATION_AGENT, + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final Message msg = mHandler + .obtainMessage(CHECK_PENDING_VERIFICATION); + msg.arg1 = verificationId; + mHandler.sendMessageDelayed(msg, getVerificationTimeout()); + } + }, + null, 0, null, null); + } else { + // Create copy only if we are not in an erroneous state. + // Remote call to initiate copy using temporary file + mArgs = args; + ret = args.copyApk(mContainerService, true); + } + } else { + // There was an error, so let the processPendingInstall() break + // the bad news... uh, through a call in handleReturnCode() + mArgs = args; } + mRet = ret; } @@ -5233,14 +5428,15 @@ public class PackageManagerService extends IPackageManager.Stub { final int flags; final Uri packageURI; final String installerPackageName; + final ManifestDigest manifestDigest; - InstallArgs(Uri packageURI, - IPackageInstallObserver observer, int flags, - String installerPackageName) { + InstallArgs(Uri packageURI, IPackageInstallObserver observer, int flags, + String installerPackageName, ManifestDigest manifestDigest) { this.packageURI = packageURI; this.flags = flags; this.observer = observer; this.installerPackageName = installerPackageName; + this.manifestDigest = manifestDigest; } abstract void createCopyFile(); @@ -5265,12 +5461,12 @@ public class PackageManagerService extends IPackageManager.Stub { boolean created = false; FileInstallArgs(InstallParams params) { - super(params.packageURI, params.observer, - params.flags, params.installerPackageName); + super(params.packageURI, params.observer, params.flags, params.installerPackageName, + params.manifestDigest); } FileInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath) { - super(null, null, 0, null); + super(null, null, 0, null, null); File codeFile = new File(fullCodePath); installDir = codeFile.getParentFile(); codeFileName = fullCodePath; @@ -5279,7 +5475,7 @@ public class PackageManagerService extends IPackageManager.Stub { } FileInstallArgs(Uri packageURI, String pkgName, String dataDir) { - super(packageURI, null, 0, null); + super(packageURI, null, 0, null, null); installDir = isFwdLocked() ? mDrmAppPrivateInstallDir : mAppInstallDir; String apkName = getNextCodePath(null, pkgName, ".apk"); codeFileName = new File(installDir, apkName + ".apk").getPath(); @@ -5509,12 +5705,12 @@ public class PackageManagerService extends IPackageManager.Stub { String libraryPath; SdInstallArgs(InstallParams params) { - super(params.packageURI, params.observer, - params.flags, params.installerPackageName); + super(params.packageURI, params.observer, params.flags, params.installerPackageName, + params.manifestDigest); } SdInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath) { - super(null, null, PackageManager.INSTALL_EXTERNAL, null); + super(null, null, PackageManager.INSTALL_EXTERNAL, null, null); // Extract cid from fullCodePath int eidx = fullCodePath.lastIndexOf("/"); String subStr1 = fullCodePath.substring(0, eidx); @@ -5524,13 +5720,13 @@ public class PackageManagerService extends IPackageManager.Stub { } SdInstallArgs(String cid) { - super(null, null, PackageManager.INSTALL_EXTERNAL, null); + super(null, null, PackageManager.INSTALL_EXTERNAL, null, null); this.cid = cid; setCachePath(PackageHelper.getSdDir(cid)); } SdInstallArgs(Uri packageURI, String cid) { - super(packageURI, null, PackageManager.INSTALL_EXTERNAL, null); + super(packageURI, null, PackageManager.INSTALL_EXTERNAL, null, null); this.cid = cid; } @@ -6152,6 +6348,26 @@ public class PackageManagerService extends IPackageManager.Stub { res.returnCode = pp.getParseError(); return; } + + /* If the installer passed in a manifest digest, compare it now. */ + if (args.manifestDigest != null) { + if (DEBUG_INSTALL) { + final String parsedManifest = pkg.manifestDigest == null ? "null" + : pkg.manifestDigest.toString(); + Slog.d(TAG, "Comparing manifests: " + args.manifestDigest.toString() + " vs. " + + parsedManifest); + } + + if (!args.manifestDigest.equals(pkg.manifestDigest)) { + res.returnCode = PackageManager.INSTALL_FAILED_PACKAGE_CHANGED; + return; + } + } else if (DEBUG_INSTALL) { + final String parsedManifest = pkg.manifestDigest == null + ? "null" : pkg.manifestDigest.toString(); + Slog.d(TAG, "manifestDigest was not present, but parser got: " + parsedManifest); + } + // Get rid of all references to package scan path via parser. pp = null; String oldCodePath = null; diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index d84f1e5..501c219 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -37,6 +37,7 @@ import android.content.pm.ProviderInfo; 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; @@ -533,4 +534,22 @@ public class MockPackageManager extends PackageManager { public void updateUserFlags(int id, int flags) { throw new UnsupportedOperationException(); } + + /** + * @hide + */ + @Override + public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer, + int flags, String installerPackageName, Uri verificationURI, + ManifestDigest manifestDigest) { + throw new UnsupportedOperationException(); + } + + /** + * @hide + */ + @Override + public void verifyPendingInstall(int id, boolean verified, String failureMessage) { + throw new UnsupportedOperationException(); + } } |