1.App的启动流程
每个App都是一个独立的进程,当一个app启动的时候,当前进程也被启动,在Android中有一个类ActivityThread,就是进程的初始类,其中main方法就是整个app的入口。ActivityThread并不是一个线程,它是一个handler类,继承ClientTransactionHandler。
public final class ActivityThread extends ClientTransactionHandler
//继承ClientTransactionHandler类
public abstract class ClientTransactionHandler {
...
}
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
// Install selective syscall interception
AndroidOs.install();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
// Call per-process mainline module initialization.
initializeMainlineModules();
Process.setArgV0("" );
Looper.prepareMainLooper();
// Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
// It will be in the format "seq=114"
long startSeq = 0;
if (args != null) {
for (int i = args.length - 1; i >= 0; --i) {
if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
startSeq = Long.parseLong(
args[i].substring(PROC_START_SEQ_IDENT.length()));
}
}
}
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
每个app进程都有一个主线程,main方法就是通过主线程调用然后执行其中的代码,我们看到main方法中其实内容并不多,大部分是一些初始化的操作,那么app的启动是怎么做到的呢?
其实像App的启动、Activity的启动等,都是依赖系统服务完成,也就是说,ActivityThead是要和系统服务打交道,然后做启动操作,那么ActivityThead是如何和系统服务通信的呢?
1.1 ApplicationThread
在ActivityThead中有一个成员变量ApplicationThread,ApplicationThread就是ActivityThread与ActivityManagerService通信的桥梁,ActivityThread接收ActivityManagerService的命令做对应的操作。
当ActivityThead想要启动MainActivity时,会先通过ApplicationThread向AMS请求,AMS中存在ApplicationThread的代理,通过ApplicationThread回调给到ActivityThread做响应的处理操作,熟悉aidl流程的话这个也不难理解。
1.2 Instrumentation
如果知道Activity启动流程的话,对于这个类也不会陌生,这个类就是用于真正管理Application和Activity声明周期的类。
1.3 ActivityThread
当主线程执行main方法时,其实ActivityThread并没有创建,当执行到下面两行时,ActivityThread才真正创建完成。
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
public static void main(String[] args) {
...
initializeMainlineModules();
Process.setArgV0("" );
//初始化handler中的looper对象
Looper.prepareMainLooper();
long startSeq = 0;
if (args != null) {
for (int i = args.length - 1; i >= 0; --i) {
if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
startSeq = Long.parseLong(
args[i].substring(PROC_START_SEQ_IDENT.length()));
}
}
}
//创建一个activityThread,main是静态方法,调用时activityThread并没有创建
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
//位于Looper.java中
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
//将主线程赋值给sMainLooper,这就是为什么通过Looper.getMainLooper获取到主线程的原因
sMainLooper = myLooper();
}
}
我们可以看到,在main方法中初始化了MainLooper,这个MainLooper会一直从主线程的MessageQueue中取出消息处理消息,保证程序的运行。所以ActivityThread是一个handler,不停的接收AMS或者PMS发来的信息,进行操作处理。ActivityThread操作的线程可以理解成主线程,也就是我们的UI线程。
所以,当我们的app启动之后,第一步就是创建Application,当然这不是在ActivityThread中直接new Application这么简单,而是需要ActivityThread与AMS通信,获取Application的信息,从而创建Application。
所以接下来,看下attach的源码:
private void attach(boolean system, long startSeq) {
sCurrentActivityThread = this;
mConfigurationController = new ConfigurationController(this);
mSystemThread = system;
if (!system) {
RuntimeInit.setApplicationObject(mAppThread.asBinder());
//关键点①
final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
// Watch for getting close to heap limit.
BinderInternal.addGcWatcher(new Runnable() {
@Override public void run() {
if (!mSomeActivitiesChanged) {
return;
}
Runtime runtime = Runtime.getRuntime();
long dalvikMax = runtime.maxMemory();
long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
if (dalvikUsed > ((3*dalvikMax)/4)) {
if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
+ " total=" + (runtime.totalMemory()/1024)
+ " used=" + (dalvikUsed/1024));
mSomeActivitiesChanged = false;
try {
ActivityTaskManager.getService().releaseSomeActivities(mAppThread);
} catch (RemoteException e) {
throw e.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.makeApplication(true, null);
mInitialApplication.onCreate();
} catch (Exception e) {
throw new RuntimeException(
"Unable to instantiate Application():" + e.toString(), e);
}
}
ViewRootImpl.ConfigChangedCallback configChangedCallback = (Configuration globalConfig) -> {
synchronized (mResourcesManager) {
// TODO (b/135719017): Temporary log for debugging IME service.
if (Build.IS_DEBUGGABLE && mHasImeComponent) {
Log.d(TAG, "ViewRootImpl.ConfigChangedCallback for IME, "
+ "config=" + globalConfig);
}
// We need to apply this change to the resources immediately, because upon returning
// the view hierarchy will be informed about it.
if (mResourcesManager.applyConfigurationToResources(globalConfig,
null /* compat */,
mInitialApplication.getResources().getDisplayAdjustments())) {
mConfigurationController.updateLocaleListFromAppContext(
mInitialApplication.getApplicationContext());
// This actually changed the resources! Tell everyone about it.
final Configuration updatedConfig =
mConfigurationController.updatePendingConfiguration(globalConfig);
if (updatedConfig != null) {
sendMessage(H.CONFIGURATION_CHANGED, globalConfig);
mPendingConfiguration = updatedConfig;
}
}
}
};
ViewRootImpl.addConfigCallback(configChangedCallback);
}
关键点①:获取AMS的代理对象
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
@UnsupportedAppUsage
private static final Singleton<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@Override
protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
我们可以看到,getService方法就是从ServiceManager中获取AMS,最终拿到的是AMS的代理对象(跨进程),调用attachApplication方法,传入了ApplicationThread对象,那么我们可以看一下AMS中的attachApplication方法。
//位于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);
}
}
在AMS的attachApplication当中,会调用attachApplicationLocked方法,首先会初始化当前 进程的信息,记录在ProcessRecord类中,然后调用ApplicationThread的bindApplication,将进程的信息回调到ActivityThread。
# ActivityManagerService # attachApplicationLocked
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
ProcessRecord app;
... //初始化进程信息
final ProviderInfoList providerList = ProviderInfoList.fromList(providers);
if (app.getIsolatedEntryPoint() != null) {
// This is an isolated process which should just call an entry point instead of
// being bound to an application.
thread.runIsolatedEntryPoint(
app.getIsolatedEntryPoint(), app.getIsolatedEntryPointArgs());
} else if (instr2 != null) {
thread.bindApplication(processName, appInfo, 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);
} else {
thread.bindApplication(processName, appInfo, 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);
}
if (profilerInfo != null) {
profilerInfo.closeFd();
profilerInfo = null;
}
return true;
}
bindApplication的关键就是最后一行,发送BIND_APPLICATION消息到MessageQueue
//位于ActivityThread.java中
public final void bindApplication(String processName, ApplicationInfo appInfo,
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) {
...
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
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;
//代码关键
sendMessage(H.BIND_APPLICATION, data);
}
//位于ActivityThread.java中
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) {
...
try {
//通过类加载器创建Instrumentation
final ClassLoader cl = instrContext.getClassLoader();
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
} catch (Exception e) {
throw new RuntimeException(
"Unable to instantiate instrumentation "
+ data.instrumentationName + ": " + e.toString(), e);
}
Application app;
// 创建application对象,makeApplication也是通过类加载器和反射机制来创建的
app = data.info.makeApplication(data.restrictedBackupMode, null);
// Propagate autofill compat state
app.setAutofillOptions(data.autofillOptions);
// Propagate Content Capture options
app.setContentCaptureOptions(data.contentCaptureOptions);
mInitialApplication = app;
//调用application的onCreate方法
mInstrumentation.callApplicationOnCreate(app);
至此,Application已经启动,也就意味着当前app已经启动了。
其实整个流程每个类的分工都很明朗。AMS中属于数据管理者,管理Application和activity的数据;ApplicationThread属于桥梁传输AMS中的数据到ActivityThread中;ActivityThread负责执行任务;Instrumentation是Application和activity管理工具,供ActivityThread调用。
2 Activity的创建流程
接着回到AMS的attachApplicationLocked方法中,在Application启动之后,调用了ActivityTaskManagerInternal的attachApplication方法
// See if the top visible activity is waiting to run in this process...
if (normalMode) {
try {
didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true;
}
}
先看一下ActivityTaskManagerInternal这个类,看字面意思是Activity的任务管理类,这是一个抽象类,具体实现是LocalService
mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
//位于frameworks\base\services\core\java\com\android\server\wm\ActivityTaskManagerService.java
@HotPath(caller = HotPath.PROCESS_CHANGE)
@Override
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);
}
}
接着调用RootWindowContainer.attachApplication
boolean attachApplication(WindowProcessController app) throws RemoteException {
final String processName = app.mName;
boolean didSomething = false;
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
//DisplayContent代表一块屏幕
final DisplayContent display = getChildAt(displayNdx);
//拿到activity的栈
final ActivityStack stack = display.getFocusedStack();
if (stack == null) {
continue;
}
mTmpRemoteException = null;
mTmpBoolean = false; // Set to true if an activity was started.
//遍历ActivityStack下的所有ActivityRecord,ActivityStack便是解析apk中的xml中activity创建的,里面存放activity的信息。
//以其为参数调用startActivityForAttachedApplicationIfNeeded方法
//stack.topRunningActivity()表示从栈里拿到的第一个activity
final PooledFunction c = PooledLambda.obtainFunction(
RootWindowContainer::startActivityForAttachedApplicationIfNeeded, this,
PooledLambda.__(ActivityRecord.class), app, stack.topRunningActivity());
//遍历所有的ActivityRecord ,并执行startActivityForAttachedApplicationIfNeeded
stack.forAllActivities(c);
c.recycle();
if (mTmpRemoteException != null) {
throw mTmpRemoteException;
}
didSomething |= mTmpBoolean;
}
if (!didSomething) {
ensureActivitiesVisible(null, 0, false /* preserve_windows */);
}
return didSomething;
}
ActivityRecord 只是一个activity的数据存储类,里面有activity的各种数据,并不是一个真正的activity。
//ActivityRecord r便是每个activity的ActivityRecord
private boolean startActivityForAttachedApplicationIfNeeded(ActivityRecord r,
WindowProcessController app, ActivityRecord top) {
if (r.finishing || !r.okToShowLocked() || !r.visibleIgnoringKeyguard || r.app != null
|| app.mUid != r.info.applicationInfo.uid || !app.mName.equals(r.processName)) {
return false;
}
try {
if (mStackSupervisor.realStartActivityLocked(r, app, top == r /*andResume*/,
true /*checkConfig*/)) {
mTmpBoolean = true;
}
}
...
return false;
}
调用realStartActivityLocked方法,
boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
boolean andResume, boolean checkConfig) throws RemoteException {
...
// 创建启动activity的事务
//proc.getThread()即activitythread中的applicationThread
final ClientTransaction clientTransaction = ClientTransaction.obtain(
proc.getThread(), r.appToken);
final DisplayContent dc = r.getDisplay().mDisplayContent;
//给事务设置回调,后面要用到
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.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),
r.getSavedState(), r.getPersistentSavedState(), results, newIntents,
dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded(),
r.assistToken, r.createFixedRotationAdjustmentsIfNeeded()));
}
// 提交事务
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
//位于com\android\server\wm\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();
}
}
//位于android\app\servertransaction\ClientTransaction.java
public void schedule() throws RemoteException {
mClient.scheduleTransaction(this);//这里的mClient即activityThread中的ApplicationThread,this表示
}
ActivityThread中没有scheduleTransaction方法,故调用父类ClientTransactionHandler的方法
//位于android\app\ActivityThread.java
public abstract class ClientTransactionHandler {
// Schedule phase related logic and handlers.
/** Prepare and schedule transaction for execution. */
void scheduleTransaction(ClientTransaction transaction) {
transaction.preExecute(this);
sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);//调用sendMessage
}
}
sendMessage发送EXECUTE_TRANSACTION后,调用到activityThread中的handleMessage中
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();
}
// TODO(lifecycler): Recycle locally scheduled transactions.
break;
//位于android\app\servertransaction\TransactionExecutor.java
public void execute(ClientTransaction transaction) {
......
//调用事务
executeCallbacks(transaction);
executeLifecycleState(transaction);
mPendingActions.clear();
if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "End resolving transaction");
}
public void executeCallbacks(ClientTransaction transaction) {
//获取transaction的callback
final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
final IBinder token = transaction.getActivityToken();
ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
final ActivityLifecycleItem finalStateRequest = transaction.getLifecycleStateRequest();
final int finalState = finalStateRequest != null ? finalStateRequest.getTargetState()
: UNDEFINED;
// Index of the last callback that requests some post-execution state.
final int lastCallbackRequestingState = lastCallbackRequestingState(transaction);
final int size = callbacks.size();
for (int i = 0; i < size; ++i) {
//取出一个个callback,即LaunchActivityItem,它继承ClientTransactionItem。
final ClientTransactionItem item = callbacks.get(i);
final int postExecutionState = item.getPostExecutionState();
final int closestPreExecutionState = mHelper.getClosestPreExecutionState(r,
item.getPostExecutionState());
if (closestPreExecutionState != UNDEFINED) {
cycleToPath(r, closestPreExecutionState, transaction);
}
//调用LaunchActivityItem的execute
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);
}
if (postExecutionState != UNDEFINED && r != null) {
// Skip the very last transition and perform it by explicit state request instead.
final boolean shouldExcludeLastTransition =
i == lastCallbackRequestingState && finalState == postExecutionState;
cycleToPath(r, postExecutionState, shouldExcludeLastTransition, transaction);
}
}
}
//位于android\app\servertransaction\LaunchActivityItem.java
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
//这是activity客户端的记录类,用于activity的实例化
ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
mPendingResults, mPendingNewIntents, mIsForward,
mProfilerInfo, client, mAssistToken, mFixedRotationAdjustments);
//然后回调给activityThread,client就是activityThread
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
最终还是回调到了ActivityThread的handleLaunchActivity方法,在这个方法中,调用了performLaunchActivity
//位于android/app/ActivityThread.java
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
.....
final Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfigurationController.getConfiguration());
reportSizeConfigurations(r);
if (!r.activity.mFinished && pendingActions != null) {
pendingActions.setOldState(r.state);
pendingActions.setRestoreInstanceState(true);
pendingActions.setCallOnPostCreate(true);
}
} else {
// If there was an error, for any reason, tell the activity manager to stop us.
ActivityClient.getInstance().finishActivity(r.token, Activity.RESULT_CANCELED,
null /* resultData */, Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
}
return a;
}
在performLaunchActivity中,是通过Instrumentation类的newActivity方法,创建了一个Activity实例,看到这里是不是跟Application的很类似.Activity创建完成之后,就需要启动Activity,启动Activity还是调用了Instrumentation的callActivityOnCreate方法
//位于android/app/ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
Activity activity = null;
try {
//通过反射创建activity
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();
if (r.state != null) {
r.state.setClassLoader(cl);
}
}
...
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
...
}
结合Application和Activity的创建启动流程:
AMS的主要职责就是初始化Application和Activity需要的数据,封装成对象,为他们的创建做准备,然后回调到ActivityThread;
ApplicationThread的主要职责就是作为ActivityThread和AMS通信桥梁;
ActivityThread的主要职责就是处理AMS发送来的请求;
Instrumentation的主要职责就是创建Application或者Activity,并启动他们。
3 UI的绘制流程
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
conn = new MyServiceConnection();
}
...
}
当Activity启动之后,会执行onCreate方法,在onCreate方法中,调用setContentView.
如下:
//位于frameworks\base\core\java\android\app\Activity.java
public void setContentView(View view, ViewGroup.LayoutParams params) {
getWindow().setContentView(view, params);
initWindowDecorActionBar();
}
public Window getWindow() {
return mWindow;
}
//解释:getWindow()这里返回一个Window。
widndow.java是一个抽象类,具有唯一的实现类
//位于frameworks\base\core\java\android\view\Window.java
public abstract class Window {
...
public abstract void setContentView(@LayoutRes int layoutResID);
...
}
1、DecorView 在一般情况下,内部会包含一个竖直的 LInearLayout,里面有上下两部分(具体情况和安卓版本和主题有关),上面是标题栏,下面是内容,内容布局有一个默认的 id: content。
2、DecorView 继承自 FrameLayout,是一个 ViewGroup。在整个 ViewTree 中, DecorView 是整个 ViewTree 的顶层 View。View 的所有事件,都先经过 DecorView,然后再传递给 View
我们在 Activity 中 通过 setContentView() 方法设置的布局,其实就是添加到了内容部分里。如果我们想获取到内容布局的话,可以通过如下方法获取:
DecorView:最顶层的View,在PhoneWindow中,可以看做整个Activity的装饰器;
mContentParent:布局容器,用于放置内容视图,要么是mDecor自身,或者mDecor的子集
ViewGroup content = (ViewGroup) findViewById(android.R.id.content);
View childAt = content.getChildAt(0);
//位于frameworks\base\core\java\com\android\internal\policy\PhoneWindow.java
public class PhoneWindow extends Window implements MenuBuilder.Callback {
//这是窗口的顶层试图,包含所有的窗口装饰
private DecorView mDecor;
//布局容器
ViewGroup mContentParent;
public void setContentView(int layoutResID) {
// 第一次创建的时候肯定为空
if (mContentParent == null) {
// 初始化顶层布局
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
//
}
# PhoneWindow # installDecor
private void installDecor() {
mForceDecorInstall = false;
//初始化DecorView
if (mDecor == null) {
mDecor = generateDecor(-1);//这里面new了一个DecorView
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
// 初始化 mContentParent
mContentParent = generateLayout(mDecor);
......
}
}
初始化DecorView很简单,就是new DecorView然后返回,如果DecorView不为空,那么就将其放到PhoneWindow中。
接下来是对mContentParent的初始化,如果mContentParent是空的,那么就调用generateLayout方法(篇幅太长了,做了删减);
一开始就获取window窗体的属性,然后做一些配置,例如是不是悬浮、是否沉浸式布局、是否有ActionBar等,然后做完属性配置之后,开始装饰DecorView
//位于com/android/internal/policy/PhoneWindow.java
protected ViewGroup generateLayout(DecorView decor) {
// Apply data from current theme.
TypedArray a = getWindowStyle();
mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);
int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
& (~getForcedWindowFlags());
if (mIsFloating) {
setLayout(WRAP_CONTENT, WRAP_CONTENT);
setFlags(0, flagsToUpdate);
} else {
setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);
getAttributes().setFitInsetsSides(0);
getAttributes().setFitInsetsTypes(0);
}
// Inflate the window decor.
//装饰DecorView
int layoutResource;//表示一个资源的ID,根据主题加载不同的xml
int features = getLocalFeatures();
//下面加载系统布局,
if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogTitleIconsDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
layoutResource = R.layout.screen_title_icons;
}
// XXX Remove this once action bar supports these features.
removeFeature(FEATURE_ACTION_BAR);
// System.out.println("Title Icons!");
} else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
&& (features & (1 << FEATURE_ACTION_BAR)) == 0) {
// Special case for a window with only a progress bar (and title).
// XXX Need to have a no-title version of embedded windows.
layoutResource = R.layout.screen_progress;
// System.out.println("Progress!");
} else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
// Special case for a window with a custom title.
// If the window is floating, we need a dialog layout
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogCustomTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
layoutResource = R.layout.screen_custom_title;
}
// XXX Remove this once action bar supports these features.
removeFeature(FEATURE_ACTION_BAR);
} else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
// If no other features and not embedded, only need a title.
// If the window is floating, we need a dialog layout
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
layoutResource = a.getResourceId(
R.styleable.Window_windowActionBarFullscreenDecorLayout,
R.layout.screen_action_bar);
} else {
layoutResource = R.layout.screen_title;
}
// System.out.println("Title!");
} else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
layoutResource = R.layout.screen_simple_overlay_action_mode;
} else {
// Embedded, so no decoration is needed.
layoutResource = R.layout.screen_simple;
// System.out.println("Simple!");
}
mDecor.startChanging();
//将加载到的基础布局添加到mDecor里面
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
//初始化mContentParent完成
//通过系统的content的资源ID去进行实例化这个控件,这个控件就是R.layout.screen_simple布局中的一个帧布局,id是content。int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
if (contentParent == null) {
throw new RuntimeException("Window couldn't find content container view");
}
......
return contentParent;
}
首先声明一个layoutResource变量,这里会做多级的判断,给layoutResource赋值,一般情况下都是R.layout.screen_simple这个布局。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<ViewStub android:id="@+id/action_mode_bar_stub"
android:inflatedId="@+id/action_mode_bar"
android:layout="@layout/action_mode_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="?attr/actionBarTheme" />
<FrameLayout
android:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foregroundInsidePadding="false"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>
当我们新建一个工程,默认的界面就是一个状态栏ActionBar和空白容器,就是这个布局,调用DecorView的onResourcesLoaded方法。
//位于com/android/internal/policy/DecorView.java
void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
if (mBackdropFrameRenderer != null) {
loadBackgroundDrawablesIfNeeded();
mBackdropFrameRenderer.onResourcesLoaded(
this, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState),
getCurrentColor(mNavigationColorViewState));
}
mDecorCaptionView = createDecorCaptionView(inflater);
// 把传进来的layoutResource布局进行解析并渲染
final View root = inflater.inflate(layoutResource, null);
if (mDecorCaptionView != null) {
if (mDecorCaptionView.getParent() == null) {
addView(mDecorCaptionView,
new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
mDecorCaptionView.addView(root,
new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
} else {
// Put it below the color views.
addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
mContentRoot = (ViewGroup) root;
initializeElevation();
}
在这个方法中,其实就是调用LayoutInflater的inflate方法,将这个布局加载到DecorView中;
至此mDecor的资源加载完毕。
然后findViewById拿到一个ViewGroup,这个控件就是R.layout.screen_simple布局中的一个帧布局,id是content,也就是说,mContentParent就是这个帧布局。
至此,setContentView函数中的installDecor已经完成。其实主要做了两件事:
1.mDecor初始化
2.mContentParent 初始化
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
//加载自己的布局
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
installDecor中当基础布局加载完成之后,开始加载我们自己的布局,调用LayoutInflater的inflate方法,将布局加载到mContentParent中。
# PhoneWindow
mLayoutInflater.inflate(layoutResID, mContentParent);
//位于android/view/LayoutInflater.java
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
View view = tryInflatePrecompiled(resource, res, root, attachToRoot);
if (view != null) {
return view;
}
//解析xml
XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
//位于android/view/LayoutInflater.java
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");
final Context inflaterContext = mContext;
final AttributeSet attrs = Xml.asAttributeSet(parser);
Context lastContext = (Context) mConstructorArgs[0];
mConstructorArgs[0] = inflaterContext;
View result = root;
//将自己定义的布局,加到mContentParent中
root.addView(temp, params);
return result;
}
}
总结一下,UI的加载流程:
当调用setContentView时(拿Activity为例),会调用PhoneWindow的setContentView方法,首先会进行初始化操作;
先初始化DecorView,然后初始化mContentParent;
在初始化mContentParent时,首先会窗体做一些基础配置(是否沉浸式、是否有ActionBar等),然后加载基础布局(R.layout.screen_simple)到DecorView中,通过findViewById拿到基础布局中id为content的帧布局,作为mContentParent的初始化结果;
最后,加载我们自己的布局,通过inflate方法,将自己的布局加载到mContentParent中
3 UI绘制流程
在onCreate方法中,主要做的工作就是将我们自己的写的XML布局,加载到了DecorView当中,其实这只是一个开始,还需要对布局进行测试绘制,才能展示到手机上,这个过程,是在onResume生命周期中完成。
之前在创建Activity的时候,通过handleLaunchActivity方法,所以,如果调用Activity的onResume,那么就是调用handleResumeActivity方法,这个过程也是ActivityThread跟AMS通信完成,通过ApplicationThread回调。
public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
boolean isForward, String reason) {
...
final Activity a = r.activity;
...
if (r.window == null && !a.mFinished && willBeVisible) {
//获取Activity的PhoneWindow
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
//获取WindowManager对象 WindowManagerImpl
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
......
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
//调用绘制
wm.addView(decor, l);
} else {
a.onWindowAttributesChanged(l);
}
}
} else if (!willBeVisible) {
if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
r.hideForNow = true;
}
......
r.nextIdle = mNewActivities;
mNewActivities = r;
if (localLOGV) Slog.v(TAG, "Scheduling idle handler for " + r);
Looper.myQueue().addIdleHandler(new Idler());
}
在handleResumeActivity中,会获取Activity的相关信息,例如拿到PhoneWindow对象、DecorView等,然后获取WindowManager对象,如果做过悬浮窗相关需求的伙伴,应该对这个很熟悉,当一个应用想要悬浮在其他应用之上时,就需要在WindowManager中添加view;
//位于android/view/WindowManagerImpl.java
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
mContext.getUserId());
}
一个windowmanager对应多个activity,将每个activity的view,ViewRootImpl,wparams保存在WindowManagerGlobal中。
//位于android/view/WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow, int userId) {
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
...
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
try {
root.setView(view, wparams, panelParentView, userId);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
//位于android/view/ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
int userId) {
synchronized (this) {
if (mView == null) {
mView = view;
mAttachInfo.mDisplayState = mDisplay.getState();
mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
mFallbackEventHandler.setView(view);
mWindowAttributes.copyFrom(attrs);
requestLayout();
InputChannel inputChannel = null;
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
inputChannel = new InputChannel();
}
mForceDecorViewVisibility = (mWindowAttributes.privateFlags
& PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
adjustLayoutParamsForCompatibility(mWindowAttributes);
res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mDisplayCutout, inputChannel,
mTempInsets, mTempControls);
setFrame(mTmpFrame);
} catch (RemoteException e) {
mAdded = false;
mView = null;
mAttachInfo.mRootView = null;
inputChannel = null;
mFallbackEventHandler.setView(null);
unscheduleTraversals();
setAccessibilityFocus(null, null);
throw new RuntimeException("Adding window failed", e);
} finally {
if (restore) {
attrs.restore();
}
}
}
}
首先,调用requestLayout
requestLayout,从字面意思上来看,就是请求重新布局,也就是说每当有一个新的View添加到容器之后,都会重新测量布局。
//android/view/ViewRootImpl.java
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
这里有个标志位mHandlingLayoutInLayoutRequest,在performLayout时会被设置为true,也就说这里会判断当前是都正在绘制测量,如果没有,核心在于scheduleTraversals方法.
# ViewRootImpl # scheduleTraversals
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
在scheduleTraversals方法中,通过Handler是启动了一个线程mTraversalRunnable,执行了doTraversal方法,然后在doTraversal方法中,执行了performTraversals方法。
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
performTraversals方法中内容太多,就不再粘贴代码,只展示核心方法流程
// Ask host how big it wants to be
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
performLayout(lp, mWidth, mHeight);
performDraw();
其中performMeasure,最终调用了View的measure方法测量子View的大小;performLayout、performDraw同理。
其中
...
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
...
mWidth和mHeight是父类传下来的数据,放到MeasureSpec中
private static int getRootMeasureSpec(int windowSize, int rootDimension) {
//构建一个测量对象
int measureSpec;
switch (rootDimension) {
case ViewGroup.LayoutParams.MATCH_PARENT:
measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
break;
case ViewGroup.LayoutParams.WRAP_CONTENT:
// Window can resize. Set max size for root view.
measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
break;
default:
// Window wants to be an exact size. Force root view to be that size.
measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
break;
}
return measureSpec;
}
其实MeasureSpec是View的一个内部类,真正的身份就是帮助View完成测量功能。MeasureSpec类中最主要的部分由5个变量和3个方法组成,接下来根据原码中的代码慢慢一层层剖析。其是由高两位的mode和低30位的size组成的32位的一个int值。
五个成员变量:
private static final int MODE_SHIFT = 30;
private static final int MODE_MASK = 0x3 << MODE_SHIFT;
public static final int UNSPECIFIED = 0 << MODE_SHIFT;
public static final int EXACTLY = 1 << MODE_SHIFT;
public static final int AT_MOST = 2 << MODE_SHIFT;
三个方法
public static int makeMeasureSpec( int size,int mode) {
if (sUseBrokenMakeMeasureSpec) {
return size + mode;
} else {
return (size & ~MODE_MASK) | (mode & MODE_MASK);
}
}
@MeasureSpecMode
public static int getMode(int measureSpec) {
//noinspection ResourceType
return (measureSpec & MODE_MASK);
}
public static int getSize(int measureSpec) {
return (measureSpec & ~MODE_MASK);
}
private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
try {
//mView就是decorview
mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}