diff options
-rw-r--r-- | api/current.xml | 32 | ||||
-rw-r--r-- | core/java/android/app/ApplicationPackageManager.java | 10 | ||||
-rw-r--r-- | core/java/android/content/pm/IPackageManager.aidl | 2 | ||||
-rw-r--r-- | core/java/android/content/pm/PackageManager.java | 18 | ||||
-rw-r--r-- | services/java/com/android/server/PackageManagerService.java | 74 | ||||
-rw-r--r-- | test-runner/src/android/test/mock/MockPackageManager.java | 6 |
6 files changed, 141 insertions, 1 deletions
diff --git a/api/current.xml b/api/current.xml index 9422552..2964fb0 100644 --- a/api/current.xml +++ b/api/current.xml @@ -58662,6 +58662,21 @@ <parameter name="flags" type="int"> </parameter> </method> +<method name="setInstallerPackageName" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="targetPackage" type="java.lang.String"> +</parameter> +<parameter name="installerPackageName" type="java.lang.String"> +</parameter> +</method> <field name="COMPONENT_ENABLED_STATE_DEFAULT" type="int" transient="false" @@ -175729,6 +175744,21 @@ <parameter name="flags" type="int"> </parameter> </method> +<method name="setInstallerPackageName" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="targetPackage" type="java.lang.String"> +</parameter> +<parameter name="installerPackageName" type="java.lang.String"> +</parameter> +</method> <method name="setPackageObbPath" return="void" abstract="false" @@ -248151,7 +248181,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="arg0" type="T"> +<parameter name="t" type="T"> </parameter> </method> </interface> diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index ce9501a..abb26e3 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -914,6 +914,16 @@ final class ApplicationPackageManager extends PackageManager { } @Override + public void setInstallerPackageName(String targetPackage, + String installerPackageName) { + try { + mPM.setInstallerPackageName(targetPackage, installerPackageName); + } catch (RemoteException e) { + // Should never happen! + } + } + + @Override public void movePackage(String packageName, IPackageMoveObserver observer, int flags) { try { mPM.movePackage(packageName, observer, flags); diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 4cff3bb..d01a68a 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -158,6 +158,8 @@ interface IPackageManager { void finishPackageInstall(int token); + void setInstallerPackageName(in String targetPackage, in String installerPackageName); + /** * Delete a package. * diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index b5d1653..ac7a95a 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1918,6 +1918,24 @@ public abstract class PackageManager { String installerPackageName); /** + * Change the installer associated with a given package. There are limitations + * on how the installer package can be changed; in particular: + * <ul> + * <li> A SecurityException will be thrown if <var>installerPackageName</var> + * is not signed with the same certificate as the calling application. + * <li> A SecurityException will be thrown if <var>targetPackage</var> already + * has an installer package, and that installer package is not signed with + * the same certificate as the calling application. + * </ul> + * + * @param targetPackage The installed package whose installer will be changed. + * @param installerPackageName The package name of the new installer. May be + * null to clear the association. + */ + public abstract void setInstallerPackageName(String targetPackage, + String installerPackageName); + + /** * Attempts to delete a package. Since this may take a little while, the result will * be posted back to the given observer. A deletion will fail if the calling context * lacks the {@link android.Manifest.permission#DELETE_PACKAGES} permission, if the diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index a0a1974..c121808 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -4578,6 +4578,80 @@ class PackageManagerService extends IPackageManager.Stub { mHandler.sendMessage(msg); } + public void setInstallerPackageName(String targetPackage, + String installerPackageName) { + PackageSetting pkgSetting; + final int uid = Binder.getCallingUid(); + final int permission = mContext.checkCallingPermission( + android.Manifest.permission.INSTALL_PACKAGES); + final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED); + synchronized (mPackages) { + PackageSetting targetPackageSetting = mSettings.mPackages.get(targetPackage); + if (targetPackageSetting == null) { + throw new IllegalArgumentException("Unknown target package: " + targetPackage); + } + + PackageSetting installerPackageSetting; + if (installerPackageName != null) { + installerPackageSetting = mSettings.mPackages.get(installerPackageName); + if (installerPackageSetting == null) { + throw new IllegalArgumentException("Unknown installer package: " + + installerPackageName); + } + } else { + installerPackageSetting = null; + } + + Signature[] callerSignature; + Object obj = mSettings.getUserIdLP(uid); + if (obj != null) { + if (obj instanceof SharedUserSetting) { + callerSignature = ((SharedUserSetting)obj).signatures.mSignatures; + } else if (obj instanceof PackageSetting) { + callerSignature = ((PackageSetting)obj).signatures.mSignatures; + } else { + throw new SecurityException("Bad object " + obj + " for uid " + uid); + } + } else { + throw new SecurityException("Unknown calling uid " + uid); + } + + // Verify: can't set installerPackageName to a package that is + // not signed with the same cert as the caller. + if (installerPackageSetting != null) { + if (checkSignaturesLP(callerSignature, + installerPackageSetting.signatures.mSignatures) + != PackageManager.SIGNATURE_MATCH) { + throw new SecurityException( + "Caller does not have same cert as new installer package " + + installerPackageName); + } + } + + // Verify: if target already has an installer package, it must + // be signed with the same cert as the caller. + if (targetPackageSetting.installerPackageName != null) { + PackageSetting setting = mSettings.mPackages.get( + targetPackageSetting.installerPackageName); + // If the currently set package isn't valid, then it's always + // okay to change it. + if (setting != null) { + if (checkSignaturesLP(callerSignature, + setting.signatures.mSignatures) + != PackageManager.SIGNATURE_MATCH) { + throw new SecurityException( + "Caller does not have same cert as old installer package " + + targetPackageSetting.installerPackageName); + } + } + } + + // Okay! + targetPackageSetting.installerPackageName = installerPackageName; + scheduleWriteSettingsLocked(); + } + } + public void setPackageObbPath(String packageName, String path) { if (DEBUG_OBB) Log.v(TAG, "Setting .obb path for " + packageName + " to: " + path); diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index f0cbaa0..615870b 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -341,6 +341,12 @@ public class MockPackageManager extends PackageManager { throw new UnsupportedOperationException(); } + @Override + public void setInstallerPackageName(String targetPackage, + String installerPackageName) { + throw new UnsupportedOperationException(); + } + /** * @hide - to match hiding in superclass */ |