当用户按下电源键,固化在CPU的boot代码,会自动将ROM中的uboot代码copy到片内内存中执行,由于片内内存很小(可能只有4k),所以要求copy的代码具有以下功能:
- 初始化系统时钟
- 初始化RAM存储器
- 代码重定位
- ......
当copy的uboot代码执行以上操作后,就会跳转到linux kernel执行,而init进程
便是kernel启动后,用户空间的第一个进程,进程号为1。
一、init进程
init进程的主要工作:
- 1、创建和挂载启动需要的文件目录:如tmpfs、devpts、proc、sysfs和selinuxfs共5种文件系统。
- 2、初始化并启动属性服务。
- 3、设置子进程信号处理函数,防止init的子进程成为僵尸进程。
- 4、解析init.rc文件
- 5、通过fork+execv启动zygote、media、surfaceflinger等服务。
int main(int argc, char** argv) {
property_init();
signal_handler_init();
start_property_service();
}
二、属性服务
三、解析init.rc
init.rc语句类型包含5种:Action、Command、Service、Option和Import
on <trigger> [&&<trigger>]* //设置触发器
<command>
<command> //动作触发后要执行的命令
service <name> <pathname> [<argument>] * //设置服务
<option> //option是service的修饰词,影响什么时候、如何启动service
<option>
system/core/init/init.cpp
int main(int argc, char** argv) {
android::init::main(argc, argv);
}
在Linux新的内核中,epoll用来替换select,epoll是Linux内核为处理大批量文件描述符而做了改进的poll,是Linux下多路复用I/O接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统 CPU 利用率。epoll 内部用于保存事件的数据类型是红黑树,查找速度快,select采用的数组保存信息,查找速度很慢,只有当等待少量文件描述符时,epoll和select的效率才会差不多。
四、zygote
system/core/rootdir/init.zygote32.rc
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
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
class AppRuntime : public AndroidRuntime
{
//......
}
int main(int argc, char* const argv[])
{
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
// Process command line arguments
// ignore argv[0]
argc--;
argv++;
const char* spaced_commands[] = { "-cp", "-classpath" };
/**
* 1、将argv中的spaced_commands参数通过runtime.addOption传递给AppRuntime
* 2、解析argv,判断是哪种启动模式
* --zygote : Start in zygote mode
* --start-system-server : Start the system server.
* --application : Start in application (stand alone, non zygote) mode.
* --nice-name : The nice name for this process.
*/
Vector<String8> args;
if (!className.isEmpty()) {
// We're not in zygote mode, the only argument we need to pass
// to RuntimeInit is the application argument.
//
// The Remainder of args get passed to startup class main(). Make
// copies of them before we overwrite them with the process name.
args.add(application ? String8("application") : String8("tool"));
runtime.setClassNameAndArgs(className, argc - i, argv + i);
} else {
// We're in zygote mode.
maybeCreateDalvikCache();
if (startSystemServer) {
args.add(String8("start-system-server"));
}
char prop[PROP_VALUE_MAX];
if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
ABI_LIST_PROPERTY);
return 11;
}
String8 abiFlag("--abi-list=");
abiFlag.append(prop);
args.add(abiFlag);
// In zygote mode, pass all remaining arguments to the zygote
// main() method.
for (; i < argc; ++i) {
args.add(String8(argv[i]));
}
}
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string(), true /* setProcName */);
}
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
}
}
//frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
//......
const char* rootDir = getenv("ANDROID_ROOT");
if (rootDir == NULL) {
rootDir = "/system";
if (!hasDir("/system")) {
LOG_FATAL("No root directory specified, and /android does not exist.");
return;
}
setenv("ANDROID_ROOT", rootDir, 1);
}
//......
}
//frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
//......
/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
//......
}
//libnativehelper/JniInvocation.cpp
bool JniInvocation::Init(const char* library) {
char buffer[PROP_VALUE_MAX];
library = GetLibrary(library, buffer);
// Load with RTLD_NODELETE in order to ensure that libart.so is not unmapped when it is closed.
// This is due to the fact that it is possible that some threads might have yet to finish
// exiting even after JNI_DeleteJavaVM returns, which can lead to segfaults if the library is
// unloaded.
const int kDlopenFlags = RTLD_NOW | RTLD_NODELETE;
handle_ = dlopen(library, kDlopenFlags);
//......
if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_),
"JNI_GetDefaultJavaVMInitArgs")) {
return false;
}
if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),
"JNI_CreateJavaVM")) {
return false;
}
if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_),
"JNI_GetCreatedJavaVMs")) {
return false;
}
return true;
}
bool JniInvocation::FindSymbol(void** pointer, const char* symbol) {
*pointer = dlsym(handle_, symbol);
if (*pointer == NULL) {
ALOGE("Failed to find symbol %s: %s\n", symbol, dlerror());
dlclose(handle_);
handle_ = NULL;
return false;
}
return true;
}
//frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
//......
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
onVmCreated(env);
//......
}
//frameworks/base/core/jni/AndroidRuntime.cpp
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{
//省略大量options解析和添加代码
initArgs.version = JNI_VERSION_1_4;
initArgs.options = mOptions.editArray();
initArgs.nOptions = mOptions.size();
initArgs.ignoreUnrecognized = JNI_FALSE;
/*
* Initialize the VM.
*
* The JavaVM* is essentially per-process, and the JNIEnv* is per-thread.
* If this call succeeds, the VM is ready, and we can start issuing
* JNI calls.
*/
if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
ALOGE("JNI_CreateJavaVM failed\n");
return -1;
}
return 0;
}
//libnativehelper/JniInvocation.cpp
jint JniInvocation::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
return JNI_CreateJavaVM_(p_vm, p_env, vm_args);
}
extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
return JniInvocation::GetJniInvocation().JNI_CreateJavaVM(p_vm, p_env, vm_args);
}
这里就调用到了libart.so中。
//frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
//......
/*
* Register android functions.
*/
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
//......
}
/*
* Register android native functions with the VM.
*/
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
ATRACE_NAME("RegisterAndroidNatives");
/*
* This hook causes all future threads created in this process to be
* attached to the JavaVM. (This needs to go away in favor of JNI
* Attach calls.)
*/
androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
ALOGV("--- registering native functions ---\n");
/*
* Every "register" function calls one or more things that return
* a local reference (e.g. FindClass). Because we haven't really
* started the VM yet, they're all getting stored in the base frame
* and never released. Use Push/Pop to manage the storage.
*/
env->PushLocalFrame(200);
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
env->PopLocalFrame(NULL);
return -1;
}
env->PopLocalFrame(NULL);
//createJavaThread("fubar", quickTest, (void*) "hello");
return 0;
}
这里主要完成2个工作:
- 设置线程创建函数
- 动态注册大量Android Jni方法
//frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
//......
/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
char* slashClassName = toSlashClassName(className != NULL ? className : "");
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
free(slashClassName);
ALOGD("Shutting down VM\n");
if (mJavaVM->DetachCurrentThread() != JNI_OK)
ALOGW("Warning: unable to detach main thread\n");
if (mJavaVM->DestroyJavaVM() != 0)
ALOGW("Warning: VM did not shut down cleanly\n");
}
这里通过JNI反射调用ZygoteInit的main方法,从而进入到java世界。
总结:Zygote进程的主要工作:
- 创建AppRuntime并调用其start函数。
- 创建Java虚拟机并为Java虚拟机注册JNI函数。
- 通过JNI反射调用ZygoteInit的main方法,从而进入到java世界。
- 通过registerZygoteSocket创建服务端Socket,并通过runSelectLoop方法等待AMS的请求来创建新的应用进程。
- 启动SystemServer进程。
4.1、JVM虚拟机
运行时库又分为核心库和ART(Android 5.0系统之后,Dalvik虚拟机被ART取代)。核心库提供了Java语言核心库的 大多数功能,这样开发者可以使用Java语言来编写Android应用。
与JVM相比,Dalvik虚拟机(DVM)是专门为移动设备定制的,允许在有限的内存中同时运行多个虚拟机的实例,并且每一个Dalvik应用作为一个独立的Linux进程执行。独立的进程可以防止在虚拟机崩溃的时候所有程序都被关闭。
而替代DVM的ART的机制与DVM不同,DVM中的应用每次运行时,字节码都需要通过即时编译器(Just In Time,JIT)转换为机器码,这会使得应用的运行效率降低。而在ART中,系统在安装应用时会进行一次预编译(Ahead Of Time,AOT),将字节码预先编译成机器码并存储在本地,这样应用每次运行时就不需要执行编译了,运行效率也大大提高。
五、SystemServer
- 1、通过Looper.prepareMainLooper()创建消息队列
- 2、加载libandroid_servers.so动态库
- 3、通过createSystemContext()创建ActivityThread,并获取context。
六、Launcher
七、启动我们的app
- RootActivityContainer : Activity 容器的根节点
- ActivityDisplay:每个实例代表系统中的一个显示屏幕,也就是说如果你的Android设备是多屏的,那么将会有多个ActivityDisplay实例。
- ActivityStack: Activity栈,用于表示管理栈中的Activity。
- TaskRecord:ActivityRecord列表的封装类,在ActivityStack中用于记录历史运行的Activity。
- ActivityRecord:ActivityRecord表示历史运行的Activity对象。
通过dumpsys activity a命令可查看当前设备的activity栈结构。