Android系统启动流程

本文详细介绍了Android系统的启动流程,重点讲解了init.rc脚本的功能、语法和各个组成部分,包括导入、动作、命令、服务和选项。内容涵盖init进程如何执行动作、启动服务,以及涉及的各种命令和选项的解释,例如服务的启动、文件系统挂载、网络配置等关键步骤。
[1] BOOLOADER
[2] kernel
[3] rootfs
[4] 启动init程序
    
    功能                     Android系统                      linux
    -------                  -------------                    ------
    解析执行脚本             init.rc                          /etc/inittab
    解析处理uevent事件       init程序完成(进程名ueventd)      mdev(udevfs)
    创建设备文件             
    修改属性(系统配置信息)   接收属性修改请求,修改属性       无
                             别的程序无修改属性权限,
                             只有读权限
    回收孤儿的进程控制块     有                               有
    接收组合键               调试                             ctrl + alt + del
    
    服务(后台进程)监控       监控服务, 使得服务按照要求启动   respawn和askfirst
                             运行
    关键文件作用           
    ------------
    属性文件:
    /default.prop
    /system/build.prop
    /system/default.prop
    
    /data/local.prop(调试ro.debuggable == 1)
    
    /data/property目录下所有的属性文件
    
    logo文件:
    /initlogo.rle
    
    关键数据结构
    ------------
    1. action_list
       动作链表, 管理整个系统的动作(actions), 每个动作有一个命令(commands)链表
       
    2. service_list
       服务链表, 管理整个系统所有的服务, 每个服务有一个命令链表,存放服务重启时,运行的命令
    
    3. action_queue
       动作队列链表, 将要执行的动作排队, init进程的主循环中一条命令一条命令的执行
       
    init代码分析              
    ------------
    init程序是哪个?
    内参数中指定的init程序, 查看参数的方法:
    1. 内核启动记录中存在
    2. 系统启动后,可以查看/proc/cmdline文件获取内核启动参数
       console=/dev/ttyS0,115200 init=/init ...
       
    init程序代码在哪儿?
    find . -depth -name Android.mk -exec grep init -l {} \;
    
    如何找到main函数?
    grep main system/core/init/* -r
    
    代码分析:
    1007 int main(int argc, char **argv)
    1008 {
            
    1. 判断当前进程是否用/sbin/ueentd文件启动
    1028     if (!strcmp(basename(argv[0]), "ueventd"))
                 接收并处理uevent事件, 通知ueventd程序创建和删除设备文件
    1029         return ueventd_main(argc, argv);
    
    2. 判断当前进程是否用/sbin/watchdogd启动
    1031     if (!strcmp(basename(argv[0]), "watchdogd"))
                 设置看门狗的超时时间和喂狗
    1032         return watchdogd_main(argc, argv);
    
    3. 创建虚拟文件系统和临时文件系统的挂载点(目录)并挂载
    1041     mkdir("/dev", 0755);
    1042     mkdir("/proc", 0755);
    1043     mkdir("/sys", 0755);
    1044 
    1045     mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
    1046     mkdir("/dev/pts", 0755);
    1047     mkdir("/dev/socket", 0755);
    1048     mount("devpts", "/dev/pts", "devpts", 0, NULL);
    1049     mount("proc", "/proc", "proc", 0, NULL);
    1050     mount("sysfs", "/sys", "sysfs", 0, NULL);
    
    4. 创建"/dev/.booting"文件, 表示启动开始,启动完成时才能加载固件
    1053     close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000));
    
    5. 打开/dev/null文件,并且将它设置为init程序的标准输入、标准输出和标准错误
       屏蔽掉init进程是输入输出
    open_devnull_stdio();
    
    6. 打开init进程的log文件
    1062     klog_init();
    
    7. 打开修改属性的文件(初始化属性)
    property_init();
    
    8. 获取硬件名称和版本
    1065     get_hardware_name(hardware, &revision);  
    
    9. 从内核参数传递属性给Android系统
       (1) 通过androidboot.ro.boot.属性名=属性值形式的内核参数导入属性给Android系统
           import_kernel_cmdline(0, import_kernel_nv);
           
       (2) 转换属性
           内核参数中的属性名                  系统运行时是属性名    作用
           android.ro.boot.serialno            ro.serialno           cpu id
           android.ro.boot.mode                ro.bootmode           启动模式
                                                                     工厂模式(用于生产)
                                                                     充电模式
           android.ro.boot.baseband            ro.baseband           基带信息
           android.ro.boot.bootloader          ro.bootloader         bootloader信息
           
                                               ro.boot.console       console终端信息
                                               ro.boot.hardware      硬件信息(sun8i)
                                               ro.factorytest        是否为工厂测试模
    
    10. 加载文件(/default.prop)中的属性
        property_load_boot_defaults();
        
    11. 获取内核参数中(参数名为partittions)的分区信息
        get_kernel_cmdline_partitions();
        
    12. 读取并解析/init.rc文件
        init_parse_config_file("/init.rc");
        
    13. 促发动作(init.rc脚本中定义的动作 内部动作)
        促发动作
        action_for_each_trigger(init.rc动作, action_add_queue_tail); 
        
        添加内部动作并促发
        queue_builtin_action(内部动作(只有一个命令)函数, 动作名);
        
        
        促发动作的顺序如下:
        (1) early-init
        (2) wait_for_coldboot_done(内部)
            判断冷启动设备是否启动完成
            
        (3) keychord_init(内部)
            初始化组合键监控(打开相应的监控文件)
            
        (4) init
        (5) early-fs
        (6) console_init(内部)
            初始化console终端, 并显示logo
            
        (7) fs
        (8) post-fs
        (9) post-fs-data
        
        (10) property_service_init(内部)
            加载属性文件,打开属性修改服务, 别的进程通过socket(/dev/socket/property_service)请求服务
            
        (11) signal_init(内部)
            准备好接收SIGCHILD信号,然后帮孤儿进程回收进程控制块
            
        (12) check_startup(内部)
            确认启动结束
            
        (13) charger
            充电模式动作
            
        (14) early-boot
        (15) boot
        
        (16) queue_property_triggers(内部)
             根据属性表达式(property:属性名=属性值)促发动作的内部动作
             
   14. 主循环
       1147     for(;;) {
                    执行action_queue中的一条命令
       1150         execute_one_command();
                    
                    重启服务进程
       1151         restart_processes();
       1152 
                    // 设置属性修改请求文件描述符
       1153         if (!property_set_fd_init && get_property_set_fd() > 0) {
       1154             ufds[fd_count].fd = get_property_set_fd();
       1155             ufds[fd_count].events = POLLIN;
       1156             ufds[fd_count].revents = 0;
       1157             fd_count++;
       1158             property_set_fd_init = 1;
       1159         }
       
                    // 设置SIGCHILD信号处理文件描述符
       1160         if (!signal_fd_init && get_signal_fd() > 0) {
       1161             ufds[fd_count].fd = get_signal_fd();
       1162             ufds[fd_count].events = POLLIN;
       1163             ufds[fd_count].revents = 0;
       1164             fd_count++;
       1165             signal_fd_init = 1;
       1166         }
         
                    // 设置组合键文件描述符
       1167         if (!keychord_fd_init && get_keychord_fd() > 0) {                                          
       1168             ufds[fd_count].fd = get_keychord_fd();
       1169             ufds[fd_count].events = POLLIN;
       1170             ufds[fd_count].revents = 0;
       1171             fd_count++;
       1172             keychord_fd_init = 1;
       
                    // 有动作没有执行时, 使得poll函数不阻塞
       1181         if (!action_queue_empty() || cur_action)
       1182             timeout = 0;


       
                    // 监控上面设置的三个文件,就绪处理响应的事情
                    nr = poll(ufds, fd_count, timeout);
       1196         if (nr <= 0)
       1197             continue;
       1198 
       1199         for (i = 0; i < fd_count; i++) {
       1200             if (ufds[i].revents == POLLIN) {
       1201                 if (ufds[i].fd == get_property_set_fd())
       1202                     handle_property_set_fd();
       1203                 else if (ufds[i].fd == get_keychord_fd())
       1204                     handle_keychord();
       1205                 else if (ufds[i].fd == get_signal_fd())
       1206                     handle_signal();
       1207             }
       1208         }                                                                                          
       1209     }
       1210 
       1211     return 0;
       1212 }
       
[4] 本地服务
    1. ueventd
       处理uevent事件, 创建设备文件
       
    2. console
       在控制终端上,启动一个/bin/sh
       
    3. adbd
       adb服务
       
    4. servicemanager
       服务管理程序
       
    5. vold(volume deamon)
       大容量存储设备挂载服务, SD卡、U盘, ...
       
    6. netd
       网络服务
       
    7. surfaceflinger
       负责绘制Android UI界面, 完成2D和3D的无缝融合
       
    8. zygote
       启动虚拟机,预加载类、启动服务
       
    9. media
       多媒体服务
       
    10. bootanim
       开机音乐和动画播放服务
       
[5] bootanim服务
    功能
    ------------
    播放开机动画和开机背景音乐:
    1. 背景音乐文件
       /system/media/boot.wav
       
    2. 开机动画文件
       /system/media/bootanimation-encrypted.zip  (有加密的开机动画)
       /data/local/bootanimation.zip              用户的开机动画
       /system/media/bootanimation.zip            系统开机动画
       
       默认开机动画
       android-logo-mask.png
       android-logo-shine.png
       
    
    源代码分析
    ------------
    service bootanim /system/bin/bootanimation
    class main
    user graphics
    group graphics
    disabled
    
    如何找到bootanimation源代码?
    find . -depth -name Android.mk -exec grep bootanimation -l {} \;
    
    
    frameworks/base/cmds/bootanimation/bootanimation_main.cpp
    39 int main(int argc, char** argv)
    40 {
          ....
    56    boot->playBootMusic("/system/media/boot.wav"); 
          ......
    60    return 0;
    61 }
    
    void *proc(void *)
    {
    ...
    --readyToRun()
   
    --threadloop
    }
    
    frameworks/base/cmds/bootanimation/BootAnimation.cpp
    236 status_t BootAnimation::readyToRun() {
    
        ... 
        if ((encryptedAnimation &&
    300             (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) &&                             
    301             (mZip.open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE) == NO_ERROR)) ||
    302 
    303             ((access(USER_BOOTANIMATION_FILE, R_OK) == 0) &&
    304             (mZip.open(USER_BOOTANIMATION_FILE) == NO_ERROR)) ||
    305 
    306             ((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) &&
    307             (mZip.open(SYSTEM_BOOTANIMATION_FILE) == NO_ERROR))) {
    308         mAndroidAnimation = false;
    309     }
         ...
        }
                  
    314 bool BootAnimation::threadLoop()
    315 {
    316     bool r;
    317     if (mAndroidAnimation) {
                播放压缩版开机动画
    318         r = android();
    319     } else {
                播放默认版开机动画
    320         r = movie();
    321     }
            ....
         }
         
[6] zygote服务
    功能
    ----------
    1. 启动虚拟器
    2. 预加载类、资源
    3. 启动系统服务(java服务)
    4. 其他程序
    
    启动脚本
    -------
    service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart media
    onrestart restart netd
    
    程序名: /system/bin/app_process
    参数: -Xzygote /system/bin --zygote --start-system-server
    
    
    代码分析
    --------
    如何找到app_process代码?
    find . -depth -name Android.mk -exec grep app_process -l {} \;
    
    frameworks/base/cmds/app_process/app_main.cpp
    
    arc = 5
    argv = /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    138 int main(int argc, char* const argv[])                                                              
    139 {
         ...
    177     AppRuntime runtime;
         
    1. 参数解析
            argc--;                                                                                         
    183     argv++;
         
         // arc = 4
         // argv = -Xzygote /system/bin --zygote --start-system-server
         
         // 添加参数到runtime对象
    187     int i = runtime.addVmArguments(argc, argv);
         // 在AppRuntime类中搜索addVmArguments定义,如果没有,搜索AppRuntime父类
         // i = 1
         
         // mOptions = -Xzygote
         
    190     bool zygote = false;
    191     bool startSystemServer = false;
    192     bool application = false;                                                                       
    193     const char* parentDir = NULL;
    194     const char* niceName = NULL;
    195     const char* className = NULL;
    196     while (i < argc) {
    197         const char* arg = argv[i++];
    198         if (!parentDir) {
    199             parentDir = arg;
    200         } else if (strcmp(arg, "--zygote") == 0) {
    201             zygote = true;
    202             niceName = "zygote";
    203         } else if (strcmp(arg, "--start-system-server") == 0) {
    204             startSystemServer = true;
    205         } else if (strcmp(arg, "--application") == 0) {
    206             application = true;
    207         } else if (strncmp(arg, "--nice-name=", 12) == 0) {
    208             niceName = arg + 12;
    209         } else {
    210             className = arg;
    211             break;
    212         }
    213     }
           // parentDir = /system/bin
           // zygote = true;
           // niceName = "zygote";
           // startSystemServer = true;
           
   2. 修改程序及进程名称伪zygote
     215     if (niceName && *niceName) {                                                                    
     216         setArgv0(argv0, niceName);
     217         set_process_name(niceName);
     218     }
     
     runtime.mParentDir = parentDir
     // runtime.mParentDir = /system/bin
     
  3. 启动ZygoteInit类
     222     if (zygote) {
     223         runtime.start("com.android.internal.os.ZygoteInit",
     224                 startSystemServer ? "start-system-server" : "");
                 
                 // runtime.start("com.android.internal.os.ZygoteInit", "start-system-server")
             }
             
  
  framworks/base/core/jni/AndroidRuntime.cpp 
   
     805 void AndroidRuntime::start(const char* className, const char* options)
         {
            ...
  4. 启动虚拟机
     835     JniInvocation jni_invocation;
     836     jni_invocation.Init(NULL);
     837     JNIEnv* env;
     838     if (startVm(&mJavaVM, &env) != 0) {                                                            
     839         return;
     840     }
     841     onVmCreated(env);
            
  5. 注册android系统需要的jni本地函数
     846     if (startReg(env) < 0) {                                                                       
     847         ALOGE("Unable to register all android natives\n");
     848         return;
     849     }
     
  6. 启动"com.android.internal.os.ZygoteInit"(进入java世界)
             ....
     856     jclass stringClass;
     857     jobjectArray strArray;
     858     jstring classNameStr;
     859     jstring optionsStr;
     860 
             // 寻址java类(java/lang/String)
     861     stringClass = env->FindClass("java/lang/String");
     862     assert(stringClass != NULL);
     
             // new stringClass[2]
     863     strArray = env->NewObjectArray(2, stringClass, NULL);
     864     assert(strArray != NULL);
      
             // 将类名("com.android.internal.os.ZygoteInit")转换成unicode编码
     865     classNameStr = env->NewStringUTF(className);
     866     assert(classNameStr != NULL);
     
             // 将类名放入数组的第一个元素
     867     env->SetObjectArrayElement(strArray, 0, classNameStr);
     
             // 将参数("start-system-server")转换成unicode编码
     868     optionsStr = env->NewStringUTF(options);
     
             // 将参数设置为数组的第二个元素
     869     env->SetObjectArrayElement(strArray, 1, optionsStr);
             
             // strArray = "com.android.internal.os.ZygoteInit" "start-system-server"
             
             // 将"com.android.internal.os.ZygoteInit" 转换为"com/android/internal/os/ZygoteInit"
             char* slashClassName = toSlashClassName(className); 
             
             // 找到com/android/internal/os/ZygoteInit                                           
     876     jclass startClass = env->FindClass(slashClassName);
     
             // 找到com/android/internal/os/ZygoteInit的静态方法main
             jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
     882             "([Ljava/lang/String;)V");
     
             // 调用com/android/internal/os/ZygoteInit的静态方法main
             env->CallStaticVoidMethod(startClass, startMeth, strArray);
        
            // 关机时运行
    895     free(slashClassName);
    896 
    897     ALOGD("Shutting down VM\n");
    898     if (mJavaVM->DetachCurrentThread() != JNI_OK)
    899         ALOGW("Warning: unable to detach main thread\n");
    900     if (mJavaVM->DestroyJavaVM() != 0)                                                             
    901         ALOGW("Warning: VM did not shut down cleanly\n");
         }
         
  7. 进入java世界(启动运行com.android.internal.os.ZygoteInit)
    如何找到com.android.internal.os.ZygoteInit代码?
    find . -depth -name ZygoteInit.java
     
    frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
    556    public static void main(String argv[]) {
    557         try {
                    ...
                    
                    // 打开socket
                    registerZygoteSocket();
                    
  8. 预加载类、资源
    564             preload();
    
                    // argv[1] = "start-system-server"
    583             if (argv[1].equals("start-system-server")) {
    584                 startSystemServer();
    585             }
    
                    // 启动Home 之外的其他应用程序
    591             runSelectLoop();
    592 
                    // 关闭服务socket
    593             closeServerSocket(); 
    
                } catch (MethodAndArgsCaller caller) {
                
  9. 启动SystemServer系统服务
                   // 调用"com.android.server.SystemServer"类的main方法
    595            caller.run();
    596         } catch (RuntimeException ex) {
    597             Log.e(TAG, "Zygote died with exception", ex);
    598             closeServerSocket();
    599             throw ex;
    600         }          
               }
               
    489     private static boolean startSystemServer()
    490             throws MethodAndArgsCaller, RuntimeException { 
               
    504         String args[] = {
    505             "--setuid=1000",
    506             "--setgid=1000",
    507             "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,
    508             "--capabilities=" + capabilities + "," + capabilities,
    509             "--runtime-init",
    510             "--nice-name=system_server",
    511             "com.android.server.SystemServer",
    512         };   
    
    517         try {  
                  // 启动子进程, zygote进程预加载的类和资源也被拷贝到子进程
                  pid = Zygote.forkSystemServer(
    524                     parsedArgs.uid, parsedArgs.gid,
    525                     parsedArgs.gids,
    526                     parsedArgs.debugFlags,
    527                     null,
    528                     parsedArgs.permittedCapabilities,
    529                     parsedArgs.effectiveCapabilities);
    
                } catch (IllegalArgumentException ex) {                                                     
    531             throw new RuntimeException(ex);
    532         }
    533 
    534         
    535         if (pid == 0) {
                    // 子进程执行
    536             handleSystemServerProcess(parsedArgs);
    537         }
    538 
                // 父进程直接返回
    539         return true;   
           }
           
    459     private static void handleSystemServerProcess(
    460             ZygoteConnection.Arguments parsedArgs)
    461             throws ZygoteInit.MethodAndArgsCaller {
               
                // 关闭服务socket,只有zygote进程才需要用
                closeServerSocket();
                ...
                
                // RuntimeInit.zygoteInit("", "")
                RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);
            } 
         
    // frameworks/base/core/java/com/android/internal/os/RuntimeInit.java   
    261     public static final void zygoteInit(int targetSdkVersion, String[] argv)                        
    262             throws ZygoteInit.MethodAndArgsCaller {
    266 
                ....
                // 本地函数,如何找到呢?
                cd frameworks
                grep nativeZygoteInit * -r
    268         nativeZygoteInit();
    269 
                // applicationInit(targetSdkVersion, "")
    270         applicationInit(targetSdkVersion, argv);
    271     }
    
    291     private static void applicationInit(int targetSdkVersion, String[] argv)                        
    292             throws ZygoteInit.MethodAndArgsCaller {
                   ....
                   // invokeStaticMain("com.android.server.SystemServer", "");
                   invokeStaticMain(args.startClass, args.startArgs); 
            }
            
    110     static void invokeStaticMain(ClassLoader loader,                                                
    111             String className, String[] argv)
    112             throws ZygoteInit.MethodAndArgsCaller {
                  ...
                  // 加载类
                  cl = loader.loadClass("com.android.server.SystemServer"); 
                  
                  // 获取main方法
                  m = cl.getMethod("main", new Class[] { String[].class });
                  
                  // 抛出异常, ZygoteInit.MethodAndArgsCaller对象中放入了
                  // "com.android.server.SystemServer"类的main方法
                  // 参数见504行
                  throw new ZygoteInit.MethodAndArgsCaller(m, argv);
                  
                  
            }
     
  10. 启动com.android.server.SystemServer"类的main方法
      如何找到com.android.server.SystemServer类?
      find . -depth -name SystemServer.java
      
      // frameworks/base/services/java/com/android/server/SystemServer.java
             
      1143     public static void main(String[] args) {
          ...
          ...
          // 加载库
      System.loadLibrary("android_servers");  
      如果找到android_servers库?
      find . -depth -name Android.mk -exec grep android_servers -l {} \;
     
      ...
     
      // 调用本地函数(android_server_SystemServer_nativeInit)
      // frameworks/base/services/jni/com_android_server_SystemServer.cpp 
      nativeInit();
     
      ...
      1196         ServerThread thr = new ServerThread();
      1197         thr.initAndLoop();
     
      }
      
      93     public void initAndLoop() {
      ...
      ....
     
  11. 启动Home Activity
     956         ActivityManagerService.self().systemReady(new Runnable() {...});
           ... 
      }
      
   
    // base/services/java/com/android/server/am/ActivityManagerService.java
     9331     public void systemReady(final Runnable goingCallback) { 
          
          // 搜索homeactivity
         ...
         ...
         
     }
     
     16271                     startHomeActivityLocked(userId);
     
     2939     boolean startHomeActivityLocked(int userId) { 
          ...
     2954         Intent intent = getHomeIntent();
          ...
          ...
          mStackSupervisor.startHomeActivity(intent, aInfo); 
     }
      
     2930     Intent getHomeIntent() {
          ...
          ...
          
           // Home程序的intent过滤Category为CATEGORY_HOME
     2934             intent.addCategory(Intent.CATEGORY_HOME);
      }
      
  12. Home Activity通过socket向zygote进程发送请求,启动其他应用...
  
[系统定制]
[1] Android系统logo
    /initlogo.rle
    
[2] 定制开机背景音乐
    /system/media/boot.wav
       
[3] 开机动画文件
    /system/media/bootanimation-encrypted.zip  (有加密的开机动画)
    /data/local/bootanimation.zip              用户的开机动画
    /system/media/bootanimation.zip            系统开机动画
    
    desc.txt脚本解释:
    320(宽) 480(高) 24(frame per second)
    p 1(播放一次) 0 part0
    p 0(循环播放) 0 part1
       
    默认开机动画
    android-logo-mask.png
    android-logo-shine.png
    
[4] Home Activity
    将程序的Intent过滤器category修改成CATEGORY_HOME
    如何将普通应用程序修改成Home程序?
    development/samples/Home
    AndroidManifest.xml文件中:
    <category android:name="android.intent.category.HOME"/>                             

<category android:name="android.intent.category.DEFAULT" />


initrc脚本详解:

[概述]
用于指导init进程如何启动Android系统,由若干个段(Sections)组成;
init进程依次解析(注意不是依次执行)/init.rc脚本


[功能]
[1] 控制init进程何时如何执行某个动作
[2] 控制init进程何时如何启动某个服务


[语法]
init rc脚本包含导入(import)、动作(Actions)、命令(Commands)、服务(Service)和选项(Options)五种语句,语法如下:
[1] 基本语法
    1. 每个语句占一行,由若干个空格分隔的标记组成,标记之间用空格或TAB分割,若标记中存在空格需要用'\'转义(或使用"单词 单词"形式)
       例:init.rc文件
           export xxy /system/frame\ work
           export xxy /system/"frame work"
       
    2. 语句太长,一行写不下,可以用'\'将多行连接成一行, '\'字符后不能有任何字符,包括空格
       例: 
           service wpa_supplicant /system/bin/wpa_supplicant -Dwext -iwlan0 \
           -c/data/misc/wifi/wpa_supplicant.conf -e/data/misc/wifi/entropy.bin
           
    3. 以'#'打头的行为注释行
       例:
           # setup the global environment
           
    4. 一个导入(import)、动作(Actions)或服务(Service)语句是一个段(Sections)
       命令(Commands)属于上面离它最近的动作(Actions),单独的命令将被忽略
       选项(Options)属于上面离它最近的服务(Service),单独的选项将被忽略
       
    
[2] 语句
    导入(import)
    ------------
    包含其他init.rc脚本文件, 组成:
    import <filename>
    1. filename
       rc脚本文件
    
    例: 
        import init.sun5i.usb.rc
           
    动作(Actions)
    -------------
    动作是给一个命令序列取一个名字(name)或提供一个促发表达式(trigger), 组成:
    on <name or trigger>
       <command>
       <  ...  >
       <command>
    
    1. on
       动作的关键字
       
    2. 名字(name) 
       也称事件(event),在init rc脚本中必须唯一,如果存在相同名字(name)的动作,只有第一个动作有效,
       init进程或其他动作(Actions)的trigger命令可以通过名字促发动作(Actions),init进程可以促发如下动作:
       (1) early-init
           init进程启动后,挂载虚拟文件系统及/dev目录之后促发,通常用于完成冷启动设备文件建立
           
       (2) init
           完成默认属性(/default.prop)、logo显示和设置硬件只读属性,冷启动设备文件建立完成之后,文件系统挂载之前,通常用于完成文件系统目录结构的建立
           
       (3) early-fs、fs、post-fs和post-fs-data
           init动作执行完成之后促发,用于挂载各种类型的文件系统
           
       (4) early-boot和boot
           完成post-fs-data动作、系统属性(/system/build.prop和/system/default.prop文件)加载和用户属性(/data/local.prop文件和data/property目录下文件中)加载、信号初始化之后,
           用于完成设备使能和shell环境初始化
          
       促发表达式(trigger) 
       也称事件(event),在init rc脚本中也必须唯一
       (5) property:属性名=属性值
           属性被设置成"属性值"时促发
           
           例: init.rc文件的306行
               on property:prop.test=test_value
                  mkdir /mnt/temp 0775 root system 
       
    3. command
       命令,属于上面离它最近的动作(Actions),单独的命令将被忽略
       
    4. 执行
       当动作被促发时,动作将会被添加到动作执行队列,当动作中的所有命令依次执行完毕时,动作从执行队列中删除;
       init程序还添加了一些内部动作,详细见第二天《课堂笔记》
       
    命令(Commands)
    -------------
    1. exec <path> [ argument ... ]
       fork + exec 执行指定程序,init进程会阻塞等待程序执行完成
       path         带路径的程序名
       argument     程序参数
       
    2. export <name> <value>
       设置init进程环境变量,完成后会被所有init启动的新进程继承
       name         环境变量名
       value        环境变量的值
       例: 
           export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
           
    3. ifup <interface>
       使能网卡
       interface    网卡设备名
       例: 
           ifup lo
       
    4. hostname <name>
       设置主机名
       name         主机名
       例: 
           hostname localhost
       
    5. chmod <octal-mode> <path>
       修改文件或目录的模式(通常指权限)
       octal-mode    8进制的数表示的权限
       path          带路径的文件或目录
       例: 
           chmod 0664 /sys/module/lowmemorykiller/parameters/adj
           
    6. chown <owner> <group> <path>
       修改文件或目录的所有者和组
       owner         所有者
       group         组
       path          带路径的文件或目录
       例: 
           chown root system /sys/module/lowmemorykiller/parameters/minfree
       
    7. class_start <serviceclass>
       启动某一类的服务
       serviceclass  服务类
       例: 
           class_start core
       
    8. class_stop <serviceclass>
       停止某一类的服务
       serviceclass  服务类
       
    9.domainname <name>
       设置域名(一组计算机的集合)
       
    10.insmod <path>
       加载内核驱动模块
       path          带路径的内核驱动模块
       例:
           insmod /system/vendor/modules/gslX680.ko
           
    11.mkdir <path> [mode owner group]
       新建目录
       path          带路径的命令名
       mode          文件模式(通常指权限)
       owner         文件所有者
       group         文件组
       mode owner group为选择指定,不指定为0755 root root
       
       例: 
           mkdir /mnt 0775 root system  
       
    12.mount <type> <device> <dir> [ mountoption ... ]
       挂载文件系统
       type           文件系统类型
       device         文件系统所在设备
       dir            挂载目录
       mountoption    参数和Linux的mount命令类似
       例: 
           mount cgroup none /acct cpuacct
           
    13.setprop <name> <value>
       设置属性值
       name           属性名
       value          属性值
       例: 
           setprop net.tcp.buffersize.default 4096,87380,110208,4096,16384,110208
           
    14.setrlimit <resource> <cur> <max>
       设置系统资源限制
       resource       资源编号
       cur            资源当前(软件)限制值
       max            资源最大(硬件)限制值
       例: 
           setrlimit 13 40 40
           
    15.start <service>
       启动服务
       service       服务名
       例: 
           start ueventd
            
    16.stop <service>
       停止服务
       service       服务名
       例: 
           stop adbd
            
    17.symlink <target> <path>
       建立软链接文件
       target        软链接文件
       path          带路径的源文件
       例: 
           symlink /system/etc /etc
           
    18.sysclktz <mins_west_of_gmt>
       设置系统基准时间
       mins_west_of_gmt 设置格林尼治时间差几分钟,一般为0
       例: 
           sysclktz 0
           
    19.trigger <event>
       促发一个动作
       event         动作
       例: 
           trigger post-fs-data
           
    20.write <path> <string> [ string ... ]
       写字符串到文件中
       path          带路径的文件名
       string        字符串,可以有多个
       例: 
           write /proc/sys/kernel/panic_on_oops 1
           
    21.chdir <path>
       修改init进程的当前目录
       
    22.rm <path>
       删除文件
       path          带路径的文件名
       
    23.rmdir <path>
       删除目录
       path          带路径的目录名
       
    24.wait <path>
       等待文件被创建
       path          带路径的文件名  
       
    25.loglevel <level>
       设置内核的log级别
       level         内核级别(0-7)
       例: init.rc文件中的7行
           loglevel 6    
    以上是常用的命令,不同版本可能命令有区别,具体可以查看Android源代码的以下文件确定:
    system/core/init/builtins.c     所有命令的执行函数
    system/core/init/keywords.h     所有动作、服务、命令和选项列表
    
    服务(Service)
    -------------
    服务(Service)是由init进程启动并且保证其一直运行的程序,组成如下:
    service <name> <pathname> [argument ...]
    <option>
    <  ... >
    <option>
   
    1. name
       服务的名字,在init rc脚本中必须唯一
       
    2. pathname [argument ...]
       带路径的服务程序名及参数
       
    3. option
       说明服务的选项
       
    选项(Options)
    -------------
    用于告诉init进程什么时候如何启动服务,存在如下选项:
    1. critical
       4分钟之内重启了4次该服务,重启Android系统进入recovery模式
       
    2. disabled
       服务不能使用start_class命令启动,必须通过服务名称启动
       
    3. setenv <name> <value>
       设置环境变量,并且将其做为服务进程的环境变量
       name         环境变量名
       value        设置的值
       
    4. socket <name> <type> <perm> [user [group]]
       创建unix域socket(即创建文件/dev/socket/<name>),并且打开,将文件描述符传给服务
       文件描述符存在ANDROID_SOCKET_<name>的环境变量中
       name         socket名
       type         socket类型,只能dgram、stream和seqpacket
                    dgram       无序报文传送,不保证可靠
                    seqpacket   顺序报文传送,不保证可靠
                    stream      流传送,保证可靠
       perm         指定权限(八进制的数表示)
       user         指定所属用户, 默认root用户
       group        指定所属主,默认root组
       
     5. user <username>
        指定服务进程所属用户,默认root
        username    用户名
        
     6. group <groupname> [groupname] [...]
        指定服务进程组, 默认root
        groupname   组名
        
     7. oneshot
        服务进程退出时,不重启
        
     8. class <name>
        指定服务所属类,这样可以使用class_start命令启动同一类的多个服务
        如果没有指定,服务属于默认(default)类
        name         类名
        
     9. onrestart <command>
        服务重启时,运行指定程序
        command 命令及其参数
        
     例:在init.rc和init.sun5i.rc中寻找
     
     调试注意:默认Android系统会将进程的标准输出和标准错误重定位到/dev/null(没有设置console)或/dev/console(有设置console)
               如果想看到进程输出,请使用logwrapper程序启动进程,如:
               service akmd /system/bin/logwrapper /sbin/akmd
        
    Properties
    ----------
    init进程的属性值,使别的进程可以看到init进程当前的运行状态:
    1. init.action
       init进程当前正在执行的动作的名称
       
    2. init.command
       init进程当前正在执行的命令的名称
       
    3. init.svc.<name>
       指定服务的状态(stopped、running和restarting),name为服务名
    
    例: 
       getprop init.svc.zygote
       返回running

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值