一Android 虚拟机的进程管理
Android 虚拟机进程管理是依赖linux的进程体系结构的,要为应用程序创建一个进程,它会使用linux的fork机制来复制一个进程(复制进程比创建进程更高效) 。执行这个操作的就是zygote。
zygote是一个虚拟机进程,也是一个虚拟机实例的孵化器。当一个应用程序启动时,会通过socket发出请求,zygote在收到请求后会fork一个新的应用程序进程。
这么做的优点:
1)zygote进程是系统启动时创建的,他会完成虚拟机的初始化、库的加载、预制类库的加载和初始化等操作。
2)当系统需要一个新的虚拟机实例时,zygote通过复制自身,最快速的提供一个进程。
3)对于只读的系统库,所有虚拟机实例都和zygote共享一块内存区域,节省了内存开销。
4)调用fork()函数生成一个子进程时,内核并没有马上为这个子进程分配物理内存,而是先共享父进程的资源,如果子进程对先有资源不满足了,要做自己的修改,比如去执行exec,这时COW技术就起作用了,COW就是多个对象在起始时是共享某些资源的,直到某个对象需要修改该资源时才拥有自己的一份拷贝。所以,这个fork的过程就非常快了。
1.1 Zygote
在Android中,所有的应用程序进程及系统服务进程(SystemServer)都是有Zygote进程孕育出来的。当AMS启动一个应用程序时,会通过Socket与Zygote进程通信,请求Zygote孕育出一个子进程作为即将要启动的应用程序的进程。
Andorid是基于Linux内核的,在Linux中,所有的进程都是init进程直接或间接孕育出来的。Zygote进程也是,它是在系统启动的过程中,通过解析init.rc脚本来启动的。
Zygote的启动相关的.rc文件会32位、64位。
init.zygote32.rc
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
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
writepid /dev/cpuset/foreground/tasks
启动后看到的进程名是Zygote,其最初的名字是app_process。
1)app_process的主函数main,
frameworks/base/cmds/app_process
int main(int argc, char* const argv[])@app_main.cpp{
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
niceName.setTo(arg + 12);
} else if (strncmp(arg, "--", 2) != 0) {
className.setTo(arg);
break;
} else {
--i;
break;
}
}
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
}
}
这个函数的主要作用是创建一个AppRuntime变量,然后调用他的start方法。AppRuntime类也定义在app_main.cpp中,
app_main.cpp
class AppRuntime : public AndroidRuntime{
public:
AppRuntime(char* argBlockStart, const size_t argBlockLength)
: AndroidRuntime(argBlockStart, argBlockLength)
, mClass(NULL)
{
}
}
AppRuntime继承自AndroidRuntime(frameworks/base/core/jni)。
AndroidRuntime.cpp
AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :
mExitWithoutCleanup(false),
mArgBlockStart(argBlockStart),
mArgBlockLength(argBlockLength)
{
SkGraphics::Init();
// Pre-allocate enough space to hold a fair number of options.
mOptions.setCapacity(20);
assert(gCurRuntime == NULL); // one per process
gCurRuntime = this;
}
当创建AppRuntime对象时,会调用父类AndroidRuntime的构造函数,在AndroidRuntime的构造函数里,会将this指针保存到静态全局变量gCurRuntime中,这样其他地方需要使用这个AppRuntime对象时,可以通过下面的函数获取这个对象的指针。
AndroidRuntime* AndroidRuntime::getRuntime()
{
return gCurRuntime;
}
接着看app_main.cpp的的main()函数,根据init.rc中的启动参数:--zygote--start-system-server,最终会执行的语句是:
runtime.start("com.android.internal.os.ZygoteInit",args, zygote);
直接调用父类的start函数。
2)AndroidRuntime.start
AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)@AndroidRuntime.cpp{
static const String8 startSystemServer("start-system-server");
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
char* slashClassName = toSlashClassName(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);
}
}
}
这个函数的主要作用是启动Android系统运行时库,主要做了三件事情,一是调用函数startVM启动虚拟机,二是调用函数startReg注册jni方法,三是最后那段代码块,调用com.android.internal.os.ZygoteInit类的main函数。
在StartVm前,调用了JniInvocation的init函数,这个函数在libnativehelper/JniInvocation.cpp中
bool JniInvocation::Init(const char* library) {
#ifdef __ANDROID__
char buffer[PROP_VALUE_MAX];
#else
char* buffer = NULL;
#endif
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 (handle_ == NULL) {
if (strcmp(library, kLibraryFallback) == 0) {
// Nothing else to try.
ALOGE("Failed to dlopen %s: %s", library, dlerror());
return false;
}
// Note that this is enough to get something like the zygote
// running, we can't property_set here to fix this for the future
// because we are root and not the system user. See
// RuntimeInit.commonInit for where we fix up the property to
// avoid future fallbacks. http://b/11463182
ALOGW("Falling back from %s to %s after dlopen error: %s",
library, kLibraryFallback, dlerror());
library = kLibraryFallback;
handle_ = dlopen(library, kDlopenFlags);
if (handle_ == NULL) {
ALOGE("Failed to dlopen %s: %s", library, dlerror());
return false;
}
}
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;
}
通过其中的GetLibrary(null,,,)函数,因为参数为null,获取默认的default_library为libart.so,接着是dlopen打开这个libart.so文件,调用FindSymbol函数从
libart.so中搜索符号JNI_CreateJavaVM,对应文件ar/runtime/java_vm_ext.cc中的JNI_CreateJavaVM函数。这个不同的库文件对应不同的文件,如果是dalvik虚拟机,对应libdvm.so,相应的符号JNI_CreateJavaVM对应就是dalvikvm中的文件函数。
在调用AndroidRuntime::startVm()启动虚拟机时,函数的最后就是调用JNI_CreateJavaVM函数。
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote){
/*
* 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;
}
}
接着看art/runtime/Java_vm_ext.cc文件中的JNI_CreateJavaVM函数
extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
ScopedTrace trace(__FUNCTION__);
const JavaVMInitArgs* args = static_cast<JavaVMInitArgs*>(vm_args);
if (IsBadJniVersion(args->version)) {
LOG(ERROR) << "Bad JNI version passed to CreateJavaVM: " << args->version;
return JNI_EVERSION;
}
RuntimeOptions options;
//解析虚拟机参数存到javaVMOption中。
for (int i = 0; i < args->nOptions; ++i) {
JavaVMOption* option = &args->options[i];
options.push_back(std::make_pair(std::string(option->optionString), option->extraInfo));
}
bool ignore_unrecognized = args->ignoreUnrecognized;
//调用create函数,创建Runtime实例。
if (!Runtime::Create(options, ignore_unrecognized)) {
return JNI_ERR;
}
// Initialize native loader. This step makes sure we have
// everything set up before we start using JNI.
android::InitializeNativeLoader();
//获取runtime实例,然后调用其start方法。
Runtime* runtime = Runtime::Current();
bool started = runtime->Start();
if (!started) {
delete Thread::Current()->GetJniEnv();
delete runtime->GetJavaVM();
LOG(WARNING) << "CreateJavaVM failed";
return JNI_ERR;
}
*p_env = Thread::Current()->GetJniEnv();
*p_vm = runtime->GetJavaVM();
return JNI_OK;
}
调用art/runtime/Runtime.cc中的create函数,创建
Runtime实例,然后初始化runtime。
bool Runtime::Create(RuntimeArgumentMap&& runtime_options) {
// TODO: acquire a static mutex on Runtime to avoid racing.
if (Runtime::instance_ != nullptr) {
return false;
}
instance_ = new Runtime;
if (!instance_->Init(std::move(runtime_options))) {
// TODO: Currently deleting the instance will abort the runtime on destruction. Now This will
// leak memory, instead. Fix the destructor. b/19100793.
// delete instance_;
instance_ = nullptr;
return false;
}
return true;
调用的art/runtime/Runtime.cc中的start函数。
bool Runtime::Start() {
VLOG(startup) << "Runtime::Start entering";
CHECK(!no_sig_chain_) << "A started runtime should have sig chain enabled";
// If a debug host build, disable ptrace restriction for debugging and test timeout thread dump.
// Only 64-bit as prctl() may fail in 32 bit userspace on a 64-bit kernel.
#if defined(__linux__) && !defined(__ANDROID__) && defined(__x86_64__)
if (kIsDebugBuild) {
CHECK_EQ(prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY), 0);
}
#endif
// Restore main thread state to kNative as expected by native code.
Thread* self = Thread::Current();
self->TransitionFromRunnableToSuspended(kNative);
started_ = true;
// Create the JIT either if we have to use JIT compilation or save profiling info.
// TODO(calin): We use the JIT class as a proxy for JIT compilation and for
// recoding profiles. Maybe we should consider changing the name to be more clear it's
// not only about compiling. b/28295073.
if (jit_options_->UseJitCompilation() || jit_options_->GetSaveProfilingInfo()) {
std::string error_msg;
if (!IsZygote()) {
// If we are the zygote then we need to wait until after forking to create the code cache
// due to SELinux restrictions on r/w/x memory regions.
CreateJit();
} else if (jit_options_->UseJitCompilation()) {
if (!jit::Jit::LoadCompilerLibrary(&error_msg)) {
// Try to load compiler pre zygote to reduce PSS. b/27744947
LOG(WARNING) << "Failed to load JIT compiler with error " << error_msg;
}
}
}
if (!IsImageDex2OatEnabled() || !GetHeap()->HasBootImageSpace()) {
ScopedObjectAccess soa(self);
StackHandleScope<2> hs(soa.Self());
auto class_class(hs.NewHandle<mirror::Class>(mirror::Class::GetJavaLangClass()));
auto field_class(hs.NewHandle<mirror::Class>(mirror::Field::StaticClass()));
class_linker_->EnsureInitialized(soa.Self(), class_class, true, true);
// Field class is needed for register_java_net_InetAddress in libcore, b/28153851.
class_linker_->EnsureInitialized(soa.Self(), field_class, true, true);
}
// InitNativeMethods needs to be after started_ so that the classes
// it touches will have methods linked to the oat file if necessary.
{
ScopedTrace trace2("InitNativeMethods");
InitNativeMethods();
}
// Initialize well known thread group values that may be accessed threads while attaching.
InitThreadGroups(self);
Thread::FinishStartup();
system_class_loader_ = CreateSystemClassLoader(this);
if (is_zygote_) {
if (!InitZygote()) {
return false;
}
} else {
if (is_native_bridge_loaded_) {
PreInitializeNativeBridge(".");
}
NativeBridgeAction action = force_native_bridge_
? NativeBridgeAction::kInitialize
: NativeBridgeAction::kUnload;
InitNonZygoteOrPostFork(self->GetJniEnv(),
/* is_system_server */ false,
action,
GetInstructionSetString(kRuntimeISA));
}
StartDaemonThreads();
{
ScopedObjectAccess soa(self);
self->GetJniEnv()->locals.AssertEmpty();
}
VLOG(startup) << "Runtime::Start exiting";
finished_starting_ = true;
if (profiler_options_.IsEnabled() && !profile_output_filename_.empty()) {
// User has asked for a profile using -Xenable-profiler.
// Create the profile file if it doesn't exist.
int fd = open(profile_output_filename_.c_str(), O_RDWR|O_CREAT|O_EXCL, 0660);
if (fd >= 0) {
close(fd);
} else if (errno != EEXIST) {
LOG(WARNING) << "Failed to access the profile file. Profiler disabled.";
}
}
if (trace_config_.get() != nullptr && trace_config_->trace_file != "") {
ScopedThreadStateChange tsc(self, kWaitingForMethodTracingStart);
Trace::Start(trace_config_->trace_file.c_str(),
-1,
static_cast<int>(trace_config_->trace_file_size),
0,
trace_config_->trace_output_mode,
trace_config_->trace_mode,
0);
}
return true;
}
通过Thread::Current();获取当前的运行线程,然后将线程挂起,初始化本地函数InitNativeMethods();等等。。。
3)ZygoteInit.java (frameworks/base/core/java/com/android/internal/os)
ZygoteInit.java
public static void main(String argv[]) @ZygoteInit.java{
registerZygoteSocket(socketName);
preload();
startSystemServer(abiList, socketName);
runSelectLoop(abiList);
}
这个函数主要做了三件事情,一是调用registerZygoteSocket函数创建了一个socket接口,用来跟系统服务通信,二是调用startSystemServer函数启动SystemServer进程,三是调用runSelectLoop函数进入一个无限循环,在socket接口上等待系统服务创建应用程序进程的请求。
4) registerZygoteSocket函数
private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
private static void registerZygoteSocket(String socketName)@ZygoteInit.java {
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
String env = System.getenv(fullSocketName);
fileDesc = Integer.parseInt(env);
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
sServerSocket = new LocalServerSocket(fd);
}
这接口的socket是通过文件描述符创建的,这个文件描述符就是/dev/socket/zygote文件,可以通过环境变量ANDROID_SOCKET_PREFIX +socketName来得到。那么这个环境的值又是谁来设置的?系统启动的init.rc脚本是由init.cpp文件来解析的,具体到service命令是由Service.cpp来解析的,
system/core/init/Service.cpp
bool Service::Start() @service.cpp{
pid_t pid = fork();
for (const auto& si : sockets_) {
int socket_type = ((si.type == "stream" ? SOCK_STREAM :
(si.type == "dgram" ? SOCK_DGRAM :
SOCK_SEQPACKET)));
const char* socketcon =
!si.socketcon.empty() ? si.socketcon.c_str() : scon.c_str();
int s = create_socket(si.name.c_str(), socket_type, si.perm,
si.uid, si.gid, socketcon);
if (s >= 0) {
PublishSocket(si.name, s);
}
}
}
每个service命令都会让init进程调用fork函数来创建一个新的进程,在新的进程中会解析socket选项对于每个socket选项,会通过creae_socket函数在/dev/socket/目录下创建一个文件,这个场景中创建的文件是zygote,然后把得到的文件描述符通过publish_socket函数写入环境变量中。
void Service::PublishSocket(const std::string& name, int fd) const @service.cpp{
std::string key = StringPrintf(ANDROID_SOCKET_ENV_PREFIX "%s", name.c_str());
std::string val = StringPrintf("%d", fd);
add_environment(key.c_str(), val.c_str());
/* make sure we don't close-on-exec */
fcntl(fd, F_SETFD, 0);
}
这里传进来的参数name是zygote,添加前缀:
#defineANDROID_SOCKET_ENV_PREFIX "ANDROID_SOCKET_"
因此这个文件描述符相应的key值是:ANDROID_SOCKET_zygote,通过add_environment添加到环境变量中。
因为registerZygoteSocket()@ZygoteInit.java函数和create_socket函数都是运行在init进程中的,所以在registerZygoteSocket函数中可以直接使用这个文件描述符来创建一个java层的LocalServerSocket对象。
其他进程如果要打开/dec/socket/zygote文件来和zygote进程通信,就要文件名来连接这个LocalServerSocket对象,如AMS通过Process.start函数来创建一个新的进程,Process.start函数会先通过Socket连接到Zygote进程中,最终由Zygote进程来完成创建新的应用程序进程,这个过程中Process类是通过openZygoteSocketIfNeeded函数来连接到Zygote进程中的Socket。
public static final String ZYGOTE_SOCKET = "zygote";
private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx @Process.java{
primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);
}
这里的ZYGOTE_SOCKET对应了/dev/socket/目录下的zygote文件。
Android中的socket机制和binder机制类似,都可以用来实现进程间通信。现在回到ZygoteInit.main()函数中,接着是startSystemServer启动SystemServer进程。
5)startSystemServer
ZygoteInit.java
private static boolean startSystemServer(String abiList, String socketName)@ZygoteInit.java{
/* 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,
1032,3001,3002,3003,3006,3007,3009,3010",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"com.android.server.SystemServer",
};
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
/* For child process */
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
handleSystemServerProcess(parsedArgs);
}
}
Zygote进程通过Zygote.forkSystemServer()函数来创建新的进程,新创建的进程会执行handleSystemServerProcess函数。
6) handleSystemServerProcess
ZygoteInit.java
private static void handleSystemServerProcess(
ZygoteConnection.Arguments parsedArgs)
throws ZygoteInit.MethodAndArgsCaller@ZygoteInit.java {
closeServerSocket();
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
}
这个函数的重点是调用RuntimeInit.zygoteInit函数进一步启动SystemServer组件。由于zygote进程创建的子进程会继承zygote中socket文件描述符,如果子进程不会用到,就可以调用closeServerSocket函数关闭它。
7)zygoteInit
RuntimeInit.java
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller @RuntimeInit.java{
nativeZygoteInit();
applicationInit(targetSdkVersion, argv, classLoader);
}
这个函数执行两个操作,一是调用nativeZygoteInit函数执行Binder进程间通信机制的初始化工作,完成后,进程间的Bidner对象就可以方便地进行进程间通信了,二是调用com.android.server.systemserver类的main函数,这个是applicationInit中执行的。
8)nativeZygoteInit
这是个native函数,实现在AndroidRuntime.cpp中。
static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
@AndroidRuntime.cpp{
gCurRuntime->onZygoteInit();
}
onZygoteInit调用的具体子类AppRuntime中的实现,
virtual void onZygoteInit()@app_main.cpp{
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
proc->startThreadPool();
}
通过ProcessState,IPCThreadState完成进程间通信Binder的准备工作。
回到7)步中,接着执行com.android.server.systemserver类的main函数。
9)SystemServer.main
public static void main(String[] args) @SystemServer.java{
new SystemServer().run();
}
private void run() @SystemServer.java{
Looper.prepareMainLooper();
startBootstrapServices();
startCoreServices();
startOtherServices();
Looper.loop();
}
这里会启动一个systemserver主线程,来完成各类系统服务的启动。
各类服务启动完成后,层层返回,到3)步中ZygoteInit.main中,最后执行的是runSelectLoop进入一个无限循环,在socket上等待创建引用进程的请求。
10)runSelectLoop
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller @ZygoteInit.java{
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 = 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 {
boolean done = peers.get(i).runOnce();
if (done) {
peers.remove(i);
fds.remove(i);
}
}
}
}
}
这个循环等待系统服务来连接socket,然后调用runOnce函数创建新的进程。
系统启动时,init进程会创建zygote进程,zygote进程负责后续Android应用程序框架层的其他进程的创建和启动;
zygote进程会先创建一个systemserver进程,systemserver进程负责启动启动的关键服务,如WindowManagerService,ActivityManagerService等;
当需要启动一个Android应用程序时,AMS会通过通过socket进程间通信机制,通知zygote进程为这个应用程序创建一个新的进程。