【Android Development Advanced Series】Android Multi-Process Topic
【Android Development Advanced Series】Android Multi-Process Topic
The application process created by the Android application framework layer has two characteristics, one is that the entry function of the process is
ActivityThread.main, and the other is that the process naturally supports the Binder inter-process communication mechanism, both of which are implemented in
the process of process initialization, and this article will analyze in detail how these two characteristics are implemented in the process of creating an Android
application process.
The entry function of the application process created by the Android application framework layer is ActivityThread.main, which is easy to understand, that is,
after the process is created, the Android application framework layer will load the ActivityThread class in this process, and then execute its main function, which
is where the process executes the message loop. How should we understand the fact that the application processes created by the Android application
framework layer naturally support the Binder inter-process communication mechanism? Earlier, when we learned the Binder inter-process communication
mechanism of the Android system, we said that it has four components, namely the driver, the daemon, the Client and the Server, in which the Server
component must enter a loop to continuously interact with the Binder driver during initialization, in order to obtain the request sent by the Client component,
which can be referred to for detailsHowever, when we implement the Server component in the Android application, we do not let the process enter a loop to
wait for the request of the Client component, however, when the Client component gets the remote interface of the Server component, However, it can
smoothly communicate with the server components between processes, which is because the Android application process has already started a thread pool to
support the interaction between the server component and the binder driver when it is created, which greatly facilitates the creation of server components in the
Android application.
In the Android application framework layer, the ActivityManagerService component is responsible for creating a new process for the Android application, which
originally ran in a separate process, but this process was created during the system startup process. Under what circumstances does the
ActivityManagerService component typically create a new process for the application? When the system decides to start an activity or service in a new process,
it will create a new process, and then start the activity or service in this new processThere are three articles: Source Code Analysis of Android Application
Startup Process and Method and Process Analysis of Android Application Starting New Activities in New Process.
Before we dive into the process of starting a new process with the ActivityManagerService member function startProcessLocked, let's take a look at the
sequence diagram of the process creation process and then analyze each step in detail.
Step 1.ActivityManagerService.startProcessLocked
......
......
try{
try{
guide = mContext.getPackageManager().getPackageGuide(app.info.packageName);
} catch(PackageManager.NameNotFoundException e) {
......
......
int debugFlags = 0;
......
int pid = Process.start("android.app.ActivityThread", mSimpleProcessManagement ? app.processName : null, uid, uid, gids, debugFlags, null);
......
} catch(RuntimeException e) {
......
......
It calls the Process.start function to start creating a new process for the application, note that it passes in a first parameter "android.app.ActivityThread", which
is the Java class to be loaded when the process is initialized, and after loading this class into the process, it will use the static member function main as the
entry point of the process, as we will see later.
Step 2. Process.start
......
public static final int start(final String processClass, final String niceName, int uid, int gid, int[] gids, int debugFlags, String[] zygoteArgs)
if(supportsProcesses()) {
try{
} catch(ZygoteStartFailedEx ex) {
......
} else{
......
return 0;
......
The supportsProcesses function here returns a value of true, which is a native function implemented in the frameworks/base/core/jni/android_util_Process.cpp
file:
return ProcessState::self()->supportsProcesses();
The mDriverFD is the opening descriptor of the device file /dev/binder, and if the device file is successfully opened, its value will be greater than or equal to 0,
so its return value is true.
Back in the Process.start function, it calls the startViaZygote function to do things further.
Step3. Process.startViaZygote
......
private static int startViaZygote(final String processClass, final String niceName, final int uid,
final int gid, final int[] gids, int debugFlags, String[] extraArgs) throwsZygoteStartFailedEx
int pid;
synchronized(Process.class) {
argsForZygote.add("--runtime-init");
argsForZygote.add("--setuid="+ uid);
argsForZygote.add("--setgid="+ gid);
argsForZygote.add("--enable-safemode");
argsForZygote.add("--enable-debugger");
argsForZygote.add("--enable-checkjni");
argsForZygote.add("--enable-assert");
//argsForZygote.add("--enable-debugger");
sb.append("--setgroups=");
int sz = guide.length;
if (i != 0) {
sb.append(',');
sb.append(gids[i]);
argsForZygote.add(sb.toString());
if (niceName != null) {
argsForZygote.add("--nice-name="+ niceName);
}
argsForZygote.add(processClass);
if (extraArgs != null) {
argsForZygote.add(arg);
pid = zygoteSendArgsAndGetPid(argsForZygote);
......
This function puts the parameters of the created process into the argsForZygote list, for example, the parameter "--runtime-init" indicates that the runtime
library is to be initialized for the newly created process, and then calls the zygoteSendAndGetPid function for further operations.
Step 4. Process.zygoteSendAndGetPid
......
int pid;
openZygoteSocketIfNeeded();
try{
/**
* See com.android.internal.os.ZygoteInit.readArgumentList()
* After the zygote process reads these it will write the pid of
*/
sZygoteWriter.write(Integer.toString(args.size()));
sZygoteWriter.newLine();
int sz = args.size();
if (arg.indexOf('\n') >= 0) {
sZygoteWriter.write(arg);
sZygoteWriter.newLine();
sZygoteWriter.flush();
pid = sZygoteInputStream.readInt();
if (pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
} catch(IOException ex) {
......
return pid;
......
Here sZygoteWriter is a Socket write stream that is opened by the openZygoteSocketIfNeeded function:
......
/**
*/
int retryCount;
if(sPreviousZygoteOpenFailed) {
/*
*/
retryCount = 0;
} else{
retryCount = 10;
/*
*/
for (int retry = 0; (sZygoteSocket == null) && (retry < (retryCount + 1)); retry++ )
if (retry > 0) {
try{
Thread.sleep(ZYGOTE_RETRY_MILLIS);
} catch(InterruptedException ex) {
try{
sPreviousZygoteOpenFailed = false;
break;
} catch(IOException ex) {
......
......
......
This socket is listened to by the ZygoteInit class in the frameworks/base/core/java/com/android/internal/os/ZygoteInit .java file in the runSelectLoopMode
function.
Step 5. ZygoteInit.runSelectLoopMode
......
/**
* worth at a time.
* be executed.
*/
fds.add(sServerSocket.getFileDescriptor());
peers.add(null);
while (true) {
int index;
/*
*/
if (loopCount <= 0) {
gc();
loopCount = GC_LOOP_COUNT;
} else{
loopCount--;
try{
fdArray = fds.toArray(fdArray);
index = selectReadable(fdArray);
} catch(IOException ex) {
if (index < 0) {
} else if (index == 0) {
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else{
boolean done;
done = peers.get(index).runOnce();
if(done) {
peers.remove(index);
fds.remove(index);
......
When Step 4 sends the data through the socket interface, the following statement will be filed:
done = peers.get(index).runOnce();
What we get here from peers.get(index) is a ZygoteConnection object, which represents a Socket connection, so the next step is to call the
ZygoteConnection.runOnce function for further processing.
Step 6. ZygoteConnection.runOnce
class ZygoteConnection
......
String args[];
FileDescriptor[] descriptors;
try{
args = readArgumentList();
descriptors = mSocket.getAncillaryFileDescriptors();
} catch(IOException ex) {
......
return true;
......
int pid;
try{
applyUidSecurityPolicy(parsedArgs, peer);
applyDebuggerSecurityPolicy(parsedArgs);
applyRlimitSecurityPolicy(parsedArgs, peer);
applyCapabilitiesSecurityPolicy(parsedArgs, peer);
if (parsedArgs.rlimits != null) {
rlimits = parsedArgs.rlimits.toArray(intArray2d);
} catch(IllegalArgumentException ex) {
......
} catch(ZygoteSecurityException ex) {
......
if (pid == 0) {
// in child
return true;
} else { /* pid != 0 */
......
Readers with Linux development experience can easily understand this function call, this function will create a process, and there are two return values, one is
returned in the current process, and the other is returned in the newly created process, that is, it is returned in the child process of the current process, and the
return value in the current process is the pid value of the newly created child process, and the return value in the child process is 0. Since we only care about
the new process we create, let's continue along the execution path of the child process:
if (pid == 0) {
// in child
return true;
} else {
/* pid != 0 */
......
Step7. ZygoteConnection.handleChildProc
class ZygoteConnection {
......
private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, PrintStream newStderr) throws ZygoteInit.MethodAndArgsCaller
......
if(parsedArgs.runtimeInit) {
RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
} else{
......
......
Since in Step 3, the "--runtime-init" parameter is specified, which means that the runtime library is to be initialized for the newly created process, so the
parseArgs.runtimeInit value here is true, so we continue to run RuntimeInit.zygoteInit for further processing.
Step 8. RuntimeInit.zygoteInit
......
// TODO: Doing this here works, but it seems kind of arbitrary. Find
commonInit();
zygoteInitNative();
int curArg = 0;
if (arg.equals("--")) {
curArg++;
break;
} else if (!arg.startsWith("--")) {
break;
} else if (arg.startsWith("--nice-name=")) {
Process.setArgV0(niceName);
if(curArg == argv.length) {
return;
invokeStaticMain(startClass, startArgs);
......
There are two key function calls here, one is the zygoteInitNative function call, and the other is the invokeStaticMain function call, the former is to perform the
related work of Binder driver initialization, it is because of this work that the Binder object in the process can smoothly communicate between Binder processes,
and the latter function call is the entry function of the execution process. This is the main function of the startClass class, and this startClass is the
"android.app.ActivityThread" value we passed in Step 1, which means that the main function of the android.app.ActivityThread class is to be executed.
Let's take a look at the call process of the zygoteInitNative function, and then go back to the RuntimeInit.zygoteInit function to see how it calls the main
function of the android.app.ActivityThread class.
step 9. RuntimeInit.zygoteInitNative
......
......
As you can see here, the function zygoteInitNative is a native function implemented in the frameworks/base/core/jni/AndroidRuntime.cpp file:
gCurRuntime->onZygoteInit();
Here it calls the onZygoteInit function of the global variable gCurRuntime, which is defined at the beginning of the frameworks/base/core/jni/AndroidRuntime
.cpp file:
As you can see here, its type is AndroidRuntime, which is initialized in the constructor of the AndroidRuntime class, which is also defined in the
frameworks/base/core/jni/AndroidRuntime .cpp file:
AndroidRuntime::AndroidRuntime()
......
So when was the constructor of this AndroidRuntime class called? The declaration of the AndroidRuntime class is in
frameworks/base/include/android_runtime/ AndroidRuntime.h file, if we open this file, we will see that it is a virtual class, that is, we can't directly create an
AndroidRuntime object, we can only use a pointer of an AndroidRuntime class to point to a subclass of it, this subclass is AppRuntime, which is defined in
frameworks/base/cmds/app_process/app_ main.cpp file:
......
AppRuntime runtime;
......
The AppRuntime class continues with the AndroidRuntime class, which is also defined in the frameworks/base/cmds/app_process/app_main.cpp file:
......
};
Therefore, in the previous com_android_internal_os_RuntimeInit_zygoteInit function, the onZygoteInit function of the AppRuntime class is actually executed.
......
sp proc = ProcessState::self();
if(proc->supportsProcesses()) {
proc->startThreadPool();
......
};
这里它就是调用ProcessState::startThreadPool启动线程池了,这个线程池中的线程就是用来和Binder驱动程序进行交互的了。
这个函数定义在frameworks/base/libs/binder/ProcessState.cpp文件中:
void ProcessState::startThreadPool()
AutoMutex _l(mLock);
if(!mThreadPoolStarted) {
mThreadPoolStarted = true;
spawnPooledThread(true);
ProcessState类是Binder进程间通信机制的一个基础组件,它的作用可以参考浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service
Manager接口之路、Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析和Android系统进程间通信(IPC)机制Binder中的Client获得Server远
程接口过程源代码分析这三篇文章。这里它调用spawnPooledThread函数进一步处理。
Step 12. ProcessState.spawnPooledThread
这个函数定义在frameworks/base/libs/binder/ProcessState.cpp文件中:
if(mThreadPoolStarted) {
char buf[32];
sp t = new PoolThread(isMain);
t->run(buf);
这里它会创建一个PoolThread线程类,然后执行它的run函数,最终就会执行PoolThread类的threadLoop函数了。
这个函数定义在frameworks/base/libs/binder/ProcessState.cpp文件中:
public:
protected:
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
};
这里它执行了IPCThreadState::joinThreadPool函数进一步处理。IPCThreadState也是Binder进程间通信机制的一个基础组件,它的作用可以参考浅谈
Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路、Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码
分析和Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析这三篇文章。
Step14. IPCThreadState.joinThreadPool
这个函数定义在frameworks/base/libs/binder/IPCThreadState.cpp文件中:
......
......
status_t result;
do{
int32_t cmd;
......
result = talkWithDriver();
if(result >= NO_ERROR) {
size_t IN = mIn.dataAvail();
cmd = mIn.readInt32();
......
result = executeCommand(cmd);
......
......
mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);
这个函数首先告诉Binder驱动程序,这条线程要进入循环了:
然后在中间的while循环中通过talkWithDriver不断与Binder驱动程序进行交互,以便获得Client端的进程间调用:
result = talkWithDriver();
获得了Client端的进程间调用后,就调用excuteCommand函数来处理这个请求:
result = executeCommand(cmd);
Finally, when the thread exits, it also tells the binder driver that it has exited, so that the binder driver can no longer be called and distributed to it between
processes on the client side:
mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);
......
binder_write_read bwr;
bwr.write_size = outAvail;
bwr.read_size = mIn.dataCapacity();
} else{
bwr.read_size = 0;
......
// Return immediately if there is nothing to do.
return NO_ERROR;
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
of the{
......
#if defined(HAVE_ANDROID_OS)
err = NO_ERROR;
else
err = -errno;
#else
err = INVALID_OPERATION;
#endif
......
} while(err == -EINTR);
....
mOut.remove(0, bwr.write_consumed);
else
mOut.setDataSize(0);
if(bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);
......
return NO_ERROR;
return err;
这个函数的具体作用可以参考Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析一文,它只要就是通过ioctl文件操作函数来和Binder
驱动程序交互的了:
有了这个线程池之后,我们在开发Android应用程序的时候,当我们要和其它进程中进行通信时,只要定义自己的Binder对象,然后把这个Binder对象的远程
接口通过其它途径传给其它进程后,其它进程就可以通过这个Binder对象的远程接口来调用我们的应用程序进程的函数了,它不像我们在C++层实现Binder进程
间通信机制的Server时,必须要手动调用IPCThreadState.joinThreadPool函数来进入一个无限循环中与Binder驱动程序交互以便获得Client端的请求,这样就实
现了我们在文章开头处说的Android应用程序进程天然地支持Binder进程间通信机制。
......
static void invokeStaticMain(ClassLoader loader, String className, String[] argv) throws ZygoteInit.MethodAndArgsCaller
Class cl;
try{
cl = loader.loadClass(className);
} catch(ClassNotFoundException ex) {
......
Method m;
try{
} catch(NoSuchMethodException ex) {
......
} catch(SecurityException ex) {
......
......
/*
* up the process.
*/
......
As we said earlier, the value of the className string of the parameter passed here is "android.app.ActivityThread", and here it is loaded into the process
through the ClassLoader.loadClass function:
cl = loader.loadClass(className);
The function finally does not call the static member function main directly, but by throwing an exception ZygoteInit.MethodAndArgsCaller, and then letting the
ZygoteInit.main function call the main function of the android.app.ActivityThread class when the exception is caught. Why? The comment has made it clear that
it is meant to clean up the stack, so that the main function of the android .app.ActivityThread class thinks that it is the entry function of the process, when in
fact, a lot of work has been done before the main function of the android.app.ActivityThread class is executed.
Let's take a look at what the ZygoteInit.main function does when it catches this exception:
......
......
} catch(MethodAndArgsCaller caller) {
caller.run();
} catch(RuntimeException ex) {
......
......
......
mMethod = method;
mArgs = args;
try{
} catch(IllegalAccessException ex) {
......
} catch(InvocationTargetException ex) {
......
......
这里的成员变量mMethod和mArgs都是在前面构造异常对象时传进来的,这里的mMethod就对应android.app.ActivityThread类的main函数了,于是最后就
通过下面语句执行这个函数:
这样,android.app.ActivityThread类的main函数就被执行了。
这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:
......
SamplingProfilerIntegration.start();
Process.setArgV0("");
Looper.prepareMainLooper();
if (sMainThreadHandler == null) {
thread.attach(false);
if (false) {
Looper.loop();
if(Process.supportsProcesses()) {
thread.detach();
: "";
......
从这里我们可以看出,这个函数首先会在进程中创建一个ActivityThread对象:
然后进入消息循环中:
Looper.loop();
这样,我们以后就可以在这个进程中启动Activity或者Service了。
至此,Android应用程序进程启动过程的源代码就分析完成了,它除了指定新的进程的入口函数是ActivityThread的main函数之外,还为进程内的Binder对象提
供了Binder进程间通信机制的基础设施,由此可见,Binder进程间通信机制在Android系统中是何等的重要,而且是无处不在,想进一步学习Android系统的
Binder进程间通信机制,请参考Android进程间通信(IPC)机制Binder简要介绍和学习计划一文。
2 进程创建
Android系统中的进程管理:进程的创建
http://mobile.51cto.com/android-520139.htm
2.1 概述
Android系统以Linux内核为基础,所以对于进程的管理自然离不开Linux本身提供的机制。例如:
· 通过fork来创建进行
· 通过信号量来管理进程
· 通过proc文件系统来查询和调整进程状态等
对于Android来说,进程管理的主要内容包括以下几个部分内容:
· 进程的创建
· 进程的优先级管理
· 进程的内存管理
· 进程的回收和死亡处理
本文会专门讲解进程的创建,其余部分将在后面的文章中讲解。
2.2 主要模块
为了便于下文的讲解,这里先介绍一下Android系统中牵涉到进程创建的几个主要模块。同时为了便于读者更详细的了解这些模块,这里也同时提供了这些
模块的代码路径。
这里提到的代码路径是指AOSP的源码数中的路径。
相关模块:
· app_process
代码路径:frameworks/base/cmds/app_process
说明:app_process是一个可执行程序,该程序的主要作用是启动zygote和system_server进程。
· Zygote
代码路径:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
说明:zygote进程是所有应用进程的父进程,这是系统中一个非常重要的进程,下文我们会详细讲解。
代码路径:frameworks/base/services/core/java/com/android/server/am/
说明:am是ActivityManager的缩写。
这个目录下的代码负责了Android全部四大组件(Activity,Service,ContentProvider,BroadcastReceiver)的管理,并且还掌控了所有应用程序进程的创建
和进程的优先级管理。
因此,这个部分的内容将是本系列文章讲解的重点。
2.3 关于进程
在Android系统中,进程可以大致分为系统进程和应用进程两大类。
系统进程是系统内置的(例如:init,zygote,system_server进程),属于操作系统必不可少的一部分。系统进程的作用在于:
· 管理硬件设备
· 提供访问设备的基本能力
· 管理应用进程
应用进程是指应用程序运行的进程。这些应用程序可能是系统出厂自带的(例如Launcher,电话,短信等应用),也可能是用户自己安装的(例如:微信,支付
宝等)。
系统进程的数量通常是固定的(出厂或者系统升级之后就确定了),并且系统进程通常是一直存活,常驻内存的。系统进程的异常退出将可能导致设备无法正
常使用。
而应用程序和应用进程在每个人使用的设备上通常是各不一样的。如何管理好这些不确定的应用进程,就是操作系统本身要仔细考虑的内容。也是衡量一个
操作系统好坏的标准之一。
在本文中,我们会介绍init,zygote和system_server三个系统进程。
除此之外,本系列文章将会把主要精力集中在讲解Android系统如何管理应用进程上。
2.4 init进程(核心)
init进程是一切的开始,在Android系统中,所有进程的进程号都是不确定的,唯独init进程的进程号一定是1。因为这个进程一定是系统起来的第一个进程。
并且,init进程掌控了整个系统的启动逻辑。
我们知道,Android可能运行在各种不同的平台,不同的设备上。因此,启动的逻辑是不尽相同的。为了适应各种平台和设备的需求,init进程的初始化工作
通过init.rc配置文件来管理。你可以在AOSP源码的system/core/rootdir/路径找到这些配置文件。配置文件的主入口文件是init.rc,这个文件会通过import引入其他
几个文件。
建议读者大致阅读一下其语法说明 。
init.rc中配置了系统启动的时候该做哪些事情,以及启动哪些系统进程。
这其中有两个特别重要的进程就是:zygote和system_server进程。
· zygote的中文意思是“受精卵“。这是一个很有寓意的名称:所有的应用进程都是由zygote fork出来的子进程,因此zygote进程是所有应用进程的父进程。
2.5 Zygote进程
init.rc文件会根据平台不一样,选择下面几个文件中的一个来启动zygote进程:
· init.zygote32.rc
· init.zygote32_64.rc
· init.zygote64.rc
· init.zygote64_32.rc
这几个文件的内容是大致一致的,仅仅是为了不同平台服务的。这里我们以init.zygote32.rc的文件为例,来看看其中的内容:
class main
onrestart write/sys/power/state on
onrestart restartaudioserver
onrestart restartcameraserver
writepid/dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
class main`这些参数。
要知道这里到底做了什么,我们需要看一下app_process的源码。app_process的源码在这个路径:
frameworks/base/cmds/app_process/app_main.cpp。
这个文件的main函数的有如下代码:
...
if (strcmp(arg, "--zygote")== 0) {
zygote = true;
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg,"--start-system-server") == 0) {
startSystemServer = true;
...
...
if (!className.isEmpty()) {
...
} else {
...
if (startSystemServer) {
args.add(String8("start-system-server"));
...
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args,zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit",args, zygote);
} else {
app_usage();
return 10;
这里会判断,
· 如果执行这个命令时带了--zygote参数,就会通过runtime.start启动com.android.internal.os.ZygoteInit。
· 如果参数中带有--start-system-server参数,就会将start-system-server添加到args中。
这段代码是C++实现的。在执行这段代码的时候还没有任何Java的环境。而runtime.start就是启动Java虚拟机,并在虚拟机中启动指定的类。于是接下来的
逻辑就在ZygoteInit.java中了。
这个文件的main函数主要代码如下:
...
try {
...
if("start-system-server".equals(argv[i])) {
startSystemServer = true;
} else if(argv[i].startsWith(ABI_LIST_ARG)) {
...
...
registerZygoteSocket(socketName);
...
preload();
...
Zygote.nativeUnmountStorageOnInit();
ZygoteHooks.stopZygoteNoThreadCreation();
if (startSystemServer) {
startSystemServer(abiList,socketName);
runSelectLoop(abiList);
closeServerSocket();
caller.run();
throw ex;
在这段代码中,我们主要关注如下几行:
2. 通过 preload(); 预先加载所有应用都需要的公共资源
4. 通过 runSelectLoop(abiList); 在Looper上等待连接
这里需要说明的是:zygote进程启动之后,会启动一个socket套接字,并通过Looper一直在这个套接字上等待连接。
所有应用进程都是通过发送数据到这个套接字上,然后由zygote进程创建的。
这里还有一点说明的是:
在Zygote进程中,会通过preload函数加载需要应用程序都需要的公共资源。
预先加载这些公共资源有如下两个好处:
· 加快应用的启动速度 因为这些资源已经在zygote进程启动的时候加载好了
· 通过共享的方式节省内存 这是Linux本身提供的机制:父进程已经加载的内容可以在子进程中进行共享,而不用多份数据拷贝(除非子进程对这些数据进行了
修改。)
preload的资源主要是Framework相关的一些基础类和Resource资源,而这些资源正是所有应用都需要的:
开发者通过Android SDK开发应用所调用的API实现都在Framework中。
Log.d(TAG,"begin preload");
Trace.traceBegin(Trace.TRACE_TAG_DALVIK,"BeginIcuCachePinning");
beginIcuCachePinning();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
Trace.traceBegin(Trace.TRACE_TAG_DALVIK,"PreloadClasses");
preloadClasses();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadResources");
preloadResources();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadOpenGL");
preloadOpenGL();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
preloadSharedLibraries();
preloadTextResources();
WebViewFactory.prepareWebViewInZygote();
endIcuCachePinning();
warmUpJcaProviders();
Log.d(TAG,"end preload");
As mentioned above, the zygote process will start the system_server process as needed after it is up. system_server process contains a large number of
system services. For example:
Wait a minute. We will explain system_server in other articles in the future, so I won't go into too much detail here.
In this article, we will focus only on the ActivityManagerService system service in the system_server.
2.7 ActivityManagerService
As mentioned above, the zygote process starts a socket after starting, and then waits for a connection at that socket. The one that will connect to it is the
ActivityManagerService. This is because ActivityManagerService controls the creation of all application processes. All application processes are sent by the
ActivityManagerService via a socket to the Zygote process, which is then created by the zygote fork.
public static finalProcessStartResult start(final String processClass, final String niceName, int uid, int gid,int[] gids, int debugFlags, int mountExternal, int
targetSdkVersion, String seInfo, String abi, String instructionSet, String appDataDir, String[]zygoteArgs)
try {
This function assembles the parameters needed to start the process and sends it to the zygote process via the socket. The zygote process then forks the
process based on the parameters sent.
...
Process.ProcessStartResult startResult = Process.start(entryPoint, app.processName, uid, uid, gids, debugFlags, mountExternal, app.info.targetSdkVersion,
app.info.seinfo, requiredAbi, instructionSet, app.info.dataDir, entryPointArgs);
...
As we will see below, all four component processes are created by calling the startProcessLocked method here.
For each application process, there is a ProcessRecord in the ActivityManagerService. This object records all the detailed state of the application process.
PS: For the internal structure of ProcessRecord, we will explain it in the next article.
For ease of searching, each ProcessRecord will be stored in the following two collections.
/**
* objects.
*/
/**
* NOTE: This object is protected by its own lock, NOT the global
*/
2.8 关于应用组件
"When an app component starts and the app isn't running anything else, the Android system starts a new Linux process for the app using a single thread of
execution."
Therefore, any of the four components coming first will result in the creation of an application process. Let's take a closer look at how each of them leads to the
creation of the application process when it starts.
PS: The management of the four components itself is a relatively large topic, limited to space, here will not be a very in-depth explanation, here is mainly to
explain the relationship between the four components and the creation of the process.
· ContentResolver
There are some overloaded methods for startActivity, startService, and sendBroadcast.
In fact, all of these methods mentioned here are ultimately called into the ActivityManagerService through the binder, which handles them.
To make it clear, the application process and the process where the ActivityManagerService resides (i.e., the system_server process) are independent of each
other, and the methods between the two processes usually cannot be directly called to each other.
In Android, the Binder framework is provided to provide inter-process communication and method invocation capabilities.
In the ActivityManagerService, each running activity has an ActivityRecord object that records the detailed state of the activity.
The startActivity method in the ActivityManagerService accepts a request for Context.startActivity, which is coded as follows:
@Override
public final int startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestC
ode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions)
return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions,
UserHandle.getCallingUserId());
Launching an activity is a very complex process. Here is a brief background on the background:
• Each activity belongs to a task, and a task may contain multiple activities. A stack contains multiple tasks
o Intent parsing
At the end of the activity start, the previous activity will be paused, and the newly started activity resume will be visible to the user.
At this point, if it is found that the newly started Activity process has not been started, it will be started via startSpecificActivityLocked. The entire invocation
process is as follows:
· ActivityManagerService.activityPaused =>
· ActivityStack.activityPausedLocked =>
· ActivityStack.completePauseLocked =>
· ActivityStackSupervisor.ensureActivitiesVisibleLocked=>
· ActivityStack.makeVisibleAndRestartIfNeeded =>
· ActivityStackSupervisor.startSpecificActivityLocked =>
· ActivityManagerService.startProcessLocked
· ActivityStackSupervisor.startSpecificActivityLocked
r.task.stack.setLaunchTime(r);
...
}
The ProcessRecord app here describes the process in which the Activity is located.
Starting a Service is a bit simpler than an Activity. In the ActivityManagerService, there is a ServiceRecord object for each running Service, which records the
detailed state of the Service.
The startService method in ActivityManagerService handles requests from the Context.startService API, the relevant code:
@Override
public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType, String callingPackage, int userId)
throwsTransactionTooLargeException
...
synchronized(this) {
Binder.restoreCallingIdentity(origId);
return res;
The mServices object in this code is of type ActiveServices, which is responsible for managing active Services.
· ActivityManagerService.startService =>
· ActiveServices.startServiceLocked =>
· ActiveServices.startServiceInnerLocked =>
· ActiveServices.bringUpServiceLocked =>
· ActivityManagerService.startProcessLocked
ActiveServices.bringUpServiceLocked determines that if the process in which the Service is located has not been started, it will start it through
ActivityManagerService.startProcessLocked. The relevant code is as follows:
if((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags, "service", r.name, false, isolated, false)) == null) {
String msg ="Unable to launch app " + r.appInfo.packageName + "/" + r.appInfo.uid + " for service" + r.intent.getIntent() + ": process is bad";
Slog.w(TAG,msg);
bringDownServiceLocked(r);
return msg;
if (isolated) {
r.isolatedProc= app;
In the ActivityManagerService, each running ContentProvider has a ContentProviderRecord object that records the detailed state of the ContentProvider.
Developers use the insert, delete, update, and query APIs in the ContentResolver to use the ContentProvider. In the ContentResolver implementation, no
matter which interface is used, the ContentResolver will first obtain a remote interface of type IContentProvider through the acquireProvider method. This
remote interface interfaces with the implementation provider of the ContentProvider.
The same ContentProvider may be used by multiple modules at the same time, and the process that calls the ContentResolver interface is only a client of the
ContentProvider. As shown in the figure below:
@Override
public final ContentProviderHolder getContentProvider(IApplicationThread caller, String name, int userId, boolean stable)
enforceNotIsolatedCaller("getContentProvider");
if (caller == null) {
String msg ="null IApplicationThread when getting content provider " + name;
Slog.w(TAG, msg);
// The incoming user check is now handled in checkContentProviderPermissionLocked() to deal with cross-user grant.
In the getContentProviderImpl method, it will determine whether the corresponding ContentProvider process has been started, and if not, it will be started by
the startProcessLocked method.
Developers use the Context.sendBroadcast API to send broadcasts. The ActivityManagerService.broadcastIntent method handles the corresponding
broadcast send.
Broadcasting is a one-to-many form of messaging, and the number of recipients of the broadcast is indefinite. As a result, sending broadcasts can be a time-
consuming process in itself (as notifications are made on a case-by-case basis).
In the ActivityManagerService, if a request is received to send a broadcast, a BroadcastRecord is created and then placed in the BroadcastQueue.
The queue is then notified to process the broadcast itself. The ActivityManagerService itself can then proceed to process the other requests.
The broadcast queue itself handles the transmission of broadcasts on a different thread, so that the load on the main thread of the ActivityManagerService is
not too heavy.
The logic of notifying the broadcast event to the receiver is actually implemented in the BroadcastQueue.processNextBroadcast(boolean fromMsg) method. In
this method, if the recipient (i.e. BrodcastReceiver) is found to have not started, it will be started via the ActivityManagerService.startProcessLocked method.
The relevance is as follows:
...
// Hard case: need to instantiate the receiver, possibly starting its application process to host it.
...
// Not running -- get it started, to be executed when the app comes up.
if (DEBUG_BROADCAST)
Slog.v(TAG_BROADCAST,"Need to start app [" + mQueueName + "] " + targetProcess + " for broadcast " + r);
logBroadcastReceiverDiscardLocked(r);
scheduleBroadcastsLocked();
r.state = BroadcastRecord.IDLE;
return;
mPendingBroadcast = r;
mPendingBroadcastRecvIndex = recIdx;
At this point, the launch of the four major components has been analyzed.
3 Reference Links
http://blog.csdn.net/feiyang877647044/article/details/51673466
http://blog.csdn.net/a78270528/article/details/51143740
http://www.cnblogs.com/John-Chen/p/4364275.html
https://my.oschina.net/u/1393188/blog/491568
http://www.jianshu.com/p/4ac1f373e8cd
http://blog.csdn.net/goodlixueyong/article/details/49853079
http://www.2cto.com/kf/201512/455410.html
http://blog.csdn.net/hudashi/article/details/7858125
http://blog.csdn.net/Ragnaro/article/details/51569096
http://blog.csdn.net/luoshengyang/article/details/6747696
Analysis of the method and process of starting a new activity in a new process for an Android application
http://shangxun.iteye.com/blog/2124498
(Good) In-depth understanding of the Dalvik Virtual Machine - Android Application Process Startup Process Analysis
http://blog.csdn.net/threepigs/article/details/50779056
http://blog.csdn.net/qq_33326449/article/details/52748710
Summary of Android background keep-alive practice: the "stubborn disease" that instant messaging apps can't cure
http://www.52im.net/thread-429-1-1.html
http://mobile.51cto.com/android-520139.htm
http://gityuan.com/2016/03/26/app-process-create/
https://blog.csdn.net/yyh352091626/article/details/50542554
https://blog.csdn.net/a332324956/article/details/9114919
Android Booting