php网站开发需求分析,宁波网站搭建,网站建设需要什么硬件和软件有哪些,广州十大猎头公司排名Activity启动器入口 Android的Activity的启动入口是在ActivityStarter类的execute()#xff0c;在该方法里面继续调用executeRequest(Request request) #xff0c;相应的参数都设置在方法参数request中。代码挺长#xff0c;分段现在看下它的实现#xff0c;分段一#x…Activity启动器入口 Android的Activity的启动入口是在ActivityStarter类的execute()在该方法里面继续调用executeRequest(Request request) 相应的参数都设置在方法参数request中。代码挺长分段现在看下它的实现分段一 /*** Executing activity start request and starts the journey of starting an activity. Here* begins with performing several preliminary checks. The normally activity launch flow will* go through {link #startActivityUnchecked} to {link #startActivityInner}.*/private int executeRequest(Request request) {if (TextUtils.isEmpty(request.reason)) {throw new IllegalArgumentException(Need to specify a reason.);}mLastStartReason request.reason;mLastStartActivityTimeMs System.currentTimeMillis();mLastStartActivityRecord null;final IApplicationThread caller request.caller;Intent intent request.intent;NeededUriGrants intentGrants request.intentGrants;String resolvedType request.resolvedType;ActivityInfo aInfo request.activityInfo;ResolveInfo rInfo request.resolveInfo;final IVoiceInteractionSession voiceSession request.voiceSession;final IBinder resultTo request.resultTo;String resultWho request.resultWho;int requestCode request.requestCode;int callingPid request.callingPid;int callingUid request.callingUid;String callingPackage request.callingPackage;String callingFeatureId request.callingFeatureId;final int realCallingPid request.realCallingPid;final int realCallingUid request.realCallingUid;final int startFlags request.startFlags;final SafeActivityOptions options request.activityOptions;Task inTask request.inTask;int err ActivityManager.START_SUCCESS;// Pull the optional Ephemeral Installer-only bundle out of the options early.final Bundle verificationBundle options ! null ? options.popAppVerificationBundle() : null;WindowProcessController callerApp null;if (caller ! null) {callerApp mService.getProcessController(caller);if (callerApp ! null) {callingPid callerApp.getPid();callingUid callerApp.mInfo.uid;} else {Slog.w(TAG, Unable to find app for caller caller (pid callingPid ) when starting: intent.toString());err ActivityManager.START_PERMISSION_DENIED;}}final int userId aInfo ! null aInfo.applicationInfo ! null? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;if (err ActivityManager.START_SUCCESS) {Slog.i(TAG, START u userId { intent.toShortString(true, true, true, false) } from uid callingUid);}ActivityRecord sourceRecord null;ActivityRecord resultRecord null;if (resultTo ! null) {sourceRecord mRootWindowContainer.isInAnyTask(resultTo);if (DEBUG_RESULTS) {Slog.v(TAG_RESULTS, Will send result to resultTo sourceRecord);}if (sourceRecord ! null) {if (requestCode 0 !sourceRecord.finishing) {resultRecord sourceRecord;}}}final int launchFlags intent.getFlags();if ((launchFlags Intent.FLAG_ACTIVITY_FORWARD_RESULT) ! 0 sourceRecord ! null) {// Transfer the result target from the source activity to the new one being started,// including any failures.if (requestCode 0) {SafeActivityOptions.abort(options);return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;}resultRecord sourceRecord.resultTo;if (resultRecord ! null !resultRecord.isInRootTaskLocked()) {resultRecord null;}resultWho sourceRecord.resultWho;requestCode sourceRecord.requestCode;sourceRecord.resultTo null;if (resultRecord ! null) {resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);}if (sourceRecord.launchedFromUid callingUid) {// The new activity is being launched from the same uid as the previous activity// in the flow, and asking to forward its result back to the previous. In this// case the activity is serving as a trampoline between the two, so we also want// to update its launchedFromPackage to be the same as the previous activity.// Note that this is safe, since we know these two packages come from the same// uid; the caller could just as well have supplied that same package name itself// . This specifially deals with the case of an intent picker/chooser being// launched in the app flow to redirect to an activity picked by the user, where// we want the final activity to consider it to have been launched by the// previous app activity.callingPackage sourceRecord.launchedFromPackage;callingFeatureId sourceRecord.launchedFromFeatureId;}}if (err ActivityManager.START_SUCCESS intent.getComponent() null) {// We couldnt find a class that can handle the given Intent.// Thats the end of that!err ActivityManager.START_INTENT_NOT_RESOLVED;}if (err ActivityManager.START_SUCCESS aInfo null) {// We couldnt find the specific class specified in the Intent.// Also the end of the line.err ActivityManager.START_CLASS_NOT_FOUND;}if (err ActivityManager.START_SUCCESS sourceRecord ! null sourceRecord.getTask().voiceSession ! null) {// If this activity is being launched as part of a voice session, we need to ensure// that it is safe to do so. If the upcoming activity will also be part of the voice// session, we can only launch it if it has explicitly said it supports the VOICE// category, or it is a part of the calling app.if ((launchFlags FLAG_ACTIVITY_NEW_TASK) 0 sourceRecord.info.applicationInfo.uid ! aInfo.applicationInfo.uid) {try {intent.addCategory(Intent.CATEGORY_VOICE);if (!mService.getPackageManager().activitySupportsIntent(intent.getComponent(), intent, resolvedType)) {Slog.w(TAG, Activity being started in current voice task does not support voice: intent);err ActivityManager.START_NOT_VOICE_COMPATIBLE;}} catch (RemoteException e) {Slog.w(TAG, Failure checking voice capabilities, e);err ActivityManager.START_NOT_VOICE_COMPATIBLE;}}}if (err ActivityManager.START_SUCCESS voiceSession ! null) {// If the caller is starting a new voice session, just make sure the target// is actually allowing it to run this way.try {if (!mService.getPackageManager().activitySupportsIntent(intent.getComponent(),intent, resolvedType)) {Slog.w(TAG,Activity being started in new voice task does not support: intent);err ActivityManager.START_NOT_VOICE_COMPATIBLE;}} catch (RemoteException e) {Slog.w(TAG, Failure checking voice capabilities, e);err ActivityManager.START_NOT_VOICE_COMPATIBLE;}}final Task resultRootTask resultRecord null? null : resultRecord.getRootTask();if (err ! START_SUCCESS) {if (resultRecord ! null) {resultRecord.sendResult(INVALID_UID, resultWho, requestCode, RESULT_CANCELED,null /* data */, null /* dataGrants */);}SafeActivityOptions.abort(options);return err;}首先从类Request中取得对应值赋值给变量。 先将变量err设置为ActivityManager.START_SUCCESS。 caller是应用进程Java服务代理对象。如果它被设置过通过mService.getProcessController(caller)得到对应的WindowProcessController对象mService是ActivityTaskManagerService对象它里面维护着它们俩的对应关系如果它不为null则将局部变量callingPid、callingUid设置为它的对应的值。如果mService中没有找到caller不为null对应的WindowProcessController对象则会将err设置为ActivityManager.START_PERMISSION_DENIED。 下面通过应用UidaInfo.applicationInfo.uid得到用户id。 接下来sourceRecord和resultRecord和请求参数resultTo有关。resultTo是对应将启动Activity之后的应答发回到对应的Activity。在需要应答时还和requestCode有关需要将它设置为一个非负整数。所以下面通过resultTo得到sourceRecord然后通过判断requestCode 0 !sourceRecord.finishing之后才给resultRecord赋值。 接下来是处理标识Intent.FLAG_ACTIVITY_FORWARD_RESULT的情况。 在sourceRecord不为null的情况下如果设置了FLAG_ACTIVITY_FORWARD_RESULT标识就不能设置requestCode如果设置了requestCode为非负数就直接返回ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT。 设置了FLAG_ACTIVITY_FORWARD_RESULT标识是为了将结果转移到启动了sourceRecord的那个Activity。所以将resultRecord设置为sourceRecord.resultTo。如果resultRecord不在根任务的包括层级中会将resultRecord null。也会将resultWho、requestCode设置成sourceRecord的对应值。并将sourceRecord.resultTo null。如果resultRecord ! null则将resultRecord中和sourceRecord、resultWho、requestCode相关的结果删除。如果sourceRecord的启动应用和当前要启动的应用相同会将callingPackage、callingFeatureId设置为启动sourceRecord的包名和launchedFromFeatureId。 接下来判断如果intent.getComponent()为null会将err设置为ActivityManager.START_INTENT_NOT_RESOLVED。代表没有找到对应的启动的类。 如果aInfo null代表也是没找到对应的类将err设置为ActivityManager.START_CLASS_NOT_FOUND。 如果现在还没出错err为ActivityManager.START_SUCCESS 并且sourceRecord在一个语音交互任务sourceRecord.getTask().voiceSession ! null中需要检查新启动的Activity是否能支持。没有FLAG_ACTIVITY_NEW_TASK标识并且和sourceRecord不在同一个应用进程中在该种条件先需要去检测。先给intent添加Intent.CATEGORY_VOICE的Category。下面是通过mService.getPackageManager().activitySupportsIntent()来检查的最终是进入到PackageManagerService中去做检测的这里主要检查的意思就是启动的Activity是需要配置Intent.CATEGORY_VOICE的。如果检测没有通过会将err ActivityManager.START_NOT_VOICE_COMPATIBLE。 如果目前需要启动一个语音交互任务这里也是调用mService.getPackageManager().activitySupportsIntent()来检查的不过它没有加Intent.CATEGORY_VOICE。这里也就是检查它能运行。如果没通过检查同样将err ActivityManager.START_NOT_VOICE_COMPATIBLE。 如果resultRecord不为null会将它的根任务赋值给局部变量resultRootTask。 如果现在err ! START_SUCCESS则代表出错了不需要往下执行了。如果此时resultRecord不为null则调用它的sendResult方法该方法主要做如果状态为RESUMED并且在应用进程中运行则直接通知它。如果不是会将结果存在resultRecord中它是ActivityRecord类存在它的成员results中。再处理一下options之后就将错误代码返回。 继续往下看下分段二 boolean abort !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,requestCode, callingPid, callingUid, callingPackage, callingFeatureId,request.ignoreTargetSecurity, inTask ! null, callerApp, resultRecord,resultRootTask);abort | !mService.mIntentFirewall.checkStartActivity(intent, callingUid,callingPid, resolvedType, aInfo.applicationInfo);abort | !mService.getPermissionPolicyInternal().checkStartActivity(intent, callingUid,callingPackage);boolean restrictedBgActivity false;if (!abort) {try {Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER,shouldAbortBackgroundActivityStart);restrictedBgActivity shouldAbortBackgroundActivityStart(callingUid,callingPid, callingPackage, realCallingUid, realCallingPid, callerApp,request.originatingPendingIntent, request.allowBackgroundActivityStart,intent);} finally {Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);}}// Merge the two options bundles, while realCallerOptions takes precedence.ActivityOptions checkedOptions options ! null? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null;if (request.allowPendingRemoteAnimationRegistryLookup) {checkedOptions mService.getActivityStartController().getPendingRemoteAnimationRegistry().overrideOptionsIfNeeded(callingPackage, checkedOptions);}if (mService.mController ! null) {try {// The Intent we give to the watcher has the extra data stripped off, since it// can contain private information.Intent watchIntent intent.cloneFilter();abort | !mService.mController.activityStarting(watchIntent,aInfo.applicationInfo.packageName);} catch (RemoteException e) {mService.mController null;}}mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage,callingFeatureId);if (mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, callingPid,callingUid, checkedOptions)) {// activity start was intercepted, e.g. because the target user is currently in quiet// mode (turn off work) or the target application is suspendedintent mInterceptor.mIntent;rInfo mInterceptor.mRInfo;aInfo mInterceptor.mAInfo;resolvedType mInterceptor.mResolvedType;inTask mInterceptor.mInTask;callingPid mInterceptor.mCallingPid;callingUid mInterceptor.mCallingUid;checkedOptions mInterceptor.mActivityOptions;// The interception target shouldnt get any permission grants// intended for the original destinationintentGrants null;}if (abort) {if (resultRecord ! null) {resultRecord.sendResult(INVALID_UID, resultWho, requestCode, RESULT_CANCELED,null /* data */, null /* dataGrants */);}// We pretend to the caller that it was really started, but they will just get a// cancel result.ActivityOptions.abort(checkedOptions);return START_ABORTED;}// If permissions need a review before any of the app components can run, we// launch the review activity and pass a pending intent to start the activity// we are to launching now after the review is completed.if (aInfo ! null) {if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(aInfo.packageName, userId)) {final IIntentSender target mService.getIntentSenderLocked(ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage, callingFeatureId,callingUid, userId, null, null, 0, new Intent[]{intent},new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT| PendingIntent.FLAG_ONE_SHOT, null);Intent newIntent new Intent(Intent.ACTION_REVIEW_PERMISSIONS);int flags intent.getFlags();flags | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;/** Prevent reuse of review activity: Each app needs their own review activity. By* default activities launched with NEW_TASK or NEW_DOCUMENT try to reuse activities* with the same launch parameters (extras are ignored). Hence to avoid possible* reuse force a new activity via the MULTIPLE_TASK flag.** Activities that are not launched with NEW_TASK or NEW_DOCUMENT are not re-used,* hence no need to add the flag in this case.*/if ((flags (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NEW_DOCUMENT)) ! 0) {flags | Intent.FLAG_ACTIVITY_MULTIPLE_TASK;}newIntent.setFlags(flags);newIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName);newIntent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));if (resultRecord ! null) {newIntent.putExtra(Intent.EXTRA_RESULT_NEEDED, true);}intent newIntent;// The permissions review target shouldnt get any permission// grants intended for the original destinationintentGrants null;resolvedType null;callingUid realCallingUid;callingPid realCallingPid;rInfo mSupervisor.resolveIntent(intent, resolvedType, userId, 0,computeResolveFilterUid(callingUid, realCallingUid, request.filterCallingUid));aInfo mSupervisor.resolveActivity(intent, rInfo, startFlags,null /*profilerInfo*/);if (DEBUG_PERMISSIONS_REVIEW) {final Task focusedRootTask mRootWindowContainer.getTopDisplayFocusedRootTask();Slog.i(TAG, START u userId { intent.toShortString(true, true,true, false) } from uid callingUid on display (focusedRootTask null ? DEFAULT_DISPLAY: focusedRootTask.getDisplayId()));}}}mSupervisor是ActivityTaskSupervisor对象它的checkStartAnyActivityPermission方法主要是检查应用进程是否有START_ANY_ACTIVITY权限如果取得则返回true。如果没有获取到START_ANY_ACTIVITY权限还会去检查待启动的Activity所需要的权限如果存在是否被应用拒绝、Action对应的权限是否被应用拒绝、如果被限制则返回false。如果没有限制也返回true。 mService.mIntentFirewall是IntentFirewall对象看名字是Intent防火墙的意思。它的checkStartActivity方法是检查它的一些规则如果不满足这里会进行拦截将abort设置为true。 mService.getPermissionPolicyInternal()是PermissionPolicyService类中的Internal对象。它主要检测Action为TelecomManager.ACTION_CHANGE_DEFAULT_DIALER和Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT时如果调用应用的目标SDK大于等于Q时是拦截不允许启动的。 在现在没有出现问题的情况下abort为false会调用shouldAbortBackgroundActivityStart方法来检查是否允许背景应用来启动Activity。并且将返回结果存储在变量restrictedBgActivity中。 接下来就是处理参数选项类options的getOptions()方法它会检查其中的一些权限并且它会合并它里面的选项转为ActivityOptions类对象checkedOptions。 mService.mController在这里是一个观察者。这里是调用它的activityStarting方法通知它。 mInterceptor是ActivityStartInterceptor对象它是一个启动拦截器。它在符合特定条件下会进行拦截改变对应的Intent和其他对应值下面再跳转就是到拦截的界面了。mInterceptor.intercept()在符合拦截的情况下是返回true的。在这个方法里面会将mInterceptor对象的相应进行更改下面就用它里面的对应值设置局部变量intent等。如果用户是在Quiet模式、应用被暂停、锁任务模式下应用不允许启动、启动的应用有有害警告时都会进行拦截。 接下来如果abort为true代表出现问题需要终止如果resultRecord不为null将相应结果RESULT_CANCELED取消的结果设置到里面返回结果START_ABORTED。 接下来处理的是如果启动的Activity有review权限则会启动这个review Activity。它会在review 完成之后再启动目标Activity。这个权限是目标SDK在Build.VERSION_CODES.M之前才适用新的权限模式不支持。最后这段代码就是处理我说的这些。将目标Activity的启动Intent封装成IIntentSender对象传递给review Activity。之后就是解析出来它的ResolveInfo对象、ActivityInfo对象。 继续往下看下分段三 // If we have an ephemeral app, abort the process of launching the resolved intent.// Instead, launch the ephemeral installer. Once the installer is finished, it// starts either the intent we resolved here [on install error] or the ephemeral// app [on install success].if (rInfo ! null rInfo.auxiliaryInfo ! null) {intent createLaunchIntent(rInfo.auxiliaryInfo, request.ephemeralIntent,callingPackage, callingFeatureId, verificationBundle, resolvedType, userId);resolvedType null;callingUid realCallingUid;callingPid realCallingPid;// The ephemeral installer shouldnt get any permission grants// intended for the original destinationintentGrants null;aInfo mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);}// TODO (b/187680964) Correcting the caller/pid/uid when start activity from shortcut// Pending intent launched from systemui also depends on caller appif (callerApp null realCallingPid 0) {final WindowProcessController wpc mService.mProcessMap.getProcess(realCallingPid);if (wpc ! null) {callerApp wpc;}}final ActivityRecord r new ActivityRecord.Builder(mService).setCaller(callerApp).setLaunchedFromPid(callingPid).setLaunchedFromUid(callingUid).setLaunchedFromPackage(callingPackage).setLaunchedFromFeature(callingFeatureId).setIntent(intent).setResolvedType(resolvedType).setActivityInfo(aInfo).setConfiguration(mService.getGlobalConfiguration()).setResultTo(resultRecord).setResultWho(resultWho).setRequestCode(requestCode).setComponentSpecified(request.componentSpecified).setRootVoiceInteraction(voiceSession ! null).setActivityOptions(checkedOptions).setSourceRecord(sourceRecord).build();mLastStartActivityRecord r;if (r.appTimeTracker null sourceRecord ! null) {// If the caller didnt specify an explicit time tracker, we want to continue// tracking under any it has.r.appTimeTracker sourceRecord.appTimeTracker;}// Only allow app switching to be resumed if activity is not a restricted background// activity and target app is not home process, otherwise any background activity// started in background task can stop home button protection mode.// As the targeted app is not a home process and we dont need to wait for the 2nd// activity to be started to resume app switching, we can just enable app switching// directly.WindowProcessController homeProcess mService.mHomeProcess;boolean isHomeProcess homeProcess ! null aInfo.applicationInfo.uid homeProcess.mUid;if (!restrictedBgActivity !isHomeProcess) {mService.resumeAppSwitches();}mLastStartActivityResult startActivityUnchecked(r, sourceRecord, voiceSession,request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask,restrictedBgActivity, intentGrants);if (request.outActivity ! null) {request.outActivity[0] mLastStartActivityRecord;}return mLastStartActivityResult;}rInfo.auxiliaryInfo是和安装Instant应用有关如果启动的是Instant应用则会启动Instant安装者。 接着下面处理的是从快捷方式启动Activity的情况这种情况下callerApp nullrealCallingPid 0所以取出realCallingPid对应的应用赋值给callerApp 。 接下来就是构建ActivityRecord对象它是应用端Activity在系统框架层中对应的对象。它的创建是采用了建造者模式。里面用到的变量前面大多都涉及到了这里不详细说了。 创建完之后将创建的对象赋值给mLastStartActivityRecord。 r.appTimeTracker是用来跟踪用户使用应用时间如果没有设置它则将它设置为sourceRecord对象它不为null的情况下的appTimeTracker。 如果不是背景应用启动Activity并且启动的Activity不是Launcher进程可以直接使APP切换开关打开。看着注释的解释是背景应用如果是APP切换开关打开会停止Home按键的保护模式。启动的Activity如果在Launcher进程中需要等待Activity启动之后才能打开APP切换开关。 再接下来就是调用startActivityUnchecked方法来启动Activity了。并将结果存储在mLastStartActivityResult中。 request.outActivity不为null会将它设置为启动的ActivityRecord对象mLastStartActivityRecord。 最后将结果返回。 可见该方法主要就是做了一些检查主要是一些权限和拦截的处理。 executeRequest(Request request)的代码说完了Activity启动的代码是在方法startActivityUnchecked方法中所以我们继续看它的实现。
检查之后的startActivityUnchecked方法 看一下startActivityUnchecked方法的实现 /*** Start an activity while most of preliminary checks has been done and caller has been* confirmed that holds necessary permissions to do so.* Here also ensures that the starting activity is removed if the start wasnt successful.*/private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,int startFlags, boolean doResume, ActivityOptions options, Task inTask,boolean restrictedBgActivity, NeededUriGrants intentGrants) {int result START_CANCELED;final Task startedActivityRootTask;// Create a transition now to record the original intent of actions taken within// startActivityInner. Otherwise, logic in startActivityInner could start a different// transition based on a sub-action.// Only do the create here (and defer requestStart) since startActivityInner might abort.final Transition newTransition (!mService.getTransitionController().isCollecting() mService.getTransitionController().getTransitionPlayer() ! null)? mService.getTransitionController().createTransition(TRANSIT_OPEN) : null;IRemoteTransition remoteTransition r.takeRemoteTransition();if (newTransition ! null remoteTransition ! null) {newTransition.setRemoteTransition(remoteTransition);}mService.getTransitionController().collect(r);try {mService.deferWindowLayout();Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, startActivityInner);result startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,startFlags, doResume, options, inTask, restrictedBgActivity, intentGrants);} finally {Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);startedActivityRootTask handleStartResult(r, result);mService.continueWindowLayout();mSupervisor.mUserLeaving false;// Transition housekeepingif (!ActivityManager.isStartResultSuccessful(result)) {if (newTransition ! null) {newTransition.abort();}} else {if (!mAvoidMoveToFront mDoResume mRootWindowContainer.hasVisibleWindowAboveButDoesNotOwnNotificationShade(r.launchedFromUid)) {// If the UID launching the activity has a visible window on top of the// notification shade and its launching an activity thats going to be at the// front, we should move the shade out of the way so the user can see it.// We want to avoid the case where the activity is launched on top of a// background task which is not moved to the front.StatusBarManagerInternal statusBar mService.getStatusBarManagerInternal();if (statusBar ! null) {// This results in a async call since the interface is one-waystatusBar.collapsePanels();}}if (result START_SUCCESS || result START_TASK_TO_FRONT) {// The activity is started new rather than just brought forward, so record// it as an existence change.mService.getTransitionController().collectExistenceChange(r);}if (newTransition ! null) {mService.getTransitionController().requestStartTransition(newTransition,mTargetTask, remoteTransition);} else {// Make the collecting transition wait until this request is ready.mService.getTransitionController().setReady(false);}}}postStartActivityProcessing(r, result, startedActivityRootTask);return result;}Transition和Activity的转场动画相关调用mService.getTransitionController()的collect®方法将ActivityRecord对象收集到转换中。 接着mService.deferWindowLayout()是延迟窗口布局。 调用startActivityInner()方法实现启动Activity。 handleStartResult(r, result)是处理启动的结果如果启动成功会返回它的RootTask。 mService.continueWindowLayout()是恢复窗口布局。 mSupervisor.mUserLeaving是一个状态如果用户没有明确设定FLAG_ACTIVITY_NO_USER_ACTION标识在前面startActivityInner()方法中mSupervisor.mUserLeaving会被设置为true这样会在Activity执行onPause之前通知用户离开方法onUserLeaveHint()。执行完毕之后在这里将它设置为false。 如果启动Activity的结果不是成功的状态如果前面创建的newTransition不为null设置它的abort状态。 如果是启动成功在不是避免移到前面的条件下如果启动的应用在通知栏打开的上层有打开窗口这里将通知栏关闭。 接下来是处理转场相关。如果返回结果为START_SUCCESS或START_TASK_TO_FRONT的情况下这里将启动的ActivityRecord对象的改变状态记录下来Activity打开或关闭。START_SUCCESS代表正常启动一个ActivitySTART_TASK_TO_FRONT是一种什么情况呢它代表Activity已经在任务栈中并且将任务栈挪到根任务的最前端包括根任务也会移动到TaskDisplayArea对象的最前端这里根任务和任务有可能是同一个。还有一个返回值为START_DELIVERED_TO_TOP它则是代表在任务栈顶上和被启动的Activity是相同的不需要再次启动一个新的。 如果newTransition是在这里新创建的这里就开始请求开始。如果不是则是等待直到请求是准备好。 最后是调用postStartActivityProcessing方法。它是处理启动Activity之后的工作。
startActivityInner()方法 接下来看看startActivityInner()方法 /*** Start an activity and determine if the activity should be adding to the top of an existing* task or delivered new intent to an existing activity. Also manipulating the activity task* onto requested or valid root-task/display.** Note: This method should only be called from {link #startActivityUnchecked}.*/// TODO(b/152429287): Make it easier to exercise code paths through startActivityInnerVisibleForTestingint startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,int startFlags, boolean doResume, ActivityOptions options, Task inTask,boolean restrictedBgActivity, NeededUriGrants intentGrants) {setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,voiceInteractor, restrictedBgActivity);computeLaunchingTaskFlags();computeSourceRootTask();mIntent.setFlags(mLaunchFlags);final Task reusedTask getReusableTask();// If requested, freeze the task listif (mOptions ! null mOptions.freezeRecentTasksReordering() mSupervisor.mRecentTasks.isCallerRecents(r.launchedFromUid) !mSupervisor.mRecentTasks.isFreezeTaskListReorderingSet()) {mFrozeTaskList true;mSupervisor.mRecentTasks.setFreezeTaskListReordering();}// Compute if there is an existing task that should be used for.final Task targetTask reusedTask ! null ? reusedTask : computeTargetTask();final boolean newTask targetTask null;mTargetTask targetTask;computeLaunchParams(r, sourceRecord, targetTask);// Check if starting activity on given task or on a new task is allowed.int startResult isAllowedToStart(r, newTask, targetTask);if (startResult ! START_SUCCESS) {return startResult;}final ActivityRecord targetTaskTop newTask? null : targetTask.getTopNonFinishingActivity();if (targetTaskTop ! null) {// Recycle the target task for this launch.startResult recycleTask(targetTask, targetTaskTop, reusedTask, intentGrants);if (startResult ! START_SUCCESS) {return startResult;}} else {mAddingToTask true;}// If the activity being launched is the same as the one currently at the top, then// we need to check if it should only be launched once.final Task topRootTask mPreferredTaskDisplayArea.getFocusedRootTask();if (topRootTask ! null) {startResult deliverToCurrentTopIfNeeded(topRootTask, intentGrants);if (startResult ! START_SUCCESS) {return startResult;}}if (mTargetRootTask null) {mTargetRootTask getLaunchRootTask(mStartActivity, mLaunchFlags, targetTask, mOptions);}if (newTask) {final Task taskToAffiliate (mLaunchTaskBehind mSourceRecord ! null)? mSourceRecord.getTask() : null;setNewTask(taskToAffiliate);} else if (mAddingToTask) {addOrReparentStartingActivity(targetTask, adding to task);}if (!mAvoidMoveToFront mDoResume) {mTargetRootTask.getRootTask().moveToFront(reuseOrNewTask, targetTask);if (mOptions ! null) {if (mOptions.getTaskAlwaysOnTop()) {mTargetRootTask.setAlwaysOnTop(true);}}if (!mTargetRootTask.isTopRootTaskInDisplayArea() mService.mInternal.isDreaming()) {// Launching underneath dream activity (fullscreen, always-on-top). Run the launch-// -behind transition so the Activity gets created and starts in visible state.mLaunchTaskBehind true;r.mLaunchTaskBehind true;}}mService.mUgmInternal.grantUriPermissionUncheckedFromIntent(intentGrants,mStartActivity.getUriPermissionsLocked());if (mStartActivity.resultTo ! null mStartActivity.resultTo.info ! null) {// we need to resolve resultTo to a uid as grantImplicitAccess deals explicitly in UIDsfinal PackageManagerInternal pmInternal mService.getPackageManagerInternalLocked();final int resultToUid pmInternal.getPackageUid(mStartActivity.resultTo.info.packageName, 0 /* flags */,mStartActivity.mUserId);pmInternal.grantImplicitAccess(mStartActivity.mUserId, mIntent,UserHandle.getAppId(mStartActivity.info.applicationInfo.uid) /*recipient*/,resultToUid /*visible*/, true /*direct*/);}if (newTask) {EventLogTags.writeWmCreateTask(mStartActivity.mUserId,mStartActivity.getTask().mTaskId);}mStartActivity.logStartActivity(EventLogTags.WM_CREATE_ACTIVITY, mStartActivity.getTask());mTargetRootTask.mLastPausedActivity null;mRootWindowContainer.startPowerModeLaunchIfNeeded(false /* forceSend */, mStartActivity);mTargetRootTask.startActivityLocked(mStartActivity,topRootTask ! null ? topRootTask.getTopNonFinishingActivity() : null, newTask,mKeepCurTransition, mOptions, sourceRecord);if (mDoResume) {final ActivityRecord topTaskActivity mStartActivity.getTask().topRunningActivityLocked();if (!mTargetRootTask.isTopActivityFocusable()|| (topTaskActivity ! null topTaskActivity.isTaskOverlay() mStartActivity ! topTaskActivity)) {// If the activity is not focusable, we cant resume it, but still would like to// make sure it becomes visible as it starts (this will also trigger entry// animation). An example of this are PIP activities.// Also, we dont want to resume activities in a task that currently has an overlay// as the starting activity just needs to be in the visible paused state until the// over is removed.// Passing {code null} as the start parameter ensures all activities are made// visible.mTargetRootTask.ensureActivitiesVisible(null /* starting */,0 /* configChanges */, !PRESERVE_WINDOWS);// Go ahead and tell window manager to execute app transition for this activity// since the app transition will not be triggered through the resume channel.mTargetRootTask.mDisplayContent.executeAppTransition();} else {// If the target root-task was not previously focusable (previous top running// activity on that root-task was not visible) then any prior calls to move the// root-task to the will not update the focused root-task. If starting the new// activity now allows the task root-task to be focusable, then ensure that we// now update the focused root-task accordingly.if (mTargetRootTask.isTopActivityFocusable() !mRootWindowContainer.isTopDisplayFocusedRootTask(mTargetRootTask)) {mTargetRootTask.moveToFront(startActivityInner);}mRootWindowContainer.resumeFocusedTasksTopActivities(mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);}}mRootWindowContainer.updateUserRootTask(mStartActivity.mUserId, mTargetRootTask);// Update the recent tasks list immediately when the activity startsmSupervisor.mRecentTasks.add(mStartActivity.getTask());mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(),mPreferredWindowingMode, mPreferredTaskDisplayArea, mTargetRootTask);return START_SUCCESS;}setInitialState()主要用来初始化ActivityStarter对象的成员变量 computeLaunchingTaskFlags()是用来计算启动任务的标识mLaunchFlags。这里注意的一点是在没指定Task的情况下如果启动的Activity模式是LAUNCH_SINGLE_INSTANCE或LAUNCH_SINGLE_TASK会给mLaunchFlags添加FLAG_ACTIVITY_NEW_TASK标识。 computeSourceRootTask()是用来得到源根任务mSourceRootTask。 接下来将mLaunchFlags设置到mIntent中。 getReusableTask()得到新启动Activity应该添加进的Task。主要处理启动标识FLAG_ACTIVITY_NEW_TASK标识还有启动模式为LAUNCH_SINGLE_INSTANCE、LAUNCH_SINGLE_TASK的情况这样得到包含对应Activity的Task。 接下来如果设置参数里面请求冻结任务链设置冻结任务链属性。 targetTask是启动的Activity使用的Task它可能存在也可能不存在需要创建。这里如果上面得到的reusedTask不为null就使用它如果他为null再通过computeTargetTask()计算得到。computeTargetTask()会在有FLAG_ACTIVITY_NEW_TASK标识的情况下返回null。代表需要新建Task。computeTargetTask()在其他的情况下如果启动Activity不为null就返回它的Task。如果指定Task就使用指定Task。 如果targetTask为null则代表需要新建Task。 给成员变量mTargetTask赋值。 computeLaunchParams用来计算成员变量mLaunchParams。 isAllowedToStart()用来判断是否允许启动Activity。它主要用来判断ACTIVITY_TYPE_HOME类型Activity能否在显示屏上启动、后台启动的Activity是否终止、是否违法锁任务模式。如果返回的结果不为START_SUCCESS则返回对应结果。 下面如果目标Task不为null则得到目标Task上面的不为finishing的ActivityRecord targetTaskTop。 如果目标Task上的不为finishing的ActivityRecord targetTaskTop不为null则调用recycleTask()处理。注意这里的targetTaskTop可不见得就是启动的Activity像SINGLE_TASK模式启动的Activity它所属的任务栈里在它上面可能存在其他的Activity。recycleTask主要是对于目标Task的重用处理。如果目标Task的根Task不是当前获取焦点的根Task它会将目标Task的根Task移动到最前面。处理启动的标识在这里它可能会将Task里面的Activity给去除对应启动SingleTask的Activity它的实现是由complyActivityFlags()实现。它还决定是在Task顶端添加Activity还是将Task放到最前端。如果是在Task顶端添加Activity它会将成员变量mAddingToTask设置为true。 注意如果recycleTask()返回的结果不为START_SUCCESS则不会再往下执行直接返回对应的结果。这里返回START_SUCCESS也即在Task顶端添加Activity。它会继续向下处理。像我们平时启动模式为SingleTask、SingleInstance的Activity并且已经存在Task的情况下就不会继续向下执行了。 如果目标Task上的不为finishing的ActivityRecord targetTaskTop为null则将变量mAddingToTask true代表需要将Activity添加到Task中。 接下来是判断启动的Activity是否和当前Task最顶的Activity是不是相同如果相同检查是不是需要重新启动一个新的Activity。下面的deliverToCurrentTopIfNeeded(topRootTask, intentGrants)就是做这个事情的。像我们平时启动模式为SingleTop的Activity就是在这里处理的。如果不用新启动Activity返回START_DELIVERED_TO_TOP。 再接下来如果mTargetRootTask为null的话通过getLaunchRootTask()方法来获得。getLaunchRootTask()如果不能得到目前存在的Task它会新建一个Task。 下面继续是新建TasknewTask决定还是将Activity添加到Task中mAddingToTask决定。如果是新建Task在新建之后还需要将Activity添加到Task中的最顶端。在这里由于上一步可能通过getLaunchRootTask()新建了RootTask在这里也可能是使用的上一步新建的RootTask。如果不需要新建Task只是将Activity加入到Task中这里是调用addOrReparentStartingActivity(targetTask, “adding to task”)完成的。 下面如果mAvoidMoveToFront为false代表将任务移动到前面。mDoResume为true代表需要将Activity启动。这里会调用根Task的moveToFront()将任务移动到前面。 下面是检测Uri权限。 如果启动Activity之后返回结果给对应Activity存在mStartActivity.resultTo ! null。这里获取返回接收者应用对启动应用的可见性。 下面继续将mTargetRootTask.mLastPausedActivity null。 mTargetRootTask.startActivityLocked()主要是将Activity放置到Task的最上端。然后显示应用的StartingWindow。 mDoResume代表需要恢复Activity。 得到启动Activity的所在任务的最顶端可以运行的Activity topTaskActivity。 如果根任务的顶端Activity不是可以取得焦点的或者任务的顶端有一个遮罩并且不是启动的Activity这样的情况下也不恢复Activity只是让它可见。 除了上面那两种情况下就需要恢复Activity。还是检查如果根任务不是顶端获取焦点的根任务需要将它挪到最前端。接着就调用mRootWindowContainer.resumeFocusedTasksTopActivities()来恢复目标Activity的执行。在它里面会执行根Task的resumeTopActivityUncheckedLocked()方法。由于在前面已经将Activity添加到Task的最顶端所以这里就会将之前的处于Resumed状态的Activity给暂停然后将新添加的Activity启动并且将它状态改成Resumed。 接下来调用mRootWindowContainer.updateUserRootTask()方法来更新对应用户的根Task。 会将启动的Activity的Task添加到mSupervisor.mRecentTasks中。 接着调用mSupervisor的handleNonResizableTaskIfNeeded()方法来处理不是可变大小的Task。 最后返回结果START_SUCCESS。
总结 这里是启动Activity的实现。 首先是需要执行一系列检查主要是权限和拦截的处理。 接着处理主要分可以重用的Task还是新建Task。对于可以重用的Task还是要区分里面是否已经存在Activity实例SingleTask、SingleInstance、SingleTop模式的Activity进行处理。 最后会将满足条件的Activty启动起来。