Boot Rom —— Bootloader —— Linux Kernel —— init进程 —— Zygote进程(dalvik/ art)—— systemServer —— Apps
init 进程是Linux系统中,用户空间启动的第一个进程。
挂载 seLinux 文件目录,创建seLinux,加载 安全策略
启动内核日志
启动属性系统,从文件读取属性
创建epoll
包含五种类型语句:
Zygote服务 也在init.rc中配置:
//进程名为Zygote,执行的真正程序是 /system/bin/app_process
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main //classname为main
priority -20
user root
group root readproc reserved_disk
socket zygote stream 660 root system
socket usap_pool_primary stream 660 root system
onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
zygote受精卵,用于孵化子进程。所有APP及Systemserver进程 都由zygote 通过Linux的fork() 函数孵化出来的。
Zygote进程是Android系统中第一个带有art 虚拟机的进程,Zygote 与 SystemServer 进程以socket的方式进行通信。
Zygote是C/S模型的服务端,主要负责创建 Java 虚拟机,加载系统资源,启动 SystemServer 及其他进程。
启动一个应用的流程:
点击应用图标 —— AMS —— 发出socket —— Zygote —— linux fork() 新进程
/frameworks/base/cmds/app_process/app_main.cpp
App_main.main() 有两种启动模式:
(C++世界)(Zygote Service)App_main() —— AndroidRumtime.start() 【startVm() —— startReg() —— callMain() 】—— (Java世界开始)ZygoteInit.main() 【registerZygoteSocket() —— preload() —— gc() —— startSystemServer() —— runSelectLoop()】
在fork SystemServer之前执行了 gc 操作,使得被 fork 出来的子进程有尽可能少的垃圾内存。
ZygoteInit的启动入口是:
app_main.cpp(也就是Zygote的C++进程) ::main() —— AppRuntime.start(“com.android.internal.os.ZygoteInit”)
AndroidRuntime包括了:从下到上 libc、JNI、Java-VM、Java-lib
cmds/app_process.cpp
base/core/jni/AndroidRuntime.cpp startvm()
art/runtime/java_vm_ext.cc JNI_CreateJavaVM() 返回JniEnv JavaVm给Native代码,这样就可以访问java接口了
art/runtime/runtime.cc 提供art虚拟机运行时:创建堆管理对象gc::Heap、创建Java虚拟机对象JavaVmExt、为vm添加JniEnvHandler、连接主线程、创建类连接器
主要做两件事:
system/core/libutils/Threads.cpp::run() native层可以创建两种Thread:一种可以调用java方法的线程,一种是纯native的线程。
可调用java的线程,会调用vm 将线程与 JNIEnv 绑定,使之可通过JNIEnv调用java方法。
// base/core/jni/androidRuntime.cpp
/*
* Makes the current thread visible to the VM.
*
* The JNIEnv pointer returned is only valid for the current thread, and
* thus must be tucked into thread-local storage.
*/
static int javaAttachThread(const char* threadName, JNIEnv** pEnv)
{
JavaVMAttachArgs args;
JavaVM* vm;
vm = AndroidRuntime::getJavaVM();
result = vm->AttachCurrentThread(pEnv, (void*) &args);
if (result != JNI_OK)
ALOGI("NOTE: attach of thread '%s' failed\n", threadName);
return result;
}
从数据结构上看,thread.h 类中,有一个 JNIEnvExt* 的指针变量 jni_env, 表明一个thread与一个jni_env关联。
// runtime/thread.h
struct PACKED(sizeof(void*)) tls_ptr_sized_values {
// Every thread may have an associated JNI environment
JNIEnvExt* jni_env;
}
除了系统的JNI接口(javacore nativehelper)FWK还有大量的Native实现,所有这些接口一次性通过startReg()来完成
base/core/jni/androidRuntime.cpp::startReg()
/*
* Register android native functions with the VM.
*/
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
......
register_jni_procs(gRegJNI, NELEM(gRegJNI), env)
}
static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
{
for (size_t i = 0; i < count; i++) {
if (array[i].mProc(env) < 0) { ... }
}
}
static const RegJNIRec gRegJNI[] = {
REG_JNI(register_com_android_internal_os_RuntimeInit),
REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),
REG_JNI(register_android_os_SystemClock),
REG_JNI(register_android_util_EventLog),
REG_JNI(register_android_util_Log),
REG_JNI(register_android_util_MemoryIntArray),
REG_JNI(register_android_util_PathParser),
REG_JNI(register_android_util_StatsLog),
REG_JNI(register_android_app_admin_SecurityLog),
REG_JNI(register_android_content_AssetManager),
REG_JNI(register_android_content_StringBlock),
REG_JNI(register_android_content_XmlBlock),
REG_JNI(register_android_content_res_ApkAssets),
REG_JNI(register_android_text_AndroidCharacter),
... ...
}
// frameworks/base/core/jni/android_util_Log.cpp
int register_android_util_Log(JNIEnv* env)
{
jclass clazz = FindClassOrDie(env, "android/util/Log");
levels.verbose = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "VERBOSE", "I"));
levels.debug = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "DEBUG", "I"));
levels.info = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "INFO", "I"));
levels.warn = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "WARN", "I"));
levels.error = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "ERROR", "I"));
levels.assert = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "ASSERT", "I"));
return RegisterMethodsOrDie(env, "android/util/Log", gMethods, NELEM(gMethods));
}
/*
* Register native methods using JNI.
*/
/*static*/ int AndroidRuntime::registerNativeMethods(JNIEnv* env,
const char* className, const JNINativeMethod* gMethods, int numMethods)
{
return jniRegisterNativeMethods(env, className, gMethods, numMethods);
}
// libnativehelper/JNIHelp.cpp
extern "C" int jniRegisterNativeMethods(C_JNIEnv* env, const char* className, constJNINativeMethod* gMethods, int numMethods){
JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
(*env)->RegisterNatives(e, c.get(), gMethods, numMethods)
... ...
}
// frameworks/base/core/java/com.android.internal.os.RuntimeInit.java
public static final void main(String[] argv) {
......
/*
* Now that we're running in interpreted code, call back into native code
* to run the system.
*/
nativeFinishInit();
if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!");
}
// frameworks/base/core/jni/AndroidRuntime.cpp
/*
* Code written in the Java Programming Language calls here from main().
*/
static void com_android_internal_os_RuntimeInit_nativeFinishInit(JNIEnv* env, jobject clazz)
{
gCurRuntime->onStarted();
}
// frameworks/base/cmds/app_process/app_main.cpp
virtual void onStarted()
{
AndroidRuntime* ar = AndroidRuntime::getRuntime();
ar->callMain(mClassName, mClass, mArgs);
}
callMain() 将调起Java世界的 com.android.internal.os.ZygoteInit 类的main()方法。
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();
final Runnable caller;
try {
boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
boolean enableLazyPreload = false;
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
} else if ("--enable-lazy-preload".equals(argv[i])) {
enableLazyPreload = true;
} else if (argv[i].startsWith(ABI_LIST_ARG)) {
abiList = argv[i].substring(ABI_LIST_ARG.length());
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
socketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}
// 注册Server socket
zygoteServer.registerServerSocketFromEnv(socketName);
if (!enableLazyPreload) {
bootTimingsTraceLog.traceBegin("ZygotePreload");
// 加载类到内存
preload(bootTimingsTraceLog);
}
preloadTextResources();
// 垃圾回收
gcAndFinalize();
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
// {@code r == null} in the parent (zygote) process, and {@code r != null} in the
// child (system_server) process.
if (r != null) {
r.run();
return;
}
}
Log.i(TAG, "Accepting command socket connections");
// The select loop returns early in the child process after a fork and
// loops forever in the zygote.
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;
} finally {
zygoteServer.closeServerSocket();
}
}
preload是Android 启动最耗时的部分之一
/**
* Prepare the arguments and forks for the system server process.
*
* Returns an {@code Runnable} that provides an entrypoint into system_server code in the
* child process, and {@code null} in the parent.
*/
private static Runnable forkSystemServer(String abiList, String socketName,
ZygoteServer zygoteServer) {
/* 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.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
boolean profileSystemServer = SystemProperties.getBoolean(
"dalvik.vm.profilesystemserver", false);
if (profileSystemServer) {
parsedArgs.runtimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
}
/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.runtimeFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
/* For child process */
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
zygoteServer.closeServerSocket();
return handleSystemServerProcess(parsedArgs);
}
return null;
}
SystemServer 是 Zygote fork出来的第一个 Java 进程,此进程非要重要,提供了 Android 系统所有的核心服务。
SystemServer 中运行着AMS,WMS 等系统服务,Binder-x 之类的服务线程,UI-thread InputReader
SystemServer 创建:ActivityThread、SystemContext、SystemUIContext
ContextImpl 是 Context 的实现类,其中封装了生成 4 种常用的 createContext 方法:
启动Service
startBootstrapServices();
startCoreServices();
startOtherServices();
Zygote会在后台观察 SystemServer ,一旦 System 挂掉了,将其回收,然后重启 Zygote 自己。
Watchdog 也可能因某种原因,将 SystemServer Kill 掉,并重启。屏幕会黑屏一段时间。
在 Unix-like 系统,父进程必须用 waitpid 等待子进程退出,否则子进程将变成 Zombie(僵尸)进程,不仅系统资源泄漏,而且系统将崩溃。没有 SystemServer 所有 Android 应用程序都无法运行。
waitpid() 是一个阻塞函数,所以通常处理是 在 signal 函数里无阻塞调用。
每个子进程退出时 —— 发出 SIGCHID 信号 —— Zygote 会杀掉自己 —— 系统给所有子进程发送 SIGHUP 信号 —— 各子进程杀掉自己退出当前进程(子进程中的 Daemon 进程设置 SIG_IGN参数忽略 SIGHUP 信号继续运行)。
ServiceManager、SystemServer、SurfaceFlinger、Zygote自己 进程被杀
返回值 == 0:成功创建子进程,并进入子进程执行
返回值 > 0:成功创建子进程,返回子进程id,并继续沿原父进程执行
返回值 < 0:创建失败
失败原因主要有:进程数超过系统上限(EAGAIN),系统内存不足(ENOMEM)
fork() 出的子进程,是父进程的一个copy,继承了整个进程的地址空间:包括进程上下文、进程堆栈、打开的文件描述符、信号控制设定、进程优先级、进程组号等。与父进程不同的只有进程号、计时器等少量信息。由上可见,fork() 函数的开销是很大的。
Linux 的 fork 采用写时拷贝。写时拷贝是一种可能推迟甚至避免拷贝的技术。内核此时并不复制整个进程的地址空间,而是让子进程共享父进程的地址空间。只有在需要写入时,才会复制地址空间,使子进程拥有自己的地址空间。
panic
内核出现异常会导致1 进程死亡,如果是中断上下文的异常或系统关键资源受到破坏,通常会导致2 内核挂起,不再响应任何事件。
在linux中, 将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为“内核空间”。而将较低的3G字节(从虚拟地址 0x00000000到0xBFFFFFFF),供各个进程使用,称为“用户空间)
内核非法使用了用户空间的地址故存在问题。
epoll
epoll_create、epoll_wait、epoll_ctl
1. bug
2. Oops
3. panic