Android系统启动后,想要启动一个应用程序,首先需要创建并启动该应用所需的应用程序进程。
AMS在启动应用程序时会检查这个应用程序所需的进程是否存在,不存在就会请求Zygote进程启动相应的进程。
我们知道,Zygote在Java框架层会创建一个Socket的服务端,这个Socket用来等待AMS请求Zygote创建新进程。
Zygote进程通过fork自身创建应用程序进程,这样应用程序进程就获得了Zygote进程在启动时创建的虚拟机,同时还创建了Binder线程池和消息循环。
一、应用程序进程启动过程
应用程序进程创建可以分为两个部分:
- AMS发送启动应用进程的请求
- Zygote接收并创建应用程序进程
1、AMS发送创建应用进程的请求
AMS 想要启动应用程序进程,需要向Zygote发送创建应用程序进程的请求。通过AMS的 startProcessLocked
方法。
1、AMS & startProcessLocked
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
try {
try {
final int userId = UserHandle.getUserId(app.uid);
AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
int uid = app.uid;
int[] gids = null;
int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
if (!app.isolated) {
int[] permGids = null;
try {
checkTime(startTime, "startProcess: getting gids from package manager");
final IPackageManager pm = AppGlobals.getPackageManager();
permGids = pm.getPackageGids(app.info.packageName,
MATCH_DEBUG_TRIAGED_MISSING, app.userId);
MountServiceInternal mountServiceInternal = LocalServices.getService(
MountServiceInternal.class);
mountExternal = mountServiceInternal.getExternalStorageMountMode(uid,
app.info.packageName);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
/*
* Add shared application and profile GIDs so applications can share some
* resources like shared libraries and access user-wide resources
*/
if (ArrayUtils.isEmpty(permGids)) {
gids = new int[2];
} else {
gids = new int[permGids.length + 2];
System.arraycopy(permGids, 0, gids, 2, permGids.length);
}
gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
gids[1] = UserHandle.getUserGid(UserHandle.getUserId(uid));
}
checkTime(startTime, "startProcess: building args");
if (mFactoryTest != FactoryTest.FACTORY_TEST_OFF) {
if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
&& mTopComponent != null
&& app.processName.equals(mTopComponent.getPackageName())) {
uid = 0;
}
if (mFactoryTest == FactoryTest.FACTORY_TEST_HIGH_LEVEL
&& (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
uid = 0;
}
}
String instructionSet = null;
if (app.info.primaryCpuAbi != null) {
instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi);
}
app.gids = gids;
app.requiredAbi = requiredAbi;
app.instructionSet = instructionSet;
// Start the process. It will either succeed and return a result containing
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
checkTime(startTime, "startProcess: asking zygote to start proc");
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);
checkTime(startTime, "startProcess: returned from zygote!");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
...
} catch (RuntimeException e) {
...
}
}
该方法中首先会创建uid和gid,并且给entryPoint
赋值android.app.ActivityThread
,也就是应用程序主线程类名。最后调用Process.start
方法启动进程。
2、 Process & start
/**
* Start a new process.
* @param processClass The class to use as the process's main entry
* point.
*/
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 abi,
String instructionSet,
String appDataDir,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
throw new RuntimeException(
"Starting VM process through Zygote failed", ex);
}
}
从该方法的注释也可以知道该方法用于启动新进程。该方法会继续调用startViaZygote
方法。
需要注意的是processClass
的值是 android.app.ActivityThread
Process & startViaZygote
/**
* Starts a new process via the zygote mechanism.
*/
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 abi,
String instructionSet,
String appDataDir,
String[] extraArgs)
throws ZygoteStartFailedEx {
synchronized(Process.class) {
ArrayList<String> argsForZygote = new ArrayList<String>();
// --runtime-args, --setuid=, --setgid=,
// and --setgroups= must go first
//封装启动参数
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
...
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
}
该方法主要封装启动参数,最后调用zygoteSendArgsAndGetResult
方法
Process & zygoteSendArgsAndGetResult
/**
* Sends an argument list to the zygote process, which starts a new child
* and returns the child's pid. Please note: the present implementation
* replaces newlines in the argument list with spaces.
*/
private static ProcessStartResult zygoteSendArgsAndGetResult(
ZygoteState zygoteState, ArrayList<String> args)
throws ZygoteStartFailedEx {
try {
// Throw early if any of the arguments are malformed. This means we can
// avoid writing a partial response to the zygote.
int sz = args.size();
for (int i = 0; i < sz; i++) {
if (args.get(i).indexOf('\n') >= 0) {
throw new ZygoteStartFailedEx("embedded newlines not allowed");
}
}
/**
* See com.android.internal.os.ZygoteInit.readArgumentList()
* Presently the wire format to the zygote process is:
* a) a count of arguments (argc, in essence)
* b) a number of newline-separated argument strings equal to count
*
* After the zygote process reads these it will write the pid of
* the child or -1 on failure, followed by boolean to
* indicate whether a wrapper process was used.
*/
final BufferedWriter writer = zygoteState.writer;
final DataInputStream inputStream = zygoteState.inputStream;
writer.write(Integer.toString(args.size()));
writer.newLine();
for (int i = 0; i < sz; i++) {
String arg = args.get(i);
writer.write(arg);
writer.newLine();
}
writer.flush();
// Should there be a timeout on this?
ProcessStartResult result = new ProcessStartResult();
// Always read the entire result from the input stream to avoid leaving
// bytes in the stream for future process starts to accidentally stumble
// upon.
result.pid = inputStream.readInt();
result.usingWrapper = inputStream.readBoolean();
if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
return result;
} catch (IOException ex) {
zygoteState.close();
throw new ZygoteStartFailedEx(ex);
}
}
该方法的主要作用就是将启动参数argsForZygote
写入ZygoteState
中。
ZygoteState
是Process的一个静态内部类,结构如下:
用来表示与Zygote通信的状态。
在执行zygoteSendArgsAndGetResult
方法的时候会通过openZygoteSocketIfNeeded
获得一个ZygoteState 对象。
//与服务端的socketName 一致
public static final String ZYGOTE_SOCKET = "zygote";
/**
* Tries to open socket to Zygote process if not already open. If
* already open, does nothing. May block and retry.
*/
private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
try {
//与Zygote进程建立socket链接
primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
}
}
//匹配ABI
if (primaryZygoteState.matches(abi)) {
return primaryZygoteState;
}
// The primary zygote didn't match. Try the secondary.
if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
try {
secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
}
}
if (secondaryZygoteState.matches(abi)) {
return secondaryZygoteState;
}
throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
}
在该方法中建立与Zygote进程的Socket链接,并匹配ABI后返回ZygoteState 对象。
在zygoteSendArgsAndGetResult
方法中将argsForZygote
写入ZygoteState
中,这样Zygote进程就会收到一个创建新应用程序进程的请求。
2、Zygote 接收请求并创建应用程序进程
上面我们已经通过Socket向Zygote进程发送一个创建新就应用程序进程的请求。
回到ZygoteInit.java
的main()
方法中,看看服务端Socket是如何接收请求的。
public static void main(String argv[]) {
try {
boolean startSystemServer = false;
String socketName = "zygote";
...
//创建一个服务端的Socket,socketName 为zygote
registerZygoteSocket(socketName);
...
//预加载类、资源等
preload();
...
//启动SystemServer
if (startSystemServer) {
startSystemServer(abiList, socketName);
}
//等待AMS请求
runSelectLoop(abiList);
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (Throwable ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}
在main方法中创建服务端Socket后,会执行runSelectLoop
方法,等待AMS发起创建进程请求。
1、ZygoteInit & runSelectLoop
/**
* Runs the zygote process's select loop. Accepts new connections as
* they happen, and reads commands from connections one spawn-request's
* worth at a time.
*
* @throws MethodAndArgsCaller in a child process when a main() should
* be executed.
*/
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
fds.add(sServerSocket.getFileDescriptor());
peers.add(null);
while (true) {
StructPollfd[] pollFds = new StructPollfd[fds.size()];
...
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
boolean done = peers.get(i).runOnce();
if (done) {
peers.remove(i);
fds.remove(i);
}
}
}
}
}
如果服务端的Socket接收到请求的时候,pollFds
的size就会大于0,会执行:
boolean done = peers.get(i).runOnce();
即执行 ZygoteConnection
的 runOnce()
方法。
2、ZygoteConnection & runOnce()
/**
* Reads one start command from the command socket. If successful,
* a child is forked and a {@link ZygoteInit.MethodAndArgsCaller}
* exception is thrown in that child while in the parent process,
* the method returns normally. On failure, the child is not
* spawned and messages are printed to the log and stderr. Returns
* a boolean status value indicating whether an end-of-file on the command
* socket has been encountered.
*
* @return false if command socket should continue to be read from, or
* true if an end-of-file has been encountered.
* @throws ZygoteInit.MethodAndArgsCaller trampoline to invoke main()
* method in child process
*/
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;
int pid = -1;
try {
//读取进程启动参数
args = readArgumentList();
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
return true;
}
...
try {
//解析启动参数
parsedArgs = new Arguments(args);
...
//启动进程
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
parsedArgs.appDataDir);
} catch (ErrnoException ex) {
...
}
try {
if (pid == 0) {
// in child
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
//处理应用程序进程
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
return true;
} else {
// in parent...pid of < 0 means failure
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}
首先会读取启动进程的参数,并解析到Arguments中。然后调用Zygote.forkAndSpecialize
方法创建子进程,返回值为pid,pid的默认值为-1,如果pid为0,则表明当前代码运行在子进程中,执行handleChildProc
方法完善子进程创建。
ZygoteConnection & handleChildProc
private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws ZygoteInit.MethodAndArgsCaller {
//关闭socket
closeSocket();
ZygoteInit.closeServerSocket();
...
//设置进程名
if (parsedArgs.niceName != null) {
Process.setArgV0(parsedArgs.niceName);
}
// End of the postFork event.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
if (parsedArgs.invokeWith != null) {
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
VMRuntime.getCurrentInstructionSet(),
pipeFd, parsedArgs.remainingArgs);
} else {
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}
该方法会关闭子进程的Socket,并给子进程重命名(因为子进程的创建是Zygote进程通过fork自身创建的,因此需要将子进程的socket关闭和重命名)。
最后会执行RuntimeInit.zygoteInit
方法
3、RuntimeInit & zygoteInit
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
redirectLogStreams();
commonInit();
//创建Binder线程池
nativeZygoteInit();
applicationInit(targetSdkVersion, argv, classLoader);
}
在该方法中会做一些初始化的操作,并调用nativeZygoteInit()
创建Binder线程池。继续查看applicationInit
RuntimeInit & applicationInit
private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
// We want to be fairly aggressive about heap utilization, to avoid
// holding on to a lot of memory that isn't needed.
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
final Arguments args;
try {
args = new Arguments(argv);
} catch (IllegalArgumentException ex) {
Slog.e(TAG, ex.getMessage());
// let the process exit
return;
}
// The end of of the RuntimeInit event (see #zygoteInit).
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// Remaining arguments are passed to the start class's static main
invokeStaticMain(args.startClass, args.startArgs, classLoader);
}
在该方法中又会执行invokeStaticMain
方法。
其中startClass
也就是在开头提到的Process.start
方法第一个参数processClass
,值为android.app.ActivityThread
RuntimeInit & invokeStaticMain
private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
Class<?> cl;
try {
//通过className获得ActivityThread的Class对象
//className 为 android.app.ActivityThread
cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}
Method m;
try {
//通过反射获得main方法
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);
}
该方法会通过反射获得ActivityThread
的main方法,并将它传递给抛出的ZygoteInit.MethodAndArgsCaller
异常中。MethodAndArgsCaller
为 ZygoteInit
静态内部类,并且在ZygoteInit
的main方法中捕获该异常。
ZygoteInit & main
public static void main(String argv[]) {
...
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (Throwable ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}
可以看到,在补货异常的地方会执行MethodAndArgsCaller.run()
方法。
4、ZygoteInit 静态内部类 MethodAndArgsCaller & run()
public static class MethodAndArgsCaller extends Exception
implements Runnable {
/** method to call */
private final Method mMethod;
/** argument array */
private final String[] mArgs;
public MethodAndArgsCaller(Method method, String[] args) {
mMethod = method;
mArgs = args;
}
public void run() {
try {
mMethod.invoke(null, new Object[] { mArgs });
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
Throwable cause = ex.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else if (cause instanceof Error) {
throw (Error) cause;
}
throw new RuntimeException(ex);
}
}
}
在run()
方法中会执行mMethod.invoke()
,我们已经知道mMethod
为 ActivityThread
的 main
方法,这里通过 反射动态调用 ActivityThread
的 main方法。
二、Binder线程池启动过程
我们知道,在RuntimeInit.zygoteInit()
初始化方法中会调用nativeZygoteInit();
来创建Binder线程池。
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
commonInit();
nativeZygoteInit();
applicationInit(targetSdkVersion, argv, classLoader);
}
private static final native void nativeZygoteInit();
nativeZygoteInit()
是一个JNI
方法,源码如下:
/frameworks/base/include/android_runtime/AndroidRuntime.cpp
static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
gCurRuntime->onZygoteInit();
}
这里gCurRuntime
是AndroidRuntime
类型的指针,具体指向的是AndroidRuntime
的子类AppRuntime
,它在app_main.cpp
中定义,AppRuntime
的onZygoteInit
方法如下:
91 virtual void onZygoteInit()
92 {
93 sp<ProcessState> proc = ProcessState::self();
94 ALOGV("App process: starting thread pool.\n");
95 proc->startThreadPool();
96 }
最后会调用ProcessState
的startThreadPool()
启动线程池。
145void ProcessState::startThreadPool()
146{
147 AutoMutex _l(mLock);
148 if (!mThreadPoolStarted) {
149 mThreadPoolStarted = true;
150 spawnPooledThread(true);
151 }
152}
mThreadPoolStarted
默认为false
,每次启动都会设置为true
,通过标记mThreadPoolStarted
的值,确保线程池只被启动一次。
最后调用spawnPooledThread
方法创建并启动线程池。
300void ProcessState::spawnPooledThread(bool isMain)
301{
302 if (mThreadPoolStarted) {
303 String8 name = makeBinderThreadName();
304 ALOGV("Spawning new pooled thread, name=%s\n", name.string());
305 sp<Thread> t = new PoolThread(isMain);
306 t->run(name.string());
307 }
308}
该方法会创建并启动Binder
的线程池PoolThread
。
PoolThread
线程池类是在ProcessState.cpp
文件中声明的。
50class PoolThread : public Thread
51{
52public:
53 explicit PoolThread(bool isMain)
54 : mIsMain(isMain)
55 {
56 }
57
58protected:
59 virtual bool threadLoop()
60 {
61 IPCThreadState::self()->joinThreadPool(mIsMain);
62 return false;
63 }
64
65 const bool mIsMain;
66};
可以看到PoolThread
继承Thread
类,通过调用IPCThreadState
的joinThreadPool(mIsMain)
方法将当前线程注册到Binder
驱动中,这样我们创建的线程就加入了Binder线程池中去了。
新创建的应用程序就支持Binder进程间通信了。我们只需要创建当前进程的Binder对象,将它注册到ServerManager
中就可以实现Binder进程间通信。
三、消息循环创建过程
在第一节第二部分Zygote接收请求并创建应用程序进程中我们知道,最后会通过反射启动 ActivityThread
的 main
方法。
1、ActivityThread & main()
public static void main(String[] args) {
...
//创建主线程的Looper
Looper.prepareMainLooper();
//创建ActivityThread
ActivityThread thread = new ActivityThread();
thread.attach(false);
//创建主线程Handler
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
//循环工作
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
可以看到,在ActivityThread
的 main()
方法中会创建消息循环所需要的Handler
、并且绑定主线程的Looper
并启动。这样就可以处理消息了。
四、总结
Android应用进程启动主要分为:
- AMS发送创建进程请求
- Zygote 接收请求并fork子进程
笔记来源:《Android进阶解密》、袁辉辉Android系统启动系列博客