Hide system apps until installed (1/2)
Applying this mechanism for system carrier apps to make visibility reasonable from the user's perspective. In other words, before hidden system apps have been installed, they wouldn't be listed via APIs in PackageManager which are used at all apps list and search in Settings and so on. Test: manual Test: atest CarrierAppUtilsTest Test: atest PackageManagerTest Bug: 74068582 Change-Id: Id3ff138ad529b909d9bbf6719af3a553b909ccbb
This commit is contained in:
committed by
Andrew Sapperstein
parent
98cb40cf4b
commit
40ede29ed6
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -13934,6 +13934,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);
|
||||
@@ -13998,10 +14035,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);
|
||||
|
||||
@@ -152,9 +152,14 @@ public final class CarrierAppUtils {
|
||||
&& (ai.enabledSetting ==
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
|
||||
|| ai.enabledSetting ==
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
|
||||
|| (ai.flags & ApplicationInfo.FLAG_INSTALLED) == 0)) {
|
||||
Slog.i(TAG, "Update state(" + packageName + "): ENABLED for user "
|
||||
+ userId);
|
||||
packageManager.setSystemAppInstallState(
|
||||
packageName,
|
||||
true /*installed*/,
|
||||
userId);
|
||||
packageManager.setApplicationEnabledSetting(
|
||||
packageName,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
|
||||
@@ -170,9 +175,14 @@ public final class CarrierAppUtils {
|
||||
if (associatedApp.enabledSetting ==
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
|
||||
|| associatedApp.enabledSetting ==
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
|
||||
|| (ai.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
|
||||
Slog.i(TAG, "Update associated state(" + associatedApp.packageName
|
||||
+ "): ENABLED for user " + userId);
|
||||
packageManager.setSystemAppInstallState(
|
||||
associatedApp.packageName,
|
||||
true /*installed*/,
|
||||
userId);
|
||||
packageManager.setApplicationEnabledSetting(
|
||||
associatedApp.packageName,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
|
||||
@@ -190,15 +200,14 @@ public final class CarrierAppUtils {
|
||||
// updated we shouldn't touch it.
|
||||
if (!ai.isUpdatedSystemApp()
|
||||
&& ai.enabledSetting ==
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
|
||||
&& (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
|
||||
Slog.i(TAG, "Update state(" + packageName
|
||||
+ "): DISABLED_UNTIL_USED for user " + userId);
|
||||
packageManager.setApplicationEnabledSetting(
|
||||
packageManager.setSystemAppInstallState(
|
||||
packageName,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,
|
||||
0,
|
||||
userId,
|
||||
callingPackage);
|
||||
false /*installed*/,
|
||||
userId);
|
||||
}
|
||||
|
||||
// Also disable any associated apps for this carrier app if this is the first
|
||||
@@ -213,13 +222,10 @@ public final class CarrierAppUtils {
|
||||
Slog.i(TAG,
|
||||
"Update associated state(" + associatedApp.packageName
|
||||
+ "): DISABLED_UNTIL_USED for user " + userId);
|
||||
packageManager.setApplicationEnabledSetting(
|
||||
packageManager.setSystemAppInstallState(
|
||||
associatedApp.packageName,
|
||||
PackageManager
|
||||
.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,
|
||||
0,
|
||||
userId,
|
||||
callingPackage);
|
||||
false /*installed*/,
|
||||
userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -357,7 +363,8 @@ public final class CarrierAppUtils {
|
||||
String packageName) {
|
||||
try {
|
||||
ApplicationInfo ai = packageManager.getApplicationInfo(packageName,
|
||||
PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, userId);
|
||||
PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
|
||||
| PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS, userId);
|
||||
if (ai != null && ai.isSystemApp()) {
|
||||
return ai;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user