参考链接
前言
本篇基于Android11源码分析系统中桌面应用的启动过程。 在Android 系统中,桌面其本质也只是一个系统应用。下文,我们分析 launcher启动过程。 首先,我们从 package-restrications.xml 偏好文件讲起.
配置默认启动桌面
package-restrications.xml 介绍
package-restrications.xml 文件,位于/data/system/users/0/package-restrictions.xml
,文件中保存了一些关于应用状态(应用是否被禁用),应用偏好信息。其中包括桌面应用信息,默认桌面的配置信息。
<package-restrictions>
...
<preferred-activities>
...
<item name="com.my.launcher/.activity.MainActivity" match="100000" always="true" set="3">
<set name="com.android.launcher3/.uioverrides.QuickstepLauncher" />
<set name="com.my.launcher/.activity.MainActivity" />
<set name="com.android.settings/.FallbackHome" />
<filter>
<action name="android.intent.action.MAIN" />
<cat name="android.intent.category.HOME" />
<cat name="android.intent.category.DEFAULT" />
</filter>
</item>
</preferred-activities>
<persistent-preferred-activities />
...
</package-restrictions>
preferred-activities
下保存了应用偏好,filter
标签下的广播和cat 就是用于判断是否是桌面应用Activity的。
系统启动后,如果用户手动修改了应用的状态或者偏好,
package-restrictions.xml
会被重写为当前系统配置。如果用户没有涉及的操作,在关机时该文件也并不会被重写。
桌面应用的开发
在应用的
Activity
进行如下配置,该应用就是桌面应用了,按下home键,会提示你选择桌面。
但是,大多厂商会都是要求三方页面是经过他们认证的,才可以设置。比如我的小米手机,就禁止设置非认证 的三方桌面。
系统启动
此处只从 Java
层开始分析,init 进程启动了ZygoteInit 进程。
在 frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
的 main
方法中,调用了forkSystemServer
方法,启动了SystemServer
进程。
SystemService.java
public static void main(String[] args) {
new SystemServer().run();
}
private void run(){
...
startBootstrapServices(t);
startCoreServices(t);
startOtherServices(t);
...
}
private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
...
// 启动AMS
t.traceBegin("StartActivityManager");
// TODO: Might need to move after migration to WM.
ActivityTaskManagerService atm = mSystemServiceManager.startService(
ActivityTaskManagerService.Lifecycle.class).getService();
mActivityManagerService = ActivityManagerService.Lifecycle.startService(
mSystemServiceManager, atm);
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mActivityManagerService.setInstaller(installer);
mWindowManagerGlobalLock = atm.getGlobalLock();
t.traceEnd();
...
// 启动PMS
t.traceBegin("StartPackageManagerService");
try {
Watchdog.getInstance().pauseWatchingCurrentThread("packagemanagermain");
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
} finally {
Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain");
}
// Now that the package manager has started, register the dex load reporter to capture any
// dex files loaded by system server.
// These dex files will be optimized by the BackgroundDexOptService.
SystemServerDexLoadReporter.configureSystemServerDexReporter(mPackageManagerService);
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
t.traceEnd();
...
}
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
mActivityManagerService.systemReady(() -> {
},t);
}
如上代码所示,SystemServer
进程启动后调用了其run方法,run 方法中依次调用了 startBootstrapServices
、startCoreServices
、startOtherServices
。
在startBootstrapServices
方法中,启动了 ActivityManagerService
、PackageManagerService
等服务。 startCoreServices
中启动了 电池管理,用户状态以及其他核心服务。同时对ActivityManagerService
、PackageManagerService
也做了一些操作.
读取package-restrications.xml配置
启动 PMS ,创建一个 PackageManagerService
对象。而在PackageManagerService
的构造方法中,会读取package-restrications.xml配置。
PackageManagerService
public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) {
...
t.traceBegin("read user settings");
//代码1
mFirstBoot = !mSettings.readLPw(mInjector.getUserManagerInternal().getUsers(false));
t.traceEnd();
...
}
- 代码1 调用 Settings.readLPw 方法,读取用户的设置。
frameworks/base/services/core/java/com/android/server/pm/Settings.java
boolean readLPw(@NonNull List<UserInfo> users) {
...
for (UserInfo user : users) {
readPackageRestrictionsLPr(user.id);
}
...
}
void readPackageRestrictionsLPr(int userId) {
PackageSetting ps = null;
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG
|| parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG
|| type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
if (tagName.equals(TAG_PACKAGE)) {//"pkg"
//代码2 读取应用的相关信息
...
} else if (tagName.equals("preferred-activities")) {
//代码3 读取偏好实则
readPreferredActivitiesLPw(parser, userId);
} else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
readPersistentPreferredActivitiesLPw(parser, userId);
} else if (tagName.equals(TAG_CROSS_PROFILE_INTENT_FILTERS)) {
readCrossProfileIntentFiltersLPw(parser, userId);
} else if (tagName.equals(TAG_DEFAULT_APPS)) {
readDefaultAppsLPw(parser, userId);
} else if (tagName.equals(TAG_BLOCK_UNINSTALL_PACKAGES)) {
readBlockUninstallPackagesLPw(parser, userId);
} else {
Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: "
+ parser.getName());
XmlUtils.skipCurrentTag(parser);
}
}
}
- 代码1 调用
readPackageRestrictionsLPr
方法,读取package-restrications.xml
配置 - 代码2 读取应用的信息,包括应用状态,是否被禁用等
- 代码3 读取应用的偏好,其中就包括了默认桌面项(如果是第一次开机,没有配置,则没有桌面偏好项)
void readPreferredActivitiesLPw(XmlPullParser parser, int userId)
throws XmlPullParserException, IOException {
int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
if (tagName.equals(TAG_ITEM)) {
PreferredActivity pa = new PreferredActivity(parser);
if (pa.mPref.getParseError() == null) {
final PreferredIntentResolver resolver = editPreferredActivitiesLPw(userId);
ArrayList<PreferredActivity> pal = resolver.findFilters(pa);
//代码1
if (pal == null || pal.size() == 0 || pa.mPref.mAlways) {
resolver.addFilter(pa);
}
} else {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Error in package manager settings: <preferred-activity> "
+ pa.mPref.getParseError() + " at "
+ parser.getPositionDescription());
}
} else {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Unknown element under <preferred-activities>: " + parser.getName());
XmlUtils.skipCurrentTag(parser);
}
}
}
PreferredIntentResolver editPreferredActivitiesLPw(int userId) {
//代码3
PreferredIntentResolver pir = mPreferredActivities.get(userId);
if (pir == null) {
pir = new PreferredIntentResolver();
mPreferredActivities.put(userId, pir);
}
return pir;
}
- 代码2 根据userId获取
PreferredIntentResolver
对象,如果没有则创建一个,且放入mPreferredActivities
中。 - 代码1 判断该Filter是否已经存在,当Fillter不存在,或者当前偏好设置的是 always = true,则将当前偏好加入到
PreferredIntentResolver
对象中。
注意: Settings 中 mPreferredActivities 这个对象,之后会被用到
launcher应用启动过程
launcher启动过程可以追溯到 ActivtiyManagerService
的systemReady
方法。
public ActivityTaskManagerInternal mAtmInternal;
public void systemReady(final Runnable goingCallback, @NonNull TimingsTraceAndSlog t) {
...
//代码1
t.traceBegin("resumeTopActivities");
mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
t.traceEnd();
...
}
- 代码1处 ActivityTaskManagerInternal 的实现类是
ActivityTaskManagerService$LocalService
,其调用了ActivityTaskManagerService$LocalService
#resumeTopActivities
方法
ActivityTaskManagerService$LocalService
@Override
public void resumeTopActivities(boolean scheduleIdle) {
synchronized (mGlobalLock) {
mRootWindowContainer.resumeFocusedStacksTopActivities();
if (scheduleIdle) {
mStackSupervisor.scheduleIdle();
}
}
}
显然调用的是RootWindowContainer.java#resumeFocusedStacksTopActivities
//代码1
boolean resumeFocusedStacksTopActivities() {
return resumeFocusedStacksTopActivities(null, null, null);
}
boolean resumeFocusedStacksTopActivities(
ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
if (!mStackSupervisor.readyToResume()) {
return false;
}
boolean result = false;
if (targetStack != null && (targetStack.isTopStackInDisplayArea()
|| getTopDisplayFocusedStack() == targetStack)) {
result = targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
boolean resumedOnDisplay = false;
final DisplayContent display = getChildAt(displayNdx);
for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
final ActivityRecord topRunningActivity = stack.topRunningActivity();
if (!stack.isFocusableAndVisible() || topRunningActivity == null) {
continue;
}
if (stack == targetStack) {
// Simply update the result for targetStack because the targetStack had
// already resumed in above. We don't want to resume it again, especially in
// some cases, it would cause a second launch failure if app process was
// dead.
resumedOnDisplay |= result;
continue;
}
if (taskDisplayArea.isTopStack(stack) && topRunningActivity.isState(RESUMED)) {
// Kick off any lingering app transitions form the MoveTaskToFront
// operation, but only consider the top task and stack on that display.
stack.executeAppTransition(targetOptions);
} else {
resumedOnDisplay |= topRunningActivity.makeActiveIfNeeded(target);
}
}
}
if (!resumedOnDisplay) {
final ActivityStack focusedStack = display.getFocusedStack();
if (focusedStack != null) {
result |= focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions);
} else if (targetStack == null) {
//代码1
result |= resumeHomeActivity(null /* prev */, "no-focusable-task",
display.getDefaultTaskDisplayArea());
}
}
}
return result;
}
boolean resumeHomeActivity(ActivityRecord prev, String reason,
TaskDisplayArea taskDisplayArea) {
if (!mService.isBooting() && !mService.isBooted()) {
// Not ready yet!
return false;
}
if (taskDisplayArea == null) {
taskDisplayArea = getDefaultTaskDisplayArea();
}
final ActivityRecord r = taskDisplayArea.getHomeActivity();
final String myReason = reason + " resumeHomeActivity";
// Only resume home activity if isn't finishing.
//代码3
if (r != null && !r.finishing) {
r.moveFocusableActivityToTop(myReason);
return resumeFocusedStacksTopActivities(r.getRootTask(), prev, null);
}
//代码4
return startHomeOnTaskDisplayArea(mCurrentUser, myReason, taskDisplayArea,
false /* allowInstrumenting */, false /* fromHomeKey */);
}
boolean startHomeOnTaskDisplayArea(int userId, String reason, TaskDisplayArea taskDisplayArea,
boolean allowInstrumenting, boolean fromHomeKey) {
// Fallback to top focused display area if the provided one is invalid.
if (taskDisplayArea == null) {
final ActivityStack stack = getTopDisplayFocusedStack();
taskDisplayArea = stack != null ? stack.getDisplayArea()
: getDefaultTaskDisplayArea();
}
Intent homeIntent = null;
ActivityInfo aInfo = null;
if (taskDisplayArea == getDefaultTaskDisplayArea()) {
//代码5
homeIntent = mService.getHomeIntent();
//代码6
aInfo = resolveHomeActivity(userId, homeIntent);
} else if (shouldPlaceSecondaryHomeOnDisplayArea(taskDisplayArea)) {
Pair<ActivityInfo, Intent> info = resolveSecondaryHomeActivity(userId, taskDisplayArea);
aInfo = info.first;
homeIntent = info.second;
}
if (aInfo == null || homeIntent == null) {
return false;
}
if (!canStartHomeOnDisplayArea(aInfo, taskDisplayArea, allowInstrumenting)) {
return false;
}
// Updates the home component of the intent.
homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
// Updates the extra information of the intent.
if (fromHomeKey) {
homeIntent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, true);
mWindowManager.cancelRecentsAnimation(REORDER_KEEP_IN_PLACE, "startHomeActivity");
}
// Update the reason for ANR debugging to verify if the user activity is the one that
// actually launched.
final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId(
aInfo.applicationInfo.uid) + ":" + taskDisplayArea.getDisplayId();
mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason,
taskDisplayArea);
return true;
}
ActivityTaskManagerService.java
Intent getHomeIntent() {
Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
intent.setComponent(mTopComponent);
intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
intent.addCategory(Intent.CATEGORY_HOME);
}
return intent;
}
-
代码1 传入的均为null
-
代码2 显然
targetStack == null
,且刚开始,显然此时没有Activity处于 resueme状态,因此resumedOnDisplay
的值必定为false,最终走到resumeHomeActivity
方法。 -
代码3 此时显然没有homeActivity在,走到代码4
-
代码4 调用
startHomeOnTaskDisplayArea
方法 -
代码5 调用
ActivityTaskManagerService
#getHomeIntent
获取 此时应启动的桌面 信息。在getHomeIntent
方法只不过mTopComponent
值必定为 null,其实不太懂google为何在此处设置这个属性,这个值没有什么意义,因为基本其值基本一直为 null,具体可以看Android 11下ActivityTaskManagerService`。 -
代码6 调用
resolveHomeActivity
方法。该方法内会读取获取此时应启动的桌面的应用ComponentName
信息。ActivityTaskManagerService
#resolveHomeActivity
ActivityInfo resolveHomeActivity(int userId, Intent homeIntent) {
final int flags = ActivityManagerService.STOCK_PM_FLAGS;
final ComponentName comp = homeIntent.getComponent();
ActivityInfo aInfo = null;
try {
// 代码1
if (comp != null) {
aInfo = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId);
} else {
final String resolvedType =
homeIntent.resolveTypeIfNeeded(mService.mContext.getContentResolver());
//代码2
final ResolveInfo info = AppGlobals.getPackageManager()
.resolveIntent(homeIntent, resolvedType, flags, userId);
if (info != null) {
aInfo = info.activityInfo;
}
}
} catch (RemoteException e) {
// ignore
Slog.i(TAG,"chl resolveHomeActivity 4 aInfo:"+aInfo);
}
if (aInfo == null) {
Slog.wtf(TAG, "No home screen found for " + homeIntent, new Throwable());
return null;
}
aInfo = new ActivityInfo(aInfo);
aInfo.applicationInfo = mService.getAppInfoForUser(aInfo.applicationInfo, userId);
Thread.dumpStack();
return aInfo;
}
- 代码1 根据上一段代码5中的分析,
comp
值显然为null,因此走到代码2 - 代码2 查询符合条件的ActivityInfo。AppGlobals.getPackageManager() 获得的是 PackageManagerService的binder对象。
PackageManagerService.java
@Override
public ResolveInfo resolveIntent(Intent intent, String resolvedType,
int flags, int privateResolveFlags, int userId, boolean resolveForStart,
int filterCallingUid) {
return resolveIntentInternal(
intent, resolvedType, flags, privateResolveFlags, userId, resolveForStart,
filterCallingUid);
}
private ResolveInfo resolveIntentInternal(Intent intent, String resolvedType, int flags,
@PrivateResolveFlags int privateResolveFlags, int userId, boolean resolveForStart,
int filterCallingUid) {
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent");
if (!mUserManager.exists(userId)) return null;
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart,
isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
flags));
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/, "resolve intent");
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities");
final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType,
flags, privateResolveFlags, filterCallingUid, userId, resolveForStart,
true /*allowDynamicSplits*/);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
final boolean queryMayBeFiltered =
UserHandle.getAppId(filterCallingUid) >= Process.FIRST_APPLICATION_UID
&& !resolveForStart;
// 代码1
final ResolveInfo bestChoice =
chooseBestActivity(
intent, resolvedType, flags, privateResolveFlags, query, userId,
queryMayBeFiltered);
final boolean nonBrowserOnly =
(privateResolveFlags & PackageManagerInternal.RESOLVE_NON_BROWSER_ONLY) != 0;
if (nonBrowserOnly && bestChoice != null && bestChoice.handleAllWebDataURI) {
return null;
}
return bestChoice;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
- 代码1 走到此处 chooseBestActivity
private ResolveInfo chooseBestActivity(Intent intent, String resolvedType,
int flags, int privateResolveFlags, List<ResolveInfo> query, int userId,
boolean queryMayBeFiltered) {
if (query != null) {
// 有多少符合filter条件的,对于桌面来说,是有多少个桌面Activity。
final int N = query.size();
if (N == 1) {
return query.get(0);
} else if (N > 1) {
final boolean debug = ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);
// If there is more than one activity with the same priority,
// then let the user decide between them.
ResolveInfo r0 = query.get(0);
ResolveInfo r1 = query.get(1);
if (DEBUG_INTENT_MATCHING || debug) {
Slog.v(TAG, r0.activityInfo.name + "=" + r0.priority + " vs "
+ r1.activityInfo.name + "=" + r1.priority);
}
// If the first activity has a higher priority, or a different
// default, then it is always desirable to pick it.
if (r0.priority != r1.priority
|| r0.preferredOrder != r1.preferredOrder
|| r0.isDefault != r1.isDefault) {
return query.get(0);
}
// If we have saved a preference for a preferred activity for
// this Intent, use that.
//代码2
ResolveInfo ri = findPreferredActivityNotLocked(intent, resolvedType,
flags, query, r0.priority, true, false, debug, userId, queryMayBeFiltered);
if (ri != null) {
return ri;
}
//代码3
...
}
}
return null;
}
- 代码2 调用
findPreferredActivityNotLocked
查找。
// TODO: handle preferred activities missing while user has amnesia
/** <b>must not hold {@link #mLock}</b> */
ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags,
List<ResolveInfo> query, int priority, boolean always,
boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
...
// writer
synchronized (mLock) {
//代码1
// 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;
}
// 代码2
PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
// Get the list of preferred activities that handle the intent
if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities...");
//代码3
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), " ");
}
//代码4
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.
//代码5
if (always && !pa.mPref.mAlways) {
if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry");
continue;
}
// 获取对应 ActivityInfo
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");
return null;
}
- 代码1 获取持久作为 activity的偏好,一般此处为null。
- 代码2 获取setting中的偏好,其在PackageManagerService的代码中调用了
Settings.readLPw
方法,该 package-restrictions.xmlpreferred-activitie
标签下的偏好被读取存入了mPreferredActivities
属性中(如果在使用过程中,用户主动修改了偏好,该mPreferredActivities
中内容会改变,package-restrictions.xml 文件内容也会改变) - 代码3 根据
intent
查询,此处是根据
这三个条件去查找匹配 桌面应用。<action name="android.intent.action.MAIN" /> <cat name="android.intent.category.HOME" /> <cat name="android.intent.category.DEFAULT" />