Merge "Infrastructure to support package verifier"

This commit is contained in:
Kenny Root
2011-08-16 08:35:53 -07:00
committed by Android (Google) Code Review
10 changed files with 507 additions and 76 deletions

View File

@@ -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) {

View File

@@ -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;
@@ -940,6 +940,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) {

View File

@@ -1529,6 +1529,18 @@ public class Intent implements Parcelable, Cloneable {
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
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

View File

@@ -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);
}

View File

@@ -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
@@ -482,6 +491,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)}
@@ -994,36 +1027,64 @@ public abstract class PackageManager {
public static final String ACTION_CLEAN_EXTERNAL_STORAGE
= "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;
@@ -2060,6 +2120,46 @@ public abstract class PackageManager {
Uri packageURI, IPackageInstallObserver 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 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:

View File

@@ -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
*/

View File

@@ -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"/>

View File

@@ -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. -->

View File

@@ -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) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INSTALL_PACKAGES, null);
installPackageWithVerification(packageURI, observer, flags, installerPackageName, null,
null);
}
Message msg = mHandler.obtainMessage(INIT_COPY);
msg.obj = new InstallParams(packageURI, observer, flags,
installerPackageName);
@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.PACKAGE_VERIFICATION_AGENT, null);
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;

View File

@@ -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();
}
}