Merge changes I64ce898e,I6d21792f,Ib977ea97,I006eddb0 into sc-qpr1-dev
* changes: Update getHomeActivitiesAsUser() Move findPreferredActivity logic into Computer Normalize findPreferredActivityNotLocked() DO NOT MERGE Removed unused priority argument
This commit is contained in:
@@ -2132,6 +2132,13 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
boolean filterAppAccess(String packageName, int callingUid, int userId);
|
boolean filterAppAccess(String packageName, int callingUid, int userId);
|
||||||
@LiveImplementation(override = LiveImplementation.MANDATORY)
|
@LiveImplementation(override = LiveImplementation.MANDATORY)
|
||||||
void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState);
|
void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState);
|
||||||
|
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
|
||||||
|
FindPreferredActivityBodyResult findPreferredActivityInternal(Intent intent,
|
||||||
|
String resolvedType, int flags, List<ResolveInfo> 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<ResolveInfo> query, boolean debug, int userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2914,7 +2921,24 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
}
|
}
|
||||||
allHomeCandidates.addAll(resolveInfos);
|
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) {
|
if (packageName == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -4846,6 +4870,284 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
}
|
}
|
||||||
} // switch
|
} // switch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The body of findPreferredActivity.
|
||||||
|
protected FindPreferredActivityBodyResult findPreferredActivityBody(
|
||||||
|
Intent intent, String resolvedType, int flags,
|
||||||
|
List<ResolveInfo> 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<PreferredActivity> 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) : "<none>")
|
||||||
|
+ "\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<ResolveInfo> 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<ResolveInfo> 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<PersistentPreferredActivity> 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) : "<none>")
|
||||||
|
+ "\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 +5307,16 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
super.dump(type, fd, pw, dumpState);
|
super.dump(type, fd, pw, dumpState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public final FindPreferredActivityBodyResult findPreferredActivityBody(Intent intent,
|
||||||
|
String resolvedType, int flags, List<ResolveInfo> 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 +5884,28 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
current.release();
|
current.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public final FindPreferredActivityBodyResult findPreferredActivityInternal(Intent intent,
|
||||||
|
String resolvedType, int flags, List<ResolveInfo> 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<ResolveInfo> query, boolean debug,
|
||||||
|
int userId) {
|
||||||
|
ThreadComputer current = live();
|
||||||
|
try {
|
||||||
|
return current.mComputer.findPersistentPreferredActivityLP(intent, resolvedType,
|
||||||
|
flags, query, debug, userId);
|
||||||
|
} finally {
|
||||||
|
current.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -9068,7 +9402,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
/**
|
/**
|
||||||
* Update given intent when being used to request {@link ResolveInfo}.
|
* 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) {
|
if (intent.getSelector() != null) {
|
||||||
intent = intent.getSelector();
|
intent = intent.getSelector();
|
||||||
}
|
}
|
||||||
@@ -10240,7 +10574,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
userId);
|
userId);
|
||||||
// Find any earlier preferred or last chosen entries and nuke them
|
// Find any earlier preferred or last chosen entries and nuke them
|
||||||
findPreferredActivityNotLocked(
|
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
|
// Add the new activity as the last chosen for this filter
|
||||||
addPreferredActivity(filter, match, null, activity, false, userId,
|
addPreferredActivity(filter, match, null, activity, false, userId,
|
||||||
"Setting last chosen", false);
|
"Setting last chosen", false);
|
||||||
@@ -10256,7 +10590,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags,
|
final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags,
|
||||||
userId);
|
userId);
|
||||||
return findPreferredActivityNotLocked(
|
return findPreferredActivityNotLocked(
|
||||||
intent, resolvedType, flags, query, 0, false, false, false, userId);
|
intent, resolvedType, flags, query, false, false, false, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
|
private void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
|
||||||
@@ -10298,7 +10632,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
// If we have saved a preference for a preferred activity for
|
// If we have saved a preference for a preferred activity for
|
||||||
// this Intent, use that.
|
// this Intent, use that.
|
||||||
ResolveInfo ri = findPreferredActivityNotLocked(intent, resolvedType,
|
ResolveInfo ri = findPreferredActivityNotLocked(intent, resolvedType,
|
||||||
flags, query, r0.priority, true, false, debug, userId, queryMayBeFiltered);
|
flags, query, true, false, debug, userId, queryMayBeFiltered);
|
||||||
if (ri != null) {
|
if (ri != null) {
|
||||||
return ri;
|
return ri;
|
||||||
}
|
}
|
||||||
@@ -10411,287 +10745,72 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
private ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType,
|
private ResolveInfo findPersistentPreferredActivityLP(Intent intent,
|
||||||
|
String resolvedType,
|
||||||
int flags, List<ResolveInfo> query, boolean debug, int userId) {
|
int flags, List<ResolveInfo> query, boolean debug, int userId) {
|
||||||
final int N = query.size();
|
return mComputer.findPersistentPreferredActivityLP(intent,
|
||||||
PersistentPreferredIntentResolver ppir = mSettings.getPersistentPreferredActivities(userId);
|
resolvedType,
|
||||||
// Get the list of persistent preferred activities that handle the intent
|
flags, query, debug, userId);
|
||||||
if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for presistent preferred activities...");
|
|
||||||
List<PersistentPreferredActivity> 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) : "<none>")
|
|
||||||
+ "\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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isHomeIntent(Intent intent) {
|
private static boolean isHomeIntent(Intent intent) {
|
||||||
return ACTION_MAIN.equals(intent.getAction())
|
return ACTION_MAIN.equals(intent.getAction())
|
||||||
&& intent.hasCategory(CATEGORY_HOME)
|
&& intent.hasCategory(CATEGORY_HOME)
|
||||||
&& intent.hasCategory(CATEGORY_DEFAULT);
|
&& intent.hasCategory(CATEGORY_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// findPreferredActivityBody returns two items: a "things changed" flag and a
|
||||||
|
// ResolveInfo, which is the preferred activity itself.
|
||||||
|
private static class FindPreferredActivityBodyResult {
|
||||||
|
boolean mChanged;
|
||||||
|
ResolveInfo mPreferredResolveInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private FindPreferredActivityBodyResult findPreferredActivityInternal(
|
||||||
|
Intent intent, String resolvedType, int flags,
|
||||||
|
List<ResolveInfo> query, boolean always,
|
||||||
|
boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
|
||||||
|
return mComputer.findPreferredActivityInternal(
|
||||||
|
intent, resolvedType, flags,
|
||||||
|
query, always,
|
||||||
|
removeMatches, debug, userId, queryMayBeFiltered);
|
||||||
|
}
|
||||||
|
|
||||||
ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags,
|
ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags,
|
||||||
List<ResolveInfo> query, int priority, boolean always,
|
List<ResolveInfo> query, boolean always,
|
||||||
boolean removeMatches, boolean debug, int userId) {
|
boolean removeMatches, boolean debug, int userId) {
|
||||||
return findPreferredActivityNotLocked(
|
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);
|
UserHandle.getAppId(Binder.getCallingUid()) >= Process.FIRST_APPLICATION_UID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: handle preferred activities missing while user has amnesia
|
// TODO: handle preferred activities missing while user has amnesia
|
||||||
/** <b>must not hold {@link #mLock}</b> */
|
/** <b>must not hold {@link #mLock}</b> */
|
||||||
ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags,
|
ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags,
|
||||||
List<ResolveInfo> query, int priority, boolean always,
|
List<ResolveInfo> query, boolean always,
|
||||||
boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
|
boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
|
||||||
if (Thread.holdsLock(mLock)) {
|
if (Thread.holdsLock(mLock)) {
|
||||||
Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
|
Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
|
||||||
+ " is holding mLock", new Throwable());
|
+ " is holding mLock", new Throwable());
|
||||||
}
|
}
|
||||||
if (!mUserManager.exists(userId)) return null;
|
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.
|
FindPreferredActivityBodyResult body = findPreferredActivityInternal(
|
||||||
if (pri != null) {
|
intent, resolvedType, flags, query, always,
|
||||||
return pri;
|
removeMatches, debug, userId, queryMayBeFiltered);
|
||||||
|
if (body.mChanged) {
|
||||||
|
if (DEBUG_PREFERRED) {
|
||||||
|
Slog.v(TAG, "Preferred activity bookkeeping changed; writing restrictions");
|
||||||
}
|
}
|
||||||
|
synchronized (mLock) {
|
||||||
PreferredIntentResolver pir = mSettings.getPreferredActivities(userId);
|
scheduleWritePackageRestrictionsLocked(userId);
|
||||||
// Get the list of preferred activities that handle the intent
|
|
||||||
if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities...");
|
|
||||||
List<PreferredActivity> 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<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) : "<none>")
|
|
||||||
+ "\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<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);
|
|
||||||
changed = 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);
|
|
||||||
changed = 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);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
return ri;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (changed) {
|
|
||||||
if (DEBUG_PREFERRED) {
|
|
||||||
Slog.v(TAG, "Preferred activity bookkeeping changed; writing restrictions");
|
|
||||||
}
|
|
||||||
scheduleWritePackageRestrictionsLocked(userId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (DEBUG_PREFERRED || debug) Slog.v(TAG, "No preferred activity to return");
|
if ((DEBUG_PREFERRED || debug) && body.mPreferredResolveInfo == null) {
|
||||||
return null;
|
Slog.v(TAG, "No preferred activity to return");
|
||||||
|
}
|
||||||
|
return body.mPreferredResolveInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -23468,7 +23587,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
final List<ResolveInfo> resolveInfos = queryIntentActivitiesInternal(intent, null,
|
final List<ResolveInfo> resolveInfos = queryIntentActivitiesInternal(intent, null,
|
||||||
MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId);
|
MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId);
|
||||||
final ResolveInfo preferredResolveInfo = findPreferredActivityNotLocked(
|
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
|
final String packageName = preferredResolveInfo != null
|
||||||
&& preferredResolveInfo.activityInfo != null
|
&& preferredResolveInfo.activityInfo != null
|
||||||
? preferredResolveInfo.activityInfo.packageName : null;
|
? preferredResolveInfo.activityInfo.packageName : null;
|
||||||
|
|||||||
Reference in New Issue
Block a user