diff --git a/core/api/current.txt b/core/api/current.txt index 8b7db18980327..20530e0d11dee 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -12258,6 +12258,7 @@ package android.content.pm { method @NonNull public java.util.List queryProviderProperty(@NonNull String); method @NonNull public java.util.List queryReceiverProperty(@NonNull String); method @NonNull public java.util.List queryServiceProperty(@NonNull String); + method public void relinquishUpdateOwnership(@NonNull String); method @Deprecated public abstract void removePackageFromPreferred(@NonNull String); method public abstract void removePermission(@NonNull String); method @RequiresPermission(value="android.permission.WHITELIST_RESTRICTED_PERMISSIONS", conditional=true) public boolean removeWhitelistedRestrictedPermission(@NonNull String, @NonNull String, int); diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index a7a4b356c8d50..c11961e4c18e4 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -3890,4 +3890,14 @@ public class ApplicationPackageManager extends PackageManager { return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.SHOW_NEW_APP_INSTALLED_NOTIFICATION_ENABLED, 0) == 1; } + + @Override + public void relinquishUpdateOwnership(String targetPackage) { + Objects.requireNonNull(targetPackage); + try { + mPM.relinquishUpdateOwnership(targetPackage); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 54ca1e59aafe7..0e37c8798919e 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -214,6 +214,8 @@ interface IPackageManager { @UnsupportedAppUsage void setInstallerPackageName(in String targetPackage, in String installerPackageName); + void relinquishUpdateOwnership(in String targetPackage); + void setApplicationCategoryHint(String packageName, int categoryHint, String callerPackageName); /** @deprecated rawr, don't call AIDL methods directly! */ diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 030537510cee3..b884535a7b8b2 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -10866,4 +10866,16 @@ public abstract class PackageManager { throw new UnsupportedOperationException( "isShowNewAppInstalledNotificationEnabled not implemented in subclass"); } + + /** + * Attempt to relinquish the update ownership of the given package. Only the current + * update owner of the given package can use this API or a SecurityException will be + * thrown. + * + * @param targetPackage The installed package whose update owner will be changed. + */ + public void relinquishUpdateOwnership(@NonNull String targetPackage) { + throw new UnsupportedOperationException( + "relinquishUpdateOwnership not implemented in subclass"); + } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 9a98e1e7d0e64..41f35f580162c 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -6012,6 +6012,42 @@ public class PackageManagerService implements PackageSender, TestUtilityService } } + @Override + public void relinquishUpdateOwnership(String targetPackage) { + final int callingUid = Binder.getCallingUid(); + final int callingUserId = UserHandle.getUserId(callingUid); + final Computer snapshot = snapshotComputer(); + + final PackageStateInternal targetPackageState = + snapshot.getPackageStateForInstalledAndFiltered(targetPackage, callingUid, + callingUserId); + if (targetPackageState == null) { + throw new IllegalArgumentException("Unknown target package: " + targetPackage); + } + + final String targetUpdateOwnerPackageName = + targetPackageState.getInstallSource().mUpdateOwnerPackageName; + final PackageStateInternal targetUpdateOwnerPkgSetting = + targetUpdateOwnerPackageName == null ? null + : snapshot.getPackageStateInternal(targetUpdateOwnerPackageName); + + if (targetUpdateOwnerPkgSetting == null) { + return; + } + + final int callingAppId = UserHandle.getAppId(callingUid); + final int targetUpdateOwnerAppId = targetUpdateOwnerPkgSetting.getAppId(); + if (callingAppId != Process.SYSTEM_UID + && callingAppId != Process.SHELL_UID + && callingAppId != targetUpdateOwnerAppId) { + throw new SecurityException("Caller is not the current update owner."); + } + + commitPackageStateMutation(null /* initialState */, targetPackage, + state -> state.setUpdateOwner(null /* updateOwnerPackageName */)); + scheduleWriteSettings(); + } + @Override public boolean setInstantAppCookie(String packageName, byte[] cookie, int userId) { if (HIDE_EPHEMERAL_APIS) { diff --git a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java index 4a8ef963959b6..5947d4735faa4 100644 --- a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java +++ b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java @@ -291,6 +291,15 @@ public class PackageStateMutator { return this; } + @NonNull + @Override + public PackageStateWrite setUpdateOwner(@NonNull String updateOwnerPackageName) { + if (mState != null) { + mState.setUpdateOwnerPackage(updateOwnerPackageName); + } + return this; + } + private static class UserStateWriteWrapper implements PackageUserStateWrite { @Nullable diff --git a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateWrite.java b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateWrite.java index dc9cd3b6ceb7f..c610c02a6e9cc 100644 --- a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateWrite.java +++ b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateWrite.java @@ -57,4 +57,7 @@ public interface PackageStateWrite { @NonNull PackageStateWrite setInstaller(@Nullable String installerPackageName, int installerPackageUid); + + @NonNull + PackageStateWrite setUpdateOwner(@Nullable String updateOwnerPackageName); }