From 7113328b534fc13eeca7a6b47ebcecfc0af4b25d Mon Sep 17 00:00:00 2001 From: Lee Shombert Date: Sat, 28 Aug 2021 17:57:32 -0700 Subject: [PATCH 1/4] DO NOT MERGE Removed unused priority argument Bug: 187080582 Make S consistent with T by removing the unused 'priority' argument from findPreferredActivityNotLocked(). This is a subset of the changes made under bug 194319951. The sole purpose of this change is to allow further changes for this bug can be committed into S and merge cleanly into T. Test: atest * FrameworksServicesTests:PackageManagerServiceTest Change-Id: I006eddb00b0ec06fda7364f0ac10446aff35fcb2 --- .../android/server/pm/PackageManagerService.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 140098da57911..bbe5f0563b5c7 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -10240,7 +10240,7 @@ public class PackageManagerService extends IPackageManager.Stub userId); // Find any earlier preferred or last chosen entries and nuke them findPreferredActivityNotLocked( - intent, resolvedType, flags, query, 0, false, true, false, userId); + intent, resolvedType, flags, query, false, true, false, userId); // Add the new activity as the last chosen for this filter addPreferredActivity(filter, match, null, activity, false, userId, "Setting last chosen", false); @@ -10256,7 +10256,7 @@ public class PackageManagerService extends IPackageManager.Stub final List query = queryIntentActivitiesInternal(intent, resolvedType, flags, userId); return findPreferredActivityNotLocked( - intent, resolvedType, flags, query, 0, false, false, false, userId); + intent, resolvedType, flags, query, false, false, false, userId); } private void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj, @@ -10298,7 +10298,7 @@ public class PackageManagerService extends IPackageManager.Stub // If we have saved a preference for a preferred activity for // this Intent, use that. ResolveInfo ri = findPreferredActivityNotLocked(intent, resolvedType, - flags, query, r0.priority, true, false, debug, userId, queryMayBeFiltered); + flags, query, true, false, debug, userId, queryMayBeFiltered); if (ri != null) { return ri; } @@ -10475,17 +10475,17 @@ public class PackageManagerService extends IPackageManager.Stub } ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags, - List query, int priority, boolean always, + List query, boolean always, boolean removeMatches, boolean debug, int userId) { return findPreferredActivityNotLocked( - intent, resolvedType, flags, query, priority, always, removeMatches, debug, userId, + intent, resolvedType, flags, query, always, removeMatches, debug, userId, UserHandle.getAppId(Binder.getCallingUid()) >= Process.FIRST_APPLICATION_UID); } // TODO: handle preferred activities missing while user has amnesia /** must not hold {@link #mLock} */ ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags, - List query, int priority, boolean always, + List query, boolean always, boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) { if (Thread.holdsLock(mLock)) { Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() @@ -23468,7 +23468,7 @@ public class PackageManagerService extends IPackageManager.Stub final List resolveInfos = queryIntentActivitiesInternal(intent, null, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId); final ResolveInfo preferredResolveInfo = findPreferredActivityNotLocked( - intent, null, 0, resolveInfos, 0, true, false, false, userId); + intent, null, 0, resolveInfos, true, false, false, userId); final String packageName = preferredResolveInfo != null && preferredResolveInfo.activityInfo != null ? preferredResolveInfo.activityInfo.packageName : null; From 37dc1932703b8200cbf4d370e7d480fd92dff8e6 Mon Sep 17 00:00:00 2001 From: Lee Shombert Date: Sat, 28 Aug 2021 17:58:00 -0700 Subject: [PATCH 2/4] Normalize findPreferredActivityNotLocked() Bug: 187080582 This change modifies PackageManagerService in preparation for moving findPreferredActivityNotLocked() into Computer. The synchronized block in findPreferredActivityNotLocked() is pulled into its own function to comply with Computer rules. Two functions that are needed by findPreferredActivityNotLocked() are made static so they can be referenced from inside ComputerEngine. Note that because the functions can be made static, they do not depend on the PM snapshot. Some calls from findPreferredActivityNotLocked() that used to be outside the PM lock are now inside the PM lock. A few legacy lint errors are corrected. Test: atest * CtsContentTestCases:IntentFilterTest * CtsDynamicMimeHostTestCases * CtsRoleTestCases * FrameworksServicesTests:UserSystemPackageInstallerTest * FrameworksServicesTests:PackageManagerSettingsTests * FrameworksServicesTests:PackageManagerServiceTest * FrameworksServicesTests:AppsFilterTest * FrameworksServicesTests:PackageInstallerSessionTest * FrameworksServicesTests:ScanTests * UserLifecycleTests#startUser * UserLifecycleTests#stopUser * UserLifecycleTests#switchUser * FrameworksServicesTests:WatcherTest * android.appsecurity.cts.EphemeralTest * android.appsecurity.cts.InstantAppUserTest Change-Id: Ib977ea97d06a5eaf02080272f25e8f6139406e7d --- .../server/pm/PackageManagerService.java | 454 ++++++++++-------- 1 file changed, 250 insertions(+), 204 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index bbe5f0563b5c7..5da8d9300a5dd 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -9068,7 +9068,7 @@ public class PackageManagerService extends IPackageManager.Stub /** * Update given intent when being used to request {@link ResolveInfo}. */ - private Intent updateIntentForResolve(Intent intent) { + private static Intent updateIntentForResolve(Intent intent) { if (intent.getSelector() != null) { intent = intent.getSelector(); } @@ -10411,12 +10411,15 @@ public class PackageManagerService extends IPackageManager.Stub } @GuardedBy("mLock") - private ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType, + private ResolveInfo findPersistentPreferredActivityLP(Intent intent, + String resolvedType, int flags, List query, boolean debug, int userId) { final int N = query.size(); PersistentPreferredIntentResolver ppir = mSettings.getPersistentPreferredActivities(userId); // Get the list of persistent preferred activities that handle the intent - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for presistent preferred activities..."); + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Looking for persistent preferred activities..."); + } List pprefs = ppir != null ? ppir.queryIntent(intent, resolvedType, (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, @@ -10424,7 +10427,7 @@ public class PackageManagerService extends IPackageManager.Stub : null; if (pprefs != null && pprefs.size() > 0) { final int M = pprefs.size(); - for (int i=0; i query, boolean always, + boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered, + int callingUid, boolean isDeviceProvisioned) { + synchronized (mLock) { + FindPreferredActivityBodyResult result = new FindPreferredActivityBodyResult(); + + flags = updateFlagsForResolve( + flags, userId, callingUid, false /*includeInstantApps*/, + isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, + resolvedType, flags)); + intent = updateIntentForResolve(intent); + + // Try to find a matching persistent preferred activity. + result.mPreferredResolveInfo = findPersistentPreferredActivityLP(intent, + resolvedType, flags, query, debug, userId); + + // If a persistent preferred activity matched, use it. + if (result.mPreferredResolveInfo != null) { + return result; + } + + PreferredIntentResolver pir = mSettings.getPreferredActivities(userId); + // Get the list of preferred activities that handle the intent + if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities..."); + List prefs = pir != null + ? pir.queryIntent(intent, resolvedType, + (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, + userId) + : null; + if (prefs != null && prefs.size() > 0) { + + // First figure out how good the original match set is. + // We will only allow preferred activities that came + // from the same match quality. + int match = 0; + + if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Figuring out best match..."); + + final int N = query.size(); + for (int j = 0; j < N; j++) { + final ResolveInfo ri = query.get(j); + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Match for " + ri.activityInfo + + ": 0x" + Integer.toHexString(match)); + } + if (ri.match > match) { + match = ri.match; + } + } + + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Best match: 0x" + Integer.toHexString(match)); + } + match &= IntentFilter.MATCH_CATEGORY_MASK; + final int M = prefs.size(); + for (int i = 0; i < M; i++) { + final PreferredActivity pa = prefs.get(i); + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Checking PreferredActivity ds=" + + (pa.countDataSchemes() > 0 ? pa.getDataScheme(0) : "") + + "\n component=" + pa.mPref.mComponent); + pa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); + } + if (pa.mPref.mMatch != match) { + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Skipping bad match " + + Integer.toHexString(pa.mPref.mMatch)); + } + continue; + } + // If it's not an "always" type preferred activity and that's what we're + // looking for, skip it. + if (always && !pa.mPref.mAlways) { + if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry"); + continue; + } + final ActivityInfo ai = getActivityInfo( + pa.mPref.mComponent, flags | MATCH_DISABLED_COMPONENTS + | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, + userId); + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Found preferred activity:"); + if (ai != null) { + ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); + } else { + Slog.v(TAG, " null"); + } + } + final boolean excludeSetupWizardHomeActivity = isHomeIntent(intent) + && !isDeviceProvisioned; + final boolean allowSetMutation = !excludeSetupWizardHomeActivity + && !queryMayBeFiltered; + if (ai == null) { + // Do not remove launcher's preferred activity during SetupWizard + // due to it may not install yet + if (!allowSetMutation) { + continue; + } + + // This previously registered preferred activity + // component is no longer known. Most likely an update + // to the app was installed and in the new version this + // component no longer exists. Clean it up by removing + // it from the preferred activities list, and skip it. + Slog.w(TAG, "Removing dangling preferred activity: " + + pa.mPref.mComponent); + pir.removeFilter(pa); + result.mChanged = true; + continue; + } + for (int j = 0; j < N; j++) { + final ResolveInfo ri = query.get(j); + if (!ri.activityInfo.applicationInfo.packageName + .equals(ai.applicationInfo.packageName)) { + continue; + } + if (!ri.activityInfo.name.equals(ai.name)) { + continue; + } + + if (removeMatches && allowSetMutation) { + pir.removeFilter(pa); + result.mChanged = true; + if (DEBUG_PREFERRED) { + Slog.v(TAG, "Removing match " + pa.mPref.mComponent); + } + break; + } + + // Okay we found a previously set preferred or last chosen app. + // If the result set is different from when this + // was created, and is not a subset of the preferred set, we need to + // clear it and re-ask the user their preference, if we're looking for + // an "always" type entry. + + if (always && !pa.mPref.sameSet(query, excludeSetupWizardHomeActivity)) { + if (pa.mPref.isSuperset(query, excludeSetupWizardHomeActivity)) { + if (allowSetMutation) { + // some components of the set are no longer present in + // the query, but the preferred activity can still be reused + if (DEBUG_PREFERRED) { + Slog.i(TAG, "Result set changed, but PreferredActivity" + + " is still valid as only non-preferred" + + " components were removed for " + intent + + " type " + resolvedType); + } + // remove obsolete components and re-add the up-to-date + // filter + PreferredActivity freshPa = new PreferredActivity(pa, + pa.mPref.mMatch, + pa.mPref.discardObsoleteComponents(query), + pa.mPref.mComponent, + pa.mPref.mAlways); + pir.removeFilter(pa); + pir.addFilter(freshPa); + result.mChanged = true; + } else { + if (DEBUG_PREFERRED) { + Slog.i(TAG, "Do not remove preferred activity"); + } + } + } else { + if (allowSetMutation) { + Slog.i(TAG, + "Result set changed, dropping preferred activity " + + "for " + intent + " type " + + resolvedType); + if (DEBUG_PREFERRED) { + Slog.v(TAG, + "Removing preferred activity since set changed " + + pa.mPref.mComponent); + } + pir.removeFilter(pa); + // Re-add the filter as a "last chosen" entry (!always) + PreferredActivity lastChosen = new PreferredActivity( + pa, pa.mPref.mMatch, null, pa.mPref.mComponent, + false); + pir.addFilter(lastChosen); + result.mChanged = true; + } + result.mPreferredResolveInfo = null; + return result; + } + } + + // Yay! Either the set matched or we're looking for the last chosen + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Returning preferred activity: " + + ri.activityInfo.packageName + "/" + ri.activityInfo.name); + } + result.mPreferredResolveInfo = ri; + return result; + } + } + } + return result; + } + } + + private FindPreferredActivityBodyResult findPreferredActivityInternal( + Intent intent, String resolvedType, int flags, + List query, boolean always, + boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) { + + final int callingUid = Binder.getCallingUid(); + // Do NOT hold the packages lock; this calls up into the settings provider which + // could cause a deadlock. + final boolean isDeviceProvisioned = + android.provider.Settings.Global.getInt(mContext.getContentResolver(), + android.provider.Settings.Global.DEVICE_PROVISIONED, 0) == 1; + // Find the preferred activity - the lock is held inside the method. + return findPreferredActivityBody( + intent, resolvedType, flags, query, always, removeMatches, debug, + userId, queryMayBeFiltered, callingUid, isDeviceProvisioned); + } + ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags, List query, boolean always, boolean removeMatches, boolean debug, int userId) { @@ -10492,206 +10722,22 @@ public class PackageManagerService extends IPackageManager.Stub + " is holding mLock", new Throwable()); } if (!mUserManager.exists(userId)) return null; - final int callingUid = Binder.getCallingUid(); - // Do NOT hold the packages lock; this calls up into the settings provider which - // could cause a deadlock. - final boolean isDeviceProvisioned = - android.provider.Settings.Global.getInt(mContext.getContentResolver(), - android.provider.Settings.Global.DEVICE_PROVISIONED, 0) == 1; - flags = updateFlagsForResolve( - flags, userId, callingUid, false /*includeInstantApps*/, - isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType, - flags)); - intent = updateIntentForResolve(intent); - // writer - synchronized (mLock) { - // Try to find a matching persistent preferred activity. - ResolveInfo pri = findPersistentPreferredActivityLP(intent, resolvedType, flags, query, - debug, userId); - // If a persistent preferred activity matched, use it. - if (pri != null) { - return pri; + FindPreferredActivityBodyResult body = findPreferredActivityInternal( + intent, resolvedType, flags, query, always, + removeMatches, debug, userId, queryMayBeFiltered); + if (body.mChanged) { + if (DEBUG_PREFERRED) { + Slog.v(TAG, "Preferred activity bookkeeping changed; writing restrictions"); } - - PreferredIntentResolver pir = mSettings.getPreferredActivities(userId); - // Get the list of preferred activities that handle the intent - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities..."); - List prefs = pir != null - ? pir.queryIntent(intent, resolvedType, - (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, - userId) - : null; - if (prefs != null && prefs.size() > 0) { - boolean changed = false; - try { - // First figure out how good the original match set is. - // We will only allow preferred activities that came - // from the same match quality. - int match = 0; - - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Figuring out best match..."); - - final int N = query.size(); - for (int j=0; j match) { - match = ri.match; - } - } - - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Best match: 0x" - + Integer.toHexString(match)); - - match &= IntentFilter.MATCH_CATEGORY_MASK; - final int M = prefs.size(); - for (int i=0; i") - + "\n component=" + pa.mPref.mComponent); - pa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); - } - if (pa.mPref.mMatch != match) { - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping bad match " - + Integer.toHexString(pa.mPref.mMatch)); - continue; - } - // If it's not an "always" type preferred activity and that's what we're - // looking for, skip it. - if (always && !pa.mPref.mAlways) { - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry"); - continue; - } - final ActivityInfo ai = getActivityInfo( - pa.mPref.mComponent, flags | MATCH_DISABLED_COMPONENTS - | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, - userId); - if (DEBUG_PREFERRED || debug) { - Slog.v(TAG, "Found preferred activity:"); - if (ai != null) { - ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); - } else { - Slog.v(TAG, " null"); - } - } - final boolean excludeSetupWizardHomeActivity = isHomeIntent(intent) - && !isDeviceProvisioned; - final boolean allowSetMutation = !excludeSetupWizardHomeActivity - && !queryMayBeFiltered; - if (ai == null) { - // Do not remove launcher's preferred activity during SetupWizard - // due to it may not install yet - if (!allowSetMutation) { - continue; - } - - // This previously registered preferred activity - // component is no longer known. Most likely an update - // to the app was installed and in the new version this - // component no longer exists. Clean it up by removing - // it from the preferred activities list, and skip it. - Slog.w(TAG, "Removing dangling preferred activity: " - + pa.mPref.mComponent); - pir.removeFilter(pa); - changed = true; - continue; - } - for (int j=0; j Date: Sat, 28 Aug 2021 18:02:14 -0700 Subject: [PATCH 3/4] Move findPreferredActivity logic into Computer Bug: 187080582 Move the query portion of findPreferredActivityNotLocked() into Computer. The code is moved unchanged into ComputerEngine except that four lint errors are corrected. Test: atest * CtsContentTestCases:IntentFilterTest * CtsDynamicMimeHostTestCases * CtsRoleTestCases * FrameworksServicesTests:UserSystemPackageInstallerTest * FrameworksServicesTests:PackageManagerSettingsTests * FrameworksServicesTests:PackageManagerServiceTest * FrameworksServicesTests:AppsFilterTest * FrameworksServicesTests:PackageInstallerSessionTest * FrameworksServicesTests:ScanTests * UserLifecycleTests#startUser * UserLifecycleTests#stopUser * UserLifecycleTests#switchUser * FrameworksServicesTests:WatcherTest * android.appsecurity.cts.EphemeralTest * android.appsecurity.cts.InstantAppUserTest Change-Id: I6d21792f3208689694b917a79cbee8a75a131c8e --- .../server/pm/PackageManagerService.java | 592 ++++++++++-------- 1 file changed, 324 insertions(+), 268 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 5da8d9300a5dd..5dec110888a29 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -2132,6 +2132,13 @@ public class PackageManagerService extends IPackageManager.Stub boolean filterAppAccess(String packageName, int callingUid, int userId); @LiveImplementation(override = LiveImplementation.MANDATORY) void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) + FindPreferredActivityBodyResult findPreferredActivityInternal(Intent intent, + String resolvedType, int flags, List query, boolean always, + boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) + ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType, int flags, + List query, boolean debug, int userId); } /** @@ -4846,6 +4853,284 @@ public class PackageManagerService extends IPackageManager.Stub } } // switch } + + // The body of findPreferredActivity. + protected FindPreferredActivityBodyResult findPreferredActivityBody( + Intent intent, String resolvedType, int flags, + List query, boolean always, + boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered, + int callingUid, boolean isDeviceProvisioned) { + FindPreferredActivityBodyResult result = new FindPreferredActivityBodyResult(); + + flags = updateFlagsForResolve( + flags, userId, callingUid, false /*includeInstantApps*/, + isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, + resolvedType, flags)); + intent = updateIntentForResolve(intent); + + // Try to find a matching persistent preferred activity. + result.mPreferredResolveInfo = findPersistentPreferredActivityLP(intent, + resolvedType, flags, query, debug, userId); + + // If a persistent preferred activity matched, use it. + if (result.mPreferredResolveInfo != null) { + return result; + } + + PreferredIntentResolver pir = mSettings.getPreferredActivities(userId); + // Get the list of preferred activities that handle the intent + if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities..."); + List prefs = pir != null + ? pir.queryIntent(intent, resolvedType, + (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, + userId) + : null; + if (prefs != null && prefs.size() > 0) { + + // First figure out how good the original match set is. + // We will only allow preferred activities that came + // from the same match quality. + int match = 0; + + if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Figuring out best match..."); + + final int N = query.size(); + for (int j = 0; j < N; j++) { + final ResolveInfo ri = query.get(j); + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Match for " + ri.activityInfo + + ": 0x" + Integer.toHexString(match)); + } + if (ri.match > match) { + match = ri.match; + } + } + + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Best match: 0x" + Integer.toHexString(match)); + } + match &= IntentFilter.MATCH_CATEGORY_MASK; + final int M = prefs.size(); + for (int i = 0; i < M; i++) { + final PreferredActivity pa = prefs.get(i); + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Checking PreferredActivity ds=" + + (pa.countDataSchemes() > 0 ? pa.getDataScheme(0) : "") + + "\n component=" + pa.mPref.mComponent); + pa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); + } + if (pa.mPref.mMatch != match) { + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Skipping bad match " + + Integer.toHexString(pa.mPref.mMatch)); + } + continue; + } + // If it's not an "always" type preferred activity and that's what we're + // looking for, skip it. + if (always && !pa.mPref.mAlways) { + if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry"); + continue; + } + final ActivityInfo ai = getActivityInfo( + pa.mPref.mComponent, flags | MATCH_DISABLED_COMPONENTS + | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, + userId); + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Found preferred activity:"); + if (ai != null) { + ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); + } else { + Slog.v(TAG, " null"); + } + } + final boolean excludeSetupWizardHomeActivity = isHomeIntent(intent) + && !isDeviceProvisioned; + final boolean allowSetMutation = !excludeSetupWizardHomeActivity + && !queryMayBeFiltered; + if (ai == null) { + // Do not remove launcher's preferred activity during SetupWizard + // due to it may not install yet + if (!allowSetMutation) { + continue; + } + + // This previously registered preferred activity + // component is no longer known. Most likely an update + // to the app was installed and in the new version this + // component no longer exists. Clean it up by removing + // it from the preferred activities list, and skip it. + Slog.w(TAG, "Removing dangling preferred activity: " + + pa.mPref.mComponent); + pir.removeFilter(pa); + result.mChanged = true; + continue; + } + for (int j = 0; j < N; j++) { + final ResolveInfo ri = query.get(j); + if (!ri.activityInfo.applicationInfo.packageName + .equals(ai.applicationInfo.packageName)) { + continue; + } + if (!ri.activityInfo.name.equals(ai.name)) { + continue; + } + + if (removeMatches && allowSetMutation) { + pir.removeFilter(pa); + result.mChanged = true; + if (DEBUG_PREFERRED) { + Slog.v(TAG, "Removing match " + pa.mPref.mComponent); + } + break; + } + + // Okay we found a previously set preferred or last chosen app. + // If the result set is different from when this + // was created, and is not a subset of the preferred set, we need to + // clear it and re-ask the user their preference, if we're looking for + // an "always" type entry. + + if (always && !pa.mPref.sameSet(query, excludeSetupWizardHomeActivity)) { + if (pa.mPref.isSuperset(query, excludeSetupWizardHomeActivity)) { + if (allowSetMutation) { + // some components of the set are no longer present in + // the query, but the preferred activity can still be reused + if (DEBUG_PREFERRED) { + Slog.i(TAG, "Result set changed, but PreferredActivity" + + " is still valid as only non-preferred" + + " components were removed for " + intent + + " type " + resolvedType); + } + // remove obsolete components and re-add the up-to-date + // filter + PreferredActivity freshPa = new PreferredActivity(pa, + pa.mPref.mMatch, + pa.mPref.discardObsoleteComponents(query), + pa.mPref.mComponent, + pa.mPref.mAlways); + pir.removeFilter(pa); + pir.addFilter(freshPa); + result.mChanged = true; + } else { + if (DEBUG_PREFERRED) { + Slog.i(TAG, "Do not remove preferred activity"); + } + } + } else { + if (allowSetMutation) { + Slog.i(TAG, + "Result set changed, dropping preferred activity " + + "for " + intent + " type " + + resolvedType); + if (DEBUG_PREFERRED) { + Slog.v(TAG, + "Removing preferred activity since set changed " + + pa.mPref.mComponent); + } + pir.removeFilter(pa); + // Re-add the filter as a "last chosen" entry (!always) + PreferredActivity lastChosen = new PreferredActivity( + pa, pa.mPref.mMatch, null, pa.mPref.mComponent, + false); + pir.addFilter(lastChosen); + result.mChanged = true; + } + result.mPreferredResolveInfo = null; + return result; + } + } + + // Yay! Either the set matched or we're looking for the last chosen + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Returning preferred activity: " + + ri.activityInfo.packageName + "/" + ri.activityInfo.name); + } + result.mPreferredResolveInfo = ri; + return result; + } + } + } + return result; + } + + public final FindPreferredActivityBodyResult findPreferredActivityInternal( + Intent intent, String resolvedType, int flags, + List query, boolean always, + boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) { + + final int callingUid = Binder.getCallingUid(); + // Do NOT hold the packages lock; this calls up into the settings provider which + // could cause a deadlock. + final boolean isDeviceProvisioned = + android.provider.Settings.Global.getInt(mContext.getContentResolver(), + android.provider.Settings.Global.DEVICE_PROVISIONED, 0) == 1; + // Find the preferred activity - the lock is held inside the method. + return findPreferredActivityBody( + intent, resolvedType, flags, query, always, removeMatches, debug, + userId, queryMayBeFiltered, callingUid, isDeviceProvisioned); + } + + public final ResolveInfo findPersistentPreferredActivityLP(Intent intent, + String resolvedType, + int flags, List query, boolean debug, int userId) { + final int N = query.size(); + PersistentPreferredIntentResolver ppir = + mSettings.getPersistentPreferredActivities(userId); + // Get the list of persistent preferred activities that handle the intent + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Looking for persistent preferred activities..."); + } + List pprefs = ppir != null + ? ppir.queryIntent(intent, resolvedType, + (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, + userId) + : null; + if (pprefs != null && pprefs.size() > 0) { + final int M = pprefs.size(); + for (int i = 0; i < M; i++) { + final PersistentPreferredActivity ppa = pprefs.get(i); + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Checking PersistentPreferredActivity ds=" + + (ppa.countDataSchemes() > 0 ? ppa.getDataScheme(0) : "") + + "\n component=" + ppa.mComponent); + ppa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); + } + final ActivityInfo ai = getActivityInfo(ppa.mComponent, + flags | MATCH_DISABLED_COMPONENTS, userId); + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Found persistent preferred activity:"); + if (ai != null) { + ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); + } else { + Slog.v(TAG, " null"); + } + } + if (ai == null) { + // This previously registered persistent preferred activity + // component is no longer known. Ignore it and do NOT remove it. + continue; + } + for (int j = 0; j < N; j++) { + final ResolveInfo ri = query.get(j); + if (!ri.activityInfo.applicationInfo.packageName + .equals(ai.applicationInfo.packageName)) { + continue; + } + if (!ri.activityInfo.name.equals(ai.name)) { + continue; + } + // Found a persistent preference that can handle the intent. + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Returning persistent preferred activity: " + + ri.activityInfo.packageName + "/" + ri.activityInfo.name); + } + return ri; + } + } + } + return null; + } } /** @@ -5005,6 +5290,16 @@ public class PackageManagerService extends IPackageManager.Stub super.dump(type, fd, pw, dumpState); } } + public final FindPreferredActivityBodyResult findPreferredActivityBody(Intent intent, + String resolvedType, int flags, List query, boolean always, + boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered, + int callingUid, boolean isDeviceProvisioned) { + synchronized (mLock) { + return super.findPreferredActivityBody(intent, resolvedType, flags, query, always, + removeMatches, debug, userId, queryMayBeFiltered, callingUid, + isDeviceProvisioned); + } + } } /** @@ -5572,6 +5867,28 @@ public class PackageManagerService extends IPackageManager.Stub current.release(); } } + public final FindPreferredActivityBodyResult findPreferredActivityInternal(Intent intent, + String resolvedType, int flags, List query, boolean always, + boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) { + ThreadComputer current = live(); + try { + return current.mComputer.findPreferredActivityInternal(intent, resolvedType, flags, + query, always, removeMatches, debug, userId, queryMayBeFiltered); + } finally { + current.release(); + } + } + public final ResolveInfo findPersistentPreferredActivityLP(Intent intent, + String resolvedType, int flags, List query, boolean debug, + int userId) { + ThreadComputer current = live(); + try { + return current.mComputer.findPersistentPreferredActivityLP(intent, resolvedType, + flags, query, debug, userId); + } finally { + current.release(); + } + } } @@ -10414,61 +10731,9 @@ public class PackageManagerService extends IPackageManager.Stub private ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType, int flags, List query, boolean debug, int userId) { - final int N = query.size(); - PersistentPreferredIntentResolver ppir = mSettings.getPersistentPreferredActivities(userId); - // Get the list of persistent preferred activities that handle the intent - if (DEBUG_PREFERRED || debug) { - Slog.v(TAG, "Looking for persistent preferred activities..."); - } - List pprefs = ppir != null - ? ppir.queryIntent(intent, resolvedType, - (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, - userId) - : null; - if (pprefs != null && pprefs.size() > 0) { - final int M = pprefs.size(); - for (int i = 0; i < M; i++) { - final PersistentPreferredActivity ppa = pprefs.get(i); - if (DEBUG_PREFERRED || debug) { - Slog.v(TAG, "Checking PersistentPreferredActivity ds=" - + (ppa.countDataSchemes() > 0 ? ppa.getDataScheme(0) : "") - + "\n component=" + ppa.mComponent); - ppa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); - } - final ActivityInfo ai = getActivityInfo(ppa.mComponent, - flags | MATCH_DISABLED_COMPONENTS, userId); - if (DEBUG_PREFERRED || debug) { - Slog.v(TAG, "Found persistent preferred activity:"); - if (ai != null) { - ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); - } else { - Slog.v(TAG, " null"); - } - } - if (ai == null) { - // This previously registered persistent preferred activity - // component is no longer known. Ignore it and do NOT remove it. - continue; - } - for (int j = 0; j < N; j++) { - final ResolveInfo ri = query.get(j); - if (!ri.activityInfo.applicationInfo.packageName - .equals(ai.applicationInfo.packageName)) { - continue; - } - if (!ri.activityInfo.name.equals(ai.name)) { - continue; - } - // Found a persistent preference that can handle the intent. - if (DEBUG_PREFERRED || debug) { - Slog.v(TAG, "Returning persistent preferred activity: " - + ri.activityInfo.packageName + "/" + ri.activityInfo.name); - } - return ri; - } - } - } - return null; + return mComputer.findPersistentPreferredActivityLP(intent, + resolvedType, + flags, query, debug, userId); } private static boolean isHomeIntent(Intent intent) { @@ -10485,223 +10750,14 @@ public class PackageManagerService extends IPackageManager.Stub ResolveInfo mPreferredResolveInfo; } - // The body of findPreferredActivity. - private FindPreferredActivityBodyResult findPreferredActivityBody( - Intent intent, String resolvedType, int flags, - List query, boolean always, - boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered, - int callingUid, boolean isDeviceProvisioned) { - synchronized (mLock) { - FindPreferredActivityBodyResult result = new FindPreferredActivityBodyResult(); - - flags = updateFlagsForResolve( - flags, userId, callingUid, false /*includeInstantApps*/, - isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, - resolvedType, flags)); - intent = updateIntentForResolve(intent); - - // Try to find a matching persistent preferred activity. - result.mPreferredResolveInfo = findPersistentPreferredActivityLP(intent, - resolvedType, flags, query, debug, userId); - - // If a persistent preferred activity matched, use it. - if (result.mPreferredResolveInfo != null) { - return result; - } - - PreferredIntentResolver pir = mSettings.getPreferredActivities(userId); - // Get the list of preferred activities that handle the intent - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities..."); - List prefs = pir != null - ? pir.queryIntent(intent, resolvedType, - (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, - userId) - : null; - if (prefs != null && prefs.size() > 0) { - - // First figure out how good the original match set is. - // We will only allow preferred activities that came - // from the same match quality. - int match = 0; - - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Figuring out best match..."); - - final int N = query.size(); - for (int j = 0; j < N; j++) { - final ResolveInfo ri = query.get(j); - if (DEBUG_PREFERRED || debug) { - Slog.v(TAG, "Match for " + ri.activityInfo - + ": 0x" + Integer.toHexString(match)); - } - if (ri.match > match) { - match = ri.match; - } - } - - if (DEBUG_PREFERRED || debug) { - Slog.v(TAG, "Best match: 0x" + Integer.toHexString(match)); - } - match &= IntentFilter.MATCH_CATEGORY_MASK; - final int M = prefs.size(); - for (int i = 0; i < M; i++) { - final PreferredActivity pa = prefs.get(i); - if (DEBUG_PREFERRED || debug) { - Slog.v(TAG, "Checking PreferredActivity ds=" - + (pa.countDataSchemes() > 0 ? pa.getDataScheme(0) : "") - + "\n component=" + pa.mPref.mComponent); - pa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); - } - if (pa.mPref.mMatch != match) { - if (DEBUG_PREFERRED || debug) { - Slog.v(TAG, "Skipping bad match " - + Integer.toHexString(pa.mPref.mMatch)); - } - continue; - } - // If it's not an "always" type preferred activity and that's what we're - // looking for, skip it. - if (always && !pa.mPref.mAlways) { - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry"); - continue; - } - final ActivityInfo ai = getActivityInfo( - pa.mPref.mComponent, flags | MATCH_DISABLED_COMPONENTS - | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, - userId); - if (DEBUG_PREFERRED || debug) { - Slog.v(TAG, "Found preferred activity:"); - if (ai != null) { - ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); - } else { - Slog.v(TAG, " null"); - } - } - final boolean excludeSetupWizardHomeActivity = isHomeIntent(intent) - && !isDeviceProvisioned; - final boolean allowSetMutation = !excludeSetupWizardHomeActivity - && !queryMayBeFiltered; - if (ai == null) { - // Do not remove launcher's preferred activity during SetupWizard - // due to it may not install yet - if (!allowSetMutation) { - continue; - } - - // This previously registered preferred activity - // component is no longer known. Most likely an update - // to the app was installed and in the new version this - // component no longer exists. Clean it up by removing - // it from the preferred activities list, and skip it. - Slog.w(TAG, "Removing dangling preferred activity: " - + pa.mPref.mComponent); - pir.removeFilter(pa); - result.mChanged = true; - continue; - } - for (int j = 0; j < N; j++) { - final ResolveInfo ri = query.get(j); - if (!ri.activityInfo.applicationInfo.packageName - .equals(ai.applicationInfo.packageName)) { - continue; - } - if (!ri.activityInfo.name.equals(ai.name)) { - continue; - } - - if (removeMatches && allowSetMutation) { - pir.removeFilter(pa); - result.mChanged = true; - if (DEBUG_PREFERRED) { - Slog.v(TAG, "Removing match " + pa.mPref.mComponent); - } - break; - } - - // Okay we found a previously set preferred or last chosen app. - // If the result set is different from when this - // was created, and is not a subset of the preferred set, we need to - // clear it and re-ask the user their preference, if we're looking for - // an "always" type entry. - - if (always && !pa.mPref.sameSet(query, excludeSetupWizardHomeActivity)) { - if (pa.mPref.isSuperset(query, excludeSetupWizardHomeActivity)) { - if (allowSetMutation) { - // some components of the set are no longer present in - // the query, but the preferred activity can still be reused - if (DEBUG_PREFERRED) { - Slog.i(TAG, "Result set changed, but PreferredActivity" - + " is still valid as only non-preferred" - + " components were removed for " + intent - + " type " + resolvedType); - } - // remove obsolete components and re-add the up-to-date - // filter - PreferredActivity freshPa = new PreferredActivity(pa, - pa.mPref.mMatch, - pa.mPref.discardObsoleteComponents(query), - pa.mPref.mComponent, - pa.mPref.mAlways); - pir.removeFilter(pa); - pir.addFilter(freshPa); - result.mChanged = true; - } else { - if (DEBUG_PREFERRED) { - Slog.i(TAG, "Do not remove preferred activity"); - } - } - } else { - if (allowSetMutation) { - Slog.i(TAG, - "Result set changed, dropping preferred activity " - + "for " + intent + " type " - + resolvedType); - if (DEBUG_PREFERRED) { - Slog.v(TAG, - "Removing preferred activity since set changed " - + pa.mPref.mComponent); - } - pir.removeFilter(pa); - // Re-add the filter as a "last chosen" entry (!always) - PreferredActivity lastChosen = new PreferredActivity( - pa, pa.mPref.mMatch, null, pa.mPref.mComponent, - false); - pir.addFilter(lastChosen); - result.mChanged = true; - } - result.mPreferredResolveInfo = null; - return result; - } - } - - // Yay! Either the set matched or we're looking for the last chosen - if (DEBUG_PREFERRED || debug) { - Slog.v(TAG, "Returning preferred activity: " - + ri.activityInfo.packageName + "/" + ri.activityInfo.name); - } - result.mPreferredResolveInfo = ri; - return result; - } - } - } - return result; - } - } - private FindPreferredActivityBodyResult findPreferredActivityInternal( Intent intent, String resolvedType, int flags, List query, boolean always, boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) { - - final int callingUid = Binder.getCallingUid(); - // Do NOT hold the packages lock; this calls up into the settings provider which - // could cause a deadlock. - final boolean isDeviceProvisioned = - android.provider.Settings.Global.getInt(mContext.getContentResolver(), - android.provider.Settings.Global.DEVICE_PROVISIONED, 0) == 1; - // Find the preferred activity - the lock is held inside the method. - return findPreferredActivityBody( - intent, resolvedType, flags, query, always, removeMatches, debug, - userId, queryMayBeFiltered, callingUid, isDeviceProvisioned); + return mComputer.findPreferredActivityInternal( + intent, resolvedType, flags, + query, always, + removeMatches, debug, userId, queryMayBeFiltered); } ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags, From 271463ed473680d8ab2b9178e65e2efd3f2bb847 Mon Sep 17 00:00:00 2001 From: Lee Shombert Date: Sat, 28 Aug 2021 18:02:46 -0700 Subject: [PATCH 4/4] Update getHomeActivitiesAsUser() Bug: 187080582 Call findPreferredActivityInternalLPr() from getHomeActivitiesAsUser(). Test: atest * CtsContentTestCases:IntentFilterTest * CtsDynamicMimeHostTestCases * CtsRoleTestCases * FrameworksServicesTests:UserSystemPackageInstallerTest * FrameworksServicesTests:PackageManagerSettingsTests * FrameworksServicesTests:PackageManagerServiceTest * FrameworksServicesTests:AppsFilterTest * FrameworksServicesTests:PackageInstallerSessionTest * FrameworksServicesTests:ScanTests * UserLifecycleTests#startUser * UserLifecycleTests#stopUser * UserLifecycleTests#switchUser * FrameworksServicesTests:WatcherTest * android.appsecurity.cts.EphemeralTest * android.appsecurity.cts.InstantAppUserTest Change-Id: I64ce898e36d5164b4891d8376da603e7b849aada --- .../server/pm/PackageManagerService.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 5dec110888a29..a0654ac0f2eb7 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -2921,7 +2921,24 @@ public class PackageManagerService extends IPackageManager.Stub } allHomeCandidates.addAll(resolveInfos); - final String packageName = mDefaultAppProvider.getDefaultHome(userId); + String packageName = mDefaultAppProvider.getDefaultHome(userId); + if (packageName == null) { + // Role changes are not and cannot be atomic because its implementation lives inside + // a system app, so when the home role changes, there is a window when the previous + // role holder is removed and the new role holder is granted the preferred activity, + // but hasn't become the role holder yet. However, this case may be easily hit + // because the preferred activity change triggers a broadcast and receivers may try + // to get the default home activity there. So we need to fix it for this time + // window, and an easy workaround is to fallback to the current preferred activity. + final int appId = UserHandle.getAppId(Binder.getCallingUid()); + final boolean filtered = appId >= Process.FIRST_APPLICATION_UID; + FindPreferredActivityBodyResult result = findPreferredActivityInternal( + intent, null, 0, resolveInfos, true, false, false, userId, filtered); + ResolveInfo preferredResolveInfo = result.mPreferredResolveInfo; + if (preferredResolveInfo != null && preferredResolveInfo.activityInfo != null) { + packageName = preferredResolveInfo.activityInfo.packageName; + } + } if (packageName == null) { return null; }