1.linux的启动过程最后,内核将读取init.rc文件,并启动该文件中的各种服务程序,android系统内核也声明在init.rc文件中,从而linux内核启动后能接着运行android内核.
- 系统中运行的第一个dalvik虚拟机程序叫zygote,他负责启动接下来所有的dalvik虚拟机进程.
- zygote包括两个模块,Socket服务端,用于接收启动新的Dalvik虚拟机进程的命令.Framework共享类及共享资源,这些资源被加载后,新的Dalvik虚拟机进程就不用在重复装载他们了.
- zygote对应的具体程序是app_process,位于/system/bin/app_process目录下, 启动该程序的指令在init.rc中配置.源码在 frameworks\base\cmds\app_process\app_main.cpp中.
- zygote 孵化的第一个进程叫SystemServer,也是唯一/system/bin/app_process目录下,SystemServer创建了一个socket客户端,当需要启动新的APK进程时,Ams会通过该Socket客户端向zygote中的socket服务端发起一个启动命令,zygote就会孵化新进程.
- dalvikvm的作用就是创建一个虚拟机并执行参数中指定的类,虚拟机的作用就是解释并执行java程序.同时虚拟机也是一个进程.dalvikvm的操作原理是:1通过JNI_CreateJavaVM创建一个JavaVm和JNIEnv对象,然后findClass()加载指定类的class文件,然后通过GetStaticMethodId找到main方法的id,然后用CallStaticVoidMethod()执行main方法.
- dvz 的作用是创建一个dalvik虚拟机进程,该进程预装了Framework的大部分资源和类,然后解释并执行apk程序.
- 由于farmework在启动时需要加载两个类,ZygoteInit.java,SystemServer.java,所以提供了一个app_process进程,该进程本质上就是使用dalvikvm启动ZygeteInit.java,并在启动会加载FrameWork中的类和资源.原理同dalvikvm相似,先创建一个AppRuntime runtime, 然后调用runtime的start方法,在start方法内找到ZygoteInit类的class文件,然后找到main方法,执行main方法,唯一不同就是执行app_process可以指定一些特别的参数.
2.zygote启动过程
- init.rc源代码在F:\source\system\core\rootdir目录下,用来告诉操作系统将zygote程序加入到系统服务中.
- zygote服务从app_process开始启动后,会启动ZygoteInit.java类的main方法.如下
public static void main(String argv[]) {
try {
registerZygoteSocket(socketName);//1.启动一个socket服务端
preload();//2.预装Framework大部分类及资源
// Do an initial gc to clean up after startup
gc();
if (startSystemServer) {
startSystemServer(abiList, socketName); //3.fork一个ZygoteInit进程.
}
runSelectLoop(abiList);//4.非阻塞式的读取socket客户端数据
closeServerSocket();//5.关闭新进程的socket服务端,保证socket服务端只有一个在运行.
} catch (MethodAndArgsCaller caller) {
throw ex;
}
}
分布来看,先看2.1 通过文件描述符来创建Socket服务端.
//ZygoteInit类代码
private static void registerZygoteSocket(String socketName) {
if (sServerSocket == null) {
int fileDesc;
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
String env = System.getenv(fullSocketName);//1.获取系统为zygote进程分配的Socket文件描述符号
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException(fullSocketName + " unset or invalid", ex);
}
try {
sServerSocket = new LocalServerSocket(
createFileDescriptor(fileDesc));//调用createFileDescriptor创建一个真正的文件描述符,然后创建Socket服务端,
Linux系统将所有设备都当作文件来处理,而Linux用文件描述符来标识每个文件对象.
} catch (IOException ex) {
throw new RuntimeException(
"Error binding to local socket '" + fileDesc + "'", ex);
}
}
}
接着看2.2 preload()用来加载framework大部分类及资源
static void preload() {
preloadClasses(); //1.加载类
preloadResources();//2加载系统资源
preloadOpenGL();
preloadSharedLibraries();
}
要加载的类列表在source\frameworks\base\preloaded-classes文件中,通过
source\frameworks\base\tools\preload\WritePreloadedClassFile.java文件生成.\
private static void preloadClasses() { //主要原理就是从source\frameworks\base\preloaded-classes文件中一行一行读入.忽略#注释行,
调用Class.forName装载目标类
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream(PRELOADED_CLASSES);
try {
BufferedReader br = new BufferedReader(new InputStreamReader(is), 256);
String line;
while ((line = br.readLine()) != null) {
line = line.trim();
if (line.startsWith("#") || line.equals("")) {
continue;
}
Class.forName(line);
}
} catch (IOException e) {
} finally {
IoUtils.closeQuietly(is);
}
}
private static void preloadResources() {//resources资源在F:\source\frameworks\base\core\res\res\values\arrays.xml定义,
包含drawable资源和color资源,加载方式很简单.就是把资源读出来放到一个全局变量Resources类的mResources中
final VMRuntime runtime = VMRuntime.getRuntime();
try {
runtime.runFinalizationSync();
mResources = Resources.getSystem(); //用来保存资源的Resource类
mResources.startPreloading();
if (PRELOAD_RESOURCES) {
TypedArray ar = mResources.obtainTypedArray(
com.android.internal.R.array.preloaded_drawables);
int N = preloadDrawables(runtime, ar); //保存drawable
ar.recycle();
ar = mResources.obtainTypedArray(
com.android.internal.R.array.preloaded_color_state_lists);
N = preloadColorStateLists(runtime, ar);//保存color
ar.recycle();
}
mResources.finishPreloading();
}
}
接着看2.3startSystemServer() 启动startSystemServer进程,该进程会创建一个socket客户端,之后Ams通过该Socket客户端向Zygote进程的Socket服务端发送消息,让服务端foke新的应用进程.
private static boolean startSystemServer(String abiList, String socketName)
throws MethodAndArgsCaller, RuntimeException {
ZygoteConnection.Arguments parsedArgs = null;
String args[] = { //1.要启动的进程的相关信息,最后一行指定新进程启动后装载的第一个java类.
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",
"--capabilities=" + capabilities + "," + capabilities,
"--runtime-init",
"--nice-name=system_server",
"com.android.server.SystemServer",
};
int pid; //2.新进程的进程id
try {
parsedArgs = new ZygoteConnection.Arguments(args);//1.zygoteConnextion是对socket连接的一个封装
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
//3..复制当前进程,产生新进程.新进程就是SystemServer进程.新进程和父进程暂时共享相同的进程信息(包括打开的文件描述符列表,分配的内存)
,除了pid. 当其中一个进程需要读写数据时,系统在此时给他分配内存,然后两个进程分开.pid=0时表示被复制的进程,pid>0时表示父进程id,
foke之后的代码.两个进程都会执行,此方法是native函数.
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
if (pid == 0) {//4.表示是foke出的新进程,这段代码只会被新进程执行,父进程不会执行.
因为两者pid不同.此时的新进程就是SystemServer进程.因为他是复制出来.他本身有一个Socket服务端,而他需要创建一个Socket客户端来
和Zygoye的Socket服务端进行沟通,所以在这里他需要关闭自己的Socket服务端,创建并连接一个Socket客户端
if (hasSecondZygote(abiList)) { //5.如果有第二个Zygote进程的话.创建自己的Socket客户端并连接.
waitForSecondaryZygote(socketName);
}
handleSystemServerProcess(parsedArgs); //6.销毁自己的Socket服务端并执行SystemServier类的main函数.
}
return true;
}
接着看2.4 runSelectLoop()Socket服务端接受客户端请求 slelectloop是一种非阻塞式读操作,使用selet()函数检测某一文件描述符,当该文件描述符上出现新的数据后(文件操作符有三中状态,0是标准输入,1是标准输出,2是标准错误),自动触发一个中断,然后在中断函数中去读该文件描述符上的数据.
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
ArrayList fds = new ArrayList();
ArrayList peers = new ArrayList();
FileDescriptor[] fdArray = new FileDescriptor[4];
fds.add(sServerSocket.getFileDescriptor());//1.把Socket加入到被检测的文件描述符列表中
peers.add(null);
int loopCount = GC_LOOP_COUNT;
while (true) {
int index;
if (loopCount <= 0) {
gc();
loopCount = GC_LOOP_COUNT;
} else {
loopCount--;
}
try {
fdArray = fds.toArray(fdArray);
index = selectReadable(fdArray); //2.select函数执行的地方.这是一个native函数. index表示执行结果,监听Socket描述符的变化.
} catch (IOException ex) {
throw new RuntimeException("Error in select()", ex);
}
if (index < 0) { //负值表示执行错误
throw new RuntimeException("Error in select()");
} else if (index == 0) { //3.0表示超时,文件没有变化,既socker没有可处理的连接,因此Socket服务端会重新创建一个ZygoteConnection对象并等待客户端Socket请求
ZygoteConnection newPeer = acceptCommandPeer(abiList);//newPeer标识对连接到当前服务端Socket的连接的封装,同时还要监听这个socket的描述符的变化.
peers.add(newPeer);
fds.add(newPeer.getFileDescriptor());
} else {//4.正数标识文件有修改.意味着Socket服务端接收到了上文SystemServer的客户端发来的请求,
boolean done;
done = peers.get(index).runOnce();//5.ZygoteConnection.runOnce函数会处理客服端的请求.
if (done) { //6.处理完后把index对应的请求yichu
peers.remove(index);
fds.remove(index);
}
}
}
}
接下来SystemServer类的Main函数在2.3中被加载执行.大部分系统服务都是在System进程中创建运行的,比如Wms,Ams,Pms这些系统服务都是以一个线程的方式存在于SystemServer进程中.首先看main函数.
private void run() {
// Prepare the main looper thread (this thread).
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
android.os.Process.setCanSelfBackground(false);
Looper.prepareMainLooper(); //1.设置主线程的mainLopper
// Initialize native services.
System.loadLibrary("android_servers"); //2.加载native端的service
nativeInit();
// Initialize the system context.
createSystemContext();//3.创建 ActivityThread activityThread和 Context mSystemContext
// Create the system service manager.
//创建SystemServerManager,并把Sms加入到本地service集合中
mSystemServiceManager = new SystemServiceManager(mSystemContext);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
// Start services.启动一些列系统服务,包括ActivityManagerService等等
try {
startBootstrapServices();
startCoreServices();
startOtherServices();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
}
// Loop forever.
Looper.loop(); //开启主线程的消息循环.
throw new RuntimeException("Main thread loop unexpectedly exited");
}
ActivityManagerService的启动步骤如下
1.调用main()函数,返回一个context对象本身,而不是Ams服务本身
2.调用Ams.setsystemProcess()
3.调用Ams.installSystemProviders()
4.调用Ams.systemReady() 由此加载启动第一个Acitivity.
总结,就是先启动zoygote进程.这个进程会启动一个socekt服务端,用来接受指向开启新的进程.还包括framework的一些资源,被同意加载.然后zoygote会fork一个新进程systemServer,这个进程有一个socket客户端和zoygote进程的socket通讯,让zoygote启动新进程,systemServer会创建各种服务,Ams,Wms之类,这些服务以线程方式运行.