源码在26之后貌似变了一些东西,自己学习,自己记录一下,加深一下理解
首先当你在laucher点击一个应用图标的就会去启动一个app
一个app启动的入口就是这个ActivityThread,实际就是点击图标之后启动一个线程来搞事情,这个线程就是主线程
ActivityThread方法有一个main方法,就是程序的入口了,看一下这个方法都搞了一些什么事情
public static void main(String[] args) {
....
//这一堆是初始化了系统目录等一些东西,从Environment类就可以看出来主要干什么
Environment.initForCurrentUser();
EventLogger.setReporter(new EventLoggingReporter());
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
...
//初始化化主线程的Looper
Looper.prepareMainLooper();
//绑定线程
ActivityThread thread = new ActivityThread();
thread.attach(false);
//主线程处理消息的Handler
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
...
//开启Looper进行无线循环处理
Looper.loop();
...
}
其实启动很简单,就是在主线程初始化一个Looper,然后创建一系列的消息指令放到消息队列,开启looper循环进行处理,复杂的地方全在 thread.attach这个步骤里.
先不去看其他的,先看一下主线程的这个Looper是怎们创建的,我们知道在平时使用Handler的时候不需要创建Looper(UI线程使用),其实就是用为在这个地方进行了初始化,点击方法prepareMainLooper我们查看代码发现这里首先调用了prepare方法,然后直接调用myLooper方法为主线程Looper进行了赋值
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
这俩个方法做了什么呢
prepare方法:
发现一个东西ThreadLocal,ThreadLocal是一个线程安全的包装机制
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
Looper中保存着一个ThreadLocal,首先通过ThreadLocal.get去获取looper,如果获取到了,那么久说明不对头,抛出异常,一个线程只能有一个Looper的,如果没有,那么就为ThreadLocal设置一个Looper进去
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal sThreadLocal = new ThreadLocal();
看下Looper的构造函数,挣了一个消息队列,然后保存当前这个调用他的线程,很简单,
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
然后就是看下mylooper这个方法了
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
再看get方法,这个threadLocal存放着一个map来保存looper,调用get的时候回根据线程来获取相应的looper,所以现在可以知道了,主线程的Looper以及平时可能会在子线程中调用的looper都被存放到这个map中了,现在可以看明白myLooper方法其实就是去获取一下当前线程的looper
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
到这里Looper的相关创建就完成了.
然后就是attach方法,这里面做了大部分主要内容
private void attach(boolean system) {
...
final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
...
}
上面的代码大体可以看出来是做了一个绑定applaction的操作,在api25之前这里获取到的是一个ActivityManager的代理来处理这个问题的,25之后变成了使用AIDL来做处理这个问题,看代码
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
private static final Singleton IActivityManagerSingleton =
new Singleton() {
@Override
protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
ServiceManager.getService方法会经过ServiceManagerNative类的一个内部类代理去获取AMS,最终获取到这个类ActivityManagerService
下一步会调用mgr.attachApplication(mAppThread)这个东西,去AMS中找一下这个方法看看有没有
@Override
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
--------------------------------------------------------------------------------
attachApplicationLocked(thread, callingPid);
------------------------------------------------------------------------------
Binder.restoreCallingIdentity(origId);
}
}
找到如上图一个方法,获取了一下进程,清楚了一下进程的调用标记?好像是这样子额,
然后最主要的是中间代码,看看代码
代码太长了这个方法,几百行代码,掐头去尾,留下中间比较重要的.
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
...
if (app.instr != null) {
thread.bindApplication(processName, appInfo, providers,
app.instr.mClass,
profilerInfo, app.instr.mArguments,
app.instr.mWatcher,
app.instr.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial);
} else {
thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial);
}
...
}
中间着部分代码的前半段貌似做了一些进程的相关操作,后半段做了一些安全的验证,检查下这个进程中是否还遗留一些activity啊,广播啊这类的,这些没有深看,主要看中间代码
IApplicationThread 是个什么,发现这个是个ActivityThread的内部类,并且作为一个final常量被使用,在这个方法中调用了IApplicationThread的bindApplication方法,看方法名应该是个重要操作,绑定Applaction,我们看一下这个方法做了什么
咋一看,哎呀呀好多参数,心理慌得一笔,细看其实就是一个赋值,直到最后一行代码,发现了么,这个里很明显发送了一个消息,去绑定applaction,并把相关的包信息啊什么的传过去,反正经过饶了AMS一圈还是回到了activityThread来处理...
public final void bindApplication(String processName, ApplicationInfo appInfo,
List providers, 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) {
if (services != null) {
// Setup the service cache in the ServiceManager
ServiceManager.initServiceCache(services);
}
setCoreSettings(coreSettings);
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
data.providers = providers;
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;
sendMessage(H.BIND_APPLICATION, data);
}
然后我们找一下handler是怎们处理的,这个方法也比较长,大部分代码为进行一些启动app前的配置操作,比如配置时区啊等等一些根据data的内容进行的,所以我们删除一些不重要的,慢慢看,留下几个看起来有用的代码
private void handleBindApplication(AppBindData data) {
// 将UI线程注册为敏感线程
VMRuntime.registerSensitiveThread();
if (data.trackAllocation) {
DdmVmInternal.enableRecentAllocations(true);
}
...
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName())
.newInstance();
//通过反射初始化一个Instrumentation仪表。
...
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
//通过LoadedApp命令创建Application实例
mInitialApplication = app;
...
mInstrumentation.callApplicationOnCreate(app);
//让仪器调用Application的onCreate()方法
...
}
我们发现在一顿猛如虎的操作者之后有个名字叫mInstrumentation的少年调用了applaction的onCreat方法,只是简单的调用了一下 app.onCreate(),为什么不直接调用呢?
public void callApplicationOnCreate(Application app) {
app.onCreate();
}
我们先看mInstrumentation这个是什么?
Android instrumentation是Android系统里面的一套控制方法或者”钩子“。这些钩子可以在正常的生命周期(正常是由操作系统控制的)之外控制Android控件的运行,其实指的就是Instrumentation类提供的各种流程控制方法.
然后我们继续发现callApplicationOnCreate要一个app参数,这个app是从哪里来的?继续像上看代码发现app产自这么一个方法makeApplication()
看一下这个方法干了什么事情
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
if (mApplication != null) {
return mApplication;
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");
Application app = null;
String appClass = mApplicationInfo.className;
if (forceDefaultAppClass || (appClass == null)) {
appClass = "android.app.Application";
}
try {
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);
}
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
...........
}
发现是由一个叫LoadedApk的类去执行的,这个类是维护这本地已经加载的apk,不管为啥要用它去创建applaction,看这个代码的意思就是如果有这个app就直接返回,没有就用反射创建一个,创建过程又交给了仪表盘mInstrumentation
static public Application newApplication(Class> clazz, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = (Application)clazz.newInstance();
app.attach(context);
return app;
}
简单的反射创建了applaction,整个过程操作犹如猛虎下山,势不可挡啊.
然后就是Application初始化完毕之后会给主线程的handler发送一个启动activity的消息,最终会走这么一个方法
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
创建一个activty
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
reportSizeConfigurations(r);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
}
首先调用performLaunchActivity方法创建一个activity,然后就可以handleResumeActivity,就是可以走onResume方法了
具体看下performLaunchActivity方法
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
.....
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
.....
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
.....
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
....
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
....
}
发现任然是由仪表盘去创建的这个activity,然后做一个attach操作绑定界面,然后就是一些流程控制的操作,callActivityOnCreate,就可以执行activity的oncreat方法了...最后返回一个activity.
mInstrumentation.newActivity来创建activity其实就是一个反射区创建,很简单
基本走到handleResumeActivity方法的时候就没什么了,一个app的启动并展示第一个界面的过程就完成了,总体就是这么一个流程,但是其中还有无数细节待我们慢慢研究啊