我是靠谱客的博主 妩媚大地,最近开发中收集的这篇文章主要介绍ActivityThread分析—ActivityThread的main方法的执行流程分析前言代码分析,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

前言

前面我们分析了ActivityThread的main方法是如何被调用的,本篇我们来分析ActivityThread的main方法内的流程。

源码基于2.3,有错误还望指出。感谢。

代码分析

frameworksbasecorejavaandroidappActivityThread.java#main()


public static final void main(String[] args) {
SamplingProfilerIntegration.start();
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();// 1
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
}
ActivityThread thread = new ActivityThread();
thread.attach(false);//3
if (false) {
Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();// 2
if (Process.supportsProcesses()) {
throw new RuntimeException("Main thread loop unexpectedly exited");
}
thread.detach();
String name = (thread.mInitialApplication != null)
? thread.mInitialApplication.getPackageName()
: "<unknown>";
Slog.i(TAG, "Main thread of " + name + " is now exiting");
}

需要分析的为注释1,2,3处,1-2处是Handler-Looper消息循环的建立,着重看第3处。

frameworksbasecorejavaandroidappActivityThread.java#attach()

参数boolean system,表示当前是否为系统线程。
1.这里为true时,进入到注释1处开始进行Application的创建(这里涉及到的Instrumentation本文暂不展开,等后面专门开篇讨论这个东西),并调用Application的baseAttach和onCreate方法,这里调用的地方是在ActivityThread的sysmain方法内调用的,我觉得这里就是启动Launcher的时候的流程,这不是重点,重点看注释2处,即ActivityThread的main内。
2.ActivityManagerNative.getDefault()返回一个binder对象,这个实际上就是一个Ams实例,然后调用Ams的attachApplication方法。我们接着往下看代码。


private final void attach(boolean system) {
sThreadLocal.set(this); // 0
mSystemThread = system;
if (!system) {
......
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>");
RuntimeInit.setApplicationObject(mAppThread.asBinder());
IActivityManager mgr = ActivityManagerNative.getDefault(); //注释2.IActivityManager就是Binder,实际上是Ams
try {
mgr.attachApplication(mAppThread);//注释2.通过Binder与ApplicationThread关联
} catch (RemoteException ex) {
}
} 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");
try {
mInstrumentation = new Instrumentation();
ContextImpl context = new ContextImpl();
context.init(getSystemContext().mPackageInfo, null, this);
Application app = Instrumentation.newApplication(Application.class, context);//注释1
mAllApplications.add(app);
mInitialApplication = app;
app.onCreate();//Application的oncreate入口
} catch (Exception e) {
throw new RuntimeException(
"Unable to instantiate Application():" + e.toString(), e);
}
}
ViewRoot.addConfigCallback(new ComponentCallbacks() {
public void onConfigurationChanged(Configuration newConfig) {
synchronized (mPackages) {
// We need to apply this change to the resources
// immediately, because upon returning the view
// hierarchy will be informed about it.
if (applyConfigurationToResourcesLocked(newConfig)) {
// This actually changed the resources!
Tell
// everyone about it.
if (mPendingConfiguration == null ||
mPendingConfiguration.isOtherSeqNewer(newConfig)) {
mPendingConfiguration = newConfig;
queueOrSendMessage(H.CONFIGURATION_CHANGED, newConfig);
}
}
}
}
public void onLowMemory() {
}
});
}

frameworksbaseservicesjavacomandroidserveramActivityManagerService.java#attachApplication()

在注释1处调用了attachApplicationLocked方法,这里的参数thread是上一步传递过来的一个ApplicationThread对象。接着往下看。


public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);// 1
Binder.restoreCallingIdentity(origId);
}
}

frameworksbaseservicesjavacomandroidserveramActivityManagerService.java#attachApplication()

这个方法忒长,略去其他代码,主要有2处比较重要:
1.注释1处,这里是调用了之前传递进来的ApplicationThread的bindApplication方法。这个主要是去绑定一些应用信息。
2.注释2处,这里就是真正的去打开一个Activity了,我们先分析注释1,再分析注释2.

接下来我们点进注释1的方法内。


private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
// Find the application record that is being attached...
either via
// the pid if we are running in multiple processes, or just pull the
// next app record if we are emulating process with anonymous threads.
......
// If this application record is still attached to a previous
// process, clean it up now.
......
// Tell the process all about itself.
......
if (localLOGV) Slog.v(
TAG, "New app record " + app
+ " thread=" + thread.asBinder() + " pid=" + pid);
try {
......
// If the app is being launched for restore or full backup, set it up specially
......
//注释1
重点代码1
thread.bindApplication(processName, app.instrumentationInfo != null
? app.instrumentationInfo : app.info, providers,
app.instrumentationClass, app.instrumentationProfileFile,
app.instrumentationArguments, app.instrumentationWatcher, testMode,
isRestrictedBackupMode || !normalMode,
mConfiguration, getCommonServicesLocked());
updateLruProcessLocked(app, false, true);
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
} catch (Exception e) {
// todo: Yikes!
What should we do?
For now we will try to
// start another process, but that could easily get us in
// an infinite loop of restarting processes...
Slog.w(TAG, "Exception thrown during bind!", e);
app.resetPackageList();
startProcessLocked(app, "bind fail", processName);
return false;
}
// See if the top visible activity is waiting to run in this process...
ActivityRecord hr = mMainStack.topRunningActivityLocked(null);
if (hr != null && normalMode) {
if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
&& processName.equals(hr.processName)) {
try {
if (mMainStack.realStartActivityLocked(hr, app, true, true)) { //注释2 重点代码2
didSomething = true;
}
} catch (Exception e) {
......
}
} else {
......
}
}
......
return true;
}

frameworksbasecorejavaandroidappActivityThread.java$$ApplicationThread#bindApplication()

前面准备一堆的app信息,最后一行直接调用方法queueOrSendMessage,注意是2参的,点进去看。


public final void bindApplication(String processName,
ApplicationInfo appInfo, List<ProviderInfo> providers,
ComponentName instrumentationName, String profileFile,
Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher,
int debugMode, boolean isRestrictedBackupMode, Configuration config,
Map<String, IBinder> services) {
if (services != null) {
// Setup the service cache in the ServiceManager
ServiceManager.initServiceCache(services);
}
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
data.providers = providers;
data.instrumentationName = instrumentationName;
data.profileFile = profileFile;
data.instrumentationArgs = instrumentationArgs;
data.instrumentationWatcher = instrumentationWatcher;
data.debugMode = debugMode;
data.restrictedBackupMode = isRestrictedBackupMode;
data.config = config;
queueOrSendMessage(H.BIND_APPLICATION, data); //注释1
}

frameworksbasecorejavaandroidappActivityThread.java#queueOrSendMessage()

这里我直接把重载方法都贴出来吧,它几个最终都是去调用的4参数的方法。我们看到4参数的方法实际上最后就是去发了个handler消息。这个handler就是ActivtyThread一开始创建的H,消息的flag就是H.BIND_APPLICATION, 看注释1处。那么我们再去看这个handler——H。


// if the thread hasn't started yet, we don't have the handler, so just
// save the messages until we're ready.
private final void queueOrSendMessage(int what, Object obj) {
queueOrSendMessage(what, obj, 0, 0);
}
private final void queueOrSendMessage(int what, Object obj, int arg1) {
queueOrSendMessage(what, obj, arg1, 0);
}
private final void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {
synchronized (this) {
if (DEBUG_MESSAGES) Slog.v(
TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
+ ": " + arg1 + " / " + obj);
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
mH.sendMessage(msg); //注释1
}
}

frameworksbasecorejavaandroidappActivityThread.java$H()

本文只关注注释1和注释2处,其余地方本文暂时不关注。这里我们只需要知道它去调用handleBindApplication方法绑定application即可,接下来我们回到主线流程,去看之前的Activity是如何启动起来的。


private final class H extends Handler {
......
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + msg.what);
switch (msg.what) {
case LAUNCH_ACTIVITY: {
//注释1
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo);
handleLaunchActivity(r, null);
} break;
......
case BIND_APPLICATION:
AppBindData data = (AppBindData)msg.obj;
handleBindApplication(data);
break;
......
}
if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + msg.what);
}
void maybeSnapshot() {
if (mBoundApplication != null) {
SamplingProfilerIntegration.writeSnapshot(
mBoundApplication.processName);
}
}
}

回到主线:frameworksbaseservicesjavacomandroidserveramActivityManagerService.java#attachApplication()

1.注释1处,这里是调用了之前传递进来的ApplicationThread的bindApplication方法。这个主要是去绑定一些应用信息。
之前已经分析完了,这里开始分析注释2处。
2.注释2处,这里就是真正的去打开一个Activity了。

接下来我们点进注释2的realStartActivityLocked方法内。


private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
// Find the application record that is being attached...
either via
// the pid if we are running in multiple processes, or just pull the
// next app record if we are emulating process with anonymous threads.
......
// If this application record is still attached to a previous
// process, clean it up now.
......
// Tell the process all about itself.
......
if (localLOGV) Slog.v(
TAG, "New app record " + app
+ " thread=" + thread.asBinder() + " pid=" + pid);
try {
......
// If the app is being launched for restore or full backup, set it up specially
......
//注释1
重点代码1
thread.bindApplication(processName, app.instrumentationInfo != null
? app.instrumentationInfo : app.info, providers,
app.instrumentationClass, app.instrumentationProfileFile,
app.instrumentationArguments, app.instrumentationWatcher, testMode,
isRestrictedBackupMode || !normalMode,
mConfiguration, getCommonServicesLocked());
updateLruProcessLocked(app, false, true);
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
} catch (Exception e) {
// todo: Yikes!
What should we do?
For now we will try to
// start another process, but that could easily get us in
// an infinite loop of restarting processes...
Slog.w(TAG, "Exception thrown during bind!", e);
app.resetPackageList();
startProcessLocked(app, "bind fail", processName);
return false;
}
// See if the top visible activity is waiting to run in this process...
ActivityRecord hr = mMainStack.topRunningActivityLocked(null);
if (hr != null && normalMode) {
if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
&& processName.equals(hr.processName)) {
try {
if (mMainStack.realStartActivityLocked(hr, app, true, true)) { //注释2 重点代码2
didSomething = true;
}
} catch (Exception e) {
......
}
} else {
......
}
}
......
return true;
}

rameworksbaseservicesjavacomandroidserveramActivityStack.java#realStartActivityLocked()

这段代码也贼长,我们还是主要关注注释1处,这里调用了Application的scheduleLaunchActivity方法,点进去看。


final boolean realStartActivityLocked(ActivityRecord r,
ProcessRecord app, boolean andResume, boolean checkConfig)
throws RemoteException {
r.startFreezingScreenLocked(app, 0);
mService.mWindowManager.setAppVisibility(r, true);
// Have the window manager re-evaluate the orientation of
// the screen based on the new activity order.
Note that
// as a result of this, it can call back into the activity
// manager with a new orientation.
We don't care about that,
// because the activity is not currently running so we are
// just restarting it anyway.
if (checkConfig) {
Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
mService.mConfiguration,
r.mayFreezeScreenLocked(app) ? r : null);
mService.updateConfigurationLocked(config, r);
}
r.app = app;
if (localLOGV) Slog.v(TAG, "Launching: " + r);
int idx = app.activities.indexOf(r);
if (idx < 0) {
app.activities.add(r);
}
mService.updateLruProcessLocked(app, true, true);
try {
if (app.thread == null) {
throw new RemoteException();
}
List<ResultInfo> results = null;
List<Intent> newIntents = null;
if (andResume) {
results = r.results;
newIntents = r.newIntents;
}
if (DEBUG_SWITCH) Slog.v(TAG, "Launching: " + r
+ " icicle=" + r.icicle
+ " with results=" + results + " newIntents=" + newIntents
+ " andResume=" + andResume);
if (andResume) {
EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
System.identityHashCode(r),
r.task.taskId, r.shortComponentName);
}
if (r.isHomeActivity) {
mService.mHomeProcess = app;
}
mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
//注释1
app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
System.identityHashCode(r),
r.info, r.icicle, results, newIntents, !andResume,
mService.isNextTransitionForward());
if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
// This may be a heavy-weight process!
Note that the package
// manager will ensure that only activity can run in the main
// process of the .apk, which is the only thing that will be
// considered heavy-weight.
if (app.processName.equals(app.info.packageName)) {
if (mService.mHeavyWeightProcess != null
&& mService.mHeavyWeightProcess != app) {
Log.w(TAG, "Starting new heavy weight process " + app
+ " when already running "
+ mService.mHeavyWeightProcess);
}
mService.mHeavyWeightProcess = app;
Message msg = mService.mHandler.obtainMessage(
ActivityManagerService.POST_HEAVY_NOTIFICATION_MSG);
msg.obj = r;
mService.mHandler.sendMessage(msg);
}
}
} catch (RemoteException e) {
if (r.launchFailed) {
// This is the second time we failed -- finish activity
// and give up.
Slog.e(TAG, "Second failure launching "
+ r.intent.getComponent().flattenToShortString()
+ ", giving up", e);
mService.appDiedLocked(app, app.pid, app.thread);
requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
"2nd-crash");
return false;
}
// This is the first time we failed -- restart process and
// retry.
app.activities.remove(r);
throw e;
}
r.launchFailed = false;
if (updateLRUListLocked(r)) {
Slog.w(TAG, "Activity " + r
+ " being launched, but already in LRU list");
}
if (andResume) {
// As part of the process of launching, ActivityThread also performs
// a resume.
r.state = ActivityState.RESUMED;
r.icicle = null;
r.haveState = false;
r.stopped = false;
mResumedActivity = r;
r.task.touchActiveTime();
completeResumeLocked(r);
pauseIfSleepingLocked();
} else {
// This activity is not starting in the resumed state... which
// should look like we asked it to pause+stop (but remain visible),
// and it has done so and reported back the current icicle and
// other state.
r.state = ActivityState.STOPPED;
r.stopped = true;
}
// Launch the new version setup screen if needed.
We do this -after-
// launching the initial activity (that is, home), so that it can have
// a chance to initialize itself while in the background, making the
// switch back to it faster and look better.
if (mMainStack) {
mService.startSetupActivityLocked();
}
return true;
}

frameworksbasecorejavaandroidappActivityThread.java$$ApplicationThread#scheduleLaunchActivity()

不用多说,直接看注释1处的queueOrSendMessage方法。其中过程我们在分析bindApplication的时候就分析过了,我们直接看handler内的处理方法。


// we use token to identify this activity without having to send the
// activity itself back to the activity manager. (matters more with ipc)
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Bundle state, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) {
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.activityInfo = info;
r.state = state;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
r.startsNotResumed = notResumed;
r.isForward = isForward;
queueOrSendMessage(H.LAUNCH_ACTIVITY, r);//注释1处
}

frameworksbasecorejavaandroidappActivityThread.java#handleLaunchActivity()

在注释1处我们调用了performLaunchActivity方法,点进去看。


private final void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
if (localLOGV) Slog.v(
TAG, "Handling launch of " + r);
Activity a = performLaunchActivity(r, customIntent);//注释1
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward);
if (!r.activity.mFinished && r.startsNotResumed) {
// The activity manager actually wants this one to start out
// paused, because it needs to be visible but isn't in the
// foreground.
We accomplish this by going through the
// normal startup (because activities expect to go through
// onResume() the first time they run, before their window
// is displayed), and then pausing it.
However, in this case
// we do -not- need to do the full pause cycle (of freezing
// and such) because the activity manager assumes it can just
// retain the current state it has.
try {
r.activity.mCalled = false;
mInstrumentation.callActivityOnPause(r.activity);
// We need to keep around the original state, in case
// we need to be created again.
r.state = oldState;
if (!r.activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onPause()");
}
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
"Unable to pause activity "
+ r.intent.getComponent().toShortString()
+ ": " + e.toString(), e);
}
}
r.paused = true;
}
} else {
// If there was an error, for any reason, tell the activity
// manager to stop us.
try {
ActivityManagerNative.getDefault()
.finishActivity(r.token, Activity.RESULT_CANCELED, null);
} catch (RemoteException ex) {
}
}
}

frameworksbasecorejavaandroidappActivityThread.java#performLaunchActivity()

分析到了这一步之后,Activity就真正的启动起来了。至于其中具体逻辑,且看下篇分解。


private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo,
Context.CONTEXT_INCLUDE_CODE);
}
ComponentName component = r.intent.getComponent();
if (component == null) {
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
}
if (r.activityInfo.targetActivity != null) {
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
}
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);//重要
r.intent.setExtrasClassLoader(cl);
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.makeApplication(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());
if (activity != null) {
ContextImpl appContext = new ContextImpl();//重要
appContext.init(r.packageInfo, r.token, this);
appContext.setOuterContext(activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mConfiguration);
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
activity.attach(appContext, this, getInstrumentation(), r.token,//重要
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstance,
r.lastNonConfigurationChildInstances, config);
if (customIntent != null) {
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstance = null;
r.lastNonConfigurationChildInstances = null;
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
activity.mCalled = false;
mInstrumentation.callActivityOnCreate(activity, r.state);
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onCreate()");
}
r.activity = activity;
r.stopped = true;
if (!r.activity.mFinished) {
activity.performStart();
r.stopped = false;
}
if (!r.activity.mFinished) {
if (r.state != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);//重要
}
}
if (!r.activity.mFinished) {
activity.mCalled = false;
mInstrumentation.callActivityOnPostCreate(activity, r.state);//重要
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onPostCreate()");
}
}
}
r.paused = true;
mActivities.put(r.token, r);
} 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;
}

最后

以上就是妩媚大地为你收集整理的ActivityThread分析—ActivityThread的main方法的执行流程分析前言代码分析的全部内容,希望文章能够帮你解决ActivityThread分析—ActivityThread的main方法的执行流程分析前言代码分析所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(48)

评论列表共有 0 条评论

立即
投稿
返回
顶部