[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
本文详细介绍了Android系统的启动流程,重点讲解了init.rc脚本的功能、语法和各个组成部分,包括导入、动作、命令、服务和选项。内容涵盖init进程如何执行动作、启动服务,以及涉及的各种命令和选项的解释,例如服务的启动、文件系统挂载、网络配置等关键步骤。

4763

被折叠的 条评论
为什么被折叠?



