android13 应用冷启动

在这里插入图片描述在这里插入图片描述

1 概述

  1. launcher 通过binder到systemserver中atms中发送startActivity请求

  2. startProcess向zygote发送启动新进程请求

  3. zygote收到请求,fork新进程并调用ActivityThread的main初始化

  4. 新进程启动,发送attachApplication给ams,告诉他新进程启动成功

  5. ams收到新进程启动成功的消息,做一系列准备工作,ActivityTaskSupervisor的realStartActivityLocked方法发起启动Activity。ActivityTaskSupervisor使用ApplicationThread的Binder代理向被启动的App进程发送scheduleTransaction请求。

  6. 被启动的App进程的binder线程(ApplicationThread)在收到请求后,通过handler向主线程发送EXECUTE_TRANSACTION消息

  7. 主线程在收到Message后,通过反射机制创建目标Activity,并回调Activity.onCreate()等方法

在这里插入图片描述

2 app进程向SystemServer进程发送startActivity请求

在这里插入图片描述

1.1 startActivity

//Activity.java
public void startActivity(Intent intent, @Nullable Bundle options) {getAutofillClientController().onStartActivity(intent, mIntent);if (options != null) {startActivityForResult(intent, -1, options);} else {// 请注意,我们希望通过此调用与可能已覆盖该方法的应用程序兼容。//见小结1.2startActivityForResult(intent, -1);}
}

1.2 startActivityForResult

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,@Nullable Bundle options) {if (mParent == null) {options = transferSpringboardActivityOptions(options);Instrumentation.ActivityResult ar =//见1.3小结mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options);if (ar != null) {mMainThread.sendActivityResult(mToken, mEmbeddedID, requestCode, ar.getResultCode(),ar.getResultData());}//此时requestCode =-1if (requestCode >= 0) {// 如果此开始请求结果,我们可以避免在收到结果之前使activity 可见。 在 onCreate(Bundle // savedInstanceState) 或 onResume() 期间设置此代码将使activity 在此期间隐藏,以避免闪烁。// 这只能在请求结果时完成,因为这保证我们将在activity 完成时获得信息, 不管发生什么事。mStartedActivity = true;}cancelInputsAndStartExitTransition(options);// TODO Consider clearing/flushing other event sources and events for child windows.} else {if (options != null) {mParent.startActivityFromChild(this, intent, requestCode, options);} else {// 请注意,我们希望通过此方法与可能已覆盖它的现有应用程序兼容。mParent.startActivityFromChild(this, intent, requestCode);}}
}
  • mInstrumentation的类型是Instrumentation,它用来监控应用程序和系统之间的交互操作。由于启动Activity是应用程序与系统之间的交互操作,因此调用它的成员函数execStartActivity来代替执行启动Activity的操作,以便它可以监控这个交互过程。
  • Activity类的成员变量mMainThread的类型是ActivityThread,用来描述应用程序进程。系统每启动一个应用程序的时候,都会在它里面加载一个ActivityThread类实例,并且会将这个ActivityThread类的实例保持在每一个在该进程中启动的Activity中。ActivityThread的getApplicationThread用来获取它内部的ApplicationThread的Binder本地对象,将它作为参数传给execStartActivity方法,以便可以将它传递给ActivityTaskManagerService和ActivityManagerService,这样在ActivityManagerService接下来就可以通过它来通知App进程中的Activity进入暂停状态
  • Activity类的成员变量mToken的类型是IBinder,它是一个Binder代理对象,指向ActivityManagerService中一个类型为ActivityRecord的Binder本地对象每一个已经启动的Activity在ActivityMangerService中都一个对应的ActivityRecord对象,用来维护对应的Activity在运行状态以及信息。它作为参数传给了execStartActivity方法,以便将它传递给ActivityTaskManagerService,这样ActivityTaskManagerService和ActivityMangerService就知道App进程中发起启动Activity的这个Activity的相关组件。

1.3 execStartActivity

//Instrumentation.java
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options) {IApplicationThread whoThread = (IApplicationThread) contextThread;Uri referrer = target != null ? target.onProvideReferrer() : null;if (referrer != null) {intent.putExtra(Intent.EXTRA_REFERRER, referrer);}if (mActivityMonitors != null) {synchronized (mSync) {final int N = mActivityMonitors.size();for (int i=0; i<N; i++) {//有关正在监视的特定类型 Intent 的信息。 通过addMonitor将这个类的一个实例添加到当前的instrumentation中; //添加后,当启动新Activity时,将检查显示器,如果匹配,则更新其命中计数,并且(可选)停止调用并返回固定结果。//ActivityMonitor 也可用于通过 waitForActivity 方法查找Activity的创建。 这将在使用该Activity对象创建匹配Activity后返回。final ActivityMonitor am = mActivityMonitors.get(i);ActivityResult result = null;if (am.ignoreMatchingSpecificIntents()) {if (options == null) {options = ActivityOptions.makeBasic().toBundle();}result = am.onStartActivity(who, intent, options);}if (result != null) {am.mHits++;return result;} else if (am.match(who, null, intent)) {am.mHits++;//当该monitor阻塞activity启动,则直接返回if (am.isBlocking()) {return requestCode >= 0 ? am.getResult() : null;}break;}}}}try {intent.migrateExtraStreamToClipData(who);intent.prepareToLeaveProcess(who);//见1.4和1.5小结int result = ActivityTaskManager.getService().startActivity(whoThread,who.getOpPackageName(), who.getAttributionTag(), intent,intent.resolveTypeIfNeeded(who.getContentResolver()), token,target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);//如果Activity启动不成功的,挂起启动的ActivitynotifyStartActivityResult(result, options);//检查activity是否启动成功checkStartActivityResult(result, intent);} catch (RemoteException e) {throw new RuntimeException("Failure from system", e);}return null;
}
  • ActivityTaskManager.getService()返回的是一个ActivityTaskManagerService的Binder代理对象,接着调用startActivity方法通知ActivityTaskManagerService要启动一个Activity组件。 此处startActivity函数的共有11个参数, 下面说说每个参数传递ATMS.startActivity()每一项的对应值:
public final int startActivity(IApplicationThread caller, String callingPackage,String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,Bundle bOptions)
  1. caller: 当前应用的ApplicationThread对象mAppThread;
  2. callingPackage: 调用当前ContextImpl.getBasePackageName(),获取当前Activity所在包名;
  3. callingFeatureId: 访问权限保护数据的应用程序的属性标签。
  4. intent: 这便是启动Activity时,传递过来的参数;
  5. resolvedType: 调用intent.resolveTypeIfNeeded而获取;
  6. resultTo: 来自于当前Activity.mToken,前面详细介绍过
  7. resultWho: 来自于当前Activity.mEmbeddedID
  8. requestCode = -1;
  9. startFlags = 0;
  10. profilerInfo = null;
  11. options = null;

1.4 getService

public static IActivityTaskManager getService() {return IActivityTaskManagerSingleton.get();
}

1.5 create

@UnsupportedAppUsage(trackingBug = 129726065)
private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =new Singleton<IActivityTaskManager>() {@Overrideprotected IActivityTaskManager create() {final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);return IActivityTaskManager.Stub.asInterface(b);}
};

2 SystemServer进程处理startActivity请求,需要向Zygote进程发消息

在这里插入图片描述

2.1 startActivity

// ActivityTaskManagerService.java
public final int startActivity(IApplicationThread caller, String callingPackage,String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,Bundle bOptions) {return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions,UserHandle.getCallingUserId());
}

2.2 startActivityAsUser

// ActivityTaskManagerService.java
private int startActivityAsUser(IApplicationThread caller, String callingPackage,@Nullable String callingFeatureId, Intent intent, String resolvedType,IBinder resultTo, String resultWho, int requestCode, int startFlags,ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {final SafeActivityOptions opts = SafeActivityOptions.fromBundle(bOptions);// 如果最近使用的(或桌面)Activity在后台并且可用,则通过过度动画快速启动(跳过一般意图或任务解析)。if (opts != null && opts.getOriginalOptions().getTransientLaunch()&& isCallerRecents(Binder.getCallingUid())) {final long origId = Binder.clearCallingIdentity();try {synchronized (mGlobalLock) {Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "startExistingRecents");if (mActivityStartController.startExistingRecentsIfPossible(intent, opts.getOriginalOptions())) {return ActivityManager.START_TASK_TO_FRONT;}// 否则遵循标准启动程序。}} finally {Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);Binder.restoreCallingIdentity(origId);}}assertPackageMatchesCallingUid(callingPackage);enforceNotIsolatedCaller("startActivityAsUser");if (Process.isSdkSandboxUid(Binder.getCallingUid())) {SdkSandboxManagerLocal sdkSandboxManagerLocal = LocalManagerRegistry.getManager(SdkSandboxManagerLocal.class);if (sdkSandboxManagerLocal == null) {throw new IllegalStateException("SdkSandboxManagerLocal not found when starting"+ " an activity from an SDK sandbox uid.");}sdkSandboxManagerLocal.enforceAllowedToStartActivity(intent);}userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");// ActivityStarter启动Activityreturn getActivityStartController().obtainStarter(intent, "startActivityAsUser").setCaller(caller).setCallingPackage(callingPackage).setCallingFeatureId(callingFeatureId).setResolvedType(resolvedType).setResultTo(resultTo).setResultWho(resultWho).setRequestCode(requestCode).setStartFlags(startFlags).setProfilerInfo(profilerInfo).setActivityOptions(opts).setUserId(userId).execute();
}
  • 如果需要启动的Activity在最近的任务栈中,并且并没有销毁。那么使用一个过渡动画,直接切换到要启动的Activity。如果没有走正常流程。getActivityStartController函数是获取一个ActivityStartController对象,obtainStarter是获取一个ActivityStarter对象。
  • ActivityStartController用于委派Activit启动的控制器。此类的主要目标是接收外部Activit启动请求,并将它们准备成一系列可由ActivityStarter处理Activity启动。它还负责处理Activity启动时发生的逻辑,但不一定影响Activity启动。示例包括电源提示管理、处理挂起的Activity列表以及记录home Activity启动。
  • ActivityStarter:是一个启动发射器,用于解析如何启动Activity。该类收集所有逻辑,用于确定如何将intent和标志转换为activity以及相关任务和根任务。

2.3 execute

execute:根据前面提供的请求参数解析必要的信息,并执行请求以开始启动Activity的旅程。

int execute() {try {onExecutionStarted();// 拒绝可能泄漏的文件描述符if (mRequest.intent != null && mRequest.intent.hasFileDescriptors()) {throw new IllegalArgumentException("File descriptors passed in Intent");}//当意图传入时创建的信息,但我们还不知道它是否会成功启动。final LaunchingState launchingState;synchronized (mService.mGlobalLock) {final ActivityRecord caller = ActivityRecord.forTokenLocked(mRequest.resultTo);final int callingUid = mRequest.realCallingUid == Request.DEFAULT_REAL_CALLING_UID?  Binder.getCallingUid() : mRequest.realCallingUid;//当我们开始启动Activity时,尽早通知跟踪器。 调用 notifyActivityLaunched,调用者必须确保稍后使用返回的 ActivityMetricsLogger.LaunchingState 。//如果在Activity跳转中发现调用者,它将被视为连续启动并合并到Activity跳转中。launchingState = mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(mRequest.intent, caller, callingUid);}//如果调用者尚未解析该activity,我们愿意在这里这样做。 如果调用者已经在这里持有 WM 锁,而我们需要检查动态 Uri 权限,那么我们不得不假设这些权限被拒绝以避免死锁。if (mRequest.activityInfo == null) {mRequest.resolveActivity(mSupervisor);}//为这次关机或重启尝试添加检查点,以便我们可以记录原始意图操作和包名称。if (mRequest.intent != null) {String intentAction = mRequest.intent.getAction();String callingPackage = mRequest.callingPackage;if (intentAction != null && callingPackage != null&& (Intent.ACTION_REQUEST_SHUTDOWN.equals(intentAction)|| Intent.ACTION_SHUTDOWN.equals(intentAction)|| Intent.ACTION_REBOOT.equals(intentAction))) {ShutdownCheckPoints.recordCheckPoint(intentAction, callingPackage, null);}}int res;//mGlobalLock是WindowManagerGlobalLock,拥有此服务的包使用的全局服务锁,加锁的原因是因为WMS对窗口的操作复杂而漫长,//为了防止线程间竞态的发生,WMS统一使用WindowManagerGlobalLock对所有窗口进行同步synchronized (mService.mGlobalLock) {//判断全局配置有没有发生变化,将结果赋值给当前焦点Task。final boolean globalConfigWillChange = mRequest.globalConfig != null&& mService.getGlobalConfiguration().diff(mRequest.globalConfig) != 0;final Task rootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();if (rootTask != null) {rootTask.mConfigWillChange = globalConfigWillChange;}ProtoLog.v(WM_DEBUG_CONFIGURATION, "Starting activity when config "+ "will change = %b", globalConfigWillChange);//重置当前线程上传入IPC的内核绑定器标识。如果在处理传入调用时,您将调用其他对象的接口,这些对象可能是您的进程本地的,//并且需要对传入它们的调用进行权限检查(因此,它们将检查您自己的本地进程的权限,而不是最初调用您的任何进程的权限),那么这将非常有用。//返回一个不透明令牌,通过将其传递给restoreCallingIdentity(long),该令牌可用于还原原始调用标识。final long origId = Binder.clearCallingIdentity();//如果这是一个重载进程,而另一个不同的重载进程正在运行,则更新重载切换请求.如果intent匹配到多个Activity弹出一个选择Activity的对话框列表。res = resolveToHeavyWeightSwitcherIfNeeded();if (res != START_SUCCESS) {return res;}res = executeRequest(mRequest);//将当前线程上传入IPC的内核绑定器标识还原为clearCallingIdentity返回的先前标识。Binder.restoreCallingIdentity(origId);if (globalConfigWillChange) {// 如果调用者也想切换到新的配置,现在就这样做。这允许一次干净的切换,因为我们正在等待当前的activity// 暂停(所以我们不会破坏它),并且还没有开始下一个activity。mService.mAmInternal.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,"updateConfiguration()");if (rootTask != null) {rootTask.mConfigWillChange = false;}ProtoLog.v(WM_DEBUG_CONFIGURATION,"Updating to new configuration after starting activity.");mService.updateConfigurationLocked(mRequest.globalConfig, null, false);}// 原始选项可能有关于指标的额外信息。 这里没有使用mOptions,因为它可能在setTargetRootTaskIfNeeded 中被清除。final ActivityOptions originalOptions = mRequest.activityOptions != null? mRequest.activityOptions.getOriginalOptions() : null;// If the new record is the one that started, a new activity has created.// 如果新记录是开始的记录,则新activity 已创建。final boolean newActivityCreated = mStartActivity == mLastStartActivityRecord;//通知 ActivityMetricsLogger activity已启动。ActivityMetricsLogger 然后将等待绘制窗口并填充 WaitResult。mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, res,newActivityCreated, mLastStartActivityRecord, originalOptions);if (mRequest.waitResult != null) {mRequest.waitResult.result = res;res = waitResultIfNeeded(mRequest.waitResult, mLastStartActivityRecord,launchingState);}return getExternalResult(res);}} finally {//主要是回收资源,执行完成调用时。设置完成的状态,并在适当时继续回收。onExecutionComplete();}
}

2.3.1 notifyActivityLaunching

当我们开始启动Activity时,尽早通知跟踪器。调用方必须确保稍后将使用返回的ActivityMetricsLogger.LaunchingState调用notifyActivityLaunched。如果在活动转换中发现调用方,则它将被视为连续启动并合并到活动转换中。

LaunchingState notifyActivityLaunching(Intent intent, @Nullable ActivityRecord caller,int callingUid) {final long transitionStartTimeNs = SystemClock.elapsedRealtimeNanos();//确认启动Activity时创建的信息TransitionInfo existingInfo = null;if (callingUid != IGNORE_CALLER) {//如果在其启动的activities中找到调用者,则将启动事件与activities转换相关联。for (int i = mTransitionInfoList.size() - 1; i >= 0; i--) {final TransitionInfo info = mTransitionInfoList.get(i);if (caller != null && info.contains(caller)) {existingInfo = info;break;}if (existingInfo == null && callingUid == info.mLastLaunchedActivity.getUid()) {//在调用者不是Activity的情况下回退以检查最近匹配的 uid。existingInfo = info;}}}if (DEBUG_METRICS) {Slog.i(TAG, "notifyActivityLaunching intent=" + intent+ " existingInfo=" + existingInfo);}// existingInfo 为null,说明没有找到,if (existingInfo == null) {final LaunchingState launchingState = new LaunchingState();launchingState.mCurrentTransitionStartTimeNs = transitionStartTimeNs;// 通知观察者一个新的Activity启动事件。launchObserverNotifyIntentStarted(intent, transitionStartTimeNs);return launchingState;}existingInfo.mLaunchingState.mCurrentTransitionStartTimeNs = transitionStartTimeNs;return existingInfo.mLaunchingState;
}

2.3.2 resolveActivity

void resolveActivity(ActivityTaskSupervisor supervisor) {//realCallingPid的默认值是DEFAULT_REAL_CALLING_PID,如果相等说明没有初始化if (realCallingPid == Request.DEFAULT_REAL_CALLING_PID) {realCallingPid = Binder.getCallingPid();}//realCallingPid的默认值是DEFAULT_REAL_CALLING_UID,如果相等说明没有初始化if (realCallingUid == Request.DEFAULT_REAL_CALLING_UID) {realCallingUid = Binder.getCallingUid();}if (callingUid >= 0) {callingPid = -1;} else if (caller == null) {callingPid = realCallingPid;callingUid = realCallingUid;} else {callingPid = callingUid = -1;}//要确定所需的Uri权限授予集,我们需要“已解析”的调用UID,在这里我们尽最大努力确定启动此activity的实际调用方int resolvedCallingUid = callingUid;if (caller != null) {synchronized (supervisor.mService.mGlobalLock) {// Activity Manager(AM)包通过ProcessRecord管理系统中流程的生命周期。// 然而,窗口管理器(WM)包必须了解进程及其状态,因为它会影响WM管理窗口和activities的方式。该类允许AM包中的ProcessRecord对象以结构化的方式将其状态的重要更改传递给WM包。// WM包还使用WindowProcessListener请求对AM端的进程状态进行更改。请注意,对该类的公共调用假定来自窗口管理器外部,因此在允许继续调用之前,将保持窗口管理器锁并检查适当的权限。final WindowProcessController callerApp = supervisor.mService.getProcessController(caller);if (callerApp != null) {resolvedCallingUid = callerApp.mInfo.uid;}}}// 保存副本以备临时需要ephemeralIntent = new Intent(intent);// 不要修改客户端的对象!intent = new Intent(intent);if (intent.getComponent() != null&& !(Intent.ACTION_VIEW.equals(intent.getAction()) && intent.getData() == null)&& !Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE.equals(intent.getAction())&& !Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE.equals(intent.getAction())&& supervisor.mService.getPackageManagerInternalLocked().isInstantAppInstallerComponent(intent.getComponent())) {
//拦截直接针对临时安装程序的意图,临时安装程序不应以原始意图启动;而是调整意图,使其看起来像“正常”的即时应用程序启动。intent.setComponent(null /* component */);}//根据IntentFilter解析意图返回的信息。这部分对应于从AndroidManifest.xml的<intent>标记中收集的信息。里面包含ActivityInfo,ServiceInfo,resolveInfo = supervisor.resolveIntent(intent, resolvedType, userId,0 /* matchFlags */,computeResolveFilterUid(callingUid, realCallingUid, filterCallingUid));if (resolveInfo == null) {final UserInfo userInfo = supervisor.getUserInfo(userId);if (userInfo != null && userInfo.isManagedProfile()) {// 托管配置文件的特殊情况,如果尝试从未锁定的父级在锁定的托管配置文件中启动非 cryto 感知应用程序,// 则允许它解析,因为用户将通过确认凭据发送以解锁配置文件。final UserManager userManager = UserManager.get(supervisor.mService.mContext);// 配置文件已锁定且父级正在解锁中或已解锁boolean profileLockedAndParentUnlockingOrUnlocked = false;final long token = Binder.clearCallingIdentity();try {final UserInfo parent = userManager.getProfileParent(userId);profileLockedAndParentUnlockingOrUnlocked = (parent != null)&& userManager.isUserUnlockingOrUnlocked(parent.id)&& !userManager.isUserUnlockingOrUnlocked(userId);} finally {Binder.restoreCallingIdentity(token);}if (profileLockedAndParentUnlockingOrUnlocked) {resolveInfo = supervisor.resolveIntent(intent, resolvedType, userId,PackageManager.MATCH_DIRECT_BOOT_AWARE| PackageManager.MATCH_DIRECT_BOOT_UNAWARE,computeResolveFilterUid(callingUid, realCallingUid,filterCallingUid));}}}// 收集有关目标Intent的信息。activityInfo = supervisor.resolveActivity(intent, resolveInfo, startFlags,profilerInfo);// 在不持有锁的情况下仔细收集授权if (activityInfo != null) {intentGrants = supervisor.mService.mUgmInternal.checkGrantUriPermissionFromIntent(intent, resolvedCallingUid, activityInfo.applicationInfo.packageName,UserHandle.getUserId(activityInfo.applicationInfo.uid));}
}

2.3.3 resolveToHeavyWeightSwitcherIfNeeded

resolveToHeavyWeightSwitcherIfNeeded:如果这是一个重载进程,而另一个不同的重载进程正在运行,则更新重载切换请求。

private int resolveToHeavyWeightSwitcherIfNeeded() {if (mRequest.activityInfo == null || !mService.mHasHeavyWeightFeature|| (mRequest.activityInfo.applicationInfo.privateFlags& ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) == 0) {return START_SUCCESS;}if (!mRequest.activityInfo.processName.equals(mRequest.activityInfo.applicationInfo.packageName)) {return START_SUCCESS;}final WindowProcessController heavy = mService.mHeavyWeightProcess;if (heavy == null || (heavy.mInfo.uid == mRequest.activityInfo.applicationInfo.uid&& heavy.mName.equals(mRequest.activityInfo.processName))) {return START_SUCCESS;}int appCallingUid = mRequest.callingUid;if (mRequest.caller != null) {WindowProcessController callerApp = mService.getProcessController(mRequest.caller);if (callerApp != null) {appCallingUid = callerApp.mInfo.uid;} else {Slog.w(TAG, "Unable to find app for caller " + mRequest.caller + " (pid="+ mRequest.callingPid + ") when starting: " + mRequest.intent.toString());SafeActivityOptions.abort(mRequest.activityOptions);return START_PERMISSION_DENIED;}}final IIntentSender target = mService.getIntentSenderLocked(ActivityManager.INTENT_SENDER_ACTIVITY, "android" /* packageName */,null /* featureId */, appCallingUid, mRequest.userId, null /* token */,null /* resultWho*/, 0 /* requestCode*/, new Intent[]{mRequest.intent},new String[]{mRequest.resolvedType},PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT,null /* bOptions */);final Intent newIntent = new Intent();if (mRequest.requestCode >= 0) {// Caller is requesting a result.newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);
}// HeavyWeightSwitcherActivity当系统尝试启动具有多个匹配活动的Intent时,将显示此Activity,允许用户决定要转到哪个Activity。应用程序开发人员通常不直接使用此Activity。newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT, new IntentSender(target));heavy.updateIntentForHeavyWeightActivity(newIntent);newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,mRequest.activityInfo.packageName);newIntent.setFlags(mRequest.intent.getFlags());newIntent.setClassName("android" /* packageName */,HeavyWeightSwitcherActivity.class.getName());mRequest.intent = newIntent;mRequest.resolvedType = null;mRequest.caller = null;mRequest.callingUid = Binder.getCallingUid();mRequest.callingPid = Binder.getCallingPid();mRequest.componentSpecified = true;mRequest.resolveInfo = mSupervisor.resolveIntent(mRequest.intent, null /* resolvedType */,mRequest.userId, 0 /* matchFlags */,computeResolveFilterUid(mRequest.callingUid, mRequest.realCallingUid,mRequest.filterCallingUid));mRequest.activityInfo =mRequest.resolveInfo != null ? mRequest.resolveInfo.activityInfo : null;if (mRequest.activityInfo != null) {mRequest.activityInfo = mService.mAmInternal.getActivityInfoForUser(mRequest.activityInfo, mRequest.userId);}return START_SUCCESS;
}

2.4 executeRequest

executeRequest:执行activity启动请求并开始启动activity的旅程。 这里从执行几个初步检查开始。 通常activity启动流程将通过 startActivityUnchecked到startActivityInner

private int executeRequest(Request request) {if (TextUtils.isEmpty(request.reason)) {throw new IllegalArgumentException("Need to specify a reason.");}// reason是 startActivityAsUsermLastStartReason = 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;TaskFragment inTaskFragment = request.inTaskFragment;int err = ActivityManager.START_SUCCESS;// 尽早将可选的 Ephemeral Installer-only(仅限临时安装程序) 捆绑包从选项中拉出。final Bundle verificationBundle =options != null ? options.popAppVerificationBundle() : null;// Activity Manager(AM)包通过ProcessRecord管理系统中进程的生命周期。// 然而,窗口管理器(WM)包必须了解进程及其状态,因为它会影响WM管理窗口和Activity的方式。该类允许AM包中的ProcessRecord对象以结构化的方式将其状态的重要更改传递给WM包。// WM包还使用WindowProcessListener请求对AM端的进程状态进行更改。// 请注意,对该类的公共调用假定来自窗口管理器外部,因此在允许继续调用之前,将保持窗口管理器锁并检查适当的权限。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 = 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);}//startActivityForResult相关业务处理ActivityRecord sourceRecord = null;ActivityRecord resultRecord = null;if (resultTo != null) {sourceRecord = ActivityRecord.isInAnyTask(resultTo);if (DEBUG_RESULTS) {Slog.v(TAG_RESULTS, "Will send result to " + resultTo + " " + sourceRecord);}if (sourceRecord != null) {//requestCode 是从startActivityForResult中传入的,给的是固定值-1if (requestCode >= 0 && !sourceRecord.finishing) {//如果是startActivityForResult的这种情况那么requestCode是 >= 0的,启动新Activity的Activity(sourceRecord),也是新Activty返回结果的Activity,所以resultRecord = sourceRecord。resultRecord = sourceRecord;}}}final int launchFlags = intent.getFlags();//FLAG_ACTIVITY_FORWARD_RESULT:如果flag设置给了此意图,并且该意图正用于从现有activity启动新activity,则现有activity的将跳转到新activity,现有activity是新activity的回复目标。这样,新activity可以调用android.app.activity.setResult,将结果发送回给原始(也是目标)activity。if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {// 将结果目标从源activity跳转到正在启动的新activity,包括任何失败。if (requestCode >= 0) {SafeActivityOptions.abort(options);return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;}resultRecord = sourceRecord.resultTo;// 判断是不是 WindowContainer的子类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) {// 新activity正在从与流程中前一个activity相同的 uid 启动,并要求将其结果转发回前一个activity。// 在这种情况下,该activity充当两者之间的蹦床,因此我们还希望将其 launchedFromPackage 更新为与之前的activity相同。// 请注意,这是安全的,因为我们知道这两个包来自同一个 uid; 调用者也可以自己提供相同的包名。// 这专门处理在应用程序流程中启动意图选择器/选择器以重定向到用户选择的activity的情况,我们希望最终activity将其视为已由先前的应用程序activity启动。callingPackage = sourceRecord.launchedFromPackage;callingFeatureId = sourceRecord.launchedFromFeatureId;}}if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {// 我们找不到可以处理Intent指定的类。 到此为止!err = ActivityManager.START_INTENT_NOT_RESOLVED;}if (err == ActivityManager.START_SUCCESS && aInfo == null) {// 我们找不到Intent中指定的具体类信息。err = ActivityManager.START_CLASS_NOT_FOUND;}//voiceSession是语音交互会话处理if (err == ActivityManager.START_SUCCESS && sourceRecord != null&& sourceRecord.getTask().voiceSession != null) {// 如果此activity作为语音会话的一部分启动,我们需要确保这样做是安全的。// 如果即将到来的 Activity 也将成为语音会话的一部分,我们只能在它明确表示它支持 VOICE 类别时启动它,或者它是调用应用程序的一部分。if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0&& sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {try {intent.addCategory(Intent.CATEGORY_VOICE);//原Actviity(发起启动新Activity的Activity)不支持语言会话。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;}}}//原Actviity(发起启动新Activity的Activity)支持语言会话。if (err == ActivityManager.START_SUCCESS && voiceSession != null) {// 如果调用者正在开始一个新的语音会话,只需确保目标实际上允许它以这种方式运行。try {//在新语音任务堆栈中启动的Activity不支持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;}// ATS权限检查是否允许启动Activity.boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,requestCode, callingPid, callingUid, callingPackage, callingFeatureId,request.ignoreTargetSecurity, inTask != null, callerApp, resultRecord,resultRootTask);// 这是从ActivityManager调用的,以检查是否应允许此意图启动Activity。假定调用者已持有全局ActivityManagerService锁。abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,callingPid, resolvedType, aInfo.applicationInfo);// PermissionPolicyService检查是否允许启动Activity.abort |= !mService.getPermissionPolicyInternal().checkStartActivity(intent, callingUid,callingPackage);// 合并两个选项包,而 realCallerOptions 优先。ActivityOptions checkedOptions = options != null? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null;// 终止后台Activity的启动boolean restrictedBgActivity = false;if (!abort) {try {Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER,"shouldAbortBackgroundActivityStart");BackgroundActivityStartController balController =mController.getBackgroundActivityLaunchController();restrictedBgActivity =balController.shouldAbortBackgroundActivityStart(callingUid,callingPid,callingPackage,realCallingUid,realCallingPid,callerApp,request.originatingPendingIntent,request.allowBackgroundActivityStart,intent,checkedOptions);} finally {Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);}}// 是否允许查找挂起的远程动画注册表,如果设置为true,则允许此activity开始查找PendingRemoteAnimationRegistry// PendingRemoteAnimationRegistry注册表用于跟踪activity从某个包开始时要运行的远程动画。if (request.allowPendingRemoteAnimationRegistryLookup) {checkedOptions = mService.getActivityStartController().getPendingRemoteAnimationRegistry()//如果某个调用包已注册远程动画,则使用该远程动画覆盖活动选项。.overrideOptionsIfNeeded(callingPackage, checkedOptions);}if (mService.mController != null) {try {// 我们给观察者的 Intent 去掉了额外的数据,因为它可以包含私人信息。// cloneFilter:仅克隆与筛选器匹配相关的意向部分:操作、数据、类型、组件和类别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, inTaskFragment,callingPid, callingUid, checkedOptions)) {//activity启动被拦截,例如,因为目标用户当前处于安静模式(关闭工作)或目标应用程序被挂起intent = mInterceptor.mIntent;rInfo = mInterceptor.mRInfo;aInfo = mInterceptor.mAInfo;resolvedType = mInterceptor.mResolvedType;inTask = mInterceptor.mInTask;callingPid = mInterceptor.mCallingPid;callingUid = mInterceptor.mCallingUid;checkedOptions = mInterceptor.mActivityOptions;// 拦截目标不应获得任何用于原始目的地的权限授予intentGrants = null;}if (abort) {if (resultRecord != null) {resultRecord.sendResult(INVALID_UID, resultWho, requestCode, RESULT_CANCELED,null /* data */, null /* dataGrants */);}// 我们假装调用者它真的开始了,但他们只会得到一个取消结果。ActivityOptions.abort(checkedOptions);return START_ABORTED;}// 如果在运行任何应用程序组件之前需要对权限进行审核,我们将启动审核activity,并传递一个待定的意图,以便在审核完成后立即启动该activity。if (aInfo != null) {// 获取包是否需要权限审核。从代码pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M来看,就是小于6.0版本的app需要权限审查if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(aInfo.packageName, userId)) {//target是PendingIntentRecordfinal 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);//activity操作:启动UI以查看应用程序的权限。如果启用了不支持新运行时权限模式的应用程序的权限审核,系统将使用此意图。在此模式下,任何应用程序组件都需要进行权限审核才能运行。//换句话说,应该是兼容6.0之前的老app,没有运行时权限授权的,在这里给它一种新的flag,使它也有运行时权限检查。Intent newIntent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);//FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:如果已设置,则新activity不会保留在最近启动的activity列表中。int flags = intent.getFlags();flags |= Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;// 防止重复检查activity:每个应用程序都需要自己的检查activity。// 默认情况下,使用 NEW_TASK 或 NEW_DOCUMENT 启动的activity会尝试重用具有相同启动参数的activity(忽略额外参数)。// 因此,为了避免可能的重用,通过 MULTIPLE_TASK 标志强制执行新activity。 未使用 NEW_TASK 或 NEW_DOCUMENT 启动的activity不会被重新使用,因此在这种情况下无需添加标志。if ((flags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NEW_DOCUMENT)) != 0) {//将包含FLAG_ACTIVITY_NEW_TASK 或者 FLAG_ACTIVITY_NEW_DOCUMENT的Intent的flag加上FLAG_ACTIVITY_MULTIPLE_TASK,使其强制启动新activityflags |= 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;// 权限审核目标不应获得任何针对原始目标的权限授予intentGrants = 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()));}}}// 如果我们有一个短暂的应用程序(临时安装程序),请中止启动已解析的意图的进程。相反,启动临时安装程序。一旦安装程序完成,它将启动我们在这里解析的意图[安装错误]或短暂的应用程序[安装成功]if (rInfo != null && rInfo.auxiliaryInfo != null) {intent = createLaunchIntent(rInfo.auxiliaryInfo, request.ephemeralIntent,callingPackage, callingFeatureId, verificationBundle, resolvedType, userId);resolvedType = null;callingUid = realCallingUid;callingPid = realCallingPid;// 临时安装程序不应获得任何用于原始目标Intent的权限授予。// 所以制空intent权限授予.intentGrants = null;aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);}// 当从快捷方式启动activity 时更正调用者/pid/uid 从 systemui 启动的挂起意图也取决于调用者应用程序if (callerApp == null && realCallingPid > 0) {final WindowProcessController wpc = mService.mProcessMap.getProcess(realCallingPid);if (wpc != null) {callerApp = wpc;}}//12 创建启动目标Activity的ActivityRecordfinal 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) {// 如果调用者没有指定一个明确的时间跟踪器,我们希望在它有时间跟踪器的情况下,在任何时间继续跟踪。//AppTimeTracker:设置我们是否跟踪此应用程序/任务/activity中的时间r.appTimeTracker = sourceRecord.appTimeTracker;}// 仅当activity不是受限制的后台activity且目标应用程序不是home程时,才允许恢复应用程序切换,否则在后台任务中启动的任何后台activity都可以停止home按钮保护模式。// 由于目标应用程序不是一个home进程,我们不需要等待第二个activity开始才能恢复应用程序切换,因此我们可以直接启用应用程序切换。// home process:当类型为ACTIVITY_TYPE_HOME的应用启动后会设置mHomeProcess,比如桌面APPWindowProcessController homeProcess = mService.mHomeProcess;boolean isHomeProcess = homeProcess != null&& aInfo.applicationInfo.uid == homeProcess.mUid;//13. 不是受限制的后台Activity,同时不是桌面进程。if (!restrictedBgActivity && !isHomeProcess) {mService.resumeAppSwitches();}mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,request.voiceInteractor, startFlags, true /* doResume */, checkedOptions,inTask, inTaskFragment, restrictedBgActivity, intentGrants);if (request.outActivity != null) {request.outActivity[0] = mLastStartActivityRecord;}return mLastStartActivityResult;
}
  1. 检查WindowProcessController能不能获取,如果不能,报权限异常。
  2. startActivityForResult相关业务处理,主要确定是不是这个业务,如果是,找到正确的sourceRecord和resultRecord。
  3. 给找不到可以处理Intent指定的类或者找不到Intent中指定的具体类信息这两种情况指定启动错误的代号。
  4. voiceSession是语音交互会话处理,处理失败终止启动动画。
  5. 通过ATS、ActivityManager、PermissionPolicyService检查是否有启动Activity的权限,如果没有终止启动。
  6. 判断是不是后台Activity,如果是终止启动。
  7. 如果允许查找挂起的远程动画注册表,发现有远程动画,注册远程动画,并覆盖activity选项。
  8. 判断IActivityController是否允许启动Activity。
  9. 调用ActivityStartInterceptor的intercept方法对满足条件进行activity启动拦截。
  10. 对版本小于android6.0的app做运行时权限检测;
  11. 如果我们有一个临时安装程序,请中止启动已解析的意图的进程。启动临时安装程序。一旦安装程序完成,再启动我们在这里解析的意图安装错误或安装成功。
  12. 创建启动目标Activity的ActivityRecord。
  13. 不是受限制的后台Activity,同时不是桌面进程,恢复应用程序切换。

2.5 startActivityUnchecked

startActivityUnchecked:在大多数初步检查已完成且调用者已确认拥有执行此操作所需的权限的情况下启动activity。这里还确保在启动不成功时删除启动activity

private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,int startFlags, boolean doResume, ActivityOptions options, Task inTask,TaskFragment inTaskFragment, boolean restrictedBgActivity,NeededUriGrants intentGrants) {int result = START_CANCELED;final Task startedActivityRootTask;// 现在创建一个跳转,以记录startActivityInner中执行的操作的原始意图。否则,startActivityInner中的逻辑可能会基于子操作启动不同的跳转。// 仅在此处创建(并延迟requestStart),因为startActivityInner可能会中止final TransitionController transitionController = r.mTransitionController;//表示逻辑跳转。Transition newTransition = (!transitionController.isCollecting()&& transitionController.getTransitionPlayer() != null)? transitionController.createTransition(TRANSIT_OPEN) : null;// 表示远程转换动画和运行该动画所需的信息(例如,需要增强的应用程序线程)。RemoteTransition remoteTransition = r.takeRemoteTransition();// 将wc添加到参与此跳转的WindowContainers集合中。transitionController.collect(r);try {mService.deferWindowLayout();try {Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,startFlags, doResume, options, inTask, inTaskFragment, restrictedBgActivity,intentGrants);} finally {Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);//如果启动结果为成功,请确保已启动activity的配置与当前显示相匹配。否则,清理未连接的容器以避免泄漏。startedActivityRootTask = handleStartResult(r, options, result, newTransition,remoteTransition);}} finally {mService.continueWindowLayout();}postStartActivityProcessing(r, result, startedActivityRootTask);return result;
}

2.5.1 postStartActivityProcessing

void postStartActivityProcessing(ActivityRecord r, int result,Task startedActivityRootTask) {//启动失败if (!ActivityManager.isStartResultSuccessful(result)) {if (mFrozeTaskList) {//如果我们专门冻结了任务列表作为启动Activity的一部分,如果启动失败,则重置冻结列表状态。这通常在冻结超时结束时调用。mSupervisor.mRecentTasks.resetFreezeTaskListReorderingOnTimeout();}}// 返回启动结果是否为致命错误。if (ActivityManager.isStartResultFatalError(result)) {return;}// 我们正在等待activity启动完成,但该activity只是将另一个activity推到了前面。// 我们还必须处理由于trampoline activity处于同一任务中而导致任务已经处于最前面的情况(当trampoline完成时,将被视为已聚焦)。// 让它们知道这一点,以便等待新activity变为可见,{waitResultIfNeeded}// trampoline activity的作用:从另一个activity开启一个Activity.mSupervisor.reportWaitingActivityLaunchedIfNeeded(r, result);final Task targetTask = r.getTask() != null? r.getTask(): mTargetTask;if (startedActivityRootTask == null || targetTask == null || !targetTask.isAttached()) {return;}if (result == START_TASK_TO_FRONT || result == START_DELIVERED_TO_TOP) {// 该activity已经在运行,因此它不需要启动。因为它已经在前面,新的意图已经或者将要传递给它。通知任何对此信息感兴趣的人。final Task rootHomeTask = targetTask.getDisplayArea().getRootHomeTask();final boolean homeTaskVisible = rootHomeTask != null&& rootHomeTask.shouldBeVisible(null);final ActivityRecord top = targetTask.getTopNonFinishingActivity();final boolean visible = top != null && top.isVisible();mService.getTaskChangeNotificationController().notifyActivityRestartAttempt(targetTask.getTaskInfo(), homeTaskVisible, mIsTaskCleared, visible);}// 返回启动是否成功if (ActivityManager.isStartResultSuccessful(result)) {//成功启动Activity时调用ActivityInterceptorCallback.onActivityLaunchedmInterceptor.onActivityLaunched(targetTask.getTaskInfo(), r);}
}

2.6 startActivityInner

启动一个activity,并确定该activity是应该添加到现有任务的顶部,还是应该向现有activity传递新的意图。还将activity任务操作到请求的或有效的根任务/显示上。注意:只能从startActivityUnchecked调用此方法。

int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,int startFlags, boolean doResume, ActivityOptions options, Task inTask,TaskFragment inTaskFragment, boolean restrictedBgActivity,NeededUriGrants intentGrants) {// 设置初始状态值setInitialState(r, options, inTask, inTaskFragment, doResume, startFlags, sourceRecord,voiceSession, voiceInteractor, restrictedBgActivity);// 计算启动task的标志位Flag// 主要处理一些Intent Flag冲突、复用问题// 以及SingleInstance和SingleTask的处理computeLaunchingTaskFlags();// 通过sourceActivity计算sourceTask// 主要处理 FLAG_ACTIVITY_NEW_TASK 问题computeSourceRootTask();mIntent.setFlags(mLaunchFlags);boolean dreamStopping = false;for (ActivityRecord stoppingActivity : mSupervisor.mStoppingActivities) {if (stoppingActivity.getActivityType()== WindowConfiguration.ACTIVITY_TYPE_DREAM) {dreamStopping = true;break;}}// 在开始时获取 top 任务,因为重用现有任务时可能会更改顺序。final Task prevTopRootTask = mPreferredTaskDisplayArea.getFocusedRootTask();final Task prevTopTask = prevTopRootTask != null ? prevTopRootTask.getTopLeafTask() : null;//决定是否应将新activity插入现有任务。如果不是,则返回null,或者返回ActivityRecord,其中包含应向其中添加新Activity的任务。final Task reusedTask = getReusableTask();// 如果请求,冻结任务列表if (mOptions != null && mOptions.freezeRecentTasksReordering()&& mSupervisor.mRecentTasks.isCallerRecents(r.launchedFromUid)&& !mSupervisor.mRecentTasks.isFreezeTaskListReorderingSet()) {mFrozeTaskList = true;//冻结当前最近的任务列表顺序,直到用户与当前应用程序交互或发生超。mSupervisor.mRecentTasks.setFreezeTaskListReordering();}// 计算是否存在应该用于的现有任务栈。final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();final boolean newTask = targetTask == null;mTargetTask = targetTask;computeLaunchParams(r, sourceRecord, targetTask);// 检查是否允许在给定任务或新任务上启动activity。int startResult = isAllowedToStart(r, newTask, targetTask);if (startResult != START_SUCCESS) {if (r.resultTo != null) {r.resultTo.sendResult(INVALID_UID, r.resultWho, r.requestCode, RESULT_CANCELED,null /* data */, null /* dataGrants */);}return startResult;}if (targetTask != null) {mPriorAboveTask = TaskDisplayArea.getRootTaskAbove(targetTask.getRootTask());}final ActivityRecord targetTaskTop = newTask? null : targetTask.getTopNonFinishingActivity();if (targetTaskTop != null) {// 回收本次启动的目标任务栈。// 准备要在此次启动中重用的目标任务栈,包括:将目标任务放置在有效的显示器上正在显示的根任务栈上。// 遵守指定的activity启动标志确定是否需要在顶部添加新activity,还是只是将任务置于最前面。startResult = recycleTask(targetTask, targetTaskTop, reusedTask, intentGrants);if (startResult != START_SUCCESS) {return startResult;}} else {mAddingToTask = true;}// 如果正在启动的 Activity 与当前位于顶部的 Activity 相同,那么我们需要检查它是否应该只启动一次。final Task topRootTask = mPreferredTaskDisplayArea.getFocusedRootTask();if (topRootTask != null) {startResult = deliverToCurrentTopIfNeeded(topRootTask, intentGrants);if (startResult != START_SUCCESS) {return startResult;}}if (mTargetRootTask == null) {mTargetRootTask = getOrCreateRootTask(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 (!mTargetRootTask.isTopRootTaskInDisplayArea() && mService.isDreaming()&& !dreamStopping) {// 在梦想activity下启动(全屏,始终在最上面)。 运行 launch--behind 转换,以便创建 Activity 并以可见状态启动。mLaunchTaskBehind = true;r.mLaunchTaskBehind = true;}}mService.mUgmInternal.grantUriPermissionUncheckedFromIntent(intentGrants,mStartActivity.getUriPermissionsLocked());if (mStartActivity.resultTo != null && mStartActivity.resultTo.info != null) {// 我们需要将 resultTo 解析为 uid,因为 grantImplicitAccess 在 UID 中显式处理final 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*/);}final Task startedTask = mStartActivity.getTask();if (newTask) {EventLogTags.writeWmCreateTask(mStartActivity.mUserId, startedTask.mTaskId);}mStartActivity.logStartActivity(EventLogTags.WM_CREATE_ACTIVITY, startedTask);mStartActivity.getTaskFragment().clearLastPausedActivity();mRootWindowContainer.startPowerModeLaunchIfNeeded(false /* forceSend */, mStartActivity);final boolean isTaskSwitch = startedTask != prevTopTask && !startedTask.isEmbedded();mTargetRootTask.startActivityLocked(mStartActivity, topRootTask, newTask, isTaskSwitch,mOptions, sourceRecord);if (mDoResume) {final ActivityRecord topTaskActivity = startedTask.topRunningActivityLocked();if (!mTargetRootTask.isTopActivityFocusable()|| (topTaskActivity != null && topTaskActivity.isTaskOverlay()&& mStartActivity != topTaskActivity)) {// 如果activity无法聚焦,我们无法继续,但仍希望确保它在开始时变得可见(这也会触发入场动画)。// 例如,画中画activity。此外,我们不希望在当前具有覆盖的任务栈中恢复activity,// 因为启动activity只需要处于可见的暂停状态,直到覆盖被删除。将null作为开始参数可确保所有activities都可见mTargetRootTask.ensureActivitiesVisible(null /* starting */,0 /* configChanges */, !PRESERVE_WINDOWS);// 继续并告诉窗口管理器执行此activity的应用程序跳转,因为应用程序跳转不会通过恢复手段触发。mTargetRootTask.mDisplayContent.executeAppTransition();} else {// 如果目标根任务栈以前不可聚焦(以前的顶部运行// 该根任务栈上的activity不可见),则之前任何将根任务栈移动到的调用都不会更新聚焦的根任务。如果现在启动新activity允许任务根任务可聚焦,那么确保我们现在相应地更新聚焦的根任务// Task.java :一个基本容器,可用于包含Activity或其他TaskFragment,它还能够管理Activity生命周期并更新其中Activity的可见性。if (mTargetRootTask.isTopActivityFocusable()&& !mRootWindowContainer.isTopDisplayFocusedRootTask(mTargetRootTask)) {mTargetRootTask.moveToFront("startActivityInner");}//恢复焦点任务栈顶部activitymRootWindowContainer.resumeFocusedTasksTopActivities(mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);}}mRootWindowContainer.updateUserRootTask(mStartActivity.mUserId, mTargetRootTask);// activity启动时立即更新最近的任务栈列表mSupervisor.mRecentTasks.add(startedTask);mSupervisor.handleNonResizableTaskIfNeeded(startedTask,mPreferredWindowingMode, mPreferredTaskDisplayArea, mTargetRootTask);// 如果“Activity”正在画中画中启动,请立即将mStartActivity移动到固定模式。请注意,此时mStartActivity和sourceRecord应位于同一任务栈中。if (mOptions != null && mOptions.isLaunchIntoPip()&& sourceRecord != null && sourceRecord.getTask() == mStartActivity.getTask()) {mRootWindowContainer.moveActivityToPinnedRootTask(mStartActivity,sourceRecord, "launch-into-pip");}return START_SUCCESS;
}
  1. 设置初始状态值;
  2. 计算启动task的标志位Flag,以及SingleInstance和SingleTask的处理;
  3. 通过sourceActivity计算sourceTask;
  4. 是否应将新activity插入现有任务栈;
  5. 如果需要冻结任务列表,则冻结当前最近的任务列表顺序,直到用户与当前应用程序交互或发生超。
  6. 检查是否可以复用现有的任务栈,如果可以,检查是否允许在该栈上启动Activity。
  7. 确定不需要创建新的任务栈来启动新的Activity,只需要复用当前可以用的任务栈,那么开始复用。
  8. 如果正在启动的 Activity 与当前位于顶部的 Activity 相同,那么我们需要检查它是否应该只启动一次。如果是栈顶复用的那种情况,就不需要启动Activity了。
  9. 如果不是复用,需要创建新的任务栈,则创建新的任务栈。
  10. 处理与画中画相关。

2.6.1 startActivityLocked

void startActivityLocked(ActivityRecord r, @Nullable Task topTask, boolean newTask,boolean isTaskSwitch, ActivityOptions options, @Nullable ActivityRecord sourceRecord) {//在Task开关上,查找顶部activity是否支持PiP。final ActivityRecord pipCandidate = findEnterPipOnTaskSwitchCandidate(topTask);Task rTask = r.getTask();//允许移动到前台final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();final boolean isOrhasTask = rTask == this || hasChild(rTask);// mLaunchTaskBehind任务位于任务堆栈的后面。if (!r.mLaunchTaskBehind && allowMoveToFront && (!isOrhasTask || newTask)) {// 任务中的最后一个activity已被删除,或者ActivityManagerService正在重用任务。请插入或替换。可能不在。positionChildAtTop(rTask);}Task task = null;if (!newTask && isOrhasTask && !r.shouldBeVisible()) {ActivityOptions.abort(options);return;}// 将一个新activity放在根任务的顶部,以便接下来与用户交互。如果我们不将新activity放在最前面,我们不希望将onUserLeaving回调传递给实际的最前面的activityfinal Task activityTask = r.getTask();if (task == activityTask && mChildren.indexOf(task) != (getChildCount() - 1)) {mTaskSupervisor.mUserLeaving = false;if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,"startActivity() behind front, mUserLeaving=false");}task = activityTask;// 将activity放入历史记录根任务并继续ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Adding activity %s to task %s "+ "callers: %s", r, task, new RuntimeException("here").fillInStackTrace());// 如果allowMoveToFront为false,则不需要转换动画和启动窗口,因为活动将不可见。if ((!isActivityTypeHomeOrRecents() || hasActivity()) && allowMoveToFront) {final DisplayContent dc = mDisplayContent;if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,"Prepare open transition: starting " + r);// TODO(shell-transitions): record NO_ANIMATION flag somewhere.if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {dc.prepareAppTransition(TRANSIT_NONE);mTaskSupervisor.mNoAnimActivities.add(r);} else {dc.prepareAppTransition(TRANSIT_OPEN);mTaskSupervisor.mNoAnimActivities.remove(r);}if (newTask && !r.mLaunchTaskBehind) {// 如果正在启动新任务栈,则将现有的栈顶activity标记为支持画中画,同时仅在开始的activity不被视为当前活activity顶部的覆盖(例如,非全屏或助手)时暂停// 切换到另一个任务栈时,将当前PiP候选activity标记为支持在暂停时输入PiP(如果支持)。只能设置或中的一个。enableEnterPipOnTaskSwitch(pipCandidate,null /* toFrontTask */, r, options);}boolean doShow = true;if (newTask) {// 即使此activity刚开始,我们仍需要重新设置它,以确保应用相关性将其他任务中的任何现有activity移动到其中。如果调用方已请求重置目标任务,请执行此操作。if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {resetTaskIfNeeded(r, r);doShow = topRunningNonDelayedActivityLocked(null) == r;}} else if (options != null && options.getAnimationType()== ActivityOptions.ANIM_SCENE_TRANSITION) {doShow = false;}if (r.mLaunchTaskBehind) {// 不要为mLaunchTaskBehind创建启动窗口。更重要的是,确保我们告诉WindowManager r是可见的,即使它位于根任务栈的后面。r.setVisibility(true);// 确保所有需要在根任务栈中可见的activity(也就是说,用户当前可以看到这些activity)都真实存在并更新其配置。ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);// 自应用程序转换后,继续执行此activity的应用程序转换不会通过恢复通道触发mDisplayContent.executeAppTransition();// SHOW_APP_STARTING_PREVIEW 设置为false可禁用在启动新activity时显示的预览} else if (SHOW_APP_STARTING_PREVIEW && doShow) {// 弄清楚我们是否正在从“具有与下一个相同的开始图标”。这允许窗口管理器保留它以前创建的前一个窗口(如果它仍然有)。Task baseTask = r.getTask();if (baseTask.isEmbedded()) {// 如果任务嵌入到任务片段中,则父任务中可能有一个现有的启动窗口。这允许嵌入的activity共享开始窗口,并通过转移到顶部活动来确保窗口可以具有顶部z顺序。baseTask = baseTask.getParent().asTaskFragment().getTask();}final ActivityRecord prev = baseTask.getActivity(a -> a.mStartingData != null && a.showToCurrentUser());mWmService.mStartingSurfaceController.showStartingWindow(r, prev, newTask,isTaskSwitch, sourceRecord);}} else {// 如果这是第一个activity,不要做任何花哨的动画,因为没有什么可以在上面制作动画。ActivityOptions.abort(options);}
}

2.7 resumeFocusedTasksTopActivities

//RootWindowContainer.java
boolean resumeFocusedTasksTopActivities(Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions,boolean deferPause) {if (!mTaskSupervisor.readyToResume()) {return false;}boolean result = false;if (targetRootTask != null && (targetRootTask.isTopRootTaskInDisplayArea()|| getTopDisplayFocusedRootTask() == targetRootTask)) {result = targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions,deferPause);}for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {final DisplayContent display = getChildAt(displayNdx);final boolean curResult = result;boolean[] resumedOnDisplay = new boolean[1];display.forAllRootTasks(rootTask -> {final ActivityRecord topRunningActivity = rootTask.topRunningActivity();if (!rootTask.isFocusableAndVisible() || topRunningActivity == null) {return;}if (rootTask == targetRootTask) {// 只需更新targetRootTask的结果,因为targetRootTask已经在上面恢复。我们不想再次恢复,特别是在某些情况下,如果应用程序进程停止,将导致第二次启动失败。resumedOnDisplay[0] |= curResult;return;}if (rootTask.getDisplayArea().isTopRootTask(rootTask)&& topRunningActivity.isState(RESUMED)) {// 从MoveTaskToFront操作开始任何延迟的应用程序转换,但只考虑该显示上的顶部任务和根任务rootTask.executeAppTransition(targetOptions);} else {resumedOnDisplay[0] |= topRunningActivity.makeActiveIfNeeded(target);}});result |= resumedOnDisplay[0];if (!resumedOnDisplay[0]) {// 在没有有效activities的情况下(例如,设备刚刚启动或启动器崩溃),显示器上可能没有恢复任何内容。显式请求恢复聚焦根任务中的顶级activities将确保至少启动并恢复主activities,并且不会发生递归。final Task focusedRoot = display.getFocusedRootTask();if (focusedRoot != null) {result |= focusedRoot.resumeTopActivityUncheckedLocked(target, targetOptions);} else if (targetRootTask == null) {result |= resumeHomeActivity(null /* prev */, "no-focusable-task",display.getDefaultTaskDisplayArea());}}}return result;
}

2.8.resumeTopActivityUncheckedLocked

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options,boolean deferPause) {if (mInResumeTopActivity) {// 甚至不要开始重复。return false;}boolean someActivityResumed = false;try {// 防止递归mInResumeTopActivity = true;if (isLeafTask()) {if (isFocusableAndVisible()) {someActivityResumed = resumeTopActivityInnerLocked(prev, options, deferPause);}} else {int idx = mChildren.size() - 1;while (idx >= 0) {final Task child = (Task) getChildAt(idx--);if (!child.isTopActivityFocusable()) {continue;}if (child.getVisibility(null /* starting */)!= TASK_FRAGMENT_VISIBILITY_VISIBLE) {break;}someActivityResumed |= child.resumeTopActivityUncheckedLocked(prev, options,deferPause);// Doing so in order to prevent IndexOOB since hierarchy might changes while// resuming activities, for example dismissing split-screen while starting// non-resizeable activity.if (idx >= mChildren.size()) {idx = mChildren.size() - 1;}}}......} finally {mInResumeTopActivity = false;}return someActivityResumed;
}

2.9 resumeTopActivityInnerLocked

Task.java

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options,boolean deferPause) {if (!mAtmService.isBooting() && !mAtmService.isBooted()) {//还没准备好!return false;}final ActivityRecord topActivity = topRunningActivity(true /* focusableOnly */);if (topActivity == null) {// 此任务栈中没有activities,让我们看看其他地方。return resumeNextFocusableActivityWhenRootTaskIsEmpty(prev, options);}final boolean[] resumed = new boolean[1];final TaskFragment topFragment = topActivity.getTaskFragment();resumed[0] = topFragment.resumeTopActivity(prev, options, deferPause);forAllLeafTaskFragments(f -> {if (topFragment == f) {return;}if (!f.canBeResumed(null /* starting */)) {return;}resumed[0] |= f.resumeTopActivity(prev, options, deferPause);}, true);return resumed[0];
}

2.10 resumeTopActivity

TaskFragment.java

final boolean resumeTopActivity(ActivityRecord prev, ActivityOptions options,boolean deferPause) {ActivityRecord next = topRunningActivity(true /* focusableOnly */);if (next == null || !next.canResumeByCompat()) {return false;}next.delayedResume = false;final TaskDisplayArea taskDisplayArea = getDisplayArea();// 如果顶部activity是resume状态的activity,则无需执行任何操作。if (mResumedActivity == next && next.isState(RESUMED)&& taskDisplayArea.allResumedActivitiesComplete()) {// 确保可见性在执行应用程序跳转之前得到更新。taskDisplayArea.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,false /* preserveWindows */, true /* notifyClients */);// 确保我们已经执行了任何挂起的跳转,因为此时应该没有什么可做的了。executeAppTransition(options);// 在多恢复环境中,比如在自由形式的设备中,顶部可以恢复activity,但它可能不是焦点应用。 恢复顶部activity时设置焦点应用程序if (taskDisplayArea.inMultiWindowMode() && taskDisplayArea.mDisplayContent != null&& taskDisplayArea.mDisplayContent.mFocusedApp != next) {taskDisplayArea.mDisplayContent.setFocusedApp(next);}ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Top activity "+ "resumed %s", next);return false;}// 如果我们当前正在暂停一个activity,那么在它完成之前不要做任何事情。final boolean allPausedComplete = mRootWindowContainer.allPausedActivitiesComplete();if (!allPausedComplete) {ProtoLog.v(WM_DEBUG_STATES,"resumeTopActivity: Skip resume: some activity pausing.");return false;}// 如果手机正在锁屏,并且没有恢复activity,并且顶部activity暂停,那么这就是我们想要的状态。if (mLastPausedActivity == next && shouldSleepOrShutDownActivities()) {// 确保我们已经执行了任何挂起的跳转,因为此时应该没有什么可做的了。executeAppTransition(options);ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Going to sleep and"+ " all paused");return false;}// 确保拥有此activity的用户已启动。 如果不是,我们将保持原样,因为有人应该将另一个用户的activity带到堆栈的顶部。if (!mAtmService.mAmInternal.hasStartedUserState(next.mUserId)) {Slog.w(TAG, "Skipping resume of top activity " + next+ ": user " + next.mUserId + " is stopped");return false;}// activit可能正在等待停止,但那不再适合把它放在mStoppingActivities中。mTaskSupervisor.mStoppingActivities.remove(next);if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next);mTaskSupervisor.setLaunchSource(next.info.applicationInfo.uid);ActivityRecord lastResumed = null;final Task lastFocusedRootTask = taskDisplayArea.getLastFocusedRootTask();if (lastFocusedRootTask != null && lastFocusedRootTask != getRootTaskFragment().asTask()) {// 所以,为什么我们不在这里使用 prev??? 请参阅该方法的参数注释。// prev(previous 之前的意思) 不代表最后恢复的activity。 但是,如果最后一个焦点堆栈不为空,则它会起作用。lastResumed = lastFocusedRootTask.getTopResumedActivity();}// 不是延时暂停,next暂停成功,pausing = trueboolean pausing = !deferPause && taskDisplayArea.pauseBackTasks(next);if (mResumedActivity != null) {ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Pausing %s", mResumedActivity);pausing |= startPausing(mTaskSupervisor.mUserLeaving, false /* uiSleeping */,next, "resumeTopActivity");}if (pausing) {ProtoLog.v(WM_DEBUG_STATES, "resumeTopActivity: Skip resume: need to"+ " start pausing");// 此时我们想将即将到来的activity的进程放在 LRU(Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰) 列表的顶部,// 因为我们知道我们很快就会需要它,如果它的位置恰好在结尾。if (next.attachedToProcess()) {next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,true /* activityChange */, false /* updateOomAdj */,false /* addPendingTopUid */);} else if (!next.isProcessRunning()) {// 由于启动进程是异步的,如果我们已经知道下一个activity的进程没有运行,我们可以提前启动进程以节省等待当前activity暂停的时间。final boolean isTop = this == taskDisplayArea.getFocusedRootTask();// 见3.1mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop,isTop ? HostingRecord.HOSTING_TYPE_NEXT_TOP_ACTIVITY: HostingRecord.HOSTING_TYPE_NEXT_ACTIVITY);}if (lastResumed != null) {lastResumed.setWillCloseOrEnterPip(true);}return true;} else if (mResumedActivity == next && next.isState(RESUMED)&& taskDisplayArea.allResumedActivitiesComplete()) {// 如果下一个activity不必等待暂停完成,那么当我们在上面暂停返回堆栈时,activity可能会恢复。 所以,除了:确保我们已经执行了所有待处理的跳转之外,别无他法,因为此时应该没有什么可做的了。executeAppTransition(options);ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Top activity resumed "+ "(dontWaitForPause) %s", next);return true;}// 如果最近的activity是 noHistory 但只是停止而不是停止+完成因为设备进入睡眠状态,我们需要确保完成它,因为我们正在最顶层制作一个新activity 。
if (shouldSleepActivities()) {// 只有和next是同一个显示屏的noHistory的Activity都finishmTaskSupervisor.finishNoHistoryActivitiesIfNeeded(next);}if (prev != null && prev != next && next.nowVisible) {// 下一个activity已经可见,所以现在隐藏上一个activity的窗口,以便我们尽快显示新activity。 // 我们只有在前一个正在完成时才这样做,这意味着它在正在恢复的那个之上,所以快速隐藏它是好的。 // 否则,我们想要执行允许显示恢复activity的正常路线,以便我们可以根据是否发现新activity是全屏来决定是否应该隐藏之前的activity。if (prev.finishing) {prev.setVisibility(false);if (DEBUG_SWITCH) {Slog.v(TAG_SWITCH, "Not waiting for visible to hide: " + prev+ ", nowVisible=" + next.nowVisible);}} else {if (DEBUG_SWITCH) {Slog.v(TAG_SWITCH, "Previous already visible but still waiting to hide: " + prev+ ", nowVisible=" + next.nowVisible);}}}
......
//见2.11
mTaskSupervisor.startSpecificActivity(next, true, true);
......return true;
}

2.10.1 pauseBackTaskspauseBackTasks

pauseBackTasks:暂停所有根任务栈或后台根任务栈中的所有activity。这是在恢复activity动之前完成的,以确保以前活动的activity在不再可见的根任务中或在固定窗口模式中暂停。

这不会暂停可见根任务中的activity,因此如果在同一根任务中启动activity,那么我们应该明确暂停该根任务的顶部activity

boolean pauseBackTasks(ActivityRecord resuming) {final int[] someActivityPaused = {0};forAllLeafTasks(leafTask -> {// Check if the direct child resumed activity in the leaf task needed to be paused if// the leaf task is not a leaf task fragment.if (!leafTask.isLeafTaskFragment()) {final ActivityRecord top = topRunningActivity();final ActivityRecord resumedActivity = leafTask.getResumedActivity();if (resumedActivity != null && top.getTaskFragment() != leafTask) {// Pausing the resumed activity because it is occluded by other task fragment.if (leafTask.startPausing(false /* uiSleeping*/, resuming, "pauseBackTasks")) {someActivityPaused[0]++;}}}leafTask.forAllLeafTaskFragments((taskFrag) -> {final ActivityRecord resumedActivity = taskFrag.getResumedActivity();if (resumedActivity != null && !taskFrag.canBeResumed(resuming)) {if (taskFrag.startPausing(false /* uiSleeping*/, resuming, "pauseBackTasks")) {someActivityPaused[0]++;}}}, true /* traverseTopToBottom */);}, true /* traverseTopToBottom */);return someActivityPaused[0] > 0;
}

2.10.2 startPausing

TaskFragment.java

startPausing:开始暂停当前处于焦点(活动)状态下的Activity。 如果已经有Activity被暂停或没有焦点,则调用此方法是错误的。

boolean startPausing(boolean userLeaving, boolean uiSleeping, ActivityRecord resuming,String reason) {if (!hasDirectChildActivities()) {return false;}ProtoLog.d(WM_DEBUG_STATES, "startPausing: taskFrag =%s " + "mResumedActivity=%s", this,mResumedActivity);if (mPausingActivity != null) {Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity+ " state=" + mPausingActivity.getState());if (!shouldSleepActivities()) {// 避免在检查睡眠和睡眠期间完全暂停之间进行递归。 因为activity会在resume后立即暂停,所以让pause按照clients暂停的activity顺序来完成即可。completePause(false, resuming);}}ActivityRecord prev = mResumedActivity;if (prev == null) {if (resuming == null) {Slog.wtf(TAG, "Trying to pause when nothing is resumed");mRootWindowContainer.resumeFocusedTasksTopActivities();}return false;}if (prev == resuming) {Slog.wtf(TAG, "Trying to pause activity that is in process of being resumed");return false;}ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSING: %s", prev);mPausingActivity = prev;mLastPausedActivity = prev;if (!prev.finishing && prev.isNoHistory()&& !mTaskSupervisor.mNoHistoryActivities.contains(prev)) {mTaskSupervisor.mNoHistoryActivities.add(prev);}prev.setState(PAUSING, "startPausingLocked");prev.getTask().touchActiveTime();mAtmService.updateCpuStats();boolean pauseImmediately = false;boolean shouldAutoPip = false;if (resuming != null) {// 我们不想在启动半透明activity时触发自动画中画。final boolean resumingOccludesParent = resuming.occludesParent();// Resuming the new resume activity only if the previous activity can't go into Pip// since we want to give Pip activities a chance to enter Pip before resuming the// next activity.// 仅当前一个activity无法进入画中画时才恢复新的恢复activity,因为我们想让画中画activity有机会在恢复下一个activity之前进入画中画。final boolean lastResumedCanPip = prev.checkEnterPictureInPictureState("shouldAutoPipWhilePausing", userLeaving);if (userLeaving && resumingOccludesParent && lastResumedCanPip&& prev.pictureInPictureArgs.isAutoEnterEnabled()) {shouldAutoPip = true;} else if (!lastResumedCanPip) {// 如果设置了 RESUME_WHILE_PAUSING 标志,则继续安排上一个要暂停的activity 。pauseImmediately = (resuming.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;} else {//先前的activity可能仍会进入画中画,即使它不允许自动画中画。}}if (prev.attachedToProcess()) {if (shouldAutoPip) {boolean didAutoPip = mAtmService.enterPictureInPictureMode(prev, prev.pictureInPictureArgs, false /* fromClient */);ProtoLog.d(WM_DEBUG_STATES, "Auto-PIP allowed, entering PIP mode "+ "directly: %s, didAutoPip: %b", prev, didAutoPip);} else {schedulePauseActivity(prev, userLeaving, pauseImmediately,false /* autoEnteringPip */, reason);}} else {mPausingActivity = null;mLastPausedActivity = null;mTaskSupervisor.mNoHistoryActivities.remove(prev);}// 如果我们不打算休眠,我们要确保设备是// 唤醒直到下一个activity开始。if (!uiSleeping && !mAtmService.isSleepingOrShuttingDownLocked()) {mTaskSupervisor.acquireLaunchWakelock();}// 如果已经进入画中画模式,不需要一直暂停。if (mPausingActivity != null) {// 让窗口管理器暂停其键调度,直到新activit开始。 如果我们只是因为屏幕关闭和 UI 正在休眠而暂停活动,请不要中断按键调度; 相同的activity将在唤醒时再次拾取它。if (!uiSleeping) {prev.pauseKeyDispatchingLocked();} else {ProtoLog.v(WM_DEBUG_STATES, "Key dispatch not paused for screen off");}if (pauseImmediately) {// 如果调用者说他们不想等待暂停,那么现在就完成暂停。completePause(false, resuming);return false;} else {prev.schedulePauseTimeout();// 睡眠时所有activities都会停止,不需要等待暂停。if (!uiSleeping) {// 取消准备就绪,因为我们现在需要等到暂停完成。mTransitionController.setReady(this, false /* ready */);}return true;}} else {// 这个activity 要么没有安排暂停,要么进入了画中画模式,所以现在就把它当作暂停。ProtoLog.v(WM_DEBUG_STATES, "Activity not running or entered PiP, resuming next.");if (resuming == null) {mRootWindowContainer.resumeFocusedTasksTopActivities();}return false;}
}
2.10.2.1 schedulePauseActivity

TaskFragment.java

##EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev),prev.shortComponentName, "userLeaving=" + userLeaving, reason);// 这里就把暂停的消息发送到Activity里面去了mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),prev.token, PauseActivityItem.obtain(prev.finishing, userLeaving,prev.configChangeFlags, pauseImmediately, autoEnteringPip));} catch (Exception e) {// Ignore exception, if process died other code will cleanup.Slog.w(TAG, "Exception thrown during pause", e);mPausingActivity = null;mLastPausedActivity = null;mTaskSupervisor.mNoHistoryActivities.remove(prev);}
}

在启动Activity之前,将App进程中的Activity暂停。

2.11 startSpecificActivity

ActivityTaskSupervisor.java

void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {// Is this activity's application already running?final WindowProcessController wpc =mService.getProcessController(r.processName, r.info.applicationInfo.uid);boolean knownToBeDead = false;if (wpc != null && wpc.hasThread()) {try {realStartActivityLocked(r, wpc, andResume, checkConfig);return;} catch (RemoteException e) {Slog.w(TAG, "Exception when starting activity "+ r.intent.getComponent().flattenToShortString(), e);}// If a dead object exception was thrown -- fall through to// restart the application.knownToBeDead = true;// Remove the process record so it won't be considered as alive.mService.mProcessNames.remove(wpc.mName, wpc.mUid);mService.mProcessMap.remove(wpc.getPid());}r.notifyUnknownVisibilityLaunchedForKeyguardTransition();final boolean isTop = andResume && r.isTopRunningActivity();mService.startProcessAsync(r, knownToBeDead, isTop,isTop ? HostingRecord.HOSTING_TYPE_TOP_ACTIVITY: HostingRecord.HOSTING_TYPE_ACTIVITY);
}

这个方法做的是,如果不需要创建新的进程来启动Activity那么调用realStartActivityLocked函数启动Activity,如果需要创建新进程启动Activity,那么调用startProcessAsync创建新的进程。

3 zygote fork新进程 调用ActivityThread.main()

Zygote进程收到请求后,fork新进程并调用ActivityThread的main初始化进程。
在这里插入图片描述

3.1 startProcessAsync

ActivityTaskManagerService.java

void startProcessAsync(ActivityRecord activity, boolean knownToBeDead, boolean isTop,String hostingType) {try {if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "dispatchingStartProcess:"+ activity.processName);}// 发布消息以启动进程,以避免在ATMS锁保持的情况下调用AMS可能出现死锁。final Message m = PooledLambda.obtainMessage(ActivityManagerInternal::startProcess,mAmInternal, activity.processName, activity.info.applicationInfo, knownToBeDead,isTop, hostingType, activity.intent.getComponent());mH.sendMessage(m);} finally {Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);}
}

3.2 startProcess

//ActivityManagerService.java
public void startProcess(String processName, ApplicationInfo info, boolean knownToBeDead,boolean isTop, String hostingType, ComponentName hostingName) {try {if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "startProcess:"+ processName);}synchronized (ActivityManagerService.this) {// If the process is known as top app, set a hint so when the process is// started, the top priority can be applied immediately to avoid cpu being// preempted by other processes before attaching the process of top app.// 如果进程被称为top app,请设置一个提示,以便在进程启动时,可以立即应用最高优先级,以避免在附加top app的进程之前,cpu被其他进程抢占。startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */,new HostingRecord(hostingType, hostingName, isTop),ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE, false /* allowWhileBooting */,false /* isolated */);}} finally {Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);}
}@GuardedBy("this")
final ProcessRecord startProcessLocked(String processName,ApplicationInfo info, boolean knownToBeDead, int intentFlags,HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting,boolean isolated) {return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */,false /* isSdkSandbox */, 0 /* sdkSandboxClientAppUid */,null /* sdkSandboxClientAppPackage */,null /* ABI override */, null /* entryPoint */,null /* entryPointArgs */, null /* crashHandler */);
}//ProcessList.java
ProcessRecord startProcessLocked(String processName, ApplicationInfo info,boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord,int zygotePolicyFlags, boolean allowWhileBooting, boolean isolated, int isolatedUid,boolean isSdkSandbox, int sdkSandboxUid, String sdkSandboxClientAppPackage,String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {long startTime = SystemClock.uptimeMillis();ProcessRecord app;if (!isolated) {app = getProcessRecordLocked(processName, info.uid);checkSlow(startTime, "startProcess: after getProcessRecord");if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {// If we are in the background, then check to see if this process// is bad.  If so, we will just silently fail.// 如果我们在后台,那么检查这个程序是否出错。如果是这样,我们只会默默地失败。if (mService.mAppErrors.isBadProcess(processName, info.uid)) {if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid+ "/" + processName);return null;}} else {// When the user is explicitly starting a process, then clear its// crash count so that we won't make it bad until they see at// least one crash dialog again, and make the process good again// if it had been bad.// 当用户明确启动一个进程时,请清除其崩溃计数,以便在他们再次看到至少一个崩溃对话框之前,我们不会使其变坏,如果进程变坏,则使其变好if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid+ "/" + processName);mService.mAppErrors.resetProcessCrashTime(processName, info.uid);// 是坏了的进程if (mService.mAppErrors.isBadProcess(processName, info.uid)) {EventLog.writeEvent(EventLogTags.AM_PROC_GOOD,UserHandle.getUserId(info.uid), info.uid,info.processName);// 从mBadProcesses中清除坏的进程mService.mAppErrors.clearBadProcess(processName, info.uid);if (app != null) {app.mErrorState.setBad(false);}}}} else {// If this is an isolated process, it can't re-use an existing process.// 如果这是一个独立的进程,它就不能重用现有的过程。app = null;}// We don't have  to do anything more if:// (1) There is an existing application record; and// (2) The caller doesn't think it is dead, OR there is no thread//     object attached to it so we know it couldn't have crashed; and// (3) There is a pid assigned to it, so it is either starting or//     already running.//如果出现下面情况,我们不必再做任何事情://(1) 这是一个已经存在的应用记录;//(2) 调用者不认为它已经死了,或者没有线程对象连接到它,所以我们知道它不会崩溃;//(3) 有一个pid分配给它,所以它要么正在启动,要么已经在运行。if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "startProcess: name=" + processName+ " app=" + app + " knownToBeDead=" + knownToBeDead+ " thread=" + (app != null ? app.getThread() : null)+ " pid=" + (app != null ? app.getPid() : -1));ProcessRecord predecessor = null;if (app != null && app.getPid() > 0) {if ((!knownToBeDead && !app.isKilled()) || app.getThread() == null) {// We already have the app running, or are waiting for it to// come up (we have a pid but not yet its thread), so keep it.//我们已经在运行应用程序,或者正在等待它的出现(我们有一个pid,但还没有它的线程),所以保持它。if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App already running: " + app);// If this is a new package in the process, add the package to the list// 如果这是进程中的新包,请将该包添加到列表中app.addPackage(info.packageName, info.longVersionCode, mService.mProcessStats);checkSlow(startTime, "startProcess: done, added package to proc");return app;}// An application record is attached to a previous process,// clean it up now.// 应用程序已附加到上一个进程,请立即清理。if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App died: " + app);checkSlow(startTime, "startProcess: bad proc running, killing");ProcessList.killProcessGroup(app.uid, app.getPid());checkSlow(startTime, "startProcess: done killing old proc");if (!app.isKilled()) {// Throw a wtf if it's not killed// 如果它没有被杀死,扔一个wtfSlog.wtf(TAG_PROCESSES, app.toString() + " is attached to a previous process");} else {Slog.w(TAG_PROCESSES, app.toString() + " is attached to a previous process");}// We are not going to re-use the ProcessRecord, as we haven't dealt with the cleanup// routine of it yet, but we'd set it as the predecessor of the new process.//我们不会重复使用ProcessRecord,因为我们还没有处理掉它,但我们将它设置为新程序的前身。predecessor = app;app = null;} else if (!isolated) {// This app may have been removed from process name maps, probably because we killed it// and did the cleanup before the actual death notification. Check the dying processes.// 此应用程序可能已从进程名称映射中删除,可能是因为我们在实际死亡通知之前将其删除并进行了清理。检查死亡进程。predecessor = mDyingProcesses.get(processName, info.uid);if (predecessor != null) {if (app != null) {app.mPredecessor = predecessor;predecessor.mSuccessor = app;}Slog.w(TAG_PROCESSES, predecessor.toString() + " is attached to a previous process "+ predecessor.getDyingPid());}}if (app == null) {checkSlow(startTime, "startProcess: creating new process record");app = newProcessRecordLocked(info, processName, isolated, isolatedUid, isSdkSandbox,sdkSandboxUid, sdkSandboxClientAppPackage, hostingRecord);if (app == null) {Slog.w(TAG, "Failed making new process record for "+ processName + "/" + info.uid + " isolated=" + isolated);return null;}app.mErrorState.setCrashHandler(crashHandler);app.setIsolatedEntryPoint(entryPoint);app.setIsolatedEntryPointArgs(entryPointArgs);if (predecessor != null) {app.mPredecessor = predecessor;predecessor.mSuccessor = app;}checkSlow(startTime, "startProcess: done creating new process record");} else {// If this is a new package in the process, add the package to the list// 如果这是进程中的新包,请将该包添加到列表中app.addPackage(info.packageName, info.longVersionCode, mService.mProcessStats);checkSlow(startTime, "startProcess: added package to existing proc");}// If the system is not ready yet, then hold off on starting this// process until it is.//如果系统还没有准备好,请在准备好之前不要启动此进程。if (!mService.mProcessesReady&& !mService.isAllowedWhileBooting(info)&& !allowWhileBooting) {if (!mService.mProcessesOnHold.contains(app)) {mService.mProcessesOnHold.add(app);}if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES,"System not ready, putting on hold: " + app);checkSlow(startTime, "startProcess: returning with proc on hold");return app;}checkSlow(startTime, "startProcess: stepping in to startProcess");final boolean success =startProcessLocked(app, hostingRecord, zygotePolicyFlags, abiOverride);checkSlow(startTime, "startProcess: done starting proc!");return success ? app : null;
}

3.2.1 getProcessRecordLocked

ProcessRecord getProcessRecordLocked(String processName, int uid) {if (uid == SYSTEM_UID) {// The system gets to run in any process.  If there are multiple// processes with the same uid, just pick the first (this// should never happen).// 系统可以获取正在运行中的任何进程。如果有多个进程具有相同的uid,只需选择第一个(这不应该发生)SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(processName);if (procs == null) return null;final int procCount = procs.size();for (int i = 0; i < procCount; i++) {final int procUid = procs.keyAt(i);if (!UserHandle.isCore(procUid) || !UserHandle.isSameUser(procUid, uid)) {// Don't use an app process or different user process for system component.// 不要为系统组件使用应用程序进程或其他用户进程。continue;}return procs.valueAt(i);}}return mProcessNames.get(processName, uid);
}

3.2.2 startProcessLocked

@GuardedBy("mService")
boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,int zygotePolicyFlags, String abiOverride) {return startProcessLocked(app, hostingRecord, zygotePolicyFlags,false /* disableHiddenApiChecks */, false /* disableTestApiChecks */,abiOverride);
}boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,int zygotePolicyFlags, boolean disableHiddenApiChecks, boolean disableTestApiChecks,String abiOverride) {......// 启动进程。它要么成功并返回包含新进程的PID的结果,要么抛出RuntimeException。final String entryPoint = "android.app.ActivityThread";return startProcessLocked(hostingRecord, entryPoint, app, uid, gids,runtimeFlags, zygotePolicyFlags, mountExternal, seInfo, requiredAbi,instructionSet, invokeWith, startUptime, startElapsedTime);} catch (RuntimeException e) {Slog.e(ActivityManagerService.TAG, "Failure starting process " + app.processName, e);// 尝试启动此进程时出现了严重问题;// 一种常见的情况是包由于活动升级而冻结。// 要恢复,请清理与启动此进程相关的所有活动记账。(当包最初通过KILL_APPLICATION_MSG冻结时,我们已经调用了一次该方法,因此再次使用它不会有任何问题。mService.forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid),false, false, true, false, false, app.userId, "start failure");return false;}
}boolean startProcessLocked(HostingRecord hostingRecord, String entryPoint, ProcessRecord app,int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags, int mountExternal,String seInfo, String requiredAbi, String instructionSet, String invokeWith,long startUptime, long startElapsedTime) {
......// 一般都是异步启动if (mService.mConstants.FLAG_PROCESS_START_ASYNC) {if (DEBUG_PROCESSES) Slog.i(TAG_PROCESSES,"Posting procStart msg for " + app.toShortString());mService.mProcStartHandler.post(() -> handleProcessStart(app, entryPoint, gids, runtimeFlags, zygotePolicyFlags, mountExternal,requiredAbi, instructionSet, invokeWith, startSeq));return true;} else {try {final Process.ProcessStartResult startResult = startProcess(hostingRecord,entryPoint, app,uid, gids, runtimeFlags, zygotePolicyFlags, mountExternal, seInfo,requiredAbi, instructionSet, invokeWith, startUptime);handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper,startSeq, false);} catch (RuntimeException e) {Slog.e(ActivityManagerService.TAG, "Failure starting process "+ app.processName, e);app.setPendingStart(false);mService.forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid),false, false, true, false, false, app.userId, "start failure");}return app.getPid() > 0;}
}

3.3 handleProcessStart

ProcessList.java

从ProcStartHandler启动给定进程的主处理程序。注意:此函数不会故意保持全局AM锁

private void handleProcessStart(final ProcessRecord app, final String entryPoint,final int[] gids, final int runtimeFlags, int zygotePolicyFlags,final int mountExternal, final String requiredAbi, final String instructionSet,final String invokeWith, final long startSeq) {final Runnable startRunnable = () -> {try {final Process.ProcessStartResult startResult = startProcess(app.getHostingRecord(),entryPoint, app, app.getStartUid(), gids, runtimeFlags, zygotePolicyFlags,mountExternal, app.getSeInfo(), requiredAbi, instructionSet, invokeWith,app.getStartTime());synchronized (mService) {handleProcessStartedLocked(app, startResult, startSeq);}} catch (RuntimeException e) {synchronized (mService) {Slog.e(ActivityManagerService.TAG, "Failure starting process "+ app.processName, e);mPendingStarts.remove(startSeq);app.setPendingStart(false);mService.forceStopPackageLocked(app.info.packageName,UserHandle.getAppId(app.uid),false, false, true, false, false, app.userId, "start failure");}}};// 使用本地引用,因为这里没有使用锁final ProcessRecord predecessor = app.mPredecessor;if (predecessor != null && predecessor.getDyingPid() > 0) {handleProcessStartWithPredecessor(predecessor, startRunnable);} else {// 真正启动流程。startRunnable.run();}
}

3.4 startProcess

ProcessList.java

private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint,ProcessRecord app, int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags,int mountExternal, String seInfo, String requiredAbi, String instructionSet,String invokeWith, long startTime) {......if (hostingRecord.usesWebviewZygote()) {startResult = startWebView(entryPoint,app.processName, uid, uid, gids, runtimeFlags, mountExternal,app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,app.info.dataDir, null, app.info.packageName,app.getDisabledCompatChanges(),new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()});} else if (hostingRecord.usesAppZygote()) {final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app);// 我们不能隔离应用程序数据和存储数据,因为父zygote已经做到了这一点。startResult = appZygote.getProcess().start(entryPoint,app.processName, uid, uid, gids, runtimeFlags, mountExternal,app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,app.info.dataDir, null, app.info.packageName,/*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp,app.getDisabledCompatChanges(), pkgDataInfoMap, allowlistedAppDataInfoMap,false, false,new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()});} else {regularZygote = true;startResult = Process.start(entryPoint,app.processName, uid, uid, gids, runtimeFlags, mountExternal,app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags,isTopApp, app.getDisabledCompatChanges(), pkgDataInfoMap,allowlistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs,new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()});}......checkSlow(startTime, "startProcess: returned from zygote!");return startResult;} finally {Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);}
}

3.5 start

ZygoteProcess.java

public final Process.ProcessStartResult start(@NonNull final String processClass,final String niceName,int uid, int gid, @Nullable int[] gids,int runtimeFlags, int mountExternal,int targetSdkVersion,@Nullable String seInfo,@NonNull String abi,@Nullable String instructionSet,@Nullable String appDataDir,@Nullable String invokeWith,@Nullable String packageName,int zygotePolicyFlags,boolean isTopApp,@Nullable long[] disabledCompatChanges,@Nullable Map<String, Pair<String, Long>>pkgDataInfoMap,@Nullable Map<String, Pair<String, Long>>allowlistedDataInfoList,boolean bindMountAppsData,boolean bindMountAppStorageDirs,@Nullable String[] zygoteArgs) {// TODO (chriswailes): Is there a better place to check this value?if (fetchUsapPoolEnabledPropWithMinInterval()) {informZygotesOfUsapPoolStatus();}try {return startViaZygote(processClass, niceName, uid, gid, gids,runtimeFlags, mountExternal, targetSdkVersion, seInfo,abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges,pkgDataInfoMap, allowlistedDataInfoList, bindMountAppsData,bindMountAppStorageDirs, zygoteArgs);} catch (ZygoteStartFailedEx ex) {Log.e(LOG_TAG,"Starting VM process through Zygote failed");throw new RuntimeException("Starting VM process through Zygote failed", ex);}
}private Process.ProcessStartResult startViaZygote(@NonNull final String processClass,@Nullable final String niceName,final int uid, final int gid,@Nullable final int[] gids,int runtimeFlags, int mountExternal,int targetSdkVersion,@Nullable String seInfo,@NonNull String abi,@Nullable String instructionSet,@Nullable String appDataDir,@Nullable String invokeWith,boolean startChildZygote,@Nullable String packageName,int zygotePolicyFlags,boolean isTopApp,@Nullable long[] disabledCompatChanges,@Nullable Map<String, Pair<String, Long>>pkgDataInfoMap,@Nullable Map<String, Pair<String, Long>>allowlistedDataInfoList,boolean bindMountAppsData,boolean bindMountAppStorageDirs,@Nullable String[] extraArgs)throws ZygoteStartFailedEx {......synchronized(mLock) {// 如果应用程序不使用系统图形驱动程序,则无法使用USAP池。如果请求该驱动程序,请使用Zygote应用程序启动路径。return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),zygotePolicyFlags,argsForZygote);}
}

3.6 openZygoteSocketIfNeeded

尝试使用兼容ABI打开Zygote进程的会话套接字(如果尚未打开)。如果兼容的会话套接字已打开,则返回该会话套接字。此功能可能会阻塞,可能必须尝试连接到多个Zygotes才能找到合适的Zygote。要求保持mLock。

private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {try {attemptConnectionToPrimaryZygote();if (primaryZygoteState.matches(abi)) {return primaryZygoteState;}if (mZygoteSecondarySocketAddress != null) {// The primary zygote didn't match. Try the secondary.attemptConnectionToSecondaryZygote();if (secondaryZygoteState.matches(abi)) {return secondaryZygoteState;}}} catch (IOException ioe) {throw new ZygoteStartFailedEx("Error connecting to zygote", ioe);}throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
}

3.7 attemptZygoteSendArgsAndGetResult

private Process.ProcessStartResult zygoteSendArgsAndGetResult(ZygoteState zygoteState, int zygotePolicyFlags, @NonNull ArrayList<String> args)throws ZygoteStartFailedEx {......return attemptZygoteSendArgsAndGetResult(zygoteState, msgStr);
}private Process.ProcessStartResult attemptZygoteSendArgsAndGetResult(ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx {try {final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;zygoteWriter.write(msgStr);zygoteWriter.flush();// Always read the entire result from the input stream to avoid leaving// bytes in the stream for future process starts to accidentally stumble// upon.// 始终从输入流中读取整个结果,以避免在流中留下字节,以便将来进程开始时意外发现。Process.ProcessStartResult result = new Process.ProcessStartResult();result.pid = zygoteInputStream.readInt();result.usingWrapper = zygoteInputStream.readBoolean();if (result.pid < 0) {throw new ZygoteStartFailedEx("fork() failed");}return result;} catch (IOException ex) {zygoteState.close();Log.e(LOG_TAG, "IO Exception while communicating with Zygote - "+ ex.toString());throw new ZygoteStartFailedEx(ex);}
}

消息会发送到下面的runSelectLopp方法中,处理后,以流的方式返回结果。

3.8 runSelectLoop

ZygoteServer.java

运行zygote进程的选择循环。在新连接发生时接受新连接,并每次从一个派生请求值的连接中读取命令。

Runnable runSelectLoop(String abiList) {ArrayList<FileDescriptor> socketFDs = new ArrayList<>();ArrayList<ZygoteConnection> peers = new ArrayList<>();socketFDs.add(mZygoteSocket.getFileDescriptor());peers.add(null);mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;while (true) {......try {ZygoteConnection connection = peers.get(pollIndex);boolean multipleForksOK = !isUsapPoolEnabled()&& ZygoteHooks.isIndefiniteThreadSuspensionSafe();final Runnable command =connection.processCommand(this, multipleForksOK);// TODO (chriswailes): Is this extra check necessary?if (mIsForkChild) {// We're in the child. We should always have a command to run at// this stage if processCommand hasn't called "exec".if (command == null) {throw new IllegalStateException("command == null");}return command;}
......
}
Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) {ZygoteArguments parsedArgs;......if (parsedArgs.mInvokeWith != null || parsedArgs.mStartChildZygote|| !multipleOK || peer.getUid() != Process.SYSTEM_UID) {// Continue using old code for now. TODO: Handle these cases in the other path.pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid,parsedArgs.mGids, parsedArgs.mRuntimeFlags, rlimits,parsedArgs.mMountExternal, parsedArgs.mSeInfo, parsedArgs.mNiceName,fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,parsedArgs.mInstructionSet, parsedArgs.mAppDataDir,parsedArgs.mIsTopApp, parsedArgs.mPkgDataInfoList,parsedArgs.mAllowlistedDataInfoList, parsedArgs.mBindMountAppDataDirs,parsedArgs.mBindMountAppStorageDirs);try {if (pid == 0) {// in childzygoteServer.setForkChild();zygoteServer.closeServerSocket();IoUtils.closeQuietly(serverPipeFd);serverPipeFd = null;return handleChildProc(parsedArgs, childPipeFd,parsedArgs.mStartChildZygote);} else {// In the parent. A pid < 0 indicates a failure and will be handled in// handleParentProc.IoUtils.closeQuietly(childPipeFd);childPipeFd = null;handleParentProc(pid, serverPipeFd);return null;}} finally {IoUtils.closeQuietly(childPipeFd);IoUtils.closeQuietly(serverPipeFd);}} else {ZygoteHooks.preFork();Runnable result = Zygote.forkSimpleApps(argBuffer,zygoteServer.getZygoteSocketFileDescriptor(),peer.getUid(), Zygote.minChildUid(peer), parsedArgs.mNiceName);if (result == null) {// parent; we finished some number of forks. Result is Boolean.// We already did the equivalent of handleParentProc().ZygoteHooks.postForkCommon();// argBuffer contains a command not understood by forksimpleApps.continue;} else {// child; result is a Runnable.zygoteServer.setForkChild();Zygote.setAppProcessName(parsedArgs, TAG);  // ??? Necessary?return result;}}}}......
}
private Runnable handleChildProc(ZygoteArguments parsedArgs,FileDescriptor pipeFd, boolean isZygote) {......Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);if (parsedArgs.mInvokeWith != null) {WrapperInit.execApplication(parsedArgs.mInvokeWith,parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,VMRuntime.getCurrentInstructionSet(),pipeFd, parsedArgs.mRemainingArgs);// Should not get here.throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");} else {if (!isZygote) {return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,parsedArgs.mDisabledCompatChanges,parsedArgs.mRemainingArgs, null /* classLoader */);} else {return ZygoteInit.childZygoteInit(parsedArgs.mRemainingArgs  /* classLoader */);}}
}
static Runnable childZygoteInit(String[] argv) {RuntimeInit.Arguments args = new RuntimeInit.Arguments(argv);return RuntimeInit.findStaticMain(args.startClass, args.startArgs, /* classLoader= */null);
}
protected static Runnable findStaticMain(String className, String[] argv,ClassLoader classLoader) {Class<?> cl;try {cl = Class.forName(className, true, classLoader);} catch (ClassNotFoundException ex) {throw new RuntimeException("Missing class when invoking static main " + className,ex);}Method m;try {//反射调用 ActivityThread.java的main函数m = cl.getMethod("main", new Class[] { String[].class });} catch (NoSuchMethodException ex) {throw new RuntimeException("Missing static main on " + className, ex);} catch (SecurityException ex) {throw new RuntimeException("Problem getting static main on " + className, ex);}int modifiers = m.getModifiers();if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {throw new RuntimeException("Main method is not public and static on " + className);}/** This throw gets caught in ZygoteInit.main(), which responds* by invoking the exception's run() method. This arrangement* clears up all the stack frames that were required in setting* up the process.*/return new MethodAndArgsCaller(m, argv);
}

4 attachApplication

新进程启动后,会发送attachApplication给ActivityManagerService,告诉它新进程已经启动成功了。

在这里插入图片描述

4.1 attach

//ActivityThread.java
private void attach(boolean system, long startSeq) {sCurrentActivityThread = this;mConfigurationController = new ConfigurationController(this);mSystemThread = system;if (!system) {android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",UserHandle.myUserId());RuntimeInit.setApplicationObject(mAppThread.asBinder());final IActivityManager mgr = ActivityManager.getService();try {mgr.attachApplication(mAppThread, startSeq);} catch (RemoteException ex) {throw ex.rethrowFromSystemServer();}......} else {// Don't set application object here -- if the system crashes,// we can't display an alert, we just want to die die die.android.ddm.DdmHandleAppName.setAppName("system_process",UserHandle.myUserId());try {mInstrumentation = new Instrumentation();mInstrumentation.basicInit(this);ContextImpl context = ContextImpl.createAppContext(this, getSystemContext().mPackageInfo);mInitialApplication = context.mPackageInfo.makeApplicationInner(true, null);mInitialApplication.onCreate();} catch (Exception e) {throw new RuntimeException("Unable to instantiate Application():" + e.toString(), e);}}......ViewRootImpl.addConfigCallback(configChangedCallback);
}
//ActivityManagerService.java
public final void attachApplication(IApplicationThread thread, long startSeq) {if (thread == null) {throw new SecurityException("Invalid application interface");}synchronized (this) {int callingPid = Binder.getCallingPid();final int callingUid = Binder.getCallingUid();final long origId = Binder.clearCallingIdentity();attachApplicationLocked(thread, callingPid, callingUid, startSeq);Binder.restoreCallingIdentity(origId);}
}
//ActivityManagerService.java
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,int pid, int callingUid, long startSeq) {......
synchronized (mProcLock) {app.mState.setCurAdj(ProcessList.INVALID_ADJ);app.mState.setSetAdj(ProcessList.INVALID_ADJ);app.mState.setVerifiedAdj(ProcessList.INVALID_ADJ);mOomAdjuster.setAttachingSchedGroupLSP(app);app.mState.setForcingToImportant(null);updateProcessForegroundLocked(app, false, 0, false);app.mState.setHasShownUi(false);app.mState.setCached(false);app.setDebugging(false);app.setKilledByAm(false);app.setKilled(false);// 我们谨慎地使用PackageManager用于过滤的相同状态,因为我们使用此标志来决定在稍后解锁用户时是否需要安装提供程序app.setUnlocked(StorageManager.isUserKeyUnlocked(app.userId));}//移除进程启动超时的消息mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);......final ProviderInfoList providerList = ProviderInfoList.fromList(providers);if (app.getIsolatedEntryPoint() != null) {//这是一个孤立的进程,它应该只调用入口点,而不是绑定到应用程序。thread.runIsolatedEntryPoint(app.getIsolatedEntryPoint(), app.getIsolatedEntryPointArgs());} else if (instr2 != null) {thread.bindApplication(processName, appInfo,app.sdkSandboxClientAppVolumeUuid, app.sdkSandboxClientAppPackage,providerList,instr2.mClass,profilerInfo, instr2.mArguments,instr2.mWatcher,instr2.mUiAutomationConnection, testMode,mBinderTransactionTrackingEnabled, enableTrackAllocation,isRestrictedBackupMode || !normalMode, app.isPersistent(),new Configuration(app.getWindowProcessController().getConfiguration()),app.getCompat(), getCommonServicesLocked(app.isolated),mCoreSettingsObserver.getCoreSettingsLocked(),buildSerial, autofillOptions, contentCaptureOptions,app.getDisabledCompatChanges(), serializedSystemFontMap,app.getStartElapsedTime(), app.getStartUptime());} else {thread.bindApplication(processName, appInfo,app.sdkSandboxClientAppVolumeUuid, app.sdkSandboxClientAppPackage,providerList, null, profilerInfo, null, null, null, testMode,mBinderTransactionTrackingEnabled, enableTrackAllocation,isRestrictedBackupMode || !normalMode, app.isPersistent(),new Configuration(app.getWindowProcessController().getConfiguration()),app.getCompat(), getCommonServicesLocked(app.isolated),mCoreSettingsObserver.getCoreSettingsLocked(),buildSerial, autofillOptions, contentCaptureOptions,app.getDisabledCompatChanges(), serializedSystemFontMap,app.getStartElapsedTime(), app.getStartUptime());}......// See if the top visible activity is waiting to run in this process...if (normalMode) {try {    //见 4.7didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());} catch (Exception e) {Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);badApp = true;}}
......return true;
}
//ApplicationThread
public final void bindApplication(String processName, ApplicationInfo appInfo,String sdkSandboxClientAppVolumeUuid, String sdkSandboxClientAppPackage,ProviderInfoList providerList, ComponentName instrumentationName,ProfilerInfo profilerInfo, Bundle instrumentationArgs,IInstrumentationWatcher instrumentationWatcher,IUiAutomationConnection instrumentationUiConnection, int debugMode,boolean enableBinderTracking, boolean trackAllocation,boolean isRestrictedBackupMode, boolean persistent, Configuration config,CompatibilityInfo compatInfo, Map services, Bundle coreSettings,String buildSerial, AutofillOptions autofillOptions,ContentCaptureOptions contentCaptureOptions, long[] disabledCompatChanges,SharedMemory serializedSystemFontMap,long startRequestedElapsedTime, long startRequestedUptime) {......AppBindData data = new AppBindData();data.processName = processName;data.appInfo = appInfo;data.sdkSandboxClientAppVolumeUuid = sdkSandboxClientAppVolumeUuid;data.sdkSandboxClientAppPackage = sdkSandboxClientAppPackage;data.providers = providerList.getList();data.instrumentationName = instrumentationName;data.instrumentationArgs = instrumentationArgs;data.instrumentationWatcher = instrumentationWatcher;data.instrumentationUiAutomationConnection = instrumentationUiConnection;data.debugMode = debugMode;data.enableBinderTracking = enableBinderTracking;data.trackAllocation = trackAllocation;data.restrictedBackupMode = isRestrictedBackupMode;data.persistent = persistent;data.config = config;data.compatInfo = compatInfo;data.initProfilerInfo = profilerInfo;data.buildSerial = buildSerial;data.autofillOptions = autofillOptions;data.contentCaptureOptions = contentCaptureOptions;data.disabledCompatChanges = disabledCompatChanges;data.mSerializedSystemFontMap = serializedSystemFontMap;data.startRequestedElapsedTime = startRequestedElapsedTime;data.startRequestedUptime = startRequestedUptime;sendMessage(H.BIND_APPLICATION, data);
}
public void handleMessage(Message msg) {if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));switch (msg.what) {case BIND_APPLICATION:Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");AppBindData data = (AppBindData)msg.obj;handleBindApplication(data);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);break;......
}
//ActivityThread.java
private void handleBindApplication(AppBindData data) {......// send up app name; do this *before* waiting for debuggerProcess.setArgV0(data.processName);android.ddm.DdmHandleAppName.setAppName(data.processName,data.appInfo.packageName,UserHandle.myUserId());VMRuntime.setProcessPackageName(data.appInfo.packageName);// Pass data directory path to ART. This is used for caching information and// should be set before any application code is loaded.VMRuntime.setProcessDataDirectory(data.appInfo.dataDir);if (mProfiler.profileFd != null) {mProfiler.startProfiling();}//初始化上下文final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);// Continue loading instrumentation.if (ii != null) {initInstrumentation(ii, data, appContext);} else {mInstrumentation = new Instrumentation();mInstrumentation.basicInit(this);}try {
// If the app is being launched for full backup or restore, bring it up in// a restricted environment with the base application class.app = data.info.makeApplicationInner(data.restrictedBackupMode, null);......// Do this after providers, since instrumentation tests generally start their// test thread at this point, and we don't want that racing.try {mInstrumentation.onCreate(data.instrumentationArgs);}catch (Exception e) {throw new RuntimeException("Exception thrown in onCreate() of "+ data.instrumentationName + ": " + e.toString(), e);}try {mInstrumentation.callApplicationOnCreate(app);} catch (Exception e) {if (!mInstrumentation.onException(app, e)) {throw new RuntimeException("Unable to create application " + app.getClass().getName()+ ": " + e.toString(), e);}}} finally {// If the app targets < O-MR1, or doesn't change the thread policy// during startup, clobber the policy to maintain behavior of b/36951662if (data.appInfo.targetSdkVersion < Build.VERSION_CODES.O_MR1|| StrictMode.getThreadPolicy().equals(writesAllowedPolicy)) {StrictMode.setThreadPolicy(savedPolicy);}}......
}
//LoadedApk.java
private Application makeApplicationInner(boolean forceDefaultAppClass,Instrumentation instrumentation, boolean allowDuplicateInstances) {......Application app = null;final String myProcessName = Process.myProcessName();String appClass = mApplicationInfo.getCustomApplicationClassNameForProcess(myProcessName);if (forceDefaultAppClass || (appClass == null)) {appClass = "android.app.Application";}try {final java.lang.ClassLoader cl = getClassLoader();if (!mPackageName.equals("android")) {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,"initializeJavaContextClassLoader");initializeJavaContextClassLoader();Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);}......//创建application上下文ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);// The network security config needs to be aware of multiple// applications in the same process to handle discrepanciesNetworkSecurityConfigProvider.handleNewApplication(appContext);app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);appContext.setOuterContext(app);} catch (Exception e) {......}mActivityThread.mAllApplications.add(app);mApplication = app;if (!allowDuplicateInstances) {synchronized (sApplications) {sApplications.put(mPackageName, app);}}if (instrumentation != null) {try {instrumentation.callApplicationOnCreate(app);} catch (Exception e) {if (!instrumentation.onException(app, e)) {Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);throw new RuntimeException("Unable to create application " + app.getClass().getName()+ ": " + e.toString(), e);}}}Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);return app;
}//========================
//Instrumentation.java
public Application newApplication(ClassLoader cl, String className, Context context)throws InstantiationException, IllegalAccessException, ClassNotFoundException {Application app = getFactory(context.getPackageName()).instantiateApplication(cl, className);app.attach(context);return app;
}
//==========================
public void callApplicationOnCreate(Application app) {app.onCreate();
}
//ActivityTaskManagerService
public boolean attachApplication(WindowProcessController wpc) throws RemoteException {synchronized (mGlobalLockWithoutBoost) {if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "attachApplication:" + wpc.mName);}try {return mRootWindowContainer.attachApplication(wpc);} finally {Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);}}
}//BootWindowContainer.java
boolean attachApplication(WindowProcessController app) throws RemoteException {try {return mAttachApplicationHelper.process(app);} finally {mAttachApplicationHelper.reset();}
}//AttachApplicationHelper.java
boolean process(WindowProcessController app) throws RemoteException {mApp = app;for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {getChildAt(displayNdx).forAllRootTasks(this);if (mRemoteException != null) {throw mRemoteException;}}if (!mHasActivityStarted) {ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,false /* preserveWindows */);}return mHasActivityStarted;
}void forAllRootTasks(Consumer<Task> callback, boolean traverseTopToBottom) {int count = mChildren.size();if (traverseTopToBottom) {for (int i = count - 1; i >= 0; --i) {mChildren.get(i).forAllRootTasks(callback, traverseTopToBottom);}} else {for (int i = 0; i < count; i++) {mChildren.get(i).forAllRootTasks(callback, traverseTopToBottom);// Root tasks may be removed from this display. Ensure each task will be processed// and the loop will end.int newCount = mChildren.size();i -= count - newCount;count = newCount;}}
}
//Task.java
@Override
void forAllRootTasks(Consumer<Task> callback, boolean traverseTopToBottom) {if (isRootTask()) {callback.accept(this);}
}

callback.accept(this);这个this就是Task.java

callback就是AttachApplicationHelper.java

//AttachApplicationHelper.java
private class AttachApplicationHelper implements Consumer<Task>, Predicate<ActivityRecord> {@Overridepublic void accept(Task rootTask) {if (mRemoteException != null) {return;}if (rootTask.getVisibility(null /* starting */)== TASK_FRAGMENT_VISIBILITY_INVISIBLE) {return;}mTop = rootTask.topRunningActivity();rootTask.forAllActivities(this);}
}
//WindowContainer.java
boolean forAllActivities(Predicate<ActivityRecord> callback) {return forAllActivities(callback, true /*traverseTopToBottom*/);
}
boolean forAllActivities(Predicate<ActivityRecord> callback, boolean traverseTopToBottom) {if (traverseTopToBottom) {for (int i = mChildren.size() - 1; i >= 0; --i) {if (mChildren.get(i).forAllActivities(callback, traverseTopToBottom)) return true;}} else {final int count = mChildren.size();for (int i = 0; i < count; i++) {if (mChildren.get(i).forAllActivities(callback, traverseTopToBottom)) return true;}}return false;
}
//ActivityRecord.java
boolean forAllActivities(Predicate<ActivityRecord> callback, boolean traverseTopToBottom) {return callback.test(this);
}
//这个callback是AttachApplicationHelper
public boolean test(ActivityRecord r) {if (r.finishing || !r.showToCurrentUser() || !r.visibleIgnoringKeyguard|| r.app != null || mApp.mUid != r.info.applicationInfo.uid|| !mApp.mName.equals(r.processName)) {return false;}try { if (mTaskSupervisor.realStartActivityLocked(r, mApp,mTop == r && r.getTask().canBeResumed(r) /* andResume */,true /* checkConfig */)) {mHasActivityStarted = true;}} catch (RemoteException e) {Slog.w(TAG, "Exception in new application when starting activity " + mTop, e);mRemoteException = e;return true;}return false;
}

5 ams收到消息后的工作

ActivityManagerService收到新进程启动成功的消息后,会进去一系列的准备工作,然后调用ActivityTaskSupervisor的realStartActivityLocked方法发起启动Activity
在这里插入图片描述

5.1 realStartActivityLocked

//ActivityTaskSupervisor.java
boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,boolean andResume, boolean checkConfig) throws RemoteException {......// Create activity launch transaction.final ClientTransaction clientTransaction = ClientTransaction.obtain(proc.getThread(), r.token);final boolean isTransitionForward = r.isTransitionForward();final IBinder fragmentToken = r.getTaskFragment().getFragmentToken();clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),System.identityHashCode(r), r.info,// TODO: Have this take the merged configuration instead of separate global// and override configs.mergedConfiguration.getGlobalConfiguration(),mergedConfiguration.getOverrideConfiguration(), r.compat,r.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor,proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(),results, newIntents, r.takeOptions(), isTransitionForward,proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken));// Set desired final state.final ActivityLifecycleItem lifecycleItem;if (andResume) {lifecycleItem = ResumeActivityItem.obtain(isTransitionForward);} else {lifecycleItem = PauseActivityItem.obtain();}clientTransaction.setLifecycleStateRequest(lifecycleItem);// Schedule transaction.mService.getLifecycleManager().scheduleTransaction(clientTransaction);......proc.onStartActivity(mService.mTopProcessState, r.info);return true;
}//ClientLifecycleManager.java
void scheduleTransaction(ClientTransaction transaction) throws RemoteException {final IApplicationThread client = transaction.getClient();transaction.schedule();if (!(client instanceof Binder)) {// If client is not an instance of Binder - it's a remote call and at this point it is// safe to recycle the object. All objects used for local calls will be recycled after// the transaction is executed on client in ActivityThread.transaction.recycle();}
}//ClientTransaction.java
public void schedule() throws RemoteException {mClient.scheduleTransaction(this);
}
//IApplicationThread.java
//ApplicationThread.java
@Override
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {ActivityThread.this.scheduleTransaction(transaction);
}

6 目标进程收到binder请求后

被启动的App进程中的binder线程在收到请求后,通过handler向主线程发送EXECUTE_TRANSACTION消息。

//ApplicationThread
void scheduleTransaction(ClientTransaction transaction) {transaction.preExecute(this);sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
//
case EXECUTE_TRANSACTION:final ClientTransaction transaction = (ClientTransaction) msg.obj;mTransactionExecutor.execute(transaction);if (isSystem()) {// Client transactions inside system process are recycled on the client side// instead of ClientLifecycleManager to avoid being cleared before this// message is handled.transaction.recycle();}

7 Activity.onCreate

主线程在收到Message后,通过反射机制创建目标Activity,并回调Activity.onCreate()等方法在这里插入图片描述

7.1 execute

//TransactionExecutor.java
public void execute(ClientTransaction transaction) {if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Start resolving transaction");final IBinder token = transaction.getActivityToken();if (token != null) {final Map<IBinder, ClientTransactionItem> activitiesToBeDestroyed =mTransactionHandler.getActivitiesToBeDestroyed();final ClientTransactionItem destroyItem = activitiesToBeDestroyed.get(token);if (destroyItem != null) {if (transaction.getLifecycleStateRequest() == destroyItem) {// It is going to execute the transaction that will destroy activity with the// token, so the corresponding to-be-destroyed record can be removed.activitiesToBeDestroyed.remove(token);}if (mTransactionHandler.getActivityClient(token) == null) {// The activity has not been created but has been requested to destroy, so all// transactions for the token are just like being cancelled.Slog.w(TAG, tId(transaction) + "Skip pre-destroyed transaction:\n"+ transactionToString(transaction, mTransactionHandler));return;}}}if (DEBUG_RESOLVER) Slog.d(TAG, transactionToString(transaction, mTransactionHandler));executeCallbacks(transaction);executeLifecycleState(transaction);mPendingActions.clear();if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "End resolving transaction");
}
//TransactionExecutor.java
public void executeCallbacks(ClientTransaction transaction) {final List<ClientTransactionItem> callbacks = transaction.getCallbacks();......for (int i = 0; i < size; ++i) {final ClientTransactionItem item = callbacks.get(i);if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Resolving callback: " + item);final int postExecutionState = item.getPostExecutionState();final int closestPreExecutionState = mHelper.getClosestPreExecutionState(r,item.getPostExecutionState());if (closestPreExecutionState != UNDEFINED) {cycleToPath(r, closestPreExecutionState, transaction);}item.execute(mTransactionHandler, token, mPendingActions);item.postExecute(mTransactionHandler, token, mPendingActions);if (r == null) {// Launch activity request will create an activity record.r = mTransactionHandler.getActivityClient(token);}......}
}

前面添加回调是:

clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),

所以item应该是LaunchActivityItem

//LaunchActivityItem.java
public void execute(ClientTransactionHandler client, IBinder token,PendingTransactionActions pendingActions) {Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble,mTaskFragmentToken);
// 
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
//
public Activity handleLaunchActivity(ActivityClientRecord r,PendingTransactionActions pendingActions, Intent customIntent) {......final Activity a = performLaunchActivity(r, customIntent);......return a;
}

7.2 performLaunchActivity

//ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {......
ContextImpl appContext = createBaseContextForActivity(r);Activity activity = null;try {java.lang.ClassLoader cl = appContext.getClassLoader();activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);StrictMode.incrementExpectedActivityCount(activity.getClass());r.intent.setExtrasClassLoader(cl);r.intent.prepareToEnterProcess(isProtectedComponent(r.activityInfo),appContext.getAttributionSource());if (r.state != null) {r.state.setClassLoader(cl);}} catch (Exception e) {if (!mInstrumentation.onException(activity, e)) {throw new RuntimeException("Unable to instantiate activity " + component+ ": " + e.toString(), e);}}try {Application app = r.packageInfo.makeApplicationInner(false, mInstrumentation);if (localLOGV) Slog.v(TAG, "Performing launch of " + r);if (localLOGV) Slog.v(TAG, r + ": app=" + app+ ", appName=" + app.getPackageName()+ ", pkg=" + r.packageInfo.getPackageName()+ ", comp=" + r.intent.getComponent().toShortString()+ ", dir=" + r.packageInfo.getAppDir());// updatePendingActivityConfiguration() reads from mActivities to update// ActivityClientRecord which runs in a different thread. Protect modifications to// mActivities to avoid race.synchronized (mResourcesManager) {mActivities.put(r.token, r);}if (activity != null) {CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());Configuration config =new Configuration(mConfigurationController.getCompatConfiguration());if (r.overrideConfig != null) {config.updateFrom(r.overrideConfig);}if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "+ r.activityInfo.name + " with config " + config);Window window = null;if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {window = r.mPendingRemoveWindow;r.mPendingRemoveWindow = null;r.mPendingRemoveWindowManager = null;}// Activity resources must be initialized with the same loaders as the// application context.appContext.getResources().addLoaders(app.getResources().getLoaders().toArray(new ResourcesLoader[0]));appContext.setOuterContext(activity);activity.attach(appContext, this, getInstrumentation(), r.token,r.ident, app, r.intent, r.activityInfo, title, r.parent,r.embeddedID, r.lastNonConfigurationInstances, config,r.referrer, r.voiceInteractor, window, r.activityConfigCallback,r.assistToken, r.shareableActivityToken);if (customIntent != null) {activity.mIntent = customIntent;}r.lastNonConfigurationInstances = null;checkAndBlockForNetworkAccess();activity.mStartedActivity = false;int theme = r.activityInfo.getThemeResource();if (theme != 0) {activity.setTheme(theme);}if (r.mActivityOptions != null) {activity.mPendingOptions = r.mActivityOptions;r.mActivityOptions = null;}activity.mLaunchedFromBubble = r.mLaunchedFromBubble;activity.mCalled = false;// Assigning the activity to the record before calling onCreate() allows// ActivityThread#getActivity() lookup for the callbacks triggered from// ActivityLifecycleCallbacks#onActivityCreated() or// ActivityLifecycleCallback#onActivityPostCreated().r.activity = activity;if (r.isPersistable()) {mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);} else {mInstrumentation.callActivityOnCreate(activity, r.state);}......}r.setState(ON_CREATE);} catch (SuperNotCalledException e) {throw e;} catch (Exception e) {if (!mInstrumentation.onException(activity, e)) {throw new RuntimeException("Unable to start activity " + component+ ": " + e.toString(), e);}}return activity;
}

7.2.1 createBaseContextForActivity

private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {final int displayId = ActivityClient.getInstance().getDisplayId(r.token);ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();// For debugging purposes, if the activity's package name contains the value of// the "debug.use-second-display" system property as a substring, then show// its content on a secondary display if there is one.String pkgName = SystemProperties.get("debug.second-display.pkg");if (pkgName != null && !pkgName.isEmpty()&& r.packageInfo.mPackageName.contains(pkgName)) {for (int id : dm.getDisplayIds()) {if (id != DEFAULT_DISPLAY) {Display display =dm.getCompatibleDisplay(id, appContext.getResources());appContext = (ContextImpl) appContext.createDisplayContext(display);break;}}}return appContext;
}

7.2.2 newActivity

//Instrumentation
public Activity newActivity(ClassLoader cl, String className,Intent intent)throws InstantiationException, IllegalAccessException,ClassNotFoundException {String pkg = intent != null && intent.getComponent() != null? intent.getComponent().getPackageName() : null;return getFactory(pkg).instantiateActivity(cl, className, intent);
}

7.2.3 makeApplicationInner

private Application makeApplicationInner(boolean forceDefaultAppClass,Instrumentation instrumentation, boolean allowDuplicateInstances) {if (mApplication != null) {return mApplication;}Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");synchronized (sApplications) {final Application cached = sApplications.get(mPackageName);if (cached != null) {// Looks like this is always happening for the system server, because// the LoadedApk created in systemMain() -> attach() isn't cached properly?if (!"android".equals(mPackageName)) {Slog.wtfStack(TAG, "App instance already created for package=" + mPackageName+ " instance=" + cached);}if (!allowDuplicateInstances) {mApplication = cached;return cached;}// Some apps intentionally call makeApplication() to create a new Application// instance... Sigh...}}Application app = null;final String myProcessName = Process.myProcessName();String appClass = mApplicationInfo.getCustomApplicationClassNameForProcess(myProcessName);if (forceDefaultAppClass || (appClass == null)) {appClass = "android.app.Application";}try {......app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);appContext.setOuterContext(app);} catch (Exception e) {......}mActivityThread.mAllApplications.add(app);mApplication = app;if (!allowDuplicateInstances) {synchronized (sApplications) {sApplications.put(mPackageName, app);}}if (instrumentation != null) {try {instrumentation.callApplicationOnCreate(app);} catch (Exception e) {......}}Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);return app;
}

7.2.4 attach

//Activity.java
final void attach(Context context, ActivityThread aThread,Instrumentation instr, IBinder token, int ident,Application application, Intent intent, ActivityInfo info,CharSequence title, Activity parent, String id,NonConfigurationInstances lastNonConfigurationInstances,Configuration config, String referrer, IVoiceInteractor voiceInteractor,Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken,IBinder shareableActivityToken) {attachBaseContext(context);mFragments.attachHost(null /*parent*/);//创建windowmWindow = new PhoneWindow(this, window, activityConfigCallback);mWindow.setWindowControllerCallback(mWindowControllerCallback);mWindow.setCallback(this);mWindow.setOnWindowDismissedCallback(this);mWindow.getLayoutInflater().setPrivateFactory(this);if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {mWindow.setSoftInputMode(info.softInputMode);}if (info.uiOptions != 0) {mWindow.setUiOptions(info.uiOptions);}mUiThread = Thread.currentThread();mMainThread = aThread;mInstrumentation = instr;mToken = token;mAssistToken = assistToken;mShareableActivityToken = shareableActivityToken;mIdent = ident;mApplication = application;mIntent = intent;mReferrer = referrer;mComponent = intent.getComponent();mActivityInfo = info;mTitle = title;mParent = parent;mEmbeddedID = id;mLastNonConfigurationInstances = lastNonConfigurationInstances;......mWindowManager = mWindow.getWindowManager();mCurrentConfig = config;mWindow.setColorMode(info.colorMode);mWindow.setPreferMinimalPostProcessing((info.flags & ActivityInfo.FLAG_PREFER_MINIMAL_POST_PROCESSING) != 0);}

7.3 callActivityOnCreate

//Instrumentation.java
public void callActivityOnCreate(Activity activity, Bundle icicle,PersistableBundle persistentState) {prePerformCreate(activity);activity.performCreate(icicle, persistentState);postPerformCreate(activity);
}
//Activity.java
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
final void performCreate(Bundle icicle, PersistableBundle persistentState) {......if (persistentState != null) {onCreate(icicle, persistentState);} else {onCreate(icicle);}......
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/853338.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

希亦、添可、石头洗地机哪款好用?2024洗地机深度测评

今年的洗地机市场竞争异常激烈&#xff0c;各大品牌纷纷推出了自己的旗舰产品。这对消费者来说是个好消息&#xff0c;因为有更多的选择空间。然而&#xff0c;面对如此多的优质洗地机&#xff0c;选择合适的一款也成了一种“幸福的烦恼”。 作为一个专业的测评人士&#xff0…

kaggle竞赛实战10——特征优化

特征优化思路&#xff1a; 在完成常规流程后&#xff0c;如果不知道怎么办&#xff0c;可以针对文本or时间序列特征进行进一步处理 首先&#xff0c;我们注意到&#xff0c;每一笔信用卡的交易记录都有交易时间&#xff0c;而对于时间字段和文本字段&#xff0c;普通的批量创…

AI赋能软件测试

AI赋能软件测试 AI赋能软件测试软件测试分类软件质量模型:用来衡量软件质量的维度AI赋能软件测试 随着AI时代的到来,如何轻松掌握软件测试新趋势,将AI技术应用于软件测试行业,提高测试速度与测试效率~~ 传智星云AI助手:https://nebula.itcast.cn tips:各种AI工具应有尽有…

LeetCode | 66.加一

这道题有多个思路&#xff0c;可以依次取数组的每一位&#xff0c;乘10后加下一位&#xff0c;直到最后一位&#xff0c;就得到我们数组所表示的数字&#xff0c;然后加一&#xff0c;然后把新得到的数字再转化为对应的数组&#xff0c;我的做法是直接取数组的最后一位&#xf…

人工智能GPU互联技术分析,芯片巨头UALink向英伟达NVLink开战

芯片巨头组团&#xff0c;向英伟达NVLink开战 八大科技巨头——AMD、博通、思科、Google、惠普企业、英特尔、Meta及微软——联合推出UALink&#xff08;Ultra Accelerator Link&#xff09;技术&#xff0c;为人工智能数据中心网络设定全新互联标准。此举旨在打破Nvidia的市场…

Python 小市值股票模型代码及回测分析

目录 一、模型介绍 二、代码详解 2.1 初始化函数 2.2 股票筛选过滤函数 2.3 止损函数 2.4 开盘时运行函数 2.5 调仓函数 三、回测结果分析 3.1 收益净值图与概述 3.2 模型收益概览 3.3 年度收益图 3.4 月度收益的时间序列 3.5 月度收益热力图 3.6 月度收益频次分…

java之IO流和集合框架的笔记

1 File类的使用 1.1 概述 File类及本章下的各种流&#xff0c;都定义在java.io包下。 一个File对象代表硬盘或网络中可能存在的一个文件或者文件目录&#xff08;俗称文件夹&#xff09;&#xff0c;与平台无关。&#xff08;体会万事万物皆对象&#xff09; File 能新建、删…

Java---认识异常

欢迎大家来观看本博课------Java------认识异常。1.异常的概念和体系结构 1.异常的概念和体系结构 1.1 异常的概念 在Java中&#xff0c;在程序执行过程中发生的不正常行为称为异常。如在之前我们经常遇到的算数异常&#xff08;ArithmeticException&#xff09;、数组越界…

GDB:从零开始入门GDB

目录 1.前言 2.开启项目报错 3.GDB的进入和退出 4.GDB调试中查看代码和切换文件 5.GDB调试中程序的启动和main函数传参 6.GDB中断点相关的操作 7.GDB中的调试输出指令 8.GDB中自动输出值指令 9.GDB中的调试指令 前言 在日常开发中&#xff0c;调试是我们必不可少的技能。在专业…

408数据结构-图的遍历 自学知识点整理

前置知识&#xff1a;图的存储与基本操作 图的遍历是指从图的某一顶点出发&#xff0c;按照某种搜索方法沿着图中的边对图中的所有顶点访问一次&#xff0c;且仅访问一次。因为树是一种特殊的图&#xff0c;所以树的遍历实际上也可以视为一种特殊的图的遍历。图的遍历算法是求解…

利用鱼骨图进行项目问题复盘与改进

一、引言 在项目管理中&#xff0c;问题复盘是一个至关重要的环节。它不仅能帮助我们识别项目执行过程中出现的问题&#xff0c;还能促使我们深入探究问题的根本原因&#xff0c;从而采取有效的改进措施。在这个过程中&#xff0c;鱼骨图作为一种强大的工具&#xff0c;为我们…

MEMS:Lecture 16 Gyros

陀螺仪原理 A classic spinning gyroscope measures the rotation rate by utilizing the conservation of angular momentum. 经典旋转陀螺仪通过利用角动量守恒来测量旋转速率。 Coriolis Effect and Coriolis Force 科里奥利效应是一种出现在旋转参考系中的现象。它描述了…

Internet Download Manager ( 极速下载器 ) 序列号注册码 IDM下载器注册机中文激活破解版

IDM下载器(Internet Download Manager)是一款专业的下载管理软件&#xff0c;它通过多线程技术和智能文件分段技术&#xff0c;有效提升下载速度&#xff0c;并支持断点续传&#xff0c;还具有计划下载功能&#xff0c;用户可以设置特定的下载时间&#xff0c;非常适合需要在特…

代码随想录算法训练营刷题复习1 :动态规划背包问题 01背包+完全背包

动态规划刷题复习 一、01背包 416. 分割等和子集1049. 最后一块石头的重量 II494. 目标和474. 一和零 416. 分割等和子集 class Solution { public:bool canPartition(vector<int>& nums) {int sum0;for(int i0;i<nums.size();i) {sumnums[i];}if(sum%2!0)retu…

IP地址、子网掩码、网段、网关

前面相同就是在同一个网段 如果子网掩码和网络号相与的结果是一样的&#xff0c;那么他们就在同一个子网 IP地址、子网掩码、网络号、主机号、网络地址、主机地址以及ip段/数字-如192.168.0.1/24是什么意思?_掩码248可以用几个ip-CSDN博客

谷歌上架,APP被移除了,没封号,换个包名还能重新提审上架?

对于在Google Play上架应用的开发者来说&#xff0c;尤其是那些矩阵式上架马甲包的开发者&#xff0c;可能已经遭遇过无数次应用被暂停或移除的情况了。通常这种情况下&#xff0c;账号也随之会被封&#xff0c;且大多数开发者认为&#xff0c;没有立马收到封号邮件的话&#x…

基于scikit-learn的机器学习分类任务实践——集成学习

一、传统机器学习分类流程与经典思想算法简述 传统机器学习是指&#xff0c;利用线性代数、数理统计与优化算法等数学方式从设计获取的数据集中构建预测学习器&#xff0c;进而对未知数据分类或回归。其主要流程大致可分为七个部分&#xff0c;依次为设计获取数据特征集&#x…

【C++】stack、queue和deque的使用

&#x1f497;个人主页&#x1f497; ⭐个人专栏——C学习⭐ &#x1f4ab;点击关注&#x1f929;一起学习C语言&#x1f4af;&#x1f4ab; 目录 导读 一、stack 1. stack介绍 2. stack使用 二、queue 1. queue介绍 2. queue使用 三、deque 1. deque介绍 2. deque的…

【Pandas驯化-01】一文介绍 Pandas中的Dataframe和Series 区别

【Pandas】驯化-01一文介绍 Pandas中的Dataframe和Series 区别 本次修炼方法请往下查看 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我工作、学习、实践 IT领域、真诚分享 踩坑集合&#xff0c;智慧小天地&#xff01; &#x1f387; 相关内容文档获取 微信公众…

第九届星华杯网络邀请赛

T1喵星人的身高 T2犇犇碑 T3嘤嘤词典 T4三角区间和