系统启动大致流程
流程这个我用一段文字来大概概括,因为流程并不是重点,一方面是大部分blog都是在讲流程我啰嗦了也没意思,其次是流程又长又臭一般记不住。还是研究点有意思的吧。
大概流程如下
- system/core/init/init.cpp 里面解析system/core/rootdir/init.rc
- 以64位处理器为例,在被拆分放在system/core/rootdir/init.zygote64.rc里面有启动zygote的配置
- sytem/core/init/service.cpp 的start函数会创建zygote的子进程并调用其main函数
- 对应就是frameworks/base/cmds/app_process/app_main.cpp的main函数中执行了runtime.start(...)
- frameworks/base/core/jni/AndroidRuntime.cpp中启动java虚拟机和注册JNI方法打开了Java新世界的大门
------------------Java新世界的大门分割线-------------------- - 再通过JNI调用ZygoteInit的main方法
- main方法在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java里面,执行registerServerSocketFromEnv,注册socket
- main方法接着通过forkSystemServer启动SystemServer
- main方法接着执行runSelectLoop等待AMS的请求。
SystemServer的main函数会启动一些重要的系统服务如AMS,和启动Launcher。
大致流程就是上面这样,看过很多文章看完后,得到的知识跟上面的差不多,挺枯燥的没什么意思(没卵用)。
了解registerServerSocketFromEnv
void registerServerSocketFromEnv(String socketName) {
if (mServerSocket == null) {
int fileDesc;
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
String env = System.getenv(fullSocketName);
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException(fullSocketName + " unset or invalid", ex);
}
try {
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
//通过了fileDesc的唯一来保证了mServerSocked的唯一
mServerSocket = new LocalServerSocket(fd);
mCloseSocketFd = true;
} catch (IOException ex) {
throw new RuntimeException(
"Error binding to local socket '" + fileDesc + "'", ex);
}
}
}
这里主要是通过fd参数实例化了一个LocalServerSocket。
public LocalServerSocket(FileDescriptor fd) throws IOException
{
impl = new LocalSocketImpl(fd);
impl.listen(LISTEN_BACKLOG);
localAddress = impl.getSockAddress();
}
LocalServerSocket用了代理模式,实际上是由LocalSocketImpl来实现的。
class LocalSocketImpl
{
private SocketInputStream fis;
private SocketOutputStream fos;
private Object readMonitor = new Object();
private Object writeMonitor = new Object();
/** null if closed or not yet created */
private FileDescriptor fd;
/** whether fd is created internally */
private boolean mFdCreatedInternally;
// These fields are accessed by native code;
/** file descriptor array received during a previous read */
FileDescriptor[] inboundFileDescriptors;
/** file descriptor array that should be written during next write */
FileDescriptor[] outboundFileDescriptors;
看的出具体的socket的读写都封装在LocalSocketImpl了。
了解runSelectLoop
Runnable runSelectLoop(String abiList) {
ArrayList fds = new ArrayList();
ArrayList peers = new ArrayList();
//实际上这里mServerSocket.getFileDescriptor()就是上面的fd,只有一个
fds.add(mServerSocket.getFileDescriptor());
peers.add(null); //很巧妙的在初始化的时候add了一个null
while (true) {
StructPollfd[] pollFds = new StructPollfd[fds.size()];
for (int i = 0; i < pollFds.length; ++i) {
pollFds[i] = new StructPollfd();
pollFds[i].fd = fds.get(i);
pollFds[i].events = (short) POLLIN;
}
try {
//阻塞住,等待消息
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
...
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 {
try {
ZygoteConnection connection = peers.get(i);
final Runnable command = connection.processOneCommand(this);
开始pollFds的长度为1,所以如果有客户端请求连接,会来到i==0的逻辑,实例化好ZygoteConnection 添加到peers,所以当继续有信息过来即可认为是i==1的情况,此时peer.get(1)就是在i==0的时候实例好的ZygoteConnection 。然后接着执行processOneCommand,之前的版本叫runOnce,其实一样是解析socket传过来的参数来执行对应的操作。
了解processOneCommand
Runnable processOneCommand(ZygoteServer zygoteServer) {
String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;
try {
args = readArgumentList();
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
throw new IllegalStateException("IOException on command socket", ex);
}
先是通过String数组存放readAgumentList解析从socket传过来的信息
private String[] readArgumentList()
throws IOException {
int argc;
try {
//第一行存放的参数数量
String s = mSocketReader.readLine();
if (s == null) {
// EOF reached.
return null;
}
//再把数量string转成integer类型
argc = Integer.parseInt(s);
} catch (NumberFormatException ex) {
Log.e(TAG, "invalid Zygote wire format: non-int at argc");
throw new IOException("invalid wire format");
}
// See bug 1092107: large argc can be used for a DOS attack
// 通过判断其数量大小判断是不是dos攻击,防止被dos攻击
if (argc > MAX_ZYGOTE_ARGC) {
throw new IOException("max arg count exceeded");
}
//最后遍历参数,存放再result 的String数组
String[] result = new String[argc];
for (int i = 0; i < argc; i++) {
result[i] = mSocketReader.readLine();
if (result[i] == null) {
// We got an unexpected EOF.
throw new IOException("truncated request");
}
}
return result;
}
在封装在变量中parsedArgs = new Arguments(args);
最后执行forkAndSpecialize,参数都是来自parsedArgs的,有个返回值pid
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
parsedArgs.instructionSet, parsedArgs.appDataDir);
if (pid == 0) {
// in child
zygoteServer.setForkChild();
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
return handleChildProc(parsedArgs, descriptors, childPipeFd,
parsedArgs.startChildZygote);
当返回值pid 为0代表fork的是zygote的子进程,通知zygoteServer更改一些状态和关掉socket,因为任务完成了,接着执行handleChildProc,这里参数上继续传了parsedArgs等参数。
来到
if (!isZygote) {
return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
null /* classLoader */);
} else {
return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
会执行zygoteInit
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
if (RuntimeInit.DEBUG) {
Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
RuntimeInit.redirectLogStreams();
RuntimeInit.commonInit();// 通用的一些初始化
ZygoteInit.nativeZygoteInit();// zygote初始化
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);// 应用初始化
}
我们接着跟踪argv的参数传过去的地方看看applicationInit
//args 存放了应用的startClass 和startArgs
return findStaticMain(args.startClass, args.startArgs, classLoader);
//通过反射来获得startClass的main方法
try {
cl = Class.forName(className, true, classLoader);
} 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);
}
return new MethodAndArgsCaller(m, argv);
最后return这一步以前是通过throw操作来回到ZygoteInit的main函数,为了能清空栈,新版本是通过一堆的runnable来衔接,最后在ZygoteInit执行caller.run来实现。
关于MethodAndArgsCaller最后里面的run。
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);
}
}
}
到底执行了哪个类的哪个方法?这个肯定要从arg里面的信息才知道,arg归根到底是从发送方通过socket传过来的,那么问题来了发送方是谁?发了什么?
弄清楚这个之前先来看一下上面还没有说的forkSystemServer。
了解forkSystemServer
这个本质上也是zegote的fork子进程的,虽然跟fork应用的子进程有点不一样,但其实差不多。
跟fork应用不同的是,因为这个forkSystemServer方法的调用是在zegoteinit的main函数上的,就没必要再通过socket来通知zegote fork子进程了。
/* Hardcoded command line to start the system server */
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
"com.android.server.SystemServer",
};
ZygoteConnection.Arguments parsedArgs = null;
int pid;
try {
parsedArgs = new ZygoteConnection.Arguments(args);
...
上面的代码看出来,还是使用了 ZygoteConnection.Arguments来包装参数,证明这两种fork的传参方式是一样的。
static jint com_android_internal_os_Zygote_nativeForkSystemServer(
JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
jint runtime_flags, jobjectArray rlimits, jlong permittedCapabilities,
jlong effectiveCapabilities) {
pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
runtime_flags, rlimits,
permittedCapabilities, effectiveCapabilities,
MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL,
NULL, false, NULL, NULL);
在JNI调用里面看的出实际上也调用跟fork应用子进程一样的ForkAndSpecializeCommon的方法。显然fork子进程的方式也一样。
现在再看看包装和解析参数的过程。
private void parseArgs(String args[])
throws IllegalArgumentException {
int curArg = 0;
boolean seenRuntimeArgs = false;
boolean expectRuntimeArgs = true;
if (arg.equals("--")) {
curArg++;
break;
} else if (arg.startsWith("--setuid=")) {
if (uidSpecified) {
throw new IllegalArgumentException(
"Duplicate arg specified");
}
uidSpecified = true;
uid = Integer.parseInt(
arg.substring(arg.indexOf('=') + 1));
} else if (arg.startsWith("--setgid=")) {
if (gidSpecified) {
throw new IllegalArgumentException(
"Duplicate arg specified");
}
gidSpecified = true;
gid = Integer.parseInt(
arg.substring(arg.indexOf('=') + 1));
}
...
//剩下非选项类参数,即不是--开头的参数,用remainingArgs存起来。
else if (expectRuntimeArgs) {
if (!seenRuntimeArgs) {
throw new IllegalArgumentException("Unexpected argument : " + args[curArg]);
}
remainingArgs = new String[args.length - curArg];
System.arraycopy(args, curArg, remainingArgs, 0, remainingArgs.length);
}
forkSystemServer的过程的参数里非“--.."开头的只有"com.android.server.SystemServer",所以remainingArgs存放的就是这个字符串了,也就是类名。
包装起来的parsedArgs在子进程systemserver创建成功后会接着传入handleSystemServerProcess执行
/* For child process */
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
zygoteServer.closeServerSocket();
return handleSystemServerProcess(parsedArgs);
}
在handleSystemServerPorcess中最后执行这段代码
if (systemServerClasspath != null) {
cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);
Thread.currentThread().setContextClassLoader(cl);
}
/*
* Pass the remaining arguments to SystemServer.
*/
return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
显然这里传的是remainingArgs,对于systemserver而言就是只有一个类名的String数组。
接着执行
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
if (RuntimeInit.DEBUG) {
Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
RuntimeInit.redirectLogStreams();
RuntimeInit.commonInit();// 通用的一些初始化
ZygoteInit.nativeZygoteInit();// zygote初始化
//argv包含的是类名和其他参数
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);// 应用初始化
}
applicationInit里面通过Arguments把argv包装,然后执行
final Arguments args = new Arguments(argv);
// 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
//选项的参数都是--开头的,第一个非选项的参数就类名,然后startArgs就是类名之后的参数
//args 存放了应用的startClass 和startArgs
return findStaticMain(args.startClass, args.startArgs, classLoader);
看一下Arguments 的代码
private void parseArgs(String args[])
throws IllegalArgumentException {
int curArg = 0;
for (; curArg < args.length; curArg++) {
String arg = args[curArg];
if (arg.equals("--")) {
curArg++;
break;
} else if (!arg.startsWith("--")) {
break;
}
}
if (curArg == args.length) {
throw new IllegalArgumentException("Missing classname argument to RuntimeInit!");
}
//这里curArg的位置就是非选项类的第一个,即类名,curArg ++ 指向类名之后的参数位置
startClass = args[curArg++];
//把类名之后的参数复制到startArgs的数组中
startArgs = new String[args.length - curArg];
System.arraycopy(args, curArg, startArgs, 0, startArgs.length);
}
}
经过解析后得到的startClass 就是类名,startArgs就是类名之后的参数。
到这里我们就知道最后执行了com.android.server.SystemServer的main函数。