美文网首页
FrameWork启动过程

FrameWork启动过程

作者: 刘佳阔 | 来源:发表于2017-12-26 22:00 被阅读0次

    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<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
        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启动过程

          本文链接:https://www.haomeiwen.com/subject/rjuegxtx.html