diff options
11 files changed, 188 insertions, 4 deletions
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index afcc2fc095bd..263d4315fdc3 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -6230,4 +6230,27 @@ trusted certificate using the SHA-256 digest algorithm. --> <string-array name="config_healthConnectMigrationKnownSigners"> </string-array> + + <!-- The Universal Stylus Initiative (USI) protocol version supported by each display. + (@see https://universalstylus.org/). + + The i-th value in this array corresponds to the supported USI version of the i-th display + listed in config_displayUniqueIdArray. On a single-display device, the + config_displayUniqueIdArray may be empty, in which case the only value in this array should + be the USI version for the main built-in display. + + If the display does not support USI, the version value should be an empty string. If the + display supports USI, the version must be in the following format: + "<major-version>.<minor-version>" + + For example, "", "1.0", and "2.0" are valid values. --> + <string-array name="config_displayUsiVersionArray" translatable="false"> + <item>""</item> + </string-array> + + <!-- Whether system apps should be scanned in the stopped state during initial boot. + Packages can be added by OEMs in an allowlist, to prevent them from being scanned as + "stopped" during initial boot of a device, or after an OTA update. Stopped state of + an app is not changed during subsequent reboots. --> + <bool name="config_stopSystemPackagesByDefault">false</bool> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index d82e898a64f4..fbed371d8662 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4909,4 +4909,6 @@ <java-symbol type="string" name="config_mainDisplayShape"/> <java-symbol type="string" name="config_secondaryDisplayShape"/> <java-symbol type="array" name="config_displayShapeArray" /> + + <java-symbol type="bool" name="config_stopSystemPackagesByDefault"/> </resources> diff --git a/data/etc/Android.bp b/data/etc/Android.bp index d0c3e5f6a91e..f233c6eca13b 100644 --- a/data/etc/Android.bp +++ b/data/etc/Android.bp @@ -36,6 +36,12 @@ prebuilt_etc { } prebuilt_etc { + name: "initial-package-stopped-states.xml", + sub_dir: "sysconfig", + src: "initial-package-stopped-states.xml", +} + +prebuilt_etc { name: "preinstalled-packages-platform-overlays.xml", product_specific: true, sub_dir: "sysconfig", diff --git a/data/etc/initial-package-stopped-states.xml b/data/etc/initial-package-stopped-states.xml new file mode 100644 index 000000000000..6bda2c0dbc26 --- /dev/null +++ b/data/etc/initial-package-stopped-states.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<!-- +This XML defines an allowlist for packages that should not be scanned in a "stopped" state. +When this feature is turned on (indicated by the config config_stopSystemPackagesByDefault in +core/res/res/values/config.xml) packages on the system partition that are encountered by +the PackageManagerService for the first time are scanned in the "stopped" state. This allowlist +is also considered while creating new users on the device. Stopped state is not set during +subsequent reboots. + +Example usage + 1. <initial-package-state package="com.example.app" stopped="false"/> + Indicates that a system package - com.example.app's initial stopped state should not be set + by the Package Manager. By default, system apps are marked as stopped. + 2. <initial-package-state package="com.example.app" stopped="true"/> + Indicates that a system package - com.example.app's initial state should be set by the + Package Manager to "stopped=true". It will have the same effect on the + package's stopped state even if this package was not included in the allow list. + 3. <initial-package-state package="com.example.app"/> + Invalid usage. +--> + +<config></config> diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java index 4854c37933e3..4b7612791fe7 100644 --- a/services/core/java/com/android/server/SystemConfig.java +++ b/services/core/java/com/android/server/SystemConfig.java @@ -333,6 +333,11 @@ public class SystemConfig { // Update ownership for system applications and the installers eligible to update them. private final ArrayMap<String, String> mUpdateOwnersForSystemApps = new ArrayMap<>(); + // Set of package names that should not be marked as "stopped" during initial device boot + // or when adding a new user. A new package not contained in this set will be + // marked as stopped by the system + @NonNull private final Set<String> mInitialNonStoppedSystemPackages = new ArraySet<>(); + /** * Map of system pre-defined, uniquely named actors; keys are namespace, * value maps actor name to package name. @@ -527,6 +532,10 @@ public class SystemConfig { ? null : mOverlayConfigSignaturePackage; } + public Set<String> getInitialNonStoppedSystemPackages() { + return mInitialNonStoppedSystemPackages; + } + /** * Only use for testing. Do NOT use in production code. * @param readPermissions false to create an empty SystemConfig; true to read the permissions. @@ -1445,6 +1454,19 @@ public class SystemConfig { } XmlUtils.skipCurrentTag(parser); } break; + case "initial-package-state": { + String pkgName = parser.getAttributeValue(null, "package"); + String stopped = parser.getAttributeValue(null, "stopped"); + if (TextUtils.isEmpty(pkgName)) { + Slog.w(TAG, "<" + name + "> without package in " + permFile + + " at " + parser.getPositionDescription()); + } else if (TextUtils.isEmpty(stopped)) { + Slog.w(TAG, "<" + name + "> without stopped in " + permFile + + " at " + parser.getPositionDescription()); + } else if (!Boolean.parseBoolean(stopped)) { + mInitialNonStoppedSystemPackages.add(pkgName); + } + } default: { Slog.w(TAG, "Tag " + name + " is unknown in " + permFile + " at " + parser.getPositionDescription()); diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index bd6bd75e60f3..0d5392be30ba 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -70,6 +70,7 @@ import static com.android.server.pm.PackageManagerService.SCAN_AS_ODM; import static com.android.server.pm.PackageManagerService.SCAN_AS_OEM; import static com.android.server.pm.PackageManagerService.SCAN_AS_PRIVILEGED; import static com.android.server.pm.PackageManagerService.SCAN_AS_PRODUCT; +import static com.android.server.pm.PackageManagerService.SCAN_AS_STOPPED_SYSTEM_APP; import static com.android.server.pm.PackageManagerService.SCAN_AS_SYSTEM; import static com.android.server.pm.PackageManagerService.SCAN_AS_SYSTEM_EXT; import static com.android.server.pm.PackageManagerService.SCAN_AS_VENDOR; @@ -4237,6 +4238,18 @@ final class InstallPackageHelper { } } + // A new application appeared on /system, and we are seeing it for the first time. + // Its also not updated as we don't have a copy of it on /data. So, scan it in a + // STOPPED state. Ignore if it's an APEX package since stopped state does not affect them. + final boolean isApexPkg = (scanFlags & SCAN_AS_APEX) != 0; + if (mPm.mShouldStopSystemPackagesByDefault && scanSystemPartition + && !pkgAlreadyExists && !isApexPkg) { + String packageName = parsedPackage.getPackageName(); + if (!mPm.mInitialNonStoppedSystemPackages.contains(packageName)) { + scanFlags |= SCAN_AS_STOPPED_SYSTEM_APP; + } + } + final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags, scanFlags | SCAN_UPDATE_SIGNATURE, 0 /* currentTime */, user, null); return new Pair<>(scanResult, shouldHideSystemApp); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index a02a4197bdea..c6a157968134 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -387,6 +387,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService static final int SCAN_DROP_CACHE = 1 << 24; static final int SCAN_AS_FACTORY = 1 << 25; static final int SCAN_AS_APEX = 1 << 26; + static final int SCAN_AS_STOPPED_SYSTEM_APP = 1 << 27; @IntDef(flag = true, prefix = { "SCAN_" }, value = { SCAN_NO_DEX, @@ -403,6 +404,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService SCAN_AS_INSTANT_APP, SCAN_AS_FULL_APP, SCAN_AS_VIRTUAL_PRELOAD, + SCAN_AS_STOPPED_SYSTEM_APP, }) @Retention(RetentionPolicy.SOURCE) public @interface ScanFlags {} @@ -964,6 +966,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService final @Nullable String mRecentsPackage; final @Nullable String mAmbientContextDetectionPackage; final @Nullable String mWearableSensingPackage; + final @NonNull Set<String> mInitialNonStoppedSystemPackages; + final boolean mShouldStopSystemPackagesByDefault; private final @NonNull String mRequiredSdkSandboxPackage; @GuardedBy("mLock") @@ -1771,6 +1775,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService mOverlayConfigSignaturePackage = testParams.overlayConfigSignaturePackage; mResolveComponentName = testParams.resolveComponentName; mRequiredSdkSandboxPackage = testParams.requiredSdkSandboxPackage; + mInitialNonStoppedSystemPackages = testParams.initialNonStoppedSystemPackages; + mShouldStopSystemPackagesByDefault = testParams.shouldStopSystemPackagesByDefault; mLiveComputer = createLiveComputer(); mSnapshotStatistics = null; @@ -2097,6 +2103,11 @@ public class PackageManagerService implements PackageSender, TestUtilityService mCacheDir = PackageManagerServiceUtils.preparePackageParserCache( mIsEngBuild, mIsUserDebugBuild, mIncrementalVersion); + mInitialNonStoppedSystemPackages = mInjector.getSystemConfig() + .getInitialNonStoppedSystemPackages(); + mShouldStopSystemPackagesByDefault = mContext.getResources() + .getBoolean(R.bool.config_stopSystemPackagesByDefault); + final int[] userIds = mUserManager.getUserIds(); PackageParser2 packageParser = mInjector.getScanningCachingPackageParser(); mOverlayConfig = mInitAppsHelper.initSystemApps(packageParser, packageSettings, userIds, diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java index e5cfa671a930..0ed90e478e30 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java @@ -26,6 +26,7 @@ import android.os.Build; import android.os.Handler; import android.os.incremental.IncrementalManager; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.DisplayMetrics; import com.android.internal.annotations.VisibleForTesting; @@ -40,6 +41,7 @@ import com.android.server.pm.pkg.AndroidPackage; import java.io.File; import java.util.List; +import java.util.Set; @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) public final class PackageManagerServiceTestParams { @@ -119,4 +121,6 @@ public final class PackageManagerServiceTestParams { public SuspendPackageHelper suspendPackageHelper; public DistractingPackageHelper distractingPackageHelper; public StorageEventHelper storageEventHelper; + public Set<String> initialNonStoppedSystemPackages = new ArraySet<>(); + public boolean shouldStopSystemPackagesByDefault; } diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java index 830b096c696d..253887107a04 100644 --- a/services/core/java/com/android/server/pm/ScanPackageUtils.java +++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java @@ -31,6 +31,7 @@ import static com.android.server.pm.PackageManagerService.SCAN_AS_ODM; import static com.android.server.pm.PackageManagerService.SCAN_AS_OEM; import static com.android.server.pm.PackageManagerService.SCAN_AS_PRIVILEGED; import static com.android.server.pm.PackageManagerService.SCAN_AS_PRODUCT; +import static com.android.server.pm.PackageManagerService.SCAN_AS_STOPPED_SYSTEM_APP; import static com.android.server.pm.PackageManagerService.SCAN_AS_SYSTEM; import static com.android.server.pm.PackageManagerService.SCAN_AS_SYSTEM_EXT; import static com.android.server.pm.PackageManagerService.SCAN_AS_VENDOR; @@ -198,6 +199,7 @@ final class ScanPackageUtils { if (createNewPackage) { final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0; final boolean virtualPreload = (scanFlags & SCAN_AS_VIRTUAL_PRELOAD) != 0; + final boolean isStoppedSystemApp = (scanFlags & SCAN_AS_STOPPED_SYSTEM_APP) != 0; // Flags contain system values stored in the server variant of AndroidPackage, // and so the server-side PackageInfoUtils is still called, even without a @@ -212,7 +214,7 @@ final class ScanPackageUtils { AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage), AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage), parsedPackage.getLongVersionCode(), pkgFlags, pkgPrivateFlags, user, - true /*allowInstall*/, instantApp, virtualPreload, + true /*allowInstall*/, instantApp, virtualPreload, isStoppedSystemApp, UserManagerService.getInstance(), usesSdkLibraries, parsedPackage.getUsesSdkLibrariesVersionsMajor(), usesStaticLibraries, parsedPackage.getUsesStaticLibrariesVersions(), parsedPackage.getMimeGroups(), diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 165e476b1de7..4f0a1159a492 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -1041,7 +1041,7 @@ public final class Settings implements Watchable, Snappable { File codePath, String legacyNativeLibraryPath, String primaryCpuAbi, String secondaryCpuAbi, long versionCode, int pkgFlags, int pkgPrivateFlags, UserHandle installUser, boolean allowInstall, boolean instantApp, - boolean virtualPreload, UserManagerService userManager, + boolean virtualPreload, boolean isStoppedSystemApp, UserManagerService userManager, String[] usesSdkLibraries, long[] usesSdkLibrariesVersions, String[] usesStaticLibraries, long[] usesStaticLibrariesVersions, Set<String> mimeGroupNames, @NonNull UUID domainSetId) { @@ -1068,6 +1068,9 @@ public final class Settings implements Watchable, Snappable { pkgSetting.setFlags(pkgFlags) .setPrivateFlags(pkgPrivateFlags); } else { + int installUserId = installUser != null ? installUser.getIdentifier() + : UserHandle.USER_SYSTEM; + pkgSetting = new PackageSetting(pkgName, realPkgName, codePath, legacyNativeLibraryPath, primaryCpuAbi, secondaryCpuAbi, null /*cpuAbiOverrideString*/, versionCode, pkgFlags, pkgPrivateFlags, @@ -1086,8 +1089,6 @@ public final class Settings implements Watchable, Snappable { Slog.i(PackageManagerService.TAG, "Stopping package " + pkgName, e); } List<UserInfo> users = getAllUsers(userManager); - int installUserId = installUser != null ? installUser.getIdentifier() - : UserHandle.USER_SYSTEM; if (users != null && allowInstall) { for (UserInfo user : users) { // By default we consider this app to be installed @@ -1126,6 +1127,13 @@ public final class Settings implements Watchable, Snappable { ); } } + } else if (isStoppedSystemApp) { + if (DEBUG_STOPPED) { + RuntimeException e = new RuntimeException("here"); + e.fillInStackTrace(); + Slog.i(PackageManagerService.TAG, "Stopping system package " + pkgName, e); + } + pkgSetting.setStopped(true, installUserId); } if (sharedUser != null) { pkgSetting.setAppId(sharedUser.mAppId); @@ -4422,6 +4430,15 @@ public final class Settings implements Watchable, Snappable { ps.getPackageName())); // Only system apps are initially installed. ps.setInstalled(shouldReallyInstall, userHandle); + + // Non-Apex system apps, that are not included in the allowlist in + // initialNonStoppedSystemPackages, should be marked as stopped by default. + final boolean shouldBeStopped = service.mShouldStopSystemPackagesByDefault + && ps.isSystem() + && !ps.isApex() + && !service.mInitialNonStoppedSystemPackages.contains(ps.getPackageName()); + ps.setStopped(shouldBeStopped, userHandle); + // If userTypeInstallablePackages is the *only* reason why we're not installing, // then uninstallReason is USER_TYPE. If there's a different reason, or if we // actually are installing, put UNKNOWN. diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java index 75484d162282..a39e0216f4e5 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -1129,6 +1129,7 @@ public class PackageManagerSettingsTests { false /*allowInstall*/, false /*instantApp*/, false /*virtualPreload*/, + false /* stopped */, UserManagerService.getInstance(), null /*usesSdkLibraries*/, null /*usesSdkLibrariesVersions*/, @@ -1173,6 +1174,7 @@ public class PackageManagerSettingsTests { true /*allowInstall*/, false /*instantApp*/, false /*virtualPreload*/, + false /* stopped */, UserManagerService.getInstance(), null /*usesSdkLibraries*/, null /*usesSdkLibrariesVersions*/, @@ -1217,6 +1219,7 @@ public class PackageManagerSettingsTests { false /*allowInstall*/, false /*instantApp*/, false /*virtualPreload*/, + false /* stopped */, UserManagerService.getInstance(), null /*usesSdkLibraries*/, null /*usesSdkLibrariesVersions*/, @@ -1262,6 +1265,7 @@ public class PackageManagerSettingsTests { false /*allowInstall*/, false /*instantApp*/, false /*virtualPreload*/, + false /* stopped */, UserManagerService.getInstance(), null /*usesSdkLibraries*/, null /*usesSdkLibrariesVersions*/, @@ -1284,6 +1288,48 @@ public class PackageManagerSettingsTests { verifyUserState(userState, false /*notLaunched*/, false /*stopped*/, true /*installed*/); } + /** Create a new stopped system PackageSetting */ + @Test + public void testCreateNewSetting05() { + final PackageSetting testPkgSetting01 = Settings.createNewSetting( + PACKAGE_NAME, + null /*originalPkg*/, + null /*disabledPkg*/, + null /*realPkgName*/, + null /*sharedUser*/, + UPDATED_CODE_PATH /*codePath*/, + null /*legacyNativeLibraryPath*/, + "arm64-v8a" /*primaryCpuAbi*/, + "armeabi" /*secondaryCpuAbi*/, + UPDATED_VERSION_CODE /*versionCode*/, + ApplicationInfo.FLAG_SYSTEM /*pkgFlags*/, + 0 /*pkgPrivateFlags*/, + UserHandle.SYSTEM /*installUser*/, + false /*allowInstall*/, + false /*instantApp*/, + false /*virtualPreload*/, + true /* stopped */, + UserManagerService.getInstance(), + null /*usesSdkLibraries*/, + null /*usesSdkLibrariesVersions*/, + null /*usesStaticLibraries*/, + null /*usesStaticLibrariesVersions*/, + null /*mimeGroups*/, + UUID.randomUUID()); + assertThat(testPkgSetting01.getAppId(), is(0)); + assertThat(testPkgSetting01.getPath(), is(UPDATED_CODE_PATH)); + assertThat(testPkgSetting01.getPackageName(), is(PACKAGE_NAME)); + assertThat(testPkgSetting01.getFlags(), is(ApplicationInfo.FLAG_SYSTEM)); + assertThat(testPkgSetting01.getPrivateFlags(), is(0)); + assertThat(testPkgSetting01.getPrimaryCpuAbi(), is("arm64-v8a")); + assertThat(testPkgSetting01.getPrimaryCpuAbiLegacy(), is("arm64-v8a")); + assertThat(testPkgSetting01.getSecondaryCpuAbi(), is("armeabi")); + assertThat(testPkgSetting01.getSecondaryCpuAbiLegacy(), is("armeabi")); + assertThat(testPkgSetting01.getVersionCode(), is(UPDATED_VERSION_CODE)); + final PackageUserState userState = testPkgSetting01.readUserState(0); + verifyUserState(userState, false /*notLaunched*/, true /*stopped*/, true /*installed*/); + } + @Test public void testSetPkgStateLibraryFiles_addNewFiles() { final PackageSetting packageSetting = createPackageSetting("com.foo"); |