背景
调查SystemServiceRegistry的启动流程,查看到日志,SystemServiceRegistryImpl是在zygote64进程的。
09-01 13:59:51.197488 429 429 D AndroidRuntime: >>>>>> START com.android.internal.os.ZygoteInit uid 0 <<<<<<
09-01 13:59:51.474706 430 430 D AndroidRuntime: >>>>>> START com.android.internal.os.ZygoteInit uid 0 <<<<<<
09-01 13:59:52.034022 429 429 I SystemServiceRegistry: reflect pass cls:SystemServiceRegistryImpl -- 在SystemServiceRegistry静态方法块中添加的日志。
09-01 13:59:55.574959 430 430 I SystemServiceRegistry: reflect pass cls:SystemServiceRegistryImpl
再次查看调用的上下文,是zogte在加载类的时候
09-01 13:59:51.912956 429 429 D Zygote : begin preload
09-01 13:59:51.913001 429 429 I Zygote : Calling ZygoteHooks.beginPreload()
09-01 13:59:51.964805 429 429 D Zygote64Timing: BeginPreload took to complete: 52ms
09-01 13:59:51.965014 429 429 I Zygote : Preloading classes...
09-01 13:59:51.966624 429 429 W Zygote : Class not found for preloading: android.app.-$$Lambda$ResourcesManager$QJ7UiVk_XS90KuXAsIjIEym1DnM
09-01 13:59:51.997728 429 512 I zygote64: Verified 1383 classes from mainline modules in 255.471ms
09-01 13:59:52.034022 429 429 I SystemServiceRegistry: reflect pass cls:SystemServiceRegistryImpl
定位到代码:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java #preloadClasses
加载常用类–提前替其他进程加载,因为都是从zygote64 fork出去的,zygote64 加载后,再fork,fork后的进程就不需要再单独加载了。
/**
* Performs Zygote process initialization. Loads and initializes commonly used classes.
* Most classes only cause a few hundred bytes to be allocated, but a few will allocate a dozen Kbytes (in one case, 500+K).
*/
private static void preloadClasses() {
final VMRuntime runtime = VMRuntime.getRuntime();
InputStream is;
**is = new FileInputStream(PRELOADED_CLASSES);**
Log.i(TAG, "Preloading classes...");
long startTime = SystemClock.uptimeMillis();
。。。 。。。
try {
BufferedReader br =
new BufferedReader(new InputStreamReader(is), Zygote.SOCKET_BUFFER_SIZE);
int count = 0;
int missingLambdaCount = 0;
String line;
while ((line = br.readLine()) != null) {
// Skip comments and blank lines.
line = line.trim();
if (line.startsWith("#") || line.equals("")) {
continue;
}
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, line);
try {
// Load and explicitly initialize the given class. Use
// Class.forName(String, boolean, ClassLoader) to avoid repeated stack lookups
// (to derive the caller's class-loader). Use true to force initialization, and
// null for the boot classpath class-loader (could as well cache the
// class-loader of this class in a variable).
Class.forName(line, true, null); //static native Class<?> classForName(String className, boolean shouldInitialize, ClassLoader classLoader)
count++;
} catch (ClassNotFoundException e) {
。。。 。。。
}
Log.i(TAG, "...preloaded " + count + " classes in "
+ (SystemClock.uptimeMillis() - startTime) + "ms.");
if (LOGGING_DEBUG && missingLambdaCount != 0) {
Log.i(TAG, "Unresolved lambda preloads: " + missingLambdaCount);
}
} catch (IOException e) {
Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
} finally {
IoUtils.closeQuietly(is);
// Fill in dex caches with classes, fields, and methods brought in by preloading.
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadDexCaches");
runtime.preloadDexCaches();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
。。。 。。。
}
}
1.将PRELOADED_CLASSES = "/system/etc/preloaded-classes"中记录的类按行读取出来,并且判空。
private static final String PRELOADED_CLASSES = "/system/etc/preloaded-classes";
line = line.trim();
if (line.startsWith("#") || line.equals("")) {
continue;
}
preloaded-classes部分展示
# Preloaded-classes filter file for phones.
#
# Classes in this file will be allocated into the boot image, and forcibly initialized in
# the zygote during initialization. This is a trade-off, using virtual address space to share
# common heap between apps.
#
# This file has been derived for mainline phone (and tablet) usage.
#
android.R$styleable
android.accessibilityservice.AccessibilityServiceInfo$1
android.accessibilityservice.AccessibilityServiceInfo
android.accessibilityservice.IAccessibilityServiceClient$Stub$Proxy
android.accessibilityservice.IAccessibilityServiceClient$Stub
android.accessibilityservice.IAccessibilityServiceClient
android.accounts.AbstractAccountAuthenticator$Transport
Class.forName加载类到内存并且初始化
Class.forName(line, true, null);
//static native Class<?> classForName(String className, boolean shouldInitialize, ClassLoader classLoader)
tips:Class.forName作用
-
加载: 当您调用 **
Class.forName("ClassName")
*时,负责调用代码的 Java ClassLoader 会尝试将名为 "ClassName "的类加载到 Java 虚拟机(JVM)中。加载时,会去查找classpath指定的路径中的jar文件,匹配className。
-
链接: 类加载完成后,会经历链接过程,该过程包括验证类、为类变量分配内存以及其他必要的准备工作。
-
初始化: 默认情况下,
Class.forName()
也会对类进行初始化,即处理所有静态块和静态变量。这一步至关重要,因为它为类在 JVM 中的使用做好了准备。
其他问题
SystemServiceRegistry中只在zygote中加载了,其他进程又是如何访问的呢?
由于java中不存在内存共享机制(类似c++中so文件),各个进程如果依赖同一个jar包,都是独立使用自己的类加载器将jar包加载到内存空间的。
从加的日志上看,SystemServiceRegistry只在zygote中加载了(zygote以及zygote64),但是各个应用进程都间接的调用到SystemServiceRegistry获取到Manager,这个是怎么实现的呢?
主要还是fork机制,父线程fork,子线程会继承父线程的内存空间,因此当zygote加载了SystemServiceRegistry后,其他被zygote fork出来的进程也自动获得了SystemServiceRegistry。
SystemServiceRegistry启动早于系统服务,如何能够获取系统服务呢?
SystemServiceRegistry中,getSystemService的逻辑许多都是通过ServiceManager获取服务的binder代理,通过Stub.asInterface转成接口,然后通过XXXManager的构造方法,注入进去,最后返回给应用。
但是目前发现SystemServiceRegistry的加载是在系统服务启动前,如何解决呢?
SystemServiceRegistry的加载中只是设定了系统服务名字以及服务的获取方式的匹配,并不会真的执行,所以也不会立即获取服务binder。只是在getSystemService的时候,才会去获取binder,所以并不存在矛盾。
zygote中预加载class和资源的好处
-
节省时间:
因为zygote加载的class和resource是通用的,其他进程都会用到的。
当zygote去fork进程的时候,这些都会被拷贝到自己的内存空间中,新的进程不用单独再加载一次,加快新进程的启动。
根据fork的copy-on-write机制可知,有些类如果不做改变,甚至都不用复制,子进程可以和父进程共享这部分数据,从而省去不少内存的占用。
-
减少冗余代码
新进程不用单独再去加载class和资源,减少了冗余代码
当前流程
zygote-java层的启动
孵化应用进程这种事为什么不交给SystemServer来做,而专门设计一个Zygote?
可以应用父类子类的观点来解释。
把子类的共性都抽离出来,做成父类的基本属性,这样子类就不用单独声明这些属性,就能拥有他们。
以这个角度看待孵化应用进程。
如果是SystemServer孵化应用进程的话,也就是SystemServer作为父类,其他应用进程作为子类。
如果是zygote孵化应用进程的话,也就是zygote作为父类,其他应用进程作为子类。
那么问题就变成了SystemServer和zygote相比,谁更适合做为父类?
SystemServer和zygote相比,多了很多系统服务,这些肯定不是应用进程的“属性”,所以相比 而言,zygote会更加的纯粹,更能集中体现各个应用进程的“通性”。