该篇是Android启动系列的最后一篇,本文从应用进程的创建启动角度出发,分析ActivityThread是如何创建的。相对于上篇,本文内容较少,阅读无压力~
从接触Android的那一刻开始,看到最多的是:耗时任务不能在主线程执行,UI操作要在主线程执行……当时人傻无知,从来没有想过什么是主线程,为啥不能在主线程做耗时任务等等。
大家都说ActivityThread是主线程,那它是线程吗?它为什么被称为主线程?它做啥了?
回顾
在上文《沉思曲:Activity启动》一文中,分析了Activity的启动过程。并在调用startSpecificActivityLocked方法时,提到这里会判断目的Activity进程是否存在,如果不存在,就会创建新进程,本文就从这个创建新进程的分支开始。
创建应用进程
先回顾下startSpecificActivityLocked方法
该方法在ActivityStackSupervisor.java中
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
//获取待启动Activity的进程信息
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);
r.task.stack.setLaunchTime(r);
//待启动Activity所在进程存在
if (app != null && app.thread != null) {
try {
app.addPackage(r.info.packageName, mService.mProcessStats);
//接着往下执行
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
}
//待启动Activity所在进程不存在,为其创建新进程
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);
}
- 上方法中,如果目的Activity所在进程不存在,调用AMS的startProcessLocked方法创建目的应用进程。
1.1、startProcessLocked
startProcessLocked定义在ActivityManagerService.java中,该方法会调用Process的start方法。
// Start the process. It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.
Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, null);
- 该方法调用Process的start方法,注意传入参数:<u>"android.app.ActivityThread"</u>
1.2、 start | Process.java
/**
* Start a new process.
*
* <p>If processes are enabled, a new process is created and the
* static main() function of a <var>processClass</var> is executed there.
* The process will continue running after this function returns.
*
* <p>If processes are not enabled, a new thread in the caller's
* process is created and main() of <var>processClass</var> called there.
*
* <p>The niceName parameter, if not an empty string, is a custom name to
* give to the process instead of using processClass. This allows you to
* make easily identifyable processes even if you are using the same base
* <var>processClass</var> to start them.
*
* @param processClass The class to use as the process's main entry
* point.
* @param niceName A more readable name to use for the process.
* @param uid The user-id under which the process will run.
* @param gid The group-id under which the process will run.
* @param gids Additional group-ids associated with the process.
* @param debugFlags Additional flags.
* @param targetSdkVersion The target SDK version for the app.
* @param seInfo null-ok SE Android information for the new process.
* @param zygoteArgs Additional arguments to supply to the zygote process.
*
* @return An object that describes the result of the attempt to start the process.
* @throws RuntimeException on fatal start failure
*
* {@hide}
*/
public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String[] zygoteArgs) {
try {
//通过Zygote启动新进程
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
throw new RuntimeException(
"Starting VM process through Zygote failed", ex);
}
}
从注释可知,该方法用来启动一个新进程:
- 如果进程启动,则processClass(此处入参为“android.app.ActivityThread”)会运行在该新进程中,并且在该方法调用完成后,新进程会继续运行。
- 如果进程未启动,则调用该start方法所在的进程会创建一个新的线程,然后processClass运行在该新线程中。
方法调用startViaZygote方法,从方法名看出,进程创建似乎是要交给zygote。
1.3、startViaZygote | Process.java
private static ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String[] extraArgs)
throws ZygoteStartFailedEx {
synchronized(Process.class) {
//启动新进程的参数
ArrayList<String> argsForZygote = new ArrayList<String>();
//添加各种参数到argsForZygote
argsForZygote.add("--runtime-init");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
...
if (niceName != null) {
argsForZygote.add("--nice-name=" + niceName);
}
if (seInfo != null) {
argsForZygote.add("--seinfo=" + seInfo);
}
argsForZygote.add(processClass);
...
//调用该方法,由zygote创建进程,并获取新进程信息
return zygoteSendArgsAndGetResult(argsForZygote);
}
}
这个方法设置启动新进程所需参数,并往下调用zygoteSendArgsAndGetResult方法。
1.4、zygoteSendArgsAndGetResult | Process.java
private static ProcessStartResult zygoteSendArgsAndGetResult(ArrayList<String> args)
throws ZygoteStartFailedEx {
//进程通信,连接到Zygote的Server Socket,交由Zygote创建
openZygoteSocketIfNeeded();
try {
//sZygoteWriter将参数发送到Server Socket
sZygoteWriter.write(Integer.toString(args.size()));
sZygoteWriter.newLine();
int sz = args.size();
for (int i = 0; i < sz; i++) {
String arg = args.get(i);
if (arg.indexOf('\n') >= 0) {
throw new ZygoteStartFailedEx(
"embedded newlines not allowed");
}
sZygoteWriter.write(arg);
sZygoteWriter.newLine();
}
sZygoteWriter.flush();
//sZygoteInputStream从Server Socket读取结果
ProcessStartResult result = new ProcessStartResult();
result.pid = sZygoteInputStream.readInt();
...
result.usingWrapper = sZygoteInputStream.readBoolean();
return result;
...
}
从方法名可以猜出该方法大致干啥了:发送启动参数给Zygote进程,交由Zygote进程启动,并获得启动结果。看下是否如此:
1、调用openZygoteSocketIfNeeded方法。
2、调用sZygoteWriter往ServerSocket写创建进程所需要的参数,ServerSocket是啥?
3、创建ProcessStartResult,并写入从ServerSocket读取的数据,作为结果返回。
看来重点在openZygoteSocketIfNeeded方法!
1.5、openZygoteSocketIfNeeded | Process.java
private static void openZygoteSocketIfNeeded()
throws ZygoteStartFailedEx {
//重连次数
int retryCount;
if (sPreviousZygoteOpenFailed) {
retryCount = 0;
} else {
retryCount = 10;
}
for (int retry = 0
; (sZygoteSocket == null) && (retry < (retryCount + 1))
; retry++ ) {
...
try {
//client socket
sZygoteSocket = new LocalSocket();
//连接到Zygote的server socket
sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET,
LocalSocketAddress.Namespace.RESERVED));
//sZygoteInputStream负责读取server socket信息
sZygoteInputStream
= new DataInputStream(sZygoteSocket.getInputStream());
//sZygoteWriter发送信息到server socket
sZygoteWriter =
new BufferedWriter(
new OutputStreamWriter(
sZygoteSocket.getOutputStream()),
256);
sPreviousZygoteOpenFailed = false;
break;
...
}
详细大家都能一眼看懂,这不是Java中的Socket的连接吗,这不过这里是用来进程连接。
1、创建Client Socket:sZygoteSocket
2、ClientSocket连接到服务端,ServerSocket:ZYGOTE_SOCKET
3、创建输入流负责从ServerSocket读数据,创建输出流向ServerSocket写数据。
即:
- openZygoteSocketIfNeeded方法负责连接到Zygote的Server Socket,并发送/读取Server Socket的信息。
- ServerSocket即ZYGOTE_SOCKET,它有Zygote进程创建。
既然client socket连接到Zygote的创建的ServerSocket了,那接下来看下Zygote是如何处理连接的。
Zygote处理客户端连接
Zygote进程由init进程启动,Zygote的实现在ZygoteInit.java中,其main方法调用标志着Zygote的启动。
2.1、main | ZygoteInit.java
public static void main(String argv[]) {
try {
//注册server socket
//其它进程的创建,通过连接到该Socket后,由zygote孵化出来
registerZygoteSocket();
...
//预加载android framework类和资源
preload();
...
if (argv[1].equals("start-system-server")) {
//启动SystemServer
startSystemServer();
} else if (!argv[1].equals("")) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}
//死循环接收client socket连接,由此创建新进程
runSelectLoop();
closeServerSocket();
} catch (MethodAndArgsCaller caller) { //标注加红,这个异常捕获是重点!!!
caller.run();
} catch (RuntimeException ex) {
closeServerSocket();
throw ex;
}
}
- Zygote进程启动时,注册了ServerSocket,即上面提到的ZYGOTE_SOCKET,就是它来处理client socket的连接。
- Zygote进程启动时还启动了SystemServer,这在第一篇文章中已经分析过了。
- 最后调用runSelectLoop方法,死循环处理client socket连接。
最后需要注意的是:
main方法采用了try-catch的方式,其中捕获了异常MethodAndArgsCaller。由后面代码可知,通过这种抛异常的方式,使进程跳出死循环,并执行caller.run方法。
2.2、runSelectLoop | ZygoteInit.java
上面方法调用runSelectLoop,死循环处理client连接,看下其内容。
private static void runSelectLoop() throws MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
//client socket连接列表
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
FileDescriptor[] fdArray = new FileDescriptor[4];
//将server socket添加到fds中
fds.add(sServerSocket.getFileDescriptor());
peers.add(null);
int loopCount = GC_LOOP_COUNT;
while (true) {
int index;
...
try {
//将fds转换成数组
fdArray = fds.toArray(fdArray);
//在fdArray中找到可读的连接
index = selectReadable(fdArray);
} catch (IOException ex) {
throw new RuntimeException("Error in select()", ex);
}
if (index < 0) {
throw new RuntimeException("Error in select()");
} else if (index == 0) {
//第一个为Server socket,此时等待client socket连接
ZygoteConnection newPeer = acceptCommandPeer();
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
boolean done;
//处理连接
done = peers.get(index).runOnce();
//处理完连接,从列表中移除
if (done) {
peers.remove(index);
fds.remove(index);
}
}
}
}
代码逻辑还是比较清楚:
- Zygote死循环处理已连接的client socket,client的连接封装成ZygoteConnection 表示,并调用其的runOnce()方法。
- 如果已连接的client socket都处理完成,那就等待新的client连接。
2.3、runOnce | ZygoteConnection.java
看下连接的处理方法runOnce():
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;
try {
//读取client socket传入的参数列表
args = readArgumentList();
descriptors = mSocket.getAncillaryFileDescriptors();
}
...
try {
//转换参数
parsedArgs = new Arguments(args);
...
//Zygote创建 新进程并负责虚拟机实例到该进程
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName);
}
...
try {
//新进程
if (pid == 0) {
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
//新进程中调用
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
return true;
}
...
}
要划重点了:
1、该方法读取client socket连接时传入的参数,并封装。
2、调用Zygote的forkAndSpecialize创建指定进程。
3、pid=0时即子进程,在子进程中调用handleChildProc方法。
这里涉及到以下几点:
- 应用进程的确是有Zygote进程创建的,包括前文提到的SystemServer进程
- 新进程时如何与虚拟机关联的?
在forkAndSpecialize方法中,Zygote会将创建的Dalvik虚拟机实例复制到新的应用程序进程里面去,从而使得每一个应用程序进程都有一个独立的Dalvik虚拟机实例。
好了,新进程已经创建好了,但似乎还没解决问题,ActivityThread是如何运行在新进程中的呢?接着往下看handleChildProc方法。
2.4、handleChildProc | ZygoteConnection.java
private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws ZygoteInit.MethodAndArgsCaller {
//子进程中关闭client/server socket
closeSocket();
ZygoteInit.closeServerSocket();
...
if (parsedArgs.niceName != null) {
//设置进程名
Process.setArgV0(parsedArgs.niceName);
}
//是否设置了runtimeInit参数
if (parsedArgs.runtimeInit) {
if (parsedArgs.invokeWith != null) {
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
pipeFd, parsedArgs.remainingArgs);
} else {
//zygoteInit最后仍会创建ActivityThread实例,并调用其main方法
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs);
}
} else {
String className;
try {
//传入的类全限定名,此处为:“android.app.ActivityThread”
className = parsedArgs.remainingArgs[0];
}
...
if (parsedArgs.invokeWith != null) {
WrapperInit.execStandalone(parsedArgs.invokeWith,
parsedArgs.classpath, className, mainArgs);
} else {
ClassLoader cloader;
if (parsedArgs.classpath != null) {
//ClassLoader
cloader = new PathClassLoader(parsedArgs.classpath,
ClassLoader.getSystemClassLoader());
} else {
cloader = ClassLoader.getSystemClassLoader();
}
try {
//反射创建className(此处为ActivityThread)实例,并调用其main方法
ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
}
...
}
}
}
注意哦,现在已经是在新创建的子进程了哦:
1、子进程关闭client/server socket连接,为什么呢?
2、解析参数,根据前面传入的参数“android.app.ActivityThread”,调用ZygoteInit.invokeStaticMain方法,反射创建ActivityThread实例,并调用该实例main方法。
回答两个问题:
1、子进程为什么要关闭client/server socket连接,关闭client还好理解,server socket不是在Zygote进程吗?
了解Linux的都知道,通过fork创建的子进程会继承父进程的代码、数据,也就是:子进程除了自己的堆栈地址跟父进程不同外,其它数据都是直接从父进程拷贝过来的。那新创建的子进程,肯定也是有一份ServerSocket实例拷贝,子进程在创建完成后当然需要关闭。
2、为什么ActivityThread被称为主线程?
首先,ActivityThread不是线程,被称为主线程是因为:它运行在新进程的主线程中(当然了,主线程就是进程中的第一个线程了,此处没有额外再创建新线程,那肯定是主线程了)。
2.5、invokeStaticMain | ZygoteInit.java
static void invokeStaticMain(ClassLoader loader,
String className, String[] argv)
throws ZygoteInit.MethodAndArgsCaller {
Class<?> cl;
try {
cl = loader.loadClass(className);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}
Method m;
try {
m = cl.getMethod("main", new Class[] { String[].class });
} catch (NoSuchMethodException ex) {
throw new RuntimeException(
"Missing static main on " + className, ex);
} catch (SecurityException ex) {
throw new RuntimeException(
"Problem getting static main on " + className, ex);
}
int modifiers = m.getModifiers();
if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
throw new RuntimeException(
"Main method is not public and static on " + className);
}
/*
* This throw gets caught in ZygoteInit.main(), which responds
* by invoking the exception's run() method. This arrangement
* clears up all the stack frames that were required in setting
* up the process.
*/
throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}
这个方法不写注释也能一眼看懂:
1、反射获得入参对应的Class,此处入参为:“android.app.ActivityThread”
2、反射获取main方法对应的Method
3、新建MethodAndArgsCaller,并以异常形式抛出
- 前面都好理解,关键是为什么要将main方法封装成异常的形式抛出呢?
前面提到:子进程实际是从父进程将代码数据拷贝而来,父进程Zygote在死循环中创建了子进程,那子进程当然也存在这份死循环的代码。子进程通过异常抛出的形式,然后异常被捕获,跳出死循环,并在调用异常的run方法,在该run方法中调用被封装的方法main。
ActivityThread
至此,应用进程已经创建好了,并通过反射方式创建了ActivityThread的实例,然后调用该实例的main方法。那看下其main方法都做了啥:
3.1、main | ActivityThread.java
public static void main(String[] args) {
SamplingProfilerIntegration.start();
// 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();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
Security.addProvider(new AndroidKeyStoreProvider());
Process.setArgV0("<pre-initialized>");
//为当前线程创建Looper,并未改Looper创建关联的MessageQueue
Looper.prepareMainLooper();
//创建实例
ActivityThread thread = new ActivityThread();
//入口
thread.attach(false);
//创建Handler,即:H
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
AsyncTask.init();
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
//mainLooper循环从消息队列中取消息,并交给H处理
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
有代码知,main方法创建了主线程关联的Looper已经H handler,这些相信大家都很熟了,但还是废话几句吧:
-
main方法在当前进程的主线程中运行,即主线程创建了Looper,并为Looper创建了关联的消息队列,以及handler H。创建完成后,调用Looper的loop方法,循环从消息队列中取出消息交给Looper处理。
- 关于Looper、MessageQueue、Handler以及Message的关系,大致如下:
- Looper与线程相关联,在Looper类中采用线程局部变量保存每个线程关联的Looper。主线程默认关联一个Looper,即MainLooper;当然也可以为子线程手动创建关联的Looper,即调用Looper.prepare()方法。
- 每个Looper实例中,存在一个关联的MessageQueue实例,调用Looper的prepare方法时,会创建Looper实例,以及Looper关联的MessageQueue实例。调用Looper.loop()方法,Looper会循环去关联的MessageQueue中取出消息处理。
- Handler,当构造Handler的实例时,会获取当前线程关联的Looper对象和MessageQueue对象引用。调用handler发送消息时,实际是将消息放入到MessageQueue中。
- Message,每个Message对象都关联了一个target,该target就是发送该消息的Handler实例。当Looper从MessageQueue中取出消息时,会将消息发送给其关联的target进行处理。(why:因为一个MessageQueue可能被多个handler引用。)
- 关于Looper、MessageQueue、Handler以及Message的关系,大致如下:
方法中另外创建了一个ActivityThread的实例,并调用其attach方法,开始应用的启动。
3.2、attach | ActivityThread.java
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
//普通App进这里
if (!system) {
ViewRootImpl.addFirstDrawHandler(new Runnable() {
@Override
public void run() {
ensureJitEnabled();
}
});
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
UserHandle.myUserId());
//VM中保存该应用标志,用于上报错误
//mAppThread是Binder对象,AMS通过该对象实现与该应用进程通信,ActivityThread初始化时会创建该实例
RuntimeInit.setApplicationObject(mAppThread.asBinder());
//AMS代理
IActivityManager mgr = ActivityManagerNative.getDefault();
try {
//AMS保存该应用进程信息,通过该Binder实现与该应用进程通信
mgr.attachApplication(mAppThread); //入口
} catch (RemoteException ex) {
// Ignore
}
} else {
......
}
......
}
- 该方法入参为false,即普通应用app。
- 将应用进程Binder关联到VM,用于上报错误信息;
- 将应用进程Binder关联到AMS,用于AMS与该应用进程通信;
- 最后,通过AIDL调用AMS的attachApplication方法,所以此时又交由AMS来处理了。
什么是应用进程Binder?
在上文《沉思曲:Acitivity启动》中提到,AMS通过持有应用进程的Binder实现与应用进程的通信。该Binder实现了IApplicationThread接口,实现是ApplicaitonThread。
3.3、attachApplication | ActivityManagerService.java
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
//应用进程pid
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
//入口
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
- 该方法继续调用attachApplicationLocked方法。
- attachApplicationLocked方法主要是应用进程进行校验,并调用thread的bindApplication方法。thread就是上一方法中的入参:应用进程Binder,实现为ApplicaitonThread,是Binder对象。
- 由于thread是Binder对象,即应用进程在AMS中的Binder对象,所以此处又由AMS进程切换到应用进程中!!!
3.4、bindApplication | ActivityThread.java
note:ApplicaitonThread是ActivityThread的内部类。
public final void bindApplication(String processName,
ApplicationInfo appInfo, List<ProviderInfo> providers,
ComponentName instrumentationName, String profileFile,
ParcelFileDescriptor profileFd, boolean autoStopProfiler,
Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableOpenGlTrace, boolean isRestrictedBackupMode, boolean persistent,
Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,
Bundle coreSettings) {
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.enableOpenGlTrace = enableOpenGlTrace;
data.restrictedBackupMode = isRestrictedBackupMode;
data.persistent = persistent;
data.config = config;
data.compatInfo = compatInfo;
data.initProfileFile = profileFile;
data.initProfileFd = profileFd;
data.initAutoStopProfiler = false;
//发送消息到H,消息类型为H.BIND_APPLICATION
queueOrSendMessage(H.BIND_APPLICATION, data);
}
该方法在应用进程中,调用H handler发送消息H.BIND_APPLICATION,看下H handler是如何处理该消息的。
3.5、 H处理H.BIND_APPLICATION消息 | ActivityThread.java
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;
- 该方法接着调用 handleBindApplication
3.6、 handleBindApplication | ActivityThread.java
private void handleBindApplication(AppBindData data) {
mBoundApplication = data;
mConfiguration = new Configuration(data.config);
mCompatConfiguration = new Configuration(data.config);
mProfiler = new Profiler();
mProfiler.profileFile = data.initProfileFile;
mProfiler.profileFd = data.initProfileFd;
mProfiler.autoStopProfiler = data.initAutoStopProfiler;
//设置进程名
Process.setArgV0(data.processName);
android.ddm.DdmHandleAppName.setAppName(data.processName,
UserHandle.myUserId());
//是否开启硬件加速
if (data.persistent) {
if (!ActivityManager.isHighEndGfx()) {
HardwareRenderer.disable(false);
}
}
if (mProfiler.profileFd != null) {
mProfiler.startProfiling();
}
//Honeycomb MR1版本前,设置AsyncTask的底层由线程池实现
if (data.appInfo.targetSdkVersion <= android.os.Build.VERSION_CODES.HONEYCOMB_MR1) {
AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
//设置TimeZone、Locale
TimeZone.setDefault(null);
Locale.setDefault(data.config.locale);
//更新系统设置,AppBindData中配置默认是最新的
mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo);
mCurDefaultDisplayDpi = data.config.densityDpi;
applyCompatConfiguration(mCurDefaultDisplayDpi);
//获取Package信息,返回LoadedApk对象。先从缓存读,没有则创建。
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
//设置分辨率信息
if ((data.appInfo.flags&ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES)
== 0) {
mDensityCompatMode = true;
Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEFAULT);
}
updateDefaultDensity();
//创建ContextImpl实例
final ContextImpl appContext = new ContextImpl();
appContext.init(data.info, null, this);
if (!Process.isIsolated()) {
final File cacheDir = appContext.getCacheDir();
if (cacheDir != null) {
// Provide a usable directory for temporary files
System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());
setupGraphicsSupport(data.info, cacheDir);
} else {
Log.e(TAG, "Unable to setupGraphicsSupport due to missing cache directory");
}
}
//系统应用,开启debug log
if ((data.appInfo.flags &
(ApplicationInfo.FLAG_SYSTEM |
ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0) {
StrictMode.conditionallyEnableDebugLogging();
}
//Honeycomb版本以后,不允许在主线程进行网络操作
if (data.appInfo.targetSdkVersion > 9) {
StrictMode.enableDeathOnNetwork();
}
//设置debug
......
// 是否启动GL
if (data.enableOpenGlTrace) {
GLUtils.setTracingLevel(1);
}
// Allow application-generated systrace messages if we're debuggable.
boolean appTracingAllowed = (data.appInfo.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0;
Trace.setAppTracingAllowed(appTracingAllowed);
//设置time zone时,走http代理;通过ConnectivityManager设置
IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
if (b != null) {
IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
try {
ProxyProperties proxyProperties = service.getProxy();
Proxy.setHttpProxySystemProperty(proxyProperties);
} catch (RemoteException e) {}
}
//是否指定trumentation类名,难道可以指定?!
if (data.instrumentationName != null) {
InstrumentationInfo ii = null;
try {
//获取Instrumentation信息
ii = appContext.getPackageManager().
getInstrumentationInfo(data.instrumentationName, 0);
}
......
mInstrumentationAppDir = ii.sourceDir;
mInstrumentationAppLibraryDir = ii.nativeLibraryDir;
mInstrumentationAppPackage = ii.packageName;
mInstrumentedAppDir = data.info.getAppDir();
mInstrumentedAppLibraryDir = data.info.getLibDir();
//创建ApplicationInfo,用来保存应用信息
ApplicationInfo instrApp = new ApplicationInfo();
instrApp.packageName = ii.packageName;
instrApp.sourceDir = ii.sourceDir;
instrApp.publicSourceDir = ii.publicSourceDir;
instrApp.dataDir = ii.dataDir;
instrApp.nativeLibraryDir = ii.nativeLibraryDir;
//创建LoadedApk实例,保存应用APK信息
LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
appContext.getClassLoader(), false, true);
//创建应用关联的CotextImpl
ContextImpl instrContext = new ContextImpl();
instrContext.init(pi, null, this);
try {
java.lang.ClassLoader cl = instrContext.getClassLoader();
//为应用创建指定的Instrumentation实例
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
}
......
//init,保存应用信息到Instrumentation
mInstrumentation.init(this, instrContext, appContext,
new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher,
data.instrumentationUiAutomationConnection);
......
} else {
//未指定Instrmentation名称,创建默认Instrumentation
mInstrumentation = new Instrumentation();
}
if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) {
dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
}
//允许application和provider启动时访问disk
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
try {
//创建Application实例
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
//restricted模式下,c处理provider
if (!data.restrictedBackupMode) {
List<ProviderInfo> providers = data.providers;
if (providers != null) {
installContentProviders(app, providers);
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
}
}
try {
//调用Instrumentation的onCreate方法,用于Applicaiton启动onCreate()启动前的操作
mInstrumentation.onCreate(data.instrumentationArgs);
}
......
try {
//Instrumentation回调应用Applicaiton的onCreate,启动应用
mInstrumentation.callApplicationOnCreate(app);
}
......
}
该方法负责启动应用:
- 设置进程名、是否开启硬件加速
- 设置AsyncTask的底层实现方式
- 设置TimeZone、Locale
- 设置分辨率、不允许主线程网络操作等
- 为应用进程设置Instrumentation,用于管理应用进程
- 通过Instrumentation调用应用Applicationde 的onCreate方法,实现应用的启动等
- 设置timezone、openGl等信息后,创建Instrumentation用于管理该应用进程,最后并回调该应用的Application的onCreate方法启动应用。
至此,本文内容就差不多结束了,后面应用的启动就不讲了,感兴趣的可以看源码,大同小异。
总结
三篇文章到此结束了,三文粗略的分析了Android系统启动、Activity启动、ActivityThread创建三部分内容。内容都是整理之前资料得到的,网上关于这部分内容的资料也很多,但都比较零散。这里把这部分内容整理出来,一来备忘,二来抛砖引玉。本人才疏学浅,大部分内容都是自己理解加注释,有不当错误之处,恳请指正~
网友评论