目录
- 第一节 Android系统启动流程
-
- init进程
- 第二节 init.rc 解析
- 第三节 Zygote进程的启动过程
-
- 3.1 AndroidRuntime.start 做了三件事:
-
- 3.1.1 startVm:
- 3.1.2 startReg:
-
- 3.1.2.1 设置创建可访问Java的线程方法
- 3.1.2.2 注册所有的JNI方法
- 3.1.3 callMain()
- 3.2 (Java世界开始)ZygoteInit.main()
- 第四节 SystemServer 启动流程
- 第五节 其他小点
-
- 5.1 什么情况下 Zygote 进程会重启呢?
- 5.2 fork函数
- 5.3 写时拷贝(copy-on-write)
- 5.4 内核空间、用户空间
- 5.5 epoll
- 5.6 内核的异常级别
第一节 Android系统启动流程
Boot Rom —— Bootloader —— Linux Kernel —— init进程 —— Zygote进程(dalvik/ art)—— systemServer —— Apps
init进程
init 进程是Linux系统中,用户空间启动的第一个进程。
- 创建并挂载一些文件目录
- 启动属性服务
- 解析 init.rc 配置文件,启动 Zygote 进程
挂载 seLinux 文件目录,创建seLinux,加载 安全策略
启动内核日志
启动属性系统,从文件读取属性
创建epoll
第二节 init.rc 解析
包含五种类型语句:
- Action(包含command)
- Commands
- Services(将由 init进程 启动的服务)
- Options(服务的选项)
- Import (其他配置文件)
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进程的启动过程
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() 有两种启动模式:
- Zygote初始化模式
- application模式
- Zygote初始化模式,会启动 SystemServer ,并指定自己的 socket 名字为 zygote
- application模式,就是启动普通应用,参数有 class 名字及参数
(C++世界)(Zygote Service)App_main() —— AndroidRumtime.start() 【startVm() —— startReg() —— callMain() 】—— (Java世界开始)ZygoteInit.main() 【registerZygoteSocket() —— preload() —— gc() —— startSystemServer() —— runSelectLoop()】
- AndroidRumtime.start() —— startVm() —— startReg():AndroidRumtime::Start() 函数中将启动 JavaVM,并注册所有FWK相关的系统 JNI 接口。为 Java 世界做好准备。
- ZygoteInit.main() registerZygoteSocket() —— preload() —— gc() —— startSystemServer() —— runSelectLoop():第一次进入Java世界,运行 ZygoteInit.java::main() 初始化Zygote,并创建 Socket 的 Server 端。preload 常用的 Java 类库、系统 resources,执行 gc() 清理内存,为 fork 子进程做好准备。然后 fork 出子进程,在子进程中 初始化 SystemServer,初始化的过程中 启动 Android 系统所有的 Service。
- (与此同时,Zygote 继续在后台监听 Socket 等待新的应用启动请求。)
- (与此同时,Zygote 监听 SystemServer 的 SIGHID信号,一旦SystemServer挂掉,立即 kill 掉 Zygote 自己。init 会重启 Zygote,再启动 SystemServer,使系统恢复正常。 )
- AMS ready后,寻找系统的 “Startup” Application,向 Zygote 发请求。
- Zygote fork 出“Startup” Application,也就是启动 Launcher 应用,然后显示出Home页面。
在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
3.1 AndroidRuntime.start 做了三件事:
- startVm():
- startReg():
- callMain():
3.1.1 startVm:
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、连接主线程、创建类连接器
3.1.2 startReg:
主要做两件事:
- 设置创建可访问Java的线程方法
- 注册所有的JNI方法
3.1.2.1 设置创建可访问Java的线程方法
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' failedn", 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;
}
3.1.2.2 注册所有的JNI方法
除了系统的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_castJNIEnv*>(env);
(*env)->RegisterNatives(e, c.get(), gMethods, numMethods)
... ...
}
3.1.3 callMain()
// 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()方法。
3.2 (Java世界开始)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 启动流程
SystemServer 是 Zygote fork出来的第一个 Java 进程,此进程非要重要,提供了 Android 系统所有的核心服务。
SystemServer 中运行着AMS,WMS 等系统服务,Binder-x 之类的服务线程,UI-thread InputReader
SystemServer 创建:ActivityThread、SystemContext、SystemUIContext
ContextImpl 是 Context 的实现类,其中封装了生成 4 种常用的 createContext 方法:
- createSystemContext()
- createSystemUiContext()
- createAppContext()
- createActivityContext()
启动Service
startBootstrapServices();
startCoreServices();
startOtherServices();
- startBootstrapServices():启动系统启动所需的一小堆关键服务(AMS,PMS,RecoverySystemService,LightsService,DisplayManagerService,UserManagerService,OverlayManagerService)。这些服务具有复杂的相互依赖关系,这就是为什么我们在这里将它们全部初始化的原因。除非您的服务也与这些依赖关系纠缠在一起,否则它应该在其他函数中进行初始化。
- startCoreServices():启动一些在引导过程中没有互相交互的基本服务(BatteryService, UsageStatsService, WebViewUpdateService, BinderCallsStatsService)。
- startOtherServices():启动一些杂七杂八的东西(ConnectivityService,WMS,InputManagerService,TelephonyRegistry)
Zygote会在后台观察 SystemServer ,一旦 System 挂掉了,将其回收,然后重启 Zygote 自己。
Watchdog 也可能因某种原因,将 SystemServer Kill 掉,并重启。屏幕会黑屏一段时间。
在 Unix-like 系统,父进程必须用 waitpid 等待子进程退出,否则子进程将变成 Zombie(僵尸)进程,不仅系统资源泄漏,而且系统将崩溃。没有 SystemServer 所有 Android 应用程序都无法运行。
waitpid() 是一个阻塞函数,所以通常处理是 在 signal 函数里无阻塞调用。
每个子进程退出时 —— 发出 SIGCHID 信号 —— Zygote 会杀掉自己 —— 系统给所有子进程发送 SIGHUP 信号 —— 各子进程杀掉自己退出当前进程(子进程中的 Daemon 进程设置 SIG_IGN参数忽略 SIGHUP 信号继续运行)。
第五节 其他小点
5.1 什么情况下 Zygote 进程会重启呢?
ServiceManager、SystemServer、SurfaceFlinger、Zygote自己 进程被杀
5.2 fork函数
返回值 == 0:成功创建子进程,并进入子进程执行
返回值 > 0:成功创建子进程,返回子进程id,并继续沿原父进程执行
返回值 失败原因主要有:进程数超过系统上限(EAGAIN),系统内存不足(ENOMEM)
fork() 出的子进程,是父进程的一个copy,继承了整个进程的地址空间:包括进程上下文、进程堆栈、打开的文件描述符、信号控制设定、进程优先级、进程组号等。与父进程不同的只有进程号、计时器等少量信息。由上可见,fork() 函数的开销是很大的。
5.3 写时拷贝(copy-on-write)
Linux 的 fork 采用写时拷贝。写时拷贝是一种可能推迟甚至避免拷贝的技术。内核此时并不复制整个进程的地址空间,而是让子进程共享父进程的地址空间。只有在需要写入时,才会复制地址空间,使子进程拥有自己的地址空间。
panic
内核出现异常会导致1 进程死亡,如果是中断上下文的异常或系统关键资源受到破坏,通常会导致2 内核挂起,不再响应任何事件。
5.4 内核空间、用户空间
在linux中, 将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为“内核空间”。而将较低的3G字节(从虚拟地址 0x00000000到0xBFFFFFFF),供各个进程使用,称为“用户空间)
内核非法使用了用户空间的地址故存在问题。
5.5 epoll
epoll
epoll_create、epoll_wait、epoll_ctl
5.6 内核的异常级别
1. bug
2. Oops
3. panic
- Bug:是指那些不符合内核的正常设计,但内核能够检测出来并且对系统运行不会产生影响的问题,比如在原子上下文中休眠。
- Oops:程序在内核态时,进入一种异常情况,比如引用非法指针导致的数据异常,数组越界导致的取指异常,此时异常处理机制能够捕获此异常,并将系统关键信息打印到串口上,正常情况下Oops消息会被记录到系统日志中去。
Oops发生时,进程处在内核态,很可能正在访问系统关键资源,并且获取了一些锁,当进程由于Oops异常退出时,无法释放已经获取的资源,导致其他需要获取此资源的进程挂起,对系统的正常运行造成影响。通常这种情况,系统处在不稳定的状态,很可能崩溃。 - panic:当Oops发生在中断上下文中或者在进程0和1中,系统将彻底挂起,因为中断服务程序异常后,将无法恢复,这种情况即称为内核panic。另外当系统设置了panic标志时,无论Oops发生在中断上下文还是进程上下文,都将导致内核Panic。由于在中断复位程序中panic后,系统将不再进行调度,Syslogd将不会再运行,因此这种情况下,Oops的消息仅仅打印到串口上,不会被记录在系统日志中。
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
相关推荐: 亚马逊服务问题之 WARNING: UNPROTECTED PRIVATE KEY FILE
最近一直搞亚马逊服务相关的东西: WARNING: UNPROTECTED PRIVATE KEY FILE: chmod 600 **.pem http://stackoverflow.com/questions/1009…