在讲解 Zygote 之前,考虑到不同的系统版本源码都不相同,以下分析的源码基于 Android 8.0.0。
当系统启动时,init 进程是继 Linux 内核启动后第二个启动的进程,它是在用户空间被创建的进程,可以通过命令 adb shell ps 查看 init 进程的 pid:
上图中 PID 是当前进程的 id,PPID 是父进程的 id,并且 Linux 的进程 PID 是按启动顺序从前往后排序。
init 进程在上图中的 pid=1,而 Linux 内核的 pid=0,这也是验证了 init 进程是继 Linux 内核启动后启动的下一个进程。
init 进程主要有两个作用:
启动系统关键的服务
守护关键服务,如果其中一个关键服务被杀死,将会重启手机
怎样的服务属于关键服务?关键服务是对于手机而言必不可少的服务,比如网络服务、蓝牙服务、铃声服务等,同样可以通过 adb shell ps 查看 ppid=1 的其他服务,就是由 init 进程启动守护的关键服务:
上图中例如 installd、servicemanager、surfaceflinger 等 ppid=1 的都是由 init 进程启动的关键服务。
所以 如果要实现一个系统服务又不想被杀死,最好的方式就是让服务由 init 进程启动成为关键服务。
init 进程也是一段可执行的程序,所以也有对应的相关代码。init.c 代码具体是在 Android 源码目录 /system/core/init/init.cpp。
而我们常说的 init.rc,你可以理解为它是 init 进程要执行的任务清单,其实就是一个执行脚本:
import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${ro.zygote}.rc // 启动 zygote 的执行脚本
...
可以看到 init.rc 任务清单中其实也是导入的其他待执行的任务清单的文件路径,其中就有启动 zygote 的执行脚本,ro.zygote 会根据系统类型获取对应的执行脚本文件,例如 32 位获取的就是 init.zygote32.rc,64 位获取的就是 init.zygote64.rc:
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
第一行脚本信息记录的要执行的程序入口位置,会先执行 /system/bin/app_process 下的 app_main.c,-Xzygote /system/bin --zygote --start-system-server 是入口程序传入的参数。
上面提到,init.rc 是一段执行脚本,其中就有启动 Zygote 进程的执行文件 init.zygote32.rc 或 init.zygote64.rc,该文件会执行 /frameworks/base/cmds/app_process/app_main.c 的 main() 函数启动 Zygote:
/frameworks/base/cmds/app_process/app_main.c
#if defined(__LP64__)
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist64";
static const char ZYGOTE_NICE_NAME[] = "zygote64";
#else
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist32";
static const char ZYGOTE_NICE_NAME[] = "zygote";
#endif
// argv 就是脚本传入的参数 -Xzygote /system/bin --zygote --start-system-server
int main(int argc, char* const 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;
}
...
}
...
for (; i < argc; ++i) {
args.add(String8(argv[i]));
}
// 将 app_process 修改为 zygote
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string(), true /* setProcName */);
}
if (zygote) {
// 在 system/core/rootdir/init.zygote32.rc(或 init.zygote.64.rc) 解析到参数 --zygote,所以 zygote == true,通过 runtime.start() 创建 Zygote 进程
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
}
...
}
上面的代码 将 app_process 修改为了 Zygote,所以 Zygote 一开始并不是这个名称,而是在启动时才被修改为 Zygote。
Zygote 虽然是在 Framework native 层由 C 语言的 main() 入口执行创建的,因为 init 进程是在用户空间,init 进程创建了 Zygote,所以 Zygote 是在用户空间。
我们接着看 runtime.start() 做了什么事情:
/frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
...
// 创建虚拟机,startVm() 有很多虚拟机的参数配置,比如内存大小
// 内存调优和其他虚拟机的调优就是在这个函数处理
/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
onVmCreated(env);
// 动态注册 java 调用 native 的 jni
// 我们在写 java 代码时能声明 native 方法调用 C/C++ 函数,就是因为在这里做了注册处理了映射关系
/*
* Register android functions.
*/
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
...
// 调用 com.android.internal.os.ZygoteInit 的 main 方法
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
} else {
env->CallStaticVoidMethod(startClass, startMeth, strArray);
}
...
}
runtime.start() 主要做了三件事情:
startVm() 创建虚拟机
startReg() 动态注册 java 调用 native 的 jni
反射调用 ZygoteInit 的 main()
通过 startVm() 创建虚拟机,startVm() 有很多虚拟机的参数配置,比如堆内存大小,如果是系统工程师,内存调优和其他虚拟机的调优就是在这个函数处理。
startReg() 动态注册 java 调用 native 的 jni,我们在写 java 代码时能声明 native 方法调用 C/C++ 函数,就是因为在这里做了注册处理了映射关系。以 MessageQueue 为例子:
// 在 startReg() 动态注册,将 java 和 C/C++ 的函数关联
static const JNINativeMethod gMessageQueueMethods[] = {
{."nativeInit", "()J", (void*)android_os_MessageQueue_nativeInit },
...
};
int register_android_os_MessageQueue(JNIEnv* env) {
...
}
最终就是调用 ZygoteInit 的 main() 方法,到这里就开始进入 java 的世界。
我们简单总结下 Zygote 在 native 的处理流程,如下图:
在 native 创建了 Zygote,并且通过 AndroidRuntime.start() 从 native 层转到 java 层 ZygoteInit 的 main() 入口继续处理 Zygote 相关流程:
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
// argv 就是 init.{ro.zygote}.rc 脚本写的参数
// -Xzygote /system/bin --zygote --start-system-server
public static void main(String argv[]) {
// 创建 ServerSocket
ZygoteServer zygoteServer = new ZygoteServer();
...
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]);
}
...
}
zygoteServer.registerServerSocket(socketName);
...
// 加载系统类、系统资源等
if (!enableLazyPreload) {
...
preload(bootTimingsTraceLog);
...
}
...
// 创建 SystemServer
if (startSystemServer) {
startSystemServer(abiList, socketName, zygoteServer);
}
// ZygoteServer 创建 ServerSocket 作为服务器
// 开启循环,等待接收 socket 通信 fork app 进程的请求
// 没有消息会一直阻塞休眠等待,Zygote 进程会一直存活运行
zygoteServer.runSelectLoop(abiList);
zygoteServer.closeServerSocket();
...
}
在 ZygoteInit 的 main() 入口方法主要做了三件事情:
预先加载系统资源,如系统类、资源、系统共享库等
创建 ZygoteServer,其实就是 ServerSocket 循环等待通知 fork 子进程
创建 SystemServer 进程
我们先看下预先加载资源 preload() 做了什么事情:
static void preload(TimingsTraceLog bootTimingsTraceLog) {
...
// 系统类加载
preloadClasses();
...
// 系统资源加载
preloadResources();
...
// openGL加载
preloadOpenGL();
...
// 系统共享库加载
preloadSharedLibraries();
// 文字资源加载
preloadTextResources();
...
}
private static final String PRELOADED_CLASSES = "/system/etc/preloaded-classes";
private static void preloadClasses() {
...
InputStream is;
try {
// 获取要加载的系统资源文件流
is = new FileInputStream(PRELOADED_CLASSES);
} catch (FileNotFoundException e) {
Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
return;
}
...
BufferedReader br
= new BufferedReader(new InputStreamReader(is), 256);
int count = 0;
String line;
while ((line = br.readLine()) != null) {
...
try {
// 读取 /system/etc/preloaded-classes 的类路径并加载
Class.forName(line, true, null);
}
...
}
...
}
public static final boolean PRELOAD_RESOURCES = true;
private static void preloadResources() {
...
mResources = Resources.getSystem();
mResources.startPreloading();
if (PRELOAD_RESOURCES) {
TypedArray ar = mResources.obtainTypedArray(
com.android.internal.R.array.preloaded_drawables);
int N = preloadDrawables(ar);
ar.recycle();
ar = mResources.obtainTypedArray(
com.android.internal.R.array.preloaded_color_state_lists);
N = preloadColorStateLists(ar);
ar.recycle();
...
}
mResources.finishPreloading();
}
preload() 主要是预先加载了系统类、系统资源、系统共享库、openGL、文字资源等,其中系统类是读取的 preloaded-classes。因为系统类较多,下面只截取了文件的一部分,具体可以在源码查看该文件:
frameworks/base/preloaded-classes
...
android.app.Activity
android.app.Activity$HostCallbacks
android.app.ActivityManager
android.app.ActivityManager$1
android.app.ActivityManager$RecentTaskInfo
android.app.ActivityManager$RecentTaskInfo$1
android.app.ActivityManager$RunningAppProcessInfo
android.app.ActivityManager$RunningAppProcessInfo$1
android.app.ActivityManager$RunningServiceInfo
android.app.ActivityManager$RunningServiceInfo$1
android.app.ActivityManager$RunningTaskInfo
android.app.ActivityManager$RunningTaskInfo$1
android.app.ActivityManager$StackId
android.app.ActivityManager$TaskDescription
android.app.ActivityManager$TaskDescription$1
android.app.ActivityOptions
android.app.ActivityThread
android.app.ActivityThread$1
android.app.ActivityThread$2
android.app.ActivityThread$ActivityClientRecord
android.app.ActivityThread$ActivityConfigChangeData
android.app.ActivityThread$AppBindData
android.app.ActivityThread$ApplicationThread
android.app.ActivityThread$BindServiceData
android.app.ActivityThread$ContextCleanupInfo
android.app.ActivityThread$CreateServiceData
android.app.ActivityThread$DropBoxReporter
android.app.ActivityThread$EventLoggingReporter
android.app.ActivityThread$GcIdler
android.app.ActivityThread$H
...
可以发现这些全类名路径就是我们在 app 开发中使用的四大组件 Activity、Fragment、常用控件 TextView 等。
所以我们 app 运行的时候,字体库、资源、系统类就是从这里来的,因为 Zygote 启动时已经提前预先加载好了。
在 Zygote 预先加载这些资源的好处是,不需要每个 app 都去加载这些资源,而是使用提前预先加载好的这些类和资源,可以直接使用。
需要注意的是,因为 preoload() 是在主进程调用的,而且会比较耗时,如果要对系统启动速度做优化,也可以从这个方法入手。
首先我们要明白,什么是 fork?fork 可以理解为就是复制,所以 Zygote fork 进程其实就是在 Zygote 基础上复制一个进程作为子进程,子进程拥有 Zygote 已经处理好的资源。
Zygote 其中的一个职责是负责 fork 子进程的创建,比如要接收 AMS 通过 socket 通信告知创建 app 进程,此时 AMS 是客户端,Zygote 作为服务端要接收 socket 消息,就需要创建 ServerSocket 服务器循环等待。
class ZygoteServer {
private LocalServerSocket mServerSocket;
void registerServerSocket(String socketName) {
if (mServerSocket == null) {
...
try {
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
// 创建 ServerSocket
mServerSocket = new LocalServerSocket(fd);
} catch (IOException ex) {
...
}
}
}
void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
...
// 循环等待 socket 消息通知 fork 进程
while (true) {
...
try {
// 没有消息休眠等待
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
...
}
for (int i = pollFds.length - 1; i >= 0; --i) {
...
boolean done = peers.get(i).runOnce(this);
...
}
}
}
}
ZygoteConnection.java
boolean runOnce(ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller {
...
// fork 子进程
pid = Zygote.forkAndSpecialize(...);
...
}
Zygote.java
public static int forkAndSpecialize(...) {
...
int pid = nativeForkAndSpecialize(...);
...
return pid;
}
native private static int nativeForkAndSpecialize(...);
frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(...) {
...
return ForkAndSpecializeCommon(...);
}
static pid_t ForkAndSpecializeCommon(...) {
...
// 调用 Linux 的 fork() 创建进程
pid_t pid = fork();
...
}
通过源码可以分析到,ZygoteServer 其实就是创建了一个 ServerSocket,在 ZygoteInit 调用 runSelectLoop() 作为服务端等待客户端 socket 通信告知 fork 进程,fork 进程是转到 native 层最终调用 Linux 标准函数 fork()。
在 ZygoteInit 会创建 SystemServer 进程,SystemServer 是 Zygote 创建的第一个子进程:
ZygoteInit.java
private static boolean startSystemServer(...) {
...
pid = Zygote.forkSystemServer(...);
...
return true;
}
关于如何 fork 在上一小节已经介绍,forkSystemServer() 只是创建了 SystemServer 进程,那么 SystemServer 是什么时候运行的呢?接着往下分析源码:
ZygoteInit.java
private static boolean startSystemServer(...) {
...
pid = Zygote.forkSystemServer(...);
...
if (pid == 0) {
...
handleSystemServerProcess(parsedArgs);
}
return true;
}
private static void handleSystemServerProcess(...) {
...
ZygoteInit.zygoteInit(...);
}
public static final void zygoteInit(...) {
...
// 初始化运行环境
RuntimeInit.commonInit();
// 打开 Binder 驱动,初始化 Binder
ZygoteInit.nativeZygoteInit();
// 反射调用 main() 入口函数
RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
RuntimeInit.java
protected static void applicationInit(...) {
...
// Remaining arguments are passed to the start class's static main
invokeStaticMain(args.startClass, args.startArgs, classLoader);
}
private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
Class<?> cl;
try {
cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
...
}
Method m;
try {
// 反射调用 main() 方法
m = cl.getMethod("main", new Class[] { String[].class });
} catch (NoSuchMethodException ex) {
...
}
...
}
SystemServer 进程的创建最终是通过反射 main() 函数执行。
SystemServer 是干嘛用的?继续分析 SystemServer 的源码。
SystemServer.java
public static void main(String[] args) {
new SystemServer().run();
}
private void run() {
...
// system_server 进程启动服务管理类
mSystemServiceManager = new SystemServiceManager(mSystemContext);
try {
// 启动引导服务
startBootstrapServices();
// 启动核心服务
startCoreServices();
// 启动其他服务
startOtherServices();
...
}
...
}
private void startBootstrapServices() {
...
// 启动 AMS 服务,在高版本是 ATMS
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mActivityManagerService.setInstaller(installer);
...
// 启动 PMS
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
...
}
private void startCoreServices() {
// 为了能让 SystemServiceManager 统一的方式管理服务,通过 SystemService 代理这些服务
mSystemServiceManager.startService(DropBoxManagerService.class);
mSystemServiceManager.startService(BatteryService.class);
mSystemServiceManager.startService(UsageStatsService.class);
mActivityManagerService.setUsageStatsManager(
LocalServices.getService(UsageStatsManagerInternal.class));
mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class);
}
private void startOtherServices() {
...
// 各种系统信息的管理,例如字体、系统设置、开发者选项等
mActivityManagerService.installSystemProviders();
...
}
SystemServer 其实是启动引导服务、核心服务和其他服务的入口,可以发现这些服务并不是通过 Zygote fork,而是直接 new 创建出来的,所以 这些服务都在 system_server 进程。
因为启动的服务较多,所以 SystemServer 创建了 SystemServiceManager 管理这些服务。
为了能统一的方式处理,这些服务通过 SystemService 代理的方式提供给 SystemServiceManager 管理。
在应用层各个进程都需要用到这些服务,那么这些进程是怎么获取到这些服务的?
我们以电量服务 BatteryService 举例:
public abstract class SystemService {
...
public abstract void onStart();
...
protected final void publishBinderService(String name, IBinder service,
boolean allowIsolated, int dumpPriority) {
// 将服务注册到 ServiceManager
ServiceManager.addService(name, service, allowIsolated, dumpPriority);
}
}
// 服务通过 SystemService 代理
public final class BatteryService extends SystemService {
@Override
public void onStart() {
...
// 注册服务到 ServiceManager
mBinderService = new BinderService();
publishBinderService("battery", mBinderService);
...
}
}
public final class SystemServer {
private void startCoreServices() {
...
mSystemServiceManager.startService(BatteryService.class);
...
}
}
public class SystemServiceManager {
@SuppressWarnings("unchecked")
public <T extends SystemService> T startService(Class<T> serviceClass) {
try {
final String name = serviceClass.getName();
...
final T service;
try {
Constructor<T> constructor = serviceClass.getConstructor(Context.class);
service = constructor.newInstance(mContext);
} catch (...) {
...
}
startService(service);
return service;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
public void startService(@NonNull final SystemService service) {
// Register it.
mServices.add(service);
// Start it.
long time = SystemClock.elapsedRealtime();
try {
service.onStart();
} catch (RuntimeException ex) {
throw new RuntimeException("Failed to start service " + service.getClass().getName()
+ ": onStart threw an exception", ex);
}
warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
}
}
可以看到这些服务经过 SystemServiceManager 统一管理后,最终都会把服务注册到 ServiceManager,ServiceManager 记录着 key 为服务名称 value 为服务的 Binder 列表,应用层进程根据服务名称就可以很方便的拿到要通信的 Binder。
ServiceManager 是一个独立的进程,它和 Zygote 一样也是在 init.rc 脚本执行时启动的独立进程。
我们再简单梳理下 SystemServer 做了哪些事情:
创建 SystemServiceManager 用于统一管理服务
启动各种服务如 AMS、PMS 等
将启动的服务注册到 ServiceManager
SystemServer 流程图如下:
Zygote fork 子进程启动子进程时会初始化 Binder,比如打开 Binder 驱动,每个进程都有自己的 Binder,具体调用是在子进程的 main() 函数执行之前调用 nativeZygoteInit():
ZygoteInit.java
public static final void zygoteInit(...) {
...
// 创建 Binder
ZygoteInit.nativeZygoteInit();
...
}
private static final native void nativeZygoteInit();
frameworks/base/core/jni/AndroidRuntime.cpp
static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
gCurRuntime->onZygoteInit();
}
int register_com_android_internal_os_ZygoteInit(JNIEnv* env)
{
const JNINativeMethod methods[] = {
{ "nativeZygoteInit", "()V",
(void*) com_android_internal_os_ZygoteInit_nativeZygoteInit },
};
return jniRegisterNativeMethods(env, "com/android/internal/os/ZygoteInit",
methods, NELEM(methods));
}
frameworks/base/cmds/app_process/app_main.cpp
virtual void onZygoteInit()
{
// 打开 Binder 驱动
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
// 启动 Binder 线程池
proc->startThreadPool();
}
frameworks/native/libs/binder/ProcessState.cpp
// Binder 通信数据大小 1M-8k
#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
// 最大 Binder 线程数量 15
#define DEFAULT_MAX_BINDER_THREADS 15
sp<ProcessState> ProcessState::self()
{
Mutex::Autolock _l(gProcessMutex);
if (gProcess != NULL) {
return gProcess;
}
gProcess = new ProcessState("/dev/binder");
return gProcess;
}
static int open_driver(const char *driver)
{
// 打开 Binder 驱动
int fd = open(driver, O_RDWR | O_CLOEXEC);
if (fd >= 0) {
int vers = 0;
status_t result = ioctl(fd, BINDER_VERSION, &vers);
if (result == -1) {
ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
close(fd);
fd = -1;
}
if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
ALOGE("Binder driver protocol(%d) does not match user space protocol(%d)! ioctl() return value: %d",
vers, BINDER_CURRENT_PROTOCOL_VERSION, result);
close(fd);
fd = -1;
}
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
if (result == -1) {
ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
}
} else {
ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));
}
return fd;
}
ProcessState::ProcessState(const char *driver)
: mDriverName(String8(driver))
, mDriverFD(open_driver(driver)) // 打开 binder 驱动
, mVMStart(MAP_FAILED)
, mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
, mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
, mExecutingThreadsCount(0)
, mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
, mStarvationStartTimeMs(0)
, mManagesContexts(false)
, mBinderContextCheckFunc(NULL)
, mBinderContextUserData(NULL)
, mThreadPoolStarted(false)
, mThreadPoolSeq(1)
{
if (mDriverFD >= 0) {
// mmap 内存映射
// mmap the binder, providing a chunk of virtual address space to receive transactions.
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
if (mVMStart == MAP_FAILED) {
// *sigh*
ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
close(mDriverFD);
mDriverFD = -1;
mDriverName.clear();
}
}
LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened. Terminating.");
}
在这段代码我们能了解到很多 Binder 相关的东西:
每个由 Zygote fork 的进程都会初始化自己的 Binder
Binder 有线程池是多线程的,因为进程 A 可能有多个进程与它通信,所以设计是并发的
Binder 通信最大的数据大小是 1M - 8k
Binder 线程最大数量是 15 个
AMS 使用 socket 通知 Zygote fork 进程也是走的这块流程。
我们从系统启动 init 进程开始分析到 Zygote 进程创建、SystemServer 进程创建,大致的将整体流程进行了梳理。
init 进程是系统内核启动后第二个启动的进程,该进程在用户空间。init 进程启动后会解析 init.rc 执行脚本启动 Zygote 进程和 ServiceManager 进程。
Zygote 因为是由 init 进程启动的,所以它也是在用户空间。Zygote 的业务处理横跨 native 层和 java 层。
Zygote 在 native 层处理的事情:
startVm() 创建虚拟机
startReg() 动态注册 java 调用 native 的 jni
反射调用 ZygoteInit 的 main()
Zygote 在 java 层处理的事情:
预先加载系统资源,如系统类、资源、系统共享库等
创建 ZygoteServer,其实就是 ServerSocket 等待通知 fork 子进程
创建 SystemServer 进程
Zygote 从创建到启动总体流程如下图:
Zygote fork 的第一个子进程是 SystemServer。
SystemServer 处理的事情:
创建 SystemServiceManager 用于统一管理服务
启动各种服务如 AMS、PMS 等
将启动的服务注册到 ServiceManager
SystemServer 流程图如下:
也简单说明了 Zygote fork 子进程时 Binder 的初始化过程,Binder 的初始化是在进程 fork 完成主入口 main() 方法执行之前处理。通过简单的流程分析能了解到 Binder 的一些信息:
每个由 Zygote fork 的进程都会初始化自己的 Binder
Binder 有线程池是多线程的,因为进程 A 可能有多个进程与它通信,所以设计是并发的
Binder 通信最大的数据大小是 1M - 8k
Binder 线程最大数量是 15 个
系统启动整体流程如下图:
1、Zygote 进程最原始的进程是什么进程(或者 Zygote 的由来)?【Zygote 进程最开始的名字】
Zygote 最开始是 app_process,它是在 init 进程启动时被启动的,在 app_main.c 才被修改为 Zygote。
2、Zygote 是在内核空间还是在用户空间?
因为 init 进程的创建在用户空间,而 Zygote 是由 init 进程创建启动的,所以 Zygote 是在用户空间。
3、app 的进程启动,为什么是从 Zygote fork,而不是从 init 进程 fork?
Zygote 从创建到启动做了很多事情,比如创建虚拟机,注册 jni,预加载资源等等,fork 进程其实就是复制进程,如果不在 Zygote fork 进程,那么新创建 app 进程就要重新对以上流程再做一遍,而如果从 Zygote fork 子进程,app 进程创建运行就可以直接使用相关资源,不需要再处理。
而 init 进程主要做的事情是挂载文件(识别各类文件,相当于解析硬盘)、解析 init.rc、处理脚本(启动 Zygote、ServiceManager 进程等)。
4、Zygote 为什么用 socket 通信而不是 Binder?
目前网络上有两种说法:一种是会导致死锁,另一种是会导致读写错误。
(1)Zygote 用 binder 通信会导致死锁
假设 Zygote 使用 Binder 通信,因为 Binder 是支持多线程的,存在并发问题,而并发问题的解决方案就是加锁,如果进程 fork 是在多线程情况下运行,Binder 等待锁在锁机制下就可能会出现死锁。
为什么会出现死锁呢?我们可以用一个场景来分析。
假设是 AMS 使用 Binder 通信告知 Zygote fork 一个 app 进程,为了保证不会出现并发问题,AMS 和 Zygote 的通信会加锁,AMS 要和 Zygote 通信拿的 Binder 是属于 Zygote 的(获取的要通信方的 Binder 代理),此时 Zygote fork 了进程,会连带把 Binder 等待锁的状态也复制过去,那么子进程的 Binder 加了锁由谁来解锁?子进程没有解锁,就会出现死锁。
再从 fork 的原理上分析。
在内存区域里,静态变量 mutex 的内存会被拷贝到子进程里,而且父进程里即使存在多个线程,但它们也不会被继承到子进程里,fork 的这两个特征就是造成死锁的原因。
线程里的 doit() 先执行
doit 执行的时候会给互斥体变量 mutex 加锁
mutex 变量的内容会原样拷贝到 fork 出来的子进程中(在此之前,mutex 变量的内容已经被线程改写成锁定状态)
子进程再次调用 doit 的时候,在锁定互斥体 mutex 的时候会发现它已经被加锁,所以就一直等待,直到拥有该互斥体的进程释放它(实际上没有人拥有这个 mutex 锁)
线程的 doit 执行完成之前会把自己的 mutex 释放,但这是的 mutex 和子进程里的 mutex 已经是两份内存,所以即使释放了 mutex 锁也不会对子进程里的 mutex 造成什么影响,最终导致死锁
(2)Zygote 用 binder 通信会导致读写错误
根本原因在于要 new 一个 ProcessState 用于 Binder 通信时,需要 mmap 申请一片内存用以提供给内核进行数据交换使用。
而如果直接 fork 了的话,子进程在进行 binder 通信时,内核还是会继续使用父进程申请的地址写数据,而此时会触发子进程 COW(Copy on Write),从而导致地址空间已经重新映射,而子进程还尝试访问之前父进程 mmap 的地址,会导致 SIGSEGV、SEGV_MAPERR段错误。
可以自己写一个 demo 去尝试,提供一个JNI接口用来调用 fork,待 pid == 0 时,继续使用父进程已获取的binder对象进行binder调用,你就会获得这个段错误。
5、ServiceManager 和 SystemServiceManager 的关系?
ServiceManager 和 SystemServiceManager 没有关系。
ServiceManager 是一个独立进程,和 Zygote 一样通过 init.rc 执行脚本启动,在 SystemServer 启动的服务最终会注册到 ServiceManager 提供给上层使用。
SystemServiceManager 是在 SystemServer 创建的用于在 system_server 进程管理启动服务的管理类。