/** * If set, this intent will not match any components in packages that * are currently * {@linkplain android.content.pm.ApplicationInfo#FLAG_STOPPED stopped}. * If this is not set, then the default behavior is to include such * applications in the result. */ publicstaticfinalintFLAG_EXCLUDE_STOPPED_PACKAGES=0x00000010; /** * If set, this intent will always match any components in packages that * are currently * {@linkplain android.content.pm.ApplicationInfo#FLAG_STOPPED stopped}. * This is the default behavior when * {@link #FLAG_EXCLUDE_STOPPED_PACKAGES} is not set. If both of these * flags are set, this one wins (it allows overriding of exclude for * places where the framework may automatically set the exclude flag, * such as broadcasts). */ publicstaticfinalintFLAG_INCLUDE_STOPPED_PACKAGES=0x00000020;
// System apps are never considered stopped for purposes of // filtering, because there may be no way for the user to // actually re-launch them. return !packageState.isSystem() && packageState.getUserStateOrDefault(userId).isStopped(); }
// 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. // We'll skip this step under the following conditions: // - It's "android" // - It's an APEX or overlay package since stopped state does not affect them. // - It is enumerated with a <initial-package-state> tag having the stopped attribute // set to false // - It doesn't have an enabled and exported launcher activity, which means the user // wouldn't have a way to un-stop it finalbooleanisApexPkg= (scanFlags & SCAN_AS_APEX) != 0; if (mPm.mShouldStopSystemPackagesByDefault && scanSystemPartition && !pkgAlreadyExists && !isApexPkg && !parsedPackage.isOverlayIsStatic() ) { StringpackageName= parsedPackage.getPackageName(); if (!"android".contentEquals(packageName) && !mPm.mInitialNonStoppedSystemPackages.contains(packageName) && hasLauncherEntry(parsedPackage)) { scanFlags |= SCAN_AS_STOPPED_SYSTEM_APP; } }
// Flags contain system values stored in the server variant of AndroidPackage, // and so the server-side PackageInfoUtils is still called, even without a // PackageSetting to pass in. intpkgFlags= PackageInfoUtils.appInfoFlags(parsedPackage, null); intpkgPrivateFlags= PackageInfoUtils.appInfoPrivateFlags(parsedPackage, null);
// REMOVE SharedUserSetting from method; update in a separate call pkgSetting = Settings.createNewSetting(parsedPackage.getPackageName(), originalPkgSetting, disabledPkgSetting, realPkgName, sharedUserSetting, destCodeFile, parsedPackage.getNativeLibraryRootDir(), AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage), AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage), parsedPackage.getLongVersionCode(), pkgFlags, pkgPrivateFlags, user, true/*allowInstall*/, instantApp, virtualPreload, isStoppedSystemApp, UserManagerService.getInstance(), usesSdkLibraries, parsedPackage.getUsesSdkLibrariesVersionsMajor(), usesStaticLibraries, parsedPackage.getUsesStaticLibrariesVersions(), parsedPackage.getMimeGroups(), newDomainSetId); }
// If this is not a system app, it starts out stopped. if ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) { if (DEBUG_STOPPED) { RuntimeExceptione=newRuntimeException("here"); e.fillInStackTrace(); Slog.i(PackageManagerService.TAG, "Stopping package " + pkgName, e); } List<UserInfo> users = getAllUsers(userManager); if (users != null && allowInstall) { for (UserInfo user : users) { // By default we consider this app to be installed // for the user if no user has been specified (which // means to leave it at its original value, and the // original default value is true), or we are being // asked to install for all users, or this is the // user we are installing for. finalbooleaninstalled= installUser == null || (installUserId == UserHandle.USER_ALL && !isAdbInstallDisallowed(userManager, user.id) && !user.preCreated) || installUserId == user.id; if (DEBUG_MU) { Slogf.d(TAG, "createNewSetting(pkg=%s, installUserId=%s, user=%s, " + "installed=%b)", pkgName, installUserId, user.toFullString(), installed); } pkgSetting.setUserState(user.id, 0, COMPONENT_ENABLED_STATE_DEFAULT, installed, true/*stopped*/, true/*notLaunched*/, false/*hidden*/, 0/*distractionFlags*/, null/*suspendParams*/, instantApp, virtualPreload, null/*lastDisableAppCaller*/, null/*enabledComponents*/, null/*disabledComponents*/, PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.UNINSTALL_REASON_UNKNOWN, null/*harmfulAppWarning*/, null/*splashscreenTheme*/, 0/*firstInstallTime*/, PackageManager.USER_MIN_ASPECT_RATIO_UNSET ); } } } elseif (isStoppedSystemApp) { if (DEBUG_STOPPED) { RuntimeExceptione=newRuntimeException("here"); e.fillInStackTrace(); Slog.i(PackageManagerService.TAG, "Stopping system package " + pkgName, e); } pkgSetting.setStopped(true, installUserId); }
if (packageState.isSystem()) { // A system app can be considered in the stopped state only if it was originally // scanned in the stopped state. return packageState.isScannedAsStoppedSystemApp() && packageState.getUserStateOrDefault(userId).isStopped(); } return packageState.getUserStateOrDefault(userId).isStopped(); } }
private Pair<ScanResult, Boolean> scanSystemPackageLI(ParsedPackage parsedPackage, @ParsingPackageUtils.ParseFlags int parseFlags, @PackageManagerService.ScanFlags int scanFlags, @Nullable UserHandle user)throws PackageManagerException {
// 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. // We'll skip this step under the following conditions: // - It's "android" // - It's an APEX or overlay package since stopped state does not affect them. // - It is enumerated with a <initial-package-state> tag having the stopped attribute // set to false // - It doesn't have an enabled and exported launcher activity, which means the user // wouldn't have a way to un-stop it finalbooleanisApexPkg= (scanFlags & SCAN_AS_APEX) != 0; if (mPm.mShouldStopSystemPackagesByDefault && scanSystemPartition && !pkgAlreadyExists && !isApexPkg && !parsedPackage.isOverlayIsStatic() ) { StringpackageName= parsedPackage.getPackageName(); if (!"android".contentEquals(packageName) && !mPm.mInitialNonStoppedSystemPackages.contains(packageName) && hasLauncherEntry(parsedPackage)) { scanFlags |= SCAN_AS_STOPPED_SYSTEM_APP; } } }
根据函数的注释,一个应用会被标记为“停止的系统应用”(Scanned As Stopped System App)需要满足以下所有条件:
<!-- 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. --> <boolname="config_stopSystemPackagesByDefault">true</bool>
<?xml version="1.0" encoding="utf-8"?> <!-- 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. -->