diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index c988fa907f867..03e600ed3ba18 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -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);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index c3548e5b2bbae..15aedd7cf5023 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -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 {}
@@ -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 {}
@@ -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},
@@ -4839,7 +4847,8 @@ public abstract class PackageManager {
* on the system for other users, also install it for the specified user.
* @hide
*/
- @RequiresPermission(anyOf = {
+ @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)
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 2da2cb4c92853..b8eb074d16360 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -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) {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e35b63113f596..19e5e21d50935 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3024,6 +3024,15 @@
+
+
+