[pm] fix SCAN_AS_STOPPED_SYSTEM_APP for restoreDisabledSystemPackage Use ParsedPackage to directly check if the package has a launcher entry or not. This way, we can unify the system-apps-stopped code path for 1) installing new system apps after an OTA, and 2) restoring disabled system apps after uninstalling the update. BUG: 286459841 Test: manual with a system app that doesn't have a launcher entry Test: also manually checked that a system app with a launcher entry will be stopped by default (cherry picked from commit c3415b9f2ff755cde0403eb121e99de924007edd) (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:90451b716d8b42bed7454e9a3d891f7a6c10d192) Merged-In: Ic51a9ceb7db6d887cebc390bb2878db8810cddbf Change-Id: Ic51a9ceb7db6d887cebc390bb2878db8810cddbf
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index 50f1673..2b55a61 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -110,6 +110,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.IntentSender; import android.content.pm.ApplicationInfo; import android.content.pm.DataLoaderType; @@ -119,7 +120,6 @@ import android.content.pm.PackageManager; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; -import android.content.pm.ResolveInfo; import android.content.pm.SharedLibraryInfo; import android.content.pm.Signature; import android.content.pm.SigningDetails; @@ -184,7 +184,9 @@ import com.android.server.pm.pkg.PackageStateInternal; import com.android.server.pm.pkg.SharedLibraryWrapper; import com.android.server.pm.pkg.component.ComponentMutateUtils; +import com.android.server.pm.pkg.component.ParsedActivity; import com.android.server.pm.pkg.component.ParsedInstrumentation; +import com.android.server.pm.pkg.component.ParsedIntentInfo; import com.android.server.pm.pkg.component.ParsedPermission; import com.android.server.pm.pkg.component.ParsedPermissionGroup; import com.android.server.pm.pkg.parsing.ParsingPackageUtils; @@ -207,6 +209,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -3925,23 +3928,6 @@ } } - // If this is a system app we hadn't seen before, and this is a first boot or OTA, - // we need to unstop it if it doesn't have a launcher entry. - if (mPm.mShouldStopSystemPackagesByDefault && scanResult.mRequest.mPkgSetting == null - && ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0) - && ((scanFlags & SCAN_AS_SYSTEM) != 0)) { - final Intent launcherIntent = new Intent(Intent.ACTION_MAIN); - launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER); - launcherIntent.setPackage(parsedPackage.getPackageName()); - final List<ResolveInfo> launcherActivities = - mPm.snapshotComputer().queryIntentActivitiesInternal(launcherIntent, null, - PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 0); - if (launcherActivities.isEmpty()) { - scanResult.mPkgSetting.setStopped(false, 0); - } - } - if (mIncrementalManager != null && isIncrementalPath(parsedPackage.getPath())) { if (scanResult.mPkgSetting != null && scanResult.mPkgSetting.isLoading()) { // Continue monitoring loading progress of active incremental packages @@ -4314,6 +4300,7 @@ // - 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 a launcher entry which means the user doesn't have a way to unstop it final boolean isApexPkg = (scanFlags & SCAN_AS_APEX) != 0; if (mPm.mShouldStopSystemPackagesByDefault && scanSystemPartition @@ -4322,8 +4309,9 @@ && !parsedPackage.isOverlayIsStatic() ) { String packageName = parsedPackage.getPackageName(); - if (!mPm.mInitialNonStoppedSystemPackages.contains(packageName) - && !"android".contentEquals(packageName)) { + if (!"android".contentEquals(packageName) + && !mPm.mInitialNonStoppedSystemPackages.contains(packageName) + && hasLauncherEntry(parsedPackage)) { scanFlags |= SCAN_AS_STOPPED_SYSTEM_APP; } } @@ -4333,6 +4321,22 @@ return new Pair<>(scanResult, shouldHideSystemApp); } + private static boolean hasLauncherEntry(ParsedPackage parsedPackage) { + final HashSet<String> categories = new HashSet<>(); + categories.add(Intent.CATEGORY_LAUNCHER); + final List<ParsedActivity> activities = parsedPackage.getActivities(); + for (int indexActivity = 0; indexActivity < activities.size(); indexActivity++) { + final List<ParsedIntentInfo> intents = activities.get(indexActivity).getIntents(); + for (int indexIntent = 0; indexIntent < intents.size(); indexIntent++) { + final IntentFilter intentFilter = intents.get(indexIntent).getIntentFilter(); + if (intentFilter != null && intentFilter.matchCategories(categories) == null) { + return true; + } + } + } + return false; + } + /** * Returns if forced apk verification can be skipped for the whole package, including splits. */