The Android PackageManagerService10.0 interpretation of source code (AndroidManifest. XML parsing)
Android determines whether an Activity is registered in androidmanifest.xml.
# Android ActivityManagerService(AMS) source code analysis
Android determines whether an Activity is registered in androidmanifest.xml.
In androidmanifest.xml, add the Activity registration. After all, the Activity belongs to one of the four components. When using it, you need to register it in the manifest file.
<activity android:name=".TargetActivity"></activity>
Copy the code
But what is the source of this problem? Let’s take a closer look at the source code.
Instead of entering the source code step by step, we will directly analyze the key code:
public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) {...try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
//1. Use IActivityManager to call us to execute AMS's startActivity method and return the result
intresult = ActivityManager.getService() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target ! =null ? target.mEmbeddedID : null, requestCode, 0.null, options);
//2. Check results
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
Copy the code
CheckStartActivityResult (result, intent);
public static void checkStartActivityResult(int res, Object intent) {
if(! ActivityManager.isStartResultFatalError(res)) {return;
}
switch (res) {
case ActivityManager.START_INTENT_NOT_RESOLVED:
case ActivityManager.START_CLASS_NOT_FOUND:
// set error as START_INTENT_NOT_RESOLVED
// START_CLASS_NOT_FOUND will report this error
if (intent instanceofIntent && ((Intent) intent).getComponent() ! =null)
throw new ActivityNotFoundException("Unable to find explicit activity class " + ((Intent) intent).getComponent().toShortString() + "; have you declared this activity in your AndroidManifest.xml?");
throw new ActivityNotFoundException("No Activity found to handle " + intent);
case ActivityManager.START_PERMISSION_DENIED:
throw new SecurityException("Not allowed to start activity " + intent);
case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
throw new AndroidRuntimeException("FORWARD_RESULT_FLAG used while also requesting a result");
case ActivityManager.START_NOT_ACTIVITY:
throw new IllegalArgumentException("PendingIntent is not an activity");
case ActivityManager.START_NOT_VOICE_COMPATIBLE:
throw new SecurityException("Starting under voice control not allowed for: " + intent);
case ActivityManager.START_VOICE_NOT_ACTIVE_SESSION:
throw new IllegalStateException("Session calling startVoiceActivity does not match active session");
case ActivityManager.START_VOICE_HIDDEN_SESSION:
throw new IllegalStateException("Cannot start voice activity on a hidden session");
case ActivityManager.START_ASSISTANT_NOT_ACTIVE_SESSION:
throw new IllegalStateException("Session calling startAssistantActivity does not match active session");
case ActivityManager.START_ASSISTANT_HIDDEN_SESSION:
throw new IllegalStateException("Cannot start assistant activity on a hidden session");
case ActivityManager.START_CANCELED:
throw new AndroidRuntimeException("Activity could not be started for " + intent);
default:
throw new AndroidRuntimeException("Unknown error code " + res + " when starting "+ intent); }}Copy the code
You can see when the result is zero
case ActivityManager.START_INTENT_NOT_RESOLVED:
case ActivityManager.START_CLASS_NOT_FOUND:
Will be submitted to throw new ActivityNotFoundException (” Unable to find explicit activity class “+ ((Intent) intent).getComponent().toShortString() + “; have you declared this activity in your AndroidManifest.xml?” );
Now we know where an error will be reported if the registry is not added to the manifest file.
How can AMS determine if an activity is not registered? First, we need to understand the main process of startActivity execution
This space is too much, you can go to the source code with, here is not introduced,
We examine the main process code here
The find is returned in ASR. StartActivity (ActivityStarter)
START_INTENT_NOT_RESOLVED, START_CLASS_NOT_FOUND
private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent, String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid, String callingPackage, int realCallingPid, int realCallingUid, int startFlags, SafeActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity, TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup) {
interr = ActivityManager.START_SUCCESS; .// Let's do some checking
if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
// We couldn't find a class that can handle the given Intent.
// That's the end of that! err = ActivityManager.START_INTENT_NOT_RESOLVED;
// Could not find the corresponding Component in the Intent
}
if (err == ActivityManager.START_SUCCESS && aInfo == null) {
// We couldn't find the specific class specified in the Intent.
// Also the end of the line.
err = ActivityManager.START_CLASS_NOT_FOUND;
// The corresponding ActivityInfo was not found in the Intent}...if(err ! = START_SUCCESS) {// Failed to start, return to err
if(resultRecord ! =null) {
resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode, RESULT_CANCELED, null);
}
SafeActivityOptions.abort(options);
return err;
}
// Create our target ActivityRecord object and store it on index 0 of the incoming array
ActivityRecord r = newActivityRecord(mService, callerApp, callingPid, callingUid, callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(), resultRecord, resultWho, requestCode, componentSpecified, voiceSession ! =null, mSupervisor, checkedOptions, sourceRecord); .return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask, outActivity);
}
Copy the code
But where does aInfo get its intent.getComponent() from
startActivityMayWait.
Let’s see where aInfo came from up there.
ActivityInfo resolveActivity(Intent intent, ResolveInfo rInfo, int startFlags, ProfilerInfo profilerInfo) {
finalActivityInfo aInfo = rInfo ! =null ? rInfo.activityInfo : null;
if(aInfo ! =null) {
// Store the found target back into the intent, because now that
// we have it we never want to do this again. For example, if the
// user navigates back to this point in the history, we should
// always restart the exact same activity.
intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
// Don't debug things in the system process ...
}
return aInfo;
}
Copy the code
It was found to be from rInfo
ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId, int flags, int filterCallingUid) {
synchronized (mService) {
try {...final long token = Binder.clearCallingIdentity();
try {
return mService.getPackageManagerInternalLocked().resolveIntent(intent, resolvedType, modifiedFlags, userId, true, filterCallingUid);
} finally{ Binder.restoreCallingIdentity(token); }... }}}Copy the code
RInfo access
PackageManagerInternal getPackageManagerInternalLocked(a) {
if (mPackageManagerInt == null) {
mPackageManagerInt = LocalServices.getService(PackageManagerInternal.class);
}
return mPackageManagerInt;
}
Copy the code
The implementation class is PackageManagerService
@Override
public ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags, int userId) {
return resolveIntentInternal(intent, resolvedType, flags, userId, false, Binder.getCallingUid());
}
Copy the code
See resolveIntentInternal
private ResolveInfo resolveIntentInternal(Intent intent, String resolvedType,int flags, int userId, boolean resolveForStart, int filterCallingUid) {
try {...
// Get the ResolveInfo list
final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags, filterCallingUid, userId, resolveForStart, true /*allowDynamicSplits*/);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
// Find the best return
final ResolveInfo bestChoice = chooseBestActivity(intent, resolvedType, flags, query, userId);
return bestChoice;
} finally{ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); }}Copy the code
See queryIntentActivitiesInternal
private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType, int flags, int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits) {...if(comp ! =null) {
final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
final ActivityInfo ai = getActivityInfo(comp, flags, userId);
if(ai ! =null) {... }}Copy the code
It was retrieved from getActivityInfo
@Override
public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
return getActivityInfoInternal(component, flags, Binder.getCallingUid(), userId);
}
Copy the code
GetActivityInfoInternal method
private ActivityInfo getActivityInfoInternal(ComponentName component, int flags, int filterCallingUid, int userId) {
if(! sUserManager.exists(userId))return null;
flags = updateFlagsForComponent(flags, userId, component);
if(! isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId)) { mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,false /* requireFullPermission */.false /* checkShell */."get activity info");
}
synchronized (mPackages) {
/ / key point
PackageParser.Activity a = mActivities.mActivities.get(component);
if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ":" + a);
if(a ! =null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
if (filterAppAccessLPr(ps, filterCallingUid, component, TYPE_ACTIVITY, userId)) {
return null;
}
/ / key point
return PackageParser.generateActivityInfo(a, flags, ps.readUserState(userId), userId);
}
if (mResolveComponentName.equals(component)) {
return PackageParser.generateActivityInfo(mResolveActivity, flags, newPackageUserState(), userId); }}return null;
}
Copy the code
Androidmanifest.xml; androidmanifest.xml; androidmanifest.xml; androidManifest.xml; androidManifest.xml; androidManifest.xml The Android PackageManagerService10.0 interpretation of source code (AndroidManifest. XML parsing)