因为跟launcher相关~~所以从startHomeActivityLocked开始,=.=
boolean startHomeActivityLocked(int userId) {
if (mHeadless) {
// Added because none of the other calls to ensureBootCompleted seem to fire
// when running headless.
ensureBootCompleted();
return false;
}
if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
&& mTopAction == null) {
// We are running in factory test mode, but unable to find
// the factory test app, so just sit around displaying the
// error message and don't try to start anything.
return false;
}
// YUNOS BEGIN for OSUPATE on OTT
// @author [email protected]
// Since set AliTvHomeshell as default home launcher, so that add osupdate support at here
// YUNOS BEGIN for OSUPATE on OTT
// @author [email protected]
// Since set AliTvHomeshell as default home launcher, so that add osupdate support at here
/* android code
Intent intent = new Intent(
mTopAction,
mTopData != null ? Uri.parse(mTopData) : null);
intent.setComponent(mTopComponent);
if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
intent.addCategory(Intent.CATEGORY_HOME);
}
ActivityInfo aInfo =
resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
*/
Intent intent = new Intent(
mTopAction,
mTopData != null ? Uri.parse(mTopData) : null);
ActivityInfo aInfo = null;
if (mBooting) {
Slog.i(TAG, "check if com.yunos.osupdate RebootUpdateActivity exists");
intent.setComponent(new ComponentName("com.yunos.osupdate", "com.yunos.osupdate.front.RebootUpdateActivity"));
aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
}
if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
intent.addCategory(Intent.CATEGORY_HOME);
}
if (aInfo == null) {
if (mBooting) {
Slog.i(TAG, "no com.yunos.osupdate RebootUpdateActivity, start homeshell");
}
intent.setComponent(mTopComponent);
aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
}
// YUNOS END for OSUPATE on OTT
if (aInfo != null) {
intent.setComponent(new ComponentName(
aInfo.applicationInfo.packageName, aInfo.name));
// Don't do this if the home app is currently being
// instrumented.
aInfo = new ActivityInfo(aInfo);
aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
ProcessRecord app = getProcessRecordLocked(aInfo.processName,
aInfo.applicationInfo.uid, true);
if (app == null || app.instrumentationClass == null) {
intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
mStackSupervisor.startHomeActivity(intent, aInfo);
}
}
return true;
}
private ActivityInfo resolveActivityInfo(Intent intent, int flags, int userId) {
ActivityInfo ai = null;
ComponentName comp = intent.getComponent();
try {
if (comp != null) {
ai = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId);
} else {
ResolveInfo info = AppGlobals.getPackageManager().resolveIntent(
intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
flags, userId);
if (info != null) {
ai = info.activityInfo;
}
}
} catch (RemoteException e) {
// ignore
}
return ai;
}
新建带MAIN action的Intent--->resolveActivityInfo()进行隐式Intent匹配获取Activity,mStackSupervisor.startHomeActivity()进入Launcher
private ActivityInfo resolveActivityInfo(Intent intent, int flags, int userId) {
ActivityInfo ai = null;
ComponentName comp = intent.getComponent();
try {
if (comp != null) {
ai = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId);
} else {
ResolveInfo info = AppGlobals.getPackageManager().resolveIntent(
intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
flags, userId);
if (info != null) {
ai = info.activityInfo;
}
}
} catch (RemoteException e) {
// ignore
}
return ai;
}
如果intent里有Component直接获取activityInfo,否则进行隐式Intent匹配,调用到PM里的resolveIntent(),并且调用resolveTypeIfNeeded(mContext.getContentResolver()查看Intent里是否有MIME或者Uri
@Override
public ResolveInfo resolveIntent(Intent intent, String resolvedType,
int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "resolve intent");
List query = queryIntentActivities(intent, resolvedType, flags, userId);
for(int i=0; i
找到所有匹配的Activity然后choose一下
@Override
public List queryIntentActivities(Intent intent,
String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "query intent activities");
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
intent = intent.getSelector();
comp = intent.getComponent();
}
}
if (comp != null) {
final List list = new ArrayList(1);
final ActivityInfo ai = getActivityInfo(comp, flags, userId);
if (ai != null) {
final ResolveInfo ri = new ResolveInfo();
ri.activityInfo = ai;
list.add(ri);
}
return list;
}
// reader
synchronized (mPackages) {
final String pkgName = intent.getPackage();
if (pkgName == null) {
return mActivities.queryIntent(intent, resolvedType, flags, userId);
}
final PackageParser.Package pkg = mPackages.get(pkgName);
if (pkg != null) {
return mActivities.queryIntentForPackage(intent, resolvedType, flags,
pkg.activities, userId);
}
return new ArrayList();
}
}
getPackage()返回mPackages,注释
/**
* Retrieve the application package name this Intent is limited to. When
* resolving an Intent, if non-null this limits the resolution to only
* components in the given application package.
*
* @return The name of the application package for the Intent.
*
* @see #resolveActivity
* @see #setPackage
*/
这里pkg为空,进入函数queryIntent()然后调用super.queryIntent()
public List queryIntent(Intent intent, String resolvedType, boolean defaultOnly,
int userId) {
String scheme = intent.getScheme();
ArrayList finalList = new ArrayList();
final boolean debug = localLOGV ||
((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);
if (debug)
Slog.v(
TAG, "Resolving type=" + resolvedType + " scheme=" + scheme
+ " defaultOnly=" + defaultOnly + " userId=" + userId + " of " + intent);
F[] firstTypeCut = null;
F[] secondTypeCut = null;
F[] thirdTypeCut = null;
F[] schemeCut = null;
// If the intent includes a MIME type, then we want to collect all of
// the filters that match that MIME type.
if (resolvedType != null) {
int slashpos = resolvedType.indexOf('/');
if (slashpos > 0) {
final String baseType = resolvedType.substring(0, slashpos);
if (!baseType.equals("*")) {
if (resolvedType.length() != slashpos+2
|| resolvedType.charAt(slashpos+1) != '*') {
// Not a wild card, so we can just look for all filters that
// completely match or wildcards whose base type matches.
firstTypeCut = mTypeToFilter.get(resolvedType);
if (debug)
Slog.v(TAG, "First type cut: " + Arrays.toString(firstTypeCut));
secondTypeCut = mWildTypeToFilter.get(baseType);
if (debug)
Slog.v(TAG, "Second type cut: "
+ Arrays.toString(secondTypeCut));
} else {
// We can match anything with our base type.
firstTypeCut = mBaseTypeToFilter.get(baseType);
if (debug)
Slog.v(TAG, "First type cut: " + Arrays.toString(firstTypeCut));
secondTypeCut = mWildTypeToFilter.get(baseType);
if (debug)
Slog.v(TAG, "Second type cut: "
+ Arrays.toString(secondTypeCut));
}
// Any */* types always apply, but we only need to do this
// if the intent type was not already */*.
thirdTypeCut = mWildTypeToFilter.get("*");
//if (debug)
Slog.v(TAG, "Third type cut: " + Arrays.toString(thirdTypeCut));
} else if (intent.getAction() != null) {
// The intent specified any type ({@literal *}/*). This
// can be a whole heck of a lot of things, so as a first
// cut let's use the action instead.
firstTypeCut = mTypedActionToFilter.get(intent.getAction());
if (debug)
Slog.v(TAG, "Typed Action list: " + Arrays.toString(firstTypeCut));
}
}
}
// If the intent includes a data URI, then we want to collect all of
// the filters that match its scheme (we will further refine matches
// on the authority and path by directly matching each resulting filter).
if (scheme != null) {
schemeCut = mSchemeToFilter.get(scheme);
if (debug)
Slog.v(TAG, "Scheme list: " + Arrays.toString(schemeCut));
}
// If the intent does not specify any data -- either a MIME type or
// a URI -- then we will only be looking for matches against empty
// data.
Slog.v(TAG, "Intent Resolver action= " + intent.getAction());
if (resolvedType == null && scheme == null && intent.getAction() != null) {
firstTypeCut = mActionToFilter.get(intent.getAction());
if (debug)
Slog.v(TAG, "Action list: " + Arrays.toString(firstTypeCut));
}
FastImmutableArraySet categories = getFastIntentCategories(intent);
if (firstTypeCut != null) {
buildResolveList(intent, categories, debug, defaultOnly,
resolvedType, scheme, firstTypeCut, finalList, userId);
}
if (secondTypeCut != null) {
buildResolveList(intent, categories, debug, defaultOnly,
resolvedType, scheme, secondTypeCut, finalList, userId);
}
if (thirdTypeCut != null) {
buildResolveList(intent, categories, debug, defaultOnly,
resolvedType, scheme, thirdTypeCut, finalList, userId);
}
if (schemeCut != null) {
buildResolveList(intent, categories, debug, defaultOnly,
resolvedType, scheme, schemeCut, finalList, userId);
}
sortResults(finalList);
if (debug) {
Slog.v(TAG, "Final result list:");
for (int i=0; i
firstTypeCut secondTypeCut thirdTypeCut跟MIME相关,这里只用到firstTypeCut firstTypeCut = mActionToFilter.get(intent.getAction());这一句会查找到所有action为android.intent.action.MAIN的activity。然后通过getFastIntentCategories()--->getCategories()获得到与此intent相关的所有Categories,之后来到了函数buildResolveList()
private void buildResolveList(Intent intent, FastImmutableArraySet categories,
boolean debug, boolean defaultOnly,
String resolvedType, String scheme, F[] src, List dest, int userId) {
final String action = intent.getAction();
final Uri data = intent.getData();
final String packageName = intent.getPackage();
final boolean excludingStopped = intent.isExcludingStopped();
final Printer logPrinter;
final PrintWriter logPrintWriter;
if (debug) {
logPrinter = new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM);
logPrintWriter = new FastPrintWriter(logPrinter);
} else {
logPrinter = null;
logPrintWriter = null;
}
final int N = src != null ? src.length : 0;
boolean hasNonDefaults = false;
int i;
F filter;
for (i=0; i= 0) {
if (debug)
Slog.v(TAG, " Filter matched! match=0x" +
Integer.toHexString(match) + " hasDefault="
+ filter.hasCategory(Intent.CATEGORY_DEFAULT));
if (!defaultOnly || filter.hasCategory(Intent.CATEGORY_DEFAULT)) {
final R oneResult = newResult(filter, match, userId);
if (oneResult != null) {
dest.add(oneResult);
if (debug)
{
dumpFilter(logPrintWriter, " ", filter);
logPrintWriter.flush();
filter.dump(logPrinter, " ");
}
}
} else {
hasNonDefaults = true;
}
} else {
if (debug) {
String reason;
switch (match) {
case IntentFilter.NO_MATCH_ACTION: reason = "action"; break;
case IntentFilter.NO_MATCH_CATEGORY: reason = "category"; break;
case IntentFilter.NO_MATCH_DATA: reason = "data"; break;
case IntentFilter.NO_MATCH_TYPE: reason = "type"; break;
default: reason = "unknown reason"; break;
}
Slog.v(TAG, " Filter did not match: " + reason);
}
}
}
if (hasNonDefaults) {
if (dest.size() == 0) {
Slog.w(TAG, "resolveIntent failed: found match, but none with CATEGORY_DEFAULT");
} else if (dest.size() > 1) {
Slog.w(TAG, "resolveIntent: multiple matches, only some with CATEGORY_DEFAULT");
}
}
}
public final int match(String action, String type, String scheme,
Uri data, Set categories, String logTag) {
if (action != null && !matchAction(action)) {
if (false) Log.v(
logTag, "No matching action " + action + " for " + this);
return NO_MATCH_ACTION;
}
int dataMatch = matchData(type, scheme, data);
if (dataMatch < 0) {
if (false) {
if (dataMatch == NO_MATCH_TYPE) {
Log.v(logTag, "No matching type " + type
+ " for " + this);
}
if (dataMatch == NO_MATCH_DATA) {
Log.v(logTag, "No matching scheme/path " + data
+ " for " + this);
}
}
return dataMatch;
}
String categoryMismatch = matchCategories(categories);
if (categoryMismatch != null) {
if (false) {
Log.v(logTag, "No matching category " + categoryMismatch + " for " + this);
}
return NO_MATCH_CATEGORY;
}
// It would be nice to treat container activities as more
// important than ones that can be embedded, but this is not the way...
if (false) {
if (categories != null) {
dataMatch -= mCategories.size() - categories.size();
}
}
return dataMatch;
}
可以看到match的顺序是action,data,category。这次的问题出在category上,我们来看看这个matchCategories()做了什么
public final String matchCategories(Set categories) {
if (categories == null) {
return null;
}
Iterator it = categories.iterator();
if (mCategories == null) {
return it.hasNext() ? it.next() : null;
}
/**add by ninteo**/
if(mCategories != null) {
for(int i=0;i < mCategories.size();i++) {
if(mCategories.get(i).equals("rm.android.intent.category.HOME"))
mCategories.set(i,"android.intent.category.HOME");
}
}
while (it.hasNext()) {
final String category = it.next();
if (!mCategories.contains(category)) {
return category;
}
}
return null;
}
嗯,差不多就是这样了吧