众所周知,app进程、SystemServer进程
都是由Zygote
进程孵化的,最近梳理这块逻辑的时候,无意中发现了一个叫AppZygote
和一个叫AppZygoteInit
的java类,挺新鲜的,先看看源码开头对AppZygote
的定义吧:
AppZygote is responsible for interfacing with an application-specific zygote. Application zygotes can pre-load app-specific code and data, and this interface can be used to spawn isolated services from such an application zygote. Note that we'll have only one instance of this per application / uid combination.
大概翻译一下:
AppZygote 负责与指定app的zygote进行对接。应用程序的Zygote可以预加载app指定的代码和数据,还可以从该接口派生独立的服务。请注意,对于每个application/uid组合,我们只有一个实例。
那接着看看AppZygoteInit
的注释说明吧:
Startup class for an Application zygote process. See ZygoteInit for generic zygote startup documentation.
同样附上翻译
应用程序Zygote进程的启动类。参见ZygoteInit了解zygote启动的文档。
看完一头雾水,有种“听君一席话,胜似听君一席话”的感觉。那赶紧百度,必应一把,哦豁,什么都没搜到,不合理啊,那还是看源码吧。
class AppZygoteInit {
//自定义了一个ZygoteServer,跟Zygote一样,可以接收socket访问来fork 新的app进程
private static class AppZygoteServer extends ZygoteServer {
@Override
protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList)
throws IOException {
//重写createNewConnection 方法,返回一个自定义个connection对象。
return new AppZygoteConnection(socket, abiList);
}
}
//自定义ZygoteConnection
private static class AppZygoteConnection extends ZygoteConnection {
@Override
protected void handlePreloadApp(ApplicationInfo appInfo) {
//1. 通过ApplicationInfo 构建LoadedApk
LoadedApk loadedApk = new LoadedApk(null, appInfo, null, null, false, true, false);
//2. 获取 LoadedApk的ClassLoader,后面反射ZygotePreload的实例要用
ClassLoader loader = loadedApk.getClassLoader();
//用来定义一个应用程序的组件,通过调用Intent中的setComponent方法,可以打开本应用或者其他应用中的组件,如:Activity和Service
ComponentName preloadName = ComponentName.createRelative(appInfo.packageName,
appInfo.zygotePreloadName);
//3. 反射获取ZygotePreload的Class对象
Class<?> cl = Class.forName(preloadName.getClassName(), true, loader);
//4. 反射获取ZygotePreload的构造方法
Constructor<?> ctor = cl.getConstructor();
//5. 创建ZygotePreload的具体实例对象
ZygotePreload preloadObject = (ZygotePreload) ctor.newInstance();
//6. 调用 ZygotePreload的doPreload开始预加载资源。
preloadObject.doPreload(appInfo);
//7. 向socket的输出流写入preload的结果
DataOutputStream socketOut = getSocketOutputStream();
socketOut.writeInt(loader != null ? 1 : 0);
Log.i(TAG, "Application preload done");
}
}
//看到没,main方法,说明AppZygote运行在一个独立的进程中
public static void main(String[] argv) {
AppZygoteServer server = new AppZygoteServer();
//启动一个socket server
ChildZygoteInit.runZygoteServer(server, argv);
}
}
再看看ZygotePreload
,它是一个接口:
/**
* 这个接口被AndroidManifest.xml中<application>标签下android:zygoteReloadName指定的class来实现。它负责预加载应用程序代码和数据,这些代码和数据将由所有在<service>标签下将android:useAppZygote属性设置为true的独立服务共享。请注意,此类的实现必须提供一个不带参数的默认构造函数。
*/
public interface ZygotePreload {
/**
每次启动应用程序 Zygote 时都会调用此方法一次。它通常在使用它的独立服务首次启动时启动。在所有使用它的独立服务停止时停止。
*/
void doPreload(@NonNull ApplicationInfo appInfo);
}
ZygotePreload
用于提前预加载特定资源。它有以下实现类:
- WebViewZygotePreload: WebView 组件的预加载实现类。它负责预加载 WebView 相关的资源,包括 JavaScript 引擎、Web 内容渲染引擎等。
- GraphicsEnvironmentZygotePreload:用于预加载图形环境相关资源。例如 Skia 图形库、OpenGL ES 等。
- FontZygotePreload:用于预加载字体资源。
AppZygote
是android8.0
引入,跟Zygote
一样,也是一个系统进程,跟外界也是通过socket通信。不过AppZygote
只为fork app进程服务,不像Zygote
还要负责fork其他进程,(比如SystemServer
)。AppZygote
的功能相对单一,用于加速app进程的启动。这个处理有点像AMS(ActivityManagerService
)把对Activity的管理单独提取到ATMS(ActivityTaskManagerService
)中一样。
AppZygote
的作用是:起到优化应用程序启动
和运行
的作用,怎么做到的呢?
AppZygote
会预加载一些常见的系统类
和资源
,而被fork出的子进程会拥有父进程的全部代码和状态,也就是拥有父进程的功能。这样在每次开启新的app进程时就不需要重新加载一遍,从而减少app进程启动时间。
- 系统类:如图形渲染、网络通信等。
- 系统级服务:如,位置服务、通知管理等。
AppZygote
也会预加载和初始化一些常用的应用程序组件
和资源
,并将它们缓存起来。当应用程序需要启动时,达到减少内存消耗的目的。
- 应用级共享组件:如Activity、Service等
- 应用级共享资源:如布局文件、字符串资源等。
- 支持进程的快速复用:如果一个应用程序的进程在前台和后台之间频繁切换,AppZygote可以保持该进程的虚拟机实例的状态,当下次需要启动该应用程序时,可以快速复用这个虚拟机实例,从而减少启动时间和内存消耗。
它通过共享系统类和资源、提供隔离的虚拟机实例等机制,减少了启动时间和内存消耗,提高了系统的性能和稳定性。