FrameWork启动过程

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之类,这些服务以线程方式运行.

你可能感兴趣的:(FrameWork启动过程)