概述
该篇基于Android 10的代码。在 https://www.jianshu.com/p/a3be43238458 中已经介绍了,在Android 10中,activity的调度和管理已经从AMS移到了ActivityTaskManagerService中(这里简称ATMS),这在下面关于应用第一次的启动的过程中也能清楚看到。
这个详细过程有点复杂,所以可能有不准确的地方欢迎指出交流。
应用的启动过程有点复杂,该部分简单概述下。
第二部分是跟着代码流程一步一步看的。这里涉及多次跨进程,Binder大致了解下是什么,可以参考 Binder机制。
第三部分“附上调用栈”,有助于查看源码以及理解, 这个方法很好用的。
启动过程总结
- Launcher点击应用图标:这个过程是Launcher进程中进行的,去启动应用的第一个activity。
- 通过binder进入ATMS:在ATMS中,为应用的第一个activity创建了ActivityRecord,找到其ActivityStack,将ActivityRecord插入到所在的TaskRecord的合适位置。最后执行到
ActivityManagerInternal::startProcess
。 - 进入AMS,请求创建应用进程:这个过程创建了ProcessRecord对象并处理保存了进程所需的各种信息。最后通过Process.start()请求创建应用进程。
- Zygote创建应用进程:通过socket与zygote进程通信,fork出应用进程。
- 应用进程主线程-执行ActivityThread的main():在应用主线程中,执行ActivityThread的main()。
- 进入系统进程,绑定应用进程:创建了应用的Application,将应用进程绑定到ATMS中,由它们管理。
- 回到应用进程:这里主要是创建出应用第一个Activity,并执行了attach()和onCreate()。
注:AMS和ATMS服务都是在系统进程-system server进程中。
所以,整个过程 进程变化是:Launcher进程(binder)->systemserver进程(socket)->zygote进程(socket)->应用进程(binder)->systemserver进程(binder)->应用进程。
Activity的启动过程详述
下面部分代码添加了注释,阅读源码时查看下原本英文注释是很有用的。
在最后部分“附上调用栈”,附上了部分调用栈的过程,更有助于查看和理解,这个方法很好用的。
这个根据理解画的下面流程的一个简单图示,供参考:
image.png
Launcher点击应用图标
Launcher点击图标,BaseDraggingActivity.java中startActivitySafely()调用了startActivity()。
这是的activity是Launcher的activity,在Launcher的进程中。
Activity中各种startActivity()调用,最终都是走到的startActivityForResult(@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options)方法的。
//Activity.java:
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
// Note we want to go through this call for compatibility with
// applications that may have overridden the method.
startActivityForResult(intent, -1);
}
}
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {
startActivityForResult(intent, requestCode, null);
}
所以Launcher点击图标后这里直接从startActivityForResult()开始看,从上面可以看到requestCode值为-1。
//Activity.java:
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
//mParent一般为null
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
//调用mInstrumentation.execStartActivity()
//mMainThread、mInstrumentation、mToken在attach()被赋值
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
......
} else {
//调用mParent.startActivityFromChild(),和上面逻辑类似
}
}
目前还是在Launcher进程,这里mMainThread、mInstrumentation、mToken都是在attach()被赋值。
Instrumentation监控system(主要是AM,Activity Manager)与application之间的所有交互。
mToken是IBinder对象,是Binder代理,是Android中IPC重要部分。
mMainThread是ActivityThread对象,应用的主线程。这里是Launhcer的主线程。
那么什么时候被赋值的呢?attach()在哪被调用的?看到最后就知道了v
这里关键代码 调用了mInstrumentation.execStartActivity()。
//Instrumentation.java
@UnsupportedAppUsage
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
......
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
//binder调用,获取ATMS的binder对象,调用ATMS的startActivity方法
int result = ActivityTaskManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
看下ActivityTaskManager.java里getService()方法
//ActivityTaskManager.java
public static IActivityTaskManager getService() {
return IActivityTaskManagerSingleton.get();
}
@UnsupportedAppUsage(trackingBug = 129726065)
private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
new Singleton<IActivityTaskManager>() {
@Override
protected IActivityTaskManager create() {
//获取到ATMS的binder对象
final IBinder b =
ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
return IActivityTaskManager.Stub.asInterface(b);
}
};
这里主要看ActivityTaskManager.getService().startActivity()
这个方法。
ActivityTaskManager.getService()
这个涉及Binder机制,可以参考 Binder机制 。 这里获取的服务名是Context.ACTIVITY_TASK_SERVICE(=activity_task)
,最终调用的是ActivityTaskManagerService.startActivity()
方法。
进入ATMS
通过Binder机制,由Launcher进程进入到ATMS。
ActivityTaskManagerService中的startActivity()
//ActivityTaskManagerService.java:
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
resultWho, requestCode, startFlags, profilerInfo, bOptions,
UserHandle.getCallingUserId());
}
@Override
public int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
true /*validateIncomingUser*/);
}
int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
boolean validateIncomingUser) {
enforceNotIsolatedCaller("startActivityAsUser");
userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
// TODO: Switch to user app stacks here.
return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
.setCallingPackage(callingPackage)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
.setActivityOptions(bOptions)
.setMayWait(userId)
.execute();
}
ATMS中的startActivity(),最终调用了ActivityStarter中的execute()。
//ActivityStarter.java:
ActivityStarter setMayWait(int userId) {
mRequest.mayWait = true;
mRequest.userId = userId;
return this;
}
int execute() {
try {
// TODO(b/64750076): Look into passing request directly to these methods to allow
// for transactional diffs and preprocessing.
if (mRequest.mayWait) {
return startActivityMayWait(mRequest.caller, mRequest.callingUid,
mRequest.callingPackage, mRequest.realCallingPid, mRequest.realCallingUid,
mRequest.intent, mRequest.resolvedType,
mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
mRequest.resultWho, mRequest.requestCode, mRequest.startFlags,
mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig,
mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId,
mRequest.inTask, mRequest.reason,
mRequest.allowPendingRemoteAnimationRegistryLookup,
mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart);
} else {
......
}
} finally {
onExecutionComplete();
}
}
在setMayWait()中,mRequest.mayWait = true;,因此走到startActivityMayWait()。
//ActivityStarter.java:
private int startActivityMayWait(IApplicationThread caller, int callingUid,
String callingPackage, int requestRealCallingPid, int requestRealCallingUid,
Intent intent, String resolvedType, IVoiceInteractionSession voiceSession,
IVoiceInteractor voiceInteractor, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, WaitResult outResult,
Configuration globalConfig, SafeActivityOptions options, boolean ignoreTargetSecurity,
int userId, TaskRecord inTask, String reason,
boolean allowPendingRemoteAnimationRegistryLookup,
PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
......
ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
synchronized (mService.mGlobalLock) {
final ActivityStack stack = mRootActivityContainer.getTopDisplayFocusedStack();
......
final ActivityRecord[] outRecord = new ActivityRecord[1];
int res = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo,
voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid,
callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options,
ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason,
allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent,
allowBackgroundActivityStart);
......
mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(res, outRecord[0]);
if (outResult != null) {
outResult.result = res;
final ActivityRecord r = outRecord[0];
......
}
return res;
}
}
//startActivity 1
private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
SafeActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
ActivityRecord[] outActivity, TaskRecord inTask, String reason,
boolean allowPendingRemoteAnimationRegistryLookup,
PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
if (TextUtils.isEmpty(reason)) {
throw new IllegalArgumentException("Need to specify a reason.");
}
mLastStartReason = reason;
mLastStartActivityTimeMs = System.currentTimeMillis();
mLastStartActivityRecord[0] = null;
mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,
aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
inTask, allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent,
allowBackgroundActivityStart);
if (outActivity != null) {
// mLastStartActivityRecord[0] is set in the call to startActivity above.
outActivity[0] = mLastStartActivityRecord[0];
}
return getExternalResult(mLastStartActivityResult);
}
//startActivity 2
private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
SafeActivityOptions options,
boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup,
PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
.......
ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
mSupervisor, checkedOptions, sourceRecord);
if (outActivity != null) {
outActivity[0] = r;
}
......
final ActivityStack stack = mRootActivityContainer.getTopDisplayFocusedStack();
......
final int res = startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
true /* doResume */, checkedOptions, inTask, outActivity, restrictedBgActivity);
mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(res, outActivity[0]);
return res;
}
这里主要的代码关注:startActivityMayWait()->startActivity()->startActivity()->startActivity()
。
这里3个startActivity()的同名方法,参数是不一样的。参数很多得注意点看。 这几个方法内容都很多,这里主要注意几个地方:
- ActivityRecord在对应一个activity,是activity的信息记录管理的类。
- startActivityMayWait()方法中new的ActivityRecord对象 outRecord[0],在第二个startActivity()中被赋值,指向的创建的ActivityRecord对象r。
-----这里在第二个startActivity()中创建了应用第一个activity的ActivityRecord对象
第二个startActivity()同样调用了startActivity(),也是ActivityStarter最后一个同名startActivity方法,这里标记为第三个startActivity()。
//ActivityStarter.java:
//第三个:startActivity 3
private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
ActivityRecord[] outActivity, boolean restrictedBgActivity) {
int result = START_CANCELED;
final ActivityStack startedActivityStack;
try {
mService.mWindowManager.deferSurfaceLayout();
result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, doResume, options, inTask, outActivity, restrictedBgActivity);
} finally {
final ActivityStack currentStack = r.getActivityStack();
startedActivityStack = currentStack != null ? currentStack : mTargetStack;
......
}
......
return result;
}
第三个startActivity()中获取Activity所在的ActivityStack - startedActivityStack。
这里看下startActivityUnchecked()。
//ActivityStarter.java:
// Note: This method should only be called from {@link startActivity}.
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
ActivityRecord[] outActivity, boolean restrictedBgActivity) {
......
mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
mOptions);
if (mDoResume) {
final ActivityRecord topTaskActivity =
mStartActivity.getTaskRecord().topRunningActivityLocked();
if (!mTargetStack.isFocusable()
|| (topTaskActivity != null && topTaskActivity.mTaskOverlay
&& mStartActivity != topTaskActivity)) {
// If the activity is not focusable, we can't resume it, but still would like to
// make sure it becomes visible as it starts (this will also trigger entry
// animation). An example of this are PIP activities.
// Also, we don't want to resume activities in a task that currently has an overlay
// as the starting activity just needs to be in the visible paused state until the
// over is removed.
mTargetStack.ensureActivitiesVisibleLocked(mStartActivity, 0, !PRESERVE_WINDOWS);
// Go ahead and tell window manager to execute app transition for this activity
// since the app transition will not be triggered through the resume channel.
mTargetStack.getDisplay().mDisplayContent.executeAppTransition();
} else {
// If the target stack was not previously focusable (previous top running activity
// on that stack was not visible) then any prior calls to move the stack to the
// will not update the focused stack. If starting the new activity now allows the
// task stack to be focusable, then ensure that we now update the focused stack
// accordingly.
if (mTargetStack.isFocusable()
&& !mRootActivityContainer.isTopDisplayFocusedStack(mTargetStack)) {
mTargetStack.moveToFront("startActivityUnchecked");
}
mRootActivityContainer.resumeFocusedStacksTopActivities(
mTargetStack, mStartActivity, mOptions);
}
} else if (mStartActivity != null) {
mSupervisor.mRecentTasks.add(mStartActivity.getTaskRecord());
}
mRootActivityContainer.updateUserStack(mStartActivity.mUserId, mTargetStack);
mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTaskRecord(),
preferredWindowingMode, mPreferredDisplayId, mTargetStack);
return START_SUCCESS;
}
1.startActivityUnchecked()找到目标ActivityStack - mTargetStack,然后调用了mTargetStack.startActivityLocked()找到所在TaskRecord,并将activity插入到合适位置。 这样activity对应ActivityRecord就加入到对应ActivityStack中的对应的TaskRecord中了。
2.mRootActivityContainer.resumeFocusedStacksTopActivities();获取栈顶activity并恢复,即将设置成resume状态。
这里看下这两个方法
1. startActivityLocked()
//ActivityStack.java:
void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
boolean newTask, boolean keepCurTransition, ActivityOptions options) {
TaskRecord rTask = r.getTaskRecord();
final int taskId = rTask.taskId;
final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();
// mLaunchTaskBehind tasks get placed at the back of the task stack.
if (!r.mLaunchTaskBehind && allowMoveToFront
&& (taskForIdLocked(taskId) == null || newTask)) {
// Last activity in task had been removed or ActivityManagerService is reusing task.
// Insert or replace.
// Might not even be in.
insertTaskAtTop(rTask, r);
}
TaskRecord task = null;
......
task = activityTask;
......
task.setFrontOfTask();
// The transition animation and starting window are not needed if {@code allowMoveToFront}
// is false, because the activity won't be visible.
if ((!isHomeOrRecentsStack() || numActivities() > 0) && allowMoveToFront) {
......
} else {
// If this is the first activity, don't do any fancy animations,
// because there is nothing for it to animate on top of.
ActivityOptions.abort(options);
}
}
这里找到activity的TaskRecord,并将activity对应的ActivityRecord插入到TaskRecord的合适位置。然后进行过渡动画相关判断处理。
-----到此,应用第一个activity的ActivityRecord已创建,并找到其ActivityStack。最后在ActivityStack中将ActivityRecord插入到所在的TaskRecord的合适位置。
参考下面这张图理解下,ActivityStack、ActivityStackSupervisor、TaskRecord、ActivityRecord、ProcessRecord之间的关系。
2.resumeFocusedStacksTopActivities()
/**
* Root node for activity containers.
* TODO: This class is mostly temporary to separate things out of ActivityStackSupervisor.java. The
* intention is to have this merged with RootWindowContainer.java as part of unifying the hierarchy.
*/
//RootActivityContainer.java:
boolean resumeFocusedStacksTopActivities(
ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
if (!mStackSupervisor.readyToResume()) {
return false;
}
boolean result = false;
if (targetStack != null && (targetStack.isTopStackOnDisplay()
|| getTopDisplayFocusedStack() == targetStack)) {
result = targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
......
return result;
}
这里看targetStack.resumeTopActivityUncheckedLocked()。
//ActivityStack.java:
@GuardedBy("mService")
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
if (mInResumeTopActivity) {
// Don't even start recursing.
return false;
}
boolean result = false;
try {
// Protect against recursion.
mInResumeTopActivity = true;
result = resumeTopActivityInnerLocked(prev, options);
// When resuming the top activity, it may be necessary to pause the top activity (for
// example, returning to the lock screen. We suppress the normal pause logic in
// {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the
// end. We call the {@link ActivityStackSupervisor#checkReadyForSleepLocked} again here
// to ensure any necessary pause logic occurs. In the case where the Activity will be
// shown regardless of the lock screen, the call to
// {@link ActivityStackSupervisor#checkReadyForSleepLocked} is skipped.
final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
if (next == null || !next.canTurnScreenOn()) {
checkReadyForSleep();
}
} finally {
mInResumeTopActivity = false;
}
return result;
}
//ActivityStack.java:
@GuardedBy("mService")
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
// Find the next top-most activity to resume in this stack that is not finishing and is
// focusable. If it is not focusable, we will fall into the case below to resume the
// top activity in the next focusable task.
ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
......
boolean pausing = getDisplay().pauseBackStacks(userLeaving, next, false);
if (mResumedActivity != null) {
pausing |= startPausingLocked(userLeaving, false, next, false);
}
......
if (next.attachedToProcess()) {
......
} else {
......
mStackSupervisor.startSpecificActivityLocked(next, true, true);
}
return true;
}
由于activity所在应用的进程还未生成,此时next.attachedToProcess()明显是false的。直接看mStackSupervisor.startSpecificActivityLocked(next, true, true);
//ActivityStackSupervisor.java:
void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
final WindowProcessController wpc =
mService.getProcessController(r.processName, r.info.applicationInfo.uid);
if (wpc != null && wpc.hasThread()) {
try {
realStartActivityLocked(r, wpc, andResume, checkConfig);
return;
} catch (RemoteException e) {
}
}
......
try {
if (Trace.isTagEnabled(TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "dispatchingStartProcess:"
+ r.processName);
}
// Post message to start process to avoid possible deadlock of calling into AMS with the
// ATMS lock held.
final Message msg = PooledLambda.obtainMessage(
ActivityManagerInternal::startProcess, mService.mAmInternal, r.processName,
r.info.applicationInfo, knownToBeDead, "activity", r.intent.getComponent());
mService.mH.sendMessage(msg);
} finally {
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
}
如果已有进程会走realStartActivityLocked()。 这里走startProcess(),这里的mService即ActivityTaskManagerService(ATMS),mService.mH是ATMS的内部类 自定义的Handler。
关于这个Handler:它是ATMS initialize()时创建的,它的Looper是AMS中mActivityTaskManager.initialize(mIntentFirewall, mPendingIntentController, DisplayThread.get().getLooper());
传入的,即DisplayThread.get().getLooper()。这个DisplayThread比较特别,可以看下注释。
Hanler相关可以参考下消息机制。
接着直接查看ActivityManagerInternal::startProcess。
/**
* Shared singleton foreground thread for the system. This is a thread for
* operations that affect what's on the display, which needs to have a minimum
* of latency. This thread should pretty much only be used by the WindowManager,
* DisplayManager, and InputManager to perform quick operations in real time.
*/
public final class DisplayThread extends ServiceThread {
private DisplayThread() {
// DisplayThread runs important stuff, but these are not as important as things running in
// AnimationThread. Thus, set the priority to one lower.
super("android.display", Process.THREAD_PRIORITY_DISPLAY + 1, false /*allowIo*/);
}
ActivityManagerInternal::startProcess,ActivityManagerInternal是抽象类,实现是AMS中的内部类LocalService。
由于篇幅过长,看下篇:https://www.jianshu.com/p/ba2318650a11?v=1678258849465
网友评论