Loading core/java/android/content/pm/IPackageManager.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -598,6 +598,8 @@ interface IPackageManager { boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden, int userId); boolean getApplicationHiddenSettingAsUser(String packageName, int userId); boolean setSystemAppInstallState(String packageName, boolean installed, int userId); IPackageInstaller getPackageInstaller(); boolean setBlockUninstallForUser(String packageName, boolean blockUninstall, int userId); Loading core/java/android/content/pm/PackageManager.java +10 −1 Original line number Diff line number Diff line Loading @@ -147,6 +147,7 @@ public abstract class PackageManager { GET_DISABLED_COMPONENTS, GET_DISABLED_UNTIL_USED_COMPONENTS, GET_UNINSTALLED_PACKAGES, MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS, }) @Retention(RetentionPolicy.SOURCE) public @interface PackageInfoFlags {} Loading @@ -164,6 +165,7 @@ public abstract class PackageManager { MATCH_STATIC_SHARED_LIBRARIES, GET_DISABLED_UNTIL_USED_COMPONENTS, GET_UNINSTALLED_PACKAGES, MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS, }) @Retention(RetentionPolicy.SOURCE) public @interface ApplicationInfoFlags {} Loading Loading @@ -520,6 +522,12 @@ public abstract class PackageManager { */ public static final int MATCH_DEBUG_TRIAGED_MISSING = 0x10000000; /** * Internal flag used to indicate that a package is a hidden system app. * @hide */ public static final int MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS = 0x20000000; /** * Flag for {@link #addCrossProfileIntentFilter}: if this flag is set: when * resolving an intent that matches the {@code CrossProfileIntentFilter}, Loading Loading @@ -4840,6 +4848,7 @@ public abstract class PackageManager { * @hide */ @RequiresPermission(anyOf = { Manifest.permission.INSTALL_EXISTING_PACKAGES, Manifest.permission.INSTALL_PACKAGES, Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public abstract int installExistingPackageAsUser(String packageName, @UserIdInt int userId) Loading core/java/android/content/pm/PackageParser.java +9 −1 Original line number Diff line number Diff line Loading @@ -639,11 +639,19 @@ public class PackageParser { */ private static boolean checkUseInstalledOrHidden(int flags, PackageUserState state, ApplicationInfo appInfo) { // Returns false if the package is hidden system app until installed. if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0 && !state.installed && appInfo != null && appInfo.isSystemApp()) { return false; } // If available for the target user, or trying to match uninstalled packages and it's // a system app. return state.isAvailable(flags) || (appInfo != null && appInfo.isSystemApp() && (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0); && ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0 || (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0)); } public static boolean isAvailable(PackageUserState state) { Loading core/res/AndroidManifest.xml +9 −0 Original line number Diff line number Diff line Loading @@ -3024,6 +3024,15 @@ <permission android:name="android.permission.INSTALL_PACKAGE_UPDATES" android:protectionLevel="signature|privileged" /> <!-- Allows an application to install existing system packages. This is a limited version of {@link android.Manifest.permission#INSTALL_PACKAGES}. <p>Not for use by third-party applications. TODO(b/80204953): remove this permission once we have a long-term solution. @hide --> <permission android:name="com.android.permission.INSTALL_EXISTING_PACKAGES" android:protectionLevel="signature|privileged" /> <!-- @SystemApi Allows an application to clear user data. <p>Not for use by third-party applications @hide Loading services/core/java/com/android/server/pm/PackageManagerService.java +46 −3 Original line number Diff line number Diff line Loading @@ -13943,6 +13943,43 @@ public class PackageManagerService extends IPackageManager.Stub return false; } @Override public boolean setSystemAppInstallState(String packageName, boolean installed, int userId) { enforceSystemOrPhoneCaller("setSystemAppInstallState"); PackageSetting pkgSetting = mSettings.mPackages.get(packageName); // The target app should always be in system if (pkgSetting == null || !pkgSetting.isSystem()) { return false; } // Check if the install state is the same if (pkgSetting.getInstalled(userId) == installed) { return false; } long callingId = Binder.clearCallingIdentity(); try { if (installed) { // install the app from uninstalled state installExistingPackageAsUser( packageName, userId, 0 /*installFlags*/, PackageManager.INSTALL_REASON_DEVICE_SETUP); return true; } // uninstall the app from installed state deletePackageVersioned( new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST), new LegacyPackageDeleteObserver(null).getBinder(), userId, PackageManager.DELETE_SYSTEM_APP); return true; } finally { Binder.restoreCallingIdentity(callingId); } } private void sendApplicationHiddenForUser(String packageName, PackageSetting pkgSetting, int userId) { final PackageRemovedInfo info = new PackageRemovedInfo(this); Loading Loading @@ -14007,10 +14044,16 @@ public class PackageManagerService extends IPackageManager.Stub @Override public int installExistingPackageAsUser(String packageName, int userId, int installFlags, int installReason) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null); PackageSetting pkgSetting; final int callingUid = Binder.getCallingUid(); if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES) != PackageManager.PERMISSION_GRANTED && mContext.checkCallingOrSelfPermission( android.Manifest.permission.INSTALL_EXISTING_PACKAGES) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Neither user " + callingUid + " nor current process has " + android.Manifest.permission.INSTALL_PACKAGES + "."); } PackageSetting pkgSetting; mPermissionManager.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */, true /* checkShell */, "installExistingPackage for user " + userId); Loading
core/java/android/content/pm/IPackageManager.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -598,6 +598,8 @@ interface IPackageManager { boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden, int userId); boolean getApplicationHiddenSettingAsUser(String packageName, int userId); boolean setSystemAppInstallState(String packageName, boolean installed, int userId); IPackageInstaller getPackageInstaller(); boolean setBlockUninstallForUser(String packageName, boolean blockUninstall, int userId); Loading
core/java/android/content/pm/PackageManager.java +10 −1 Original line number Diff line number Diff line Loading @@ -147,6 +147,7 @@ public abstract class PackageManager { GET_DISABLED_COMPONENTS, GET_DISABLED_UNTIL_USED_COMPONENTS, GET_UNINSTALLED_PACKAGES, MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS, }) @Retention(RetentionPolicy.SOURCE) public @interface PackageInfoFlags {} Loading @@ -164,6 +165,7 @@ public abstract class PackageManager { MATCH_STATIC_SHARED_LIBRARIES, GET_DISABLED_UNTIL_USED_COMPONENTS, GET_UNINSTALLED_PACKAGES, MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS, }) @Retention(RetentionPolicy.SOURCE) public @interface ApplicationInfoFlags {} Loading Loading @@ -520,6 +522,12 @@ public abstract class PackageManager { */ public static final int MATCH_DEBUG_TRIAGED_MISSING = 0x10000000; /** * Internal flag used to indicate that a package is a hidden system app. * @hide */ public static final int MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS = 0x20000000; /** * Flag for {@link #addCrossProfileIntentFilter}: if this flag is set: when * resolving an intent that matches the {@code CrossProfileIntentFilter}, Loading Loading @@ -4840,6 +4848,7 @@ public abstract class PackageManager { * @hide */ @RequiresPermission(anyOf = { Manifest.permission.INSTALL_EXISTING_PACKAGES, Manifest.permission.INSTALL_PACKAGES, Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public abstract int installExistingPackageAsUser(String packageName, @UserIdInt int userId) Loading
core/java/android/content/pm/PackageParser.java +9 −1 Original line number Diff line number Diff line Loading @@ -639,11 +639,19 @@ public class PackageParser { */ private static boolean checkUseInstalledOrHidden(int flags, PackageUserState state, ApplicationInfo appInfo) { // Returns false if the package is hidden system app until installed. if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0 && !state.installed && appInfo != null && appInfo.isSystemApp()) { return false; } // If available for the target user, or trying to match uninstalled packages and it's // a system app. return state.isAvailable(flags) || (appInfo != null && appInfo.isSystemApp() && (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0); && ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0 || (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0)); } public static boolean isAvailable(PackageUserState state) { Loading
core/res/AndroidManifest.xml +9 −0 Original line number Diff line number Diff line Loading @@ -3024,6 +3024,15 @@ <permission android:name="android.permission.INSTALL_PACKAGE_UPDATES" android:protectionLevel="signature|privileged" /> <!-- Allows an application to install existing system packages. This is a limited version of {@link android.Manifest.permission#INSTALL_PACKAGES}. <p>Not for use by third-party applications. TODO(b/80204953): remove this permission once we have a long-term solution. @hide --> <permission android:name="com.android.permission.INSTALL_EXISTING_PACKAGES" android:protectionLevel="signature|privileged" /> <!-- @SystemApi Allows an application to clear user data. <p>Not for use by third-party applications @hide Loading
services/core/java/com/android/server/pm/PackageManagerService.java +46 −3 Original line number Diff line number Diff line Loading @@ -13943,6 +13943,43 @@ public class PackageManagerService extends IPackageManager.Stub return false; } @Override public boolean setSystemAppInstallState(String packageName, boolean installed, int userId) { enforceSystemOrPhoneCaller("setSystemAppInstallState"); PackageSetting pkgSetting = mSettings.mPackages.get(packageName); // The target app should always be in system if (pkgSetting == null || !pkgSetting.isSystem()) { return false; } // Check if the install state is the same if (pkgSetting.getInstalled(userId) == installed) { return false; } long callingId = Binder.clearCallingIdentity(); try { if (installed) { // install the app from uninstalled state installExistingPackageAsUser( packageName, userId, 0 /*installFlags*/, PackageManager.INSTALL_REASON_DEVICE_SETUP); return true; } // uninstall the app from installed state deletePackageVersioned( new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST), new LegacyPackageDeleteObserver(null).getBinder(), userId, PackageManager.DELETE_SYSTEM_APP); return true; } finally { Binder.restoreCallingIdentity(callingId); } } private void sendApplicationHiddenForUser(String packageName, PackageSetting pkgSetting, int userId) { final PackageRemovedInfo info = new PackageRemovedInfo(this); Loading Loading @@ -14007,10 +14044,16 @@ public class PackageManagerService extends IPackageManager.Stub @Override public int installExistingPackageAsUser(String packageName, int userId, int installFlags, int installReason) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null); PackageSetting pkgSetting; final int callingUid = Binder.getCallingUid(); if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES) != PackageManager.PERMISSION_GRANTED && mContext.checkCallingOrSelfPermission( android.Manifest.permission.INSTALL_EXISTING_PACKAGES) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Neither user " + callingUid + " nor current process has " + android.Manifest.permission.INSTALL_PACKAGES + "."); } PackageSetting pkgSetting; mPermissionManager.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */, true /* checkShell */, "installExistingPackage for user " + userId);