Linux,Android 基础知识总结


linuxlinuxlinuxlinux ,Android Android Android Android 基础知识总结 1.1.1.1. Android Android Android Android 编译系统分析 2.2.2.2. 文件系统分析 3.3.3.3. 制作交叉工具链 4.4.4.4. 软件编译常识 5.5.5.5. 设置模块流程分析 6.6.6.6. linux linux linux linux 系统启动流程分析 7.7.7.7. linux linux linux linux 下svn svn svn svn 使用指南 8.8.8.8. LFSLFSLFSLFS 相关 9.9.9.9. linuxlinuxlinuxlinux 内核的初步理解 ==== ====== ====== ====== ====== ====== ====== = ==== ====== = ==== ====== ====== android 系统开发 指南(常用环 境的搭建和使 用) 说明 : 有的步骤 会用到脚本简 化操作,脚本 通过 svn 服务器获 取: svn co svn://192.168.2.148/smartphone/td0901/release/images/scripts 用户名为 各位的姓名拼 音,密码与用 户名相同 一编译 android 源码,制 作文件系统 二ubuntu 下烧录内 核和文件系统 一编译 android 源码,制 作文件系统 1. 开发主线 源码位置: svn://192.168.2.148/smartphone/td0901/trunk/cupcake-jianping //cupcake 源代码 svn://192.168.2.148/smartphone/td0901/trunk/linux-2.6.28-a1 //内核源代 码 2. 打标的源 代码位置 svn list svn://192.168.2.148/smartphone/td0901/tag 我们可以 通过 svn list svn://192.168.2.148/smartphone 查看 svn 版本库内 核 更多信息 请参卡以下文 档: http://192.168.2.148/svn/smartphone/ http://192.168.2.148/svn/smartphone/智能平台 开发部资料管 理手册 V1.0.doc http://192.168.2.148/svn/smartphone/linux 下svn 操作指南 及规范 .doc 用户名为 各位的姓名拼 音,密码与用 户名相同 3. 编译源码 进入 cupcake 工作拷贝 的顶层目录, 执行: ../make_image15.sh 部分执行 结果: out/target/product/littleton/root/ 内核需要 使用的 initramfs out/target/product/littleton/system 文件系统 的系统分区 out/target/product/littleton/data/ 文件系统 数据分区 4. 编译内核 此处内核 编译主要针对 驱动组之外的 同事 1> 设置工具 链 内核的 linux-2.6.28-a1/Makefile 中设定了 : CROSS_COMPILE?= arm-linux- 所以设置 PATH 环境变量 ,保证能找到 正确的工具链 假设工具 链位于: /usr/local/marvell-arm-linux-4.1.1/ 设置为: export PATH:=/usr/local/marvell-arm-linux-4.1.1/bin/:$PATH 2> 更改编译 选项(网络启 动或者本机启 动) 内核顶层 目录执行: make menuconfig General setup ---> [*] Initial RAM filesystem and RAM disk (initramfs/initrd) support () Initramfs source file(s) (NEW) 如果需要 支持网络启动 反选 [] Initial RAM filesystem and RAM disk (initramfs/initrd) support 如果需要 支持本地启动 选中 [*] Initial RAM filesystem and RAM disk (initramfs/initrd) support 设置 () Initramfs source file(s) (NEW) 为root 拷贝 cupcake 编译结果 out/target/product/littleton/root/ 到内核顶 层目录 3> 编译 内核顶层 目录执行 make zImage 编译好的 内核: arch/arm/boot/zImage 5. 搭建网络 开发环境 1> 安装 nfs 服务器 sudo apt-get install nfs-kernel-server nfs-common 2> 修改 nfs 服务器配 置文件 /etc/exports ,确保有 以下配置项 /nfsroot/rootfs *(rw,no_root_squash,sync) 我们在内 核中已经固定 ,手机通过网 络方式启动, 默认从 /nfsroot/rootfs 读取文件 系统,修改配 置项后需要重 启 nfs 服务器: sudo /etc/init.d/nfs-kernel-server restart 3> 配置网络 根文件系统 拷贝 out/target/product/littleton/root/ 内容到 /nfsroot/rootfs 目录 拷贝 out/target/product/littleton/system 内容到 /nfsroot/rootfs/system 修改 /nfsroot/rootfs/init.rc 去掉几个 mount 命令 为了使大 家的过程,结 果统一,可以 使用脚本 mkfs.cupcake 完成 在执行 mkfs.cupcake.nfs 脚本前先 到 cupcake-jianping 目录下执 行 :../make_env15.sh 设置环 境变量 , 获取通过 手动输入 android 源码的位 置,让脚本来 设置环境变量 。 二ubuntu 下烧录内 核和文件系统 1. 硬件: 手机一台 usb 转串口线 一根 usb 转网卡线 一根 2. 软件环境 1> tftp 服务器 执行脚本 : setup_tftpd.sh 安装和配 置 tftp 服务器, 我们默认以 /tftpboot 为tftp 服务器的 根目录,需要 下载的文件都 放在该目录下 。 2> 获取待烧 录的镜像文件 svn list svn://192.168.2.148/smartphone/td0901/release/images 查看服务 器上的 版本情况 ,通常我们下 载最新的 ,例如,下 载 9月18 号发布的 版本: svn co svn://192.168.2.148/smartphone/td0901/release/images/images20090918 3> 烧录镜像 文件 用以下文 件为例,示范 通过 tftp 烧写内核 和文件系统 内核 zImage0917 系统分区 : system0918.img 数据分区 data0918.img 待烧写的 以上文件必须 存在于 tftp 服务器根 目录 /tftpboot 下。 具体步骤 : 首先连接 好硬件设备进 入 blob 下载模式 1> blob 起来后按 任意键 Processing obm parameters... Can't detect micco. Set PMIC as normal I2C mode. NAND flash(Manu=0x98 Device=0xba) detected! Slot 0 Found get relocation table Found Main Bad block table at address 0x0f000000, version 0x01 Found Mirror Bad block table at address 0x0efc0000, version 0x01 Consider yourself BLOBed! blob version 2.0.5-pre3 for Marvell Littleton Copyright (C) 1999 2000 2001 2002 2003 Jan-Derk Bakker and Erik Mouw blob comes with ABSOLUTELYNOWARRANTY; read the GNUGPL for details. This is free software, and you are welcome to redistribute it under certain conditions; read the GNUGPL for details. length not align with page size, change to 0x0 Read flash from 0x60000, length 0x0 Done Autoboot (2 seconds) in progress, press any key to stop .. Autoboot aborted Type "help" to get a list of commands blob> 2> 通过 tftp 下载内核 到 pc 内存 0x80800000 地址处 blob> tftp zImage0917 Begin init ether usbnet!!! ***** Plug-in USB cable & config usbdnet now ****** exit check_usb_connection:1 TFTPing zImage0917*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ OK. received 6144 blocks (3145156 bytes) tftp_cmd: file 'zImage0917' loaded via tftp to address 0x80800000. 3> 擦除原来 的内核分区, 0x100000 为分区起 始地址, 0x300000 为分区长 度 blob> nanderase -z 0x100000 0x400000 the current NAND chip does not support Block Unlocking. Erase 0x300000 length data from flash: 0x100000 Erase flash from 0x100000, length 0x300000 ........................Done 4> 烧写内存 0x80800000 开始 实际长度 为 3145156 的内核数 据到起始地址 为 0x100000 的 内核分区 blob> nandwrite -z 0x80800000 0x100000 3145156 the current NAND chip does not support Block Unlocking. Write 0x2ffdc4 length data from RAM: 0x80800000 to flash: 0x100000 Write flash from 0x100000, length 0x2ffdc4 Erase flash from 0x100000, length 0x300000 ........................Done ........................Done 5> 下载系统 分区镜像文件 到 pc 内存 0x80800000 地址处 blob> tftp system0918.img TFTPing system0918.img*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ OK. received 113138 blocks (57925824 bytes) tftp_cmd: file 'system0918.img' loaded via tftp to address 0x80800000. 6> 擦除原来 的 flash 系统分区 blob> nanderase -z 0x500000 0x4000000 the current NAND chip does not support Block Unlocking. Erase 0x3e0f800 length data from flash: 0x400000 Erase flash from 0x400000, length 0x3e0f800 ................................................................................... ................................................................................... ................................................................................... ..........................Done 7> 烧写数据 到 flash 系统分区 blob> nandwrite -y 0x80800000 0x500000 57925824 the current NAND chip does not support Block Unlocking. Write 0x373e0c0 length data from RAM: 0x80800000 to flash: 0x400000 Write flash from 0x400000, length 0x3591800 Erase flash from 0x400000, length 0x3591800 .................................................................................... ..................................................................................... ................................................................................Done .................................................................................... .................................................................................... ................................................................Done 8> 下载数据 分区镜像文件 到 pc 内存 0x80800000 地址处 blob> tftp data0918.img TFTPing data0918.img*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ OK. received 33992 blocks (17402880 bytes) tftp_cmd: file 'data0918.img' loaded via tftp to address 0x80800000. blob> 9> 擦除原来 的 flash 数据分区 blob> nanderase -z 0x4500000 0xBB00000 the current NAND chip does not support Block Unlocking. Erase 0xa81f000 length data from flash: 0x4400000 Erase flash from 0x4400000, length 0xa81f000 ..................................................................................... ..................................................................................... ..................................................................................... ..................................................................................... ...................................................Done 10> 烧写数据 镜像到 flash 数据分区 blob> nandwrite -y 0x80800000 0x4500000 17402880 the current NAND chip does not support Block Unlocking. Write 0x1098c00 length data from RAM: 0x80800000 to flash: 0x4400000 Write flash from 0x4400000, length 0x1018000 Erase flash from 0x4400000, length 0x1018000 ..................................................................................Done ..................................................................................Done blob> flash 分区图: ******************************************* ***** * blob * kernel * system * data * ***** ******************************************* nanderase -z 0x100000 0x400000 tftp zImage nandwrite -z 0x80800000 0x100000 烧写 system.img: nanderase -z 0x500000 0x4000000 tftp system.img nandwrite -y 0x80800000 0x500000 烧写 userdata.img : nanderase -z 0x4500000 0xBB00000 tftp userdata.img nandwrite -y 0x80800000 0x4500000 ==== ====== ====== ====== ====== 涉及的内 容: svn 服务器的 使用 android 的编译系 统,原理,工 具链,辅助工 具,参数等, 环境变量,怎 样单独添加编 译一个 单独的模 块等。 android 的编译结 果:文件系统 分析 文件系统 的使用,启动 流程 设置模块 流程分析 ==== ====== ====== ====== ====== ==== ====== ====== ====== ====== ====== ====== = ==== ====== = 1. Android 编译系统 分析 编译脚本 及系统变量 build/envsetup.sh 脚本分析 在编译源 代码之前通常 需要在 android 源代码顶 层目录执行 ../build/envsetup.sh 目的是为 了使 用 脚本 envsetup.sh 里面定义 了一些函数: function help() function get_abs_build_var() function get_build_var() function check_product() function check_variant() function setpaths() function printconfig() function set_stuff_for_environment() function set_sequence_number() function settitle() function choosetype() function chooseproduct() function choosevariant() function tapas() function choosecombo() function print_lunch_menu() function lunch() function gettop function m() function findmakefile() function mm() function mmm() function croot() function pid() function gdbclient() function jgrep() function cgrep() function resgrep() function getprebuilt function tracedmdump() function runhat() function getbugreports() function startviewserver() function stopviewserver() function isviewserverstarted() function smoketest() function runtest() function runtest_py() function godir () choosecombo 命令分析 : function choosecombo() { choosesim $1 echo echo choosetype $2 echo echo chooseproduct $3 echo echo choosevariant $4 echo set_stuff_for_environment printconfig } 会依次进 行如下选择: Build for the simulator or the device? 1. Device 2. Simulator Which would you like? [1] Build type choices are: 1. release 2. debug Which would you like? [1] Product choices are: 1. emulator 2. generic 3. sim 4. littleton You can also type the name of a product if you know it. Which would you like? [littleton] Variant choices are: 1. user 2. userdebug 3. eng Which would you like? [eng] user 默认选择 以后会出现: TARGET_PRODUCT=littleton TARGET_BUILD_VARIANT=user TARGET_SIMULATOR=false TARGET_BUILD_TYPE=release TARGET_ARCH=arm HOST_ARCH=x86 HOST_OS=linux HOST_BUILD_TYPE=release BUILD_ID= ==== ====== function chooseproduct()函数分析 : choices=(`/bin/ls build/target/board/*/BoardConfig.mk vendor/*/*/BoardConfig.mk 2> /dev/null`) 读取 build/target/board/* 目录下的 板配置文件: BoardConfig.mk 读取 vendor/*/*/目录下的 板配置文件: BoardConfig.mk choices 的值为: build/target/board/emulator/BoardConfig.mk build/target/board/generic/BoardConfig.mk build/target/board/sim/BoardConfig.mk vendor/marvell/littleton/BoardConfig.mk 经过: for choice in ${choices[@]} do # The product name is the name of the directory containing # the makefile we found, above. prodlist=(${prodlist[@]} `dirname ${choice} | xargs basename`) done 的处理, prodlist 的值为: emulator generic sim littleton 所以选择 菜单为: Product choices are: 1. emulator 2. generic 3. sim 4. littleton 如果选择 4,那么 TARGET_PRODUCT 被赋值为 : littleton。 board_config_mk := \ $(strip $(wildcard \ $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk \ vendor/*/$(TARGET_DEVICE)/BoardConfig.mk \ )) 怎样添加 一个模块 LOCAL_PATH:= $(call my-dir) #编译静态 库 include $(CLEAR_VARS) LOCAL_MODULE = libhellos LOCAL_CFLAGS = $(L_CFLAGS) LOCAL_SRC_FILES = hellos.c LOCAL_C_INCLUDES = $(INCLUDES) LOCAL_SHARED_LIBRARIES:= libcutils LOCAL_COPY_HEADERS_TO:= libhellos LOCAL_COPY_HEADERS:= hellos.h include $(BUILD_STATIC_LIBRARY) #编译动态 库 include $(CLEAR_VARS) LOCAL_MODULE = libhellod LOCAL_CFLAGS = $(L_CFLAGS) LOCAL_SRC_FILES = hellod.c LOCAL_C_INCLUDES = $(INCLUDES) LOCAL_SHARED_LIBRARIES:= libcutils LOCAL_COPY_HEADERS_TO:= libhellod LOCAL_COPY_HEADERS:= hellod.h include $(BUILD_SHARED_LIBRARY) BUILD_TEST=true ifeq ($(BUILD_TEST),true) #使用静态 库 include $(CLEAR_VARS) LOCAL_MODULE:= hellos LOCAL_STATIC_LIBRARIES:= libhellos LOCAL_SHARED_LIBRARIES:= LOCAL_LDLIBS += -ldl LOCAL_CFLAGS:= $(L_CFLAGS) LOCAL_SRC_FILES:= mains.c LOCAL_C_INCLUDES:= $(INCLUDES) include $(BUILD_EXECUTABLE) #使用动态 库 include $(CLEAR_VARS) LOCAL_MODULE:= hellod LOCAL_MODULE_TAGS:= debug LOCAL_SHARED_LIBRARIES:= libc libcutils libhellod LOCAL_LDLIBS += -ldl LOCAL_CFLAGS:= $(L_CFLAGS) LOCAL_SRC_FILES:= maind.c LOCAL_C_INCLUDES:= $(INCLUDES) include $(BUILD_EXECUTABLE) endif # ifeq ($(WPA_BUILD_SUPPLICANT),true) ######################## #local_target_dir := $(TARGET_OUT)/etc/wifi #include $(CLEAR_VARS) #LOCAL_MODULE:= wpa_supplicant.conf #LOCAL_MODULE_TAGS:= user #LOCAL_MODULE_CLASS:= ETC #LOCAL_MODULE_PATH:= $(local_target_dir) #LOCAL_SRC_FILES:= $(LOCAL_MODULE) #include $(BUILD_PREBUILT) ######################## 系统变量 解析 LOCAL_MODULE-编译的目 标对象 LOCAL_SRC_FILES-编译的源 文件 LOCAL_C_INCLUDES-需要包含 的头文件目录 LOCAL_SHARED_LIBRARIES-链接时需 要的外部库 LOCAL_PRELINK_MODULE-是否需要 prelink 处理 BUILD_SHARED_LIBRARY-指明要编 译成动态库 LOCAL_PATH- 编译时的 目录 $(call 目录,目 录 ….) 目录引入 操作符 如该目录 下有个文件夹 名称 src,则可以 这样写 $(call src),那么就 会得到 src 目录的完 整路 径 include $(CLEAR_VARS) -清除之前 的一些系统变 量 CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk 在build/core/config.mk 定义 CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk 通过 include 包含自定 义的 .mk 文件(即 是自定义编译 规则)或是引 用系统其他的 .mk 文件 (系统定 义的编译规则 )。 LOCAL_SRC_FILES-编译的源 文件 可以是 .c, .cpp, .java, .S(汇编文 件)或是 .aidl 等格式 不同的文 件用空格隔开 。如果编译目 录子目录,采 用相对路径, 如子目录 /文件名。 也可以通 过$(call 目录 ),指明编 译某目录 下所有 .c/.cpp/.java/.S/ .aidl 文件 .追加文件 LOCAL_SRC_FILES += 文件 LOCAL_C_INCLUDES-需要包含 的头文件目录 可以是系 统定义路径, 也可以是相对 路径 . 如该编译 目录下有个 include 目录,写 法 是 include/*.h LOCAL_SHARED_LIBRARIES-链接时需 要的外部共享 库 LOCAL_STATIC_LIBRARIES-链接时需 要的外部外部 静态 LOCAL_JAVA_LIBRARIES 加入 jar 包 LOCAL_MODULE-编译的目 标对象 module 是指系统 的 native code,通常针 对 c,c++代码 ./system/core/sh/Android.mk:32:LOCAL_MODULE:= sh ./system/core/libcutils/Android.mk:71:LOCAL_MODULE := libcutils ./system/core/cpio/Android.mk:9:LOCAL_MODULE := mkbootfs ./system/core/mkbootimg/Android.mk:8:LOCAL_MODULE := mkbootimg ./system/core/toolbox/Android.mk:61:LOCAL_MODULE:= toolbox ./system/core/logcat/Android.mk:10:LOCAL_MODULE:= logcat ./system/core/adb/Android.mk:65:LOCAL_MODULE := adb ./system/core/adb/Android.mk:125:LOCAL_MODULE := adbd ./system/core/init/Android.mk:20:LOCAL_MODULE:= init ./system/core/vold/Android.mk:24:LOCAL_MODULE:= vold ./system/core/mountd/Android.mk:13:LOCAL_MODULE:= mountd LOCAL_PACKAGE_NAME Java 应用程序 的名字用该变 量定义 ./packages/apps/Music/Android.mk:9:LOCAL_PACKAGE_NAME := Music ./packages/apps/Browser/Android.mk:14:LOCAL_PACKAGE_NAME := Browser ./packages/apps/Settings/Android.mk:8:LOCAL_PACKAGE_NAME := Settings ./packages/apps/Stk/Android.mk:10:LOCAL_PACKAGE_NAME := Stk ./packages/apps/Contacts/Android.mk:10:LOCAL_PACKAGE_NAME := Contacts ./packages/apps/Mms/Android.mk:8:LOCAL_PACKAGE_NAME := Mms ./packages/apps/Camera/Android.mk:8:LOCAL_PACKAGE_NAME := Camera ./packages/apps/Phone/Android.mk:11:LOCAL_PACKAGE_NAME := Phone ./packages/apps/VoiceDialer/Android.mk:8:LOCAL_PACKAGE_NAME := VoiceDialer BUILD_SHARED_LIBRARY-指明要编 译成动态库。 编译的目 标,用 include 操作符 UILD_STATIC_LIBRARY 来指明要 编译成静态库 。 如果是 java 文件的话 ,会用到系统 的编译脚本 host_java_library.mk,用 BUILD_PACKAGE 来 指明。三 个编译 ---- ------ ------ --- include $(BUILD_STATIC_LIBRARY) BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk ---- ------ ------ --- include $(BUILD_SHARED_LIBRARY) ./build/core/config.mk:50:BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk ---- ------ ------ --- include $(BUILD_HOST_SHARED_LIBRARY) BUILD_HOST_SHARED_LIBRARY:= $(BUILD_SYSTEM)/host_shared_library.mk ---- ------ ------ --- include $(BUILD_EXECUTABLE) build/core/config.mk:51:BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk ---- ------ ------ --- include $(BUILD_HOST_EXECUTABLE) ./build/core/config.mk:53:BUILD_HOST_EXECUTABLE:= $(BUILD_SYSTEM)/host_executable.mk ---- ------ ------ --- BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk ---- ------ ------ --- BUILD_JAVA_LIBRARY ./build/core/config.mk:58:BUILD_JAVA_LIBRARY:= $(BUILD_SYSTEM)/java_library.mk ---- ------ ------ -- BUILD_STATIC_JAVA_LIBRARY 编译静态 JAVA 库 ./build/core/config.mk:59:BUILD_STATIC_JAVA_LIBRARY:= $(BUILD_SYSTEM)/static_java_library.mk ---- ------ ------ -- BUILD_HOST_JAVA_LIBRARY 编译本机 用的 JAVA 库 ./build/core/config.mk:60:BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk ---- ------ ------ -- BUILD_HOST_STATIC_LIBRARY:= $(BUILD_SYSTEM)/host_static_library.mk BUILD_HOST_SHARED_LIBRARY:= $(BUILD_SYSTEM)/host_shared_library.mk BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk BUILD_RAW_STATIC_LIBRARY:= $(BUILD_SYSTEM)/raw_static_library.mk BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk BUILD_RAW_EXECUTABLE:= $(BUILD_SYSTEM)/raw_executable.mk BUILD_HOST_EXECUTABLE:= $(BUILD_SYSTEM)/host_executable.mk BUILD_PACKAGE:= $(BUILD_SYSTEM)/package.mk BUILD_HOST_PREBUILT:= $(BUILD_SYSTEM)/host_prebuilt.mk BUILD_PREBUILT:= $(BUILD_SYSTEM)/prebuilt.mk BUILD_MULTI_PREBUILT:= $(BUILD_SYSTEM)/multi_prebuilt.mk BUILD_JAVA_LIBRARY:= $(BUILD_SYSTEM)/java_library.mk BUILD_STATIC_JAVA_LIBRARY:= $(BUILD_SYSTEM)/static_java_library.mk BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk BUILD_DROIDDOC:= $(BUILD_SYSTEM)/droiddoc.mk BUILD_COPY_HEADERS:= $(BUILD_SYSTEM)/copy_headers.mk BUILD_KEY_CHAR_MAP:= $(BUILD_SYSTEM)/key_char_map.mk ==== ====== == LOCAL_PRELINK_MODULE Prelink 利用事先 链接代替运行 时链接的方法 来加速共享库 的加载,它不 仅可以加快起 动速 度,还可 以减少部分内 存开销, 是各种 Linux 架构上用 于减少程序加 载时间、缩短 系统启动时间 和加快应用程 序启动的很受 欢 迎的一个 工具。程序运 行时的 动态链接 尤其是重定位 (relocation)的开销对 于大型系统来 说是很大的。 动态链接 和加载的过程 开销很大,并 且在大多数的 系统上 , 函数库并 不会常常被更 动 , 每次程 序被执行 时所进行的链 接 动作都是 完全相同的, 对于嵌入式系 统来说尤其如 此。因此,这 一过程可以改 在运行时之前 就 可以预先 处理好,即花 一些时间 利用 Prelink 工具对动 态共享库和可 执行文件进行 处理,修改这 些二进制文件 并加入相应的 重 定位等信 息,节约了本 来在程序 启动时的 比较耗时的查 询函数地址等 工作,这样可 以减少程序启 动的时间,同 时也减少了内 存 的耗用。 Prelink 的这种做 法当然也有代 价:每次更新 动态共享库时 ,相关的可执 行文件都需要 重新 执行一遍 Prelink 才能保 证有效, 因为新的共享 库中的符号信 息、地址等很 可能与原来的 已经不同了, 这就是为什么 android framework 代码一改 动, 这时候就 会导致相关的 应用程序重新 被编译。 这种代价 对于嵌入式系 统的开发者来 说可能稍微带 来一些复杂度 ,不过好在对 用户来说几乎 是 可以忽略 的。 ---- ------ ------ ---- 变量设置 为 false 那么将不 做 prelink 操作 LOCAL_PRELINK_MODULE:= false 默认是需 要 prlink 的,同时 需要在 build/core/prelink-linux-arm.map 中加入 libhellod.so 0x96000000 这个 map 文件好像 是制定动态库 的地址的,在 前面注释上面 有一些地址范 围的信息,注 意库 与库之间 的间隔数, 如果指定 不好的话编译 的时候会提示 说地址空间冲 突的问题。另 外,注意排序 ,这里要把数 大 的放到前 面去, 按照大小 降序排序。 解析 LOCAL_PRELINK_MODULE 变量 build/core/dynamic_binary.mk:94:ifeq ($(LOCAL_PRELINK_MODULE),true) ifeq ($(LOCAL_PRELINK_MODULE),true) $(prelink_output): $(prelink_input) $(TARGET_PRELINKER_MAP) $(APRIORI) $(transform-to-prelinked) transform-to-prelinked 定义: ./build/core/definitions.mk:1002:define transform-to-prelinked define transform-to-prelinked @mkdir -p $(dir $@) @echo "target Prelink: $(PRIVATE_MODULE) ($@)" $(hide) $(APRIORI) \ --prelinkmap $(TARGET_PRELINKER_MAP) \ --locals-only \ --quiet \ $< \ --output $@ endef ./build/core/config.mk:183:APRIORI := $(HOST_OUT_EXECUTABLES)/apriori$(HOST_EXECUTABLE_SUFFIX) prelink 工具不是 常用的 prelink 而是 apriori,其源代 码位于 ” /build/tools/apriori” 参考文档 : 动态库优 化 ——Prelink(预连接 )技术 http://www.eefocus.com/article/09-04/71629s.html ==== ====== ===== LOCAL_ARM_MODE:= arm 目前 Android 大部分都 是基于 Arm 处理器的 , Arm 指令用两 种模式 Thumb(每条指令 两个字节 ) 和arm 指令(每 条指令四个字 节) LOCAL_CFLAGS += -O3 -fstrict-aliasing -fprefetch-loop-arrays 通过设定 编译器操作, 优化级别, -O0 表示没有 优化 ,-O1 为缺省值 , -O3 优化级别 最高 LOCAL_CFLAGS += -W-Wall LOCAL_CFLAGS += -fPIC -DPIC LOCAL_CFLAGS += -O2 -g -DADB_HOST=1 -Wall -Wno-unused-parameter LOCAL_CFLAGS += -D_XOPEN_SOURCE-D_GNU_SOURCE-DSH_HISTORY LOCAL_CFLAGS += -DUSEOVERLAY2 根据条件 选择相应的编 译参数 ifeq ($(TARGET_ARCH),arm) LOCAL_CFLAGS += -DANDROID_GADGET=1 LOCAL_CFLAGS:= $(PV_CFLAGS) endif ifeq ($(TARGET_BUILD_TYPE),release) LOCAL_CFLAGS += -O2 endif LOCAL_LDLIBS:= -lpthread LOCAL_LDLIBS += -ldl ifdef USE_MARVELL_MVED LOCAL_WHOLE_STATIC_LIBRARIES += lib_il_mpeg4aspdecmved_wmmx2lnx lib_il_h264decmved_wmmx2lnx LOCAL_SHARED_LIBRARIES += libMrvlMVED else LOCAL_WHOLE_STATIC_LIBRARIES += lib_il_h264dec_wmmx2lnx lib_il_mpeg4aspdec_wmmx2lnx endif ==== ====== ====== ==== 其他一些 变量和脚本: HOST_JNILIB_SUFFIX LOCAL_MODULE_SUFFIX LOCAL_MODULE_SUFFIX:= $(HOST_JNILIB_SUFFIX) HOST_GLOBAL_LDFLAGS TARGET_GLOBAL_LDFLAGS PRIVATE_LDFLAGS LOCAL_LDLIBS LOCAL_C_INCLUDES LOCAL_STATIC_LIBRARIES LOCAL_STATIC_LIBRARIES += codecJPDec_WMMX2LNX miscGen_WMMX2LNX LOCAL_SHARED_LIBRARIES LOCAL_SHARED_LIBRARIES += libMrvlIPP LOCAL_SHARED_LIBRARIES += $(common_SHARED_LIBRARIES) LOCAL_SHARED_LIBRARIES += libMrvlIPP LOCAL_SHARED_LIBRARIES += libdl ifeq ($(TARGET_PRODUCT),littleton) LOCAL_C_INCLUDES += vendor/marvell/littleton/m2d \ LOCAL_SHARED_LIBRARIES += libOmxCore endif vendor/marvell/littleton/littleton.mk:27:PRODUCT_NAME := littleton vendor/marvell/littleton/littleton.mk:28:PRODUCT_DEVICE := littleton vendor/marvell/littleton/AndroidProducts.mk:13: $(LOCAL_DIR)/littleton.mk vendor/sample/products/sample_addon.mk:40:PRODUCT_NAME := sample_addon vendor/htc/dream-open/htc_dream.mk:6:PRODUCT_NAME := htc_dream ./vendor/htc/dream-open/htc_dream.mk:7:PRODUCT_DEVICE := dream-open ./vendor/htc/dream-open/AndroidProducts.mk:3: $(LOCAL_DIR)/htc_dream.mk build/target/product/generic.mk:26:PRODUCT_NAME := generic build/target/product/generic_with_google.mk:20:PRODUCT_NAME := generic_with_google build/target/product/min_dev.mk:6:PRODUCT_NAME := min_dev build/target/product/core.mk:2:PRODUCT_NAME := build/target/product/sim.mk:7:PRODUCT_NAME := sim build/target/product/sdk.mk:37:PRODUCT_NAME := sdk build/tools/buildinfo.sh:20:echo "ro.product.name=$PRODUCT_NAME" lunch sample_addon-eng lunch htc_dream-eng lunch generic-eng lunch 1 lunch sim-eng TARGET_BUILD_TYPE=release lunch 2 TARGET_BUILD_TYPE=debug lunch generic-user .PHONY: systemtarball-nodeps systemtarball-nodeps: $(FS_GET_STATS) \ $(filter-out systemtarball-nodeps stnod,$(MAKECMDGOALS)) $(build-systemtarball-target) .PHONY: stnod stnod: systemtarball-nodeps systemimage-nodeps snod ./core/main.mk:BUILD_SYSTEM := $(TOPDIR)build/core ./core/main.mk:include $(BUILD_SYSTEM)/config.mk ./core/main.mk:include $(BUILD_SYSTEM)/cleanbuild.mk ./core/main.mk:include $(BUILD_SYSTEM)/version_defaults.mk ./core/main.mk:include $(BUILD_SYSTEM)/definitions.mk ./core/main.mk:include $(BUILD_SYSTEM)/Makefile ./core/static_java_library.mk:include $(BUILD_SYSTEM)/java_library.mk ./core/host_java_library.mk:include $(BUILD_SYSTEM)/base_rules.mk ./core/executable.mk:include $(BUILD_SYSTEM)/dynamic_binary.mk ./core/java_library.mk:include $(BUILD_SYSTEM)/java.mk ./core/binary.mk:include $(BUILD_SYSTEM)/base_rules.mk ./core/raw_executable.mk:include $(BUILD_SYSTEM)/binary.mk ./core/prebuilt.mk:include $(BUILD_SYSTEM)/base_rules.mk ./core/host_executable.mk:include $(BUILD_SYSTEM)/binary.mk ./core/combo/select.mk:$(combo_target)PRELINKER_MAP := $(BUILD_SYSTEM)/prelink- $(combo_os_arch).map ./core/shared_library.mk:include $(BUILD_SYSTEM)/dynamic_binary.mk ./core/config.mk:include $(BUILD_SYSTEM)/pathmap.mk ./core/config.mk:BUILD_COMBOS:= $(BUILD_SYSTEM)/combo ./core/config.mk:CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk ./core/config.mk:BUILD_HOST_STATIC_LIBRARY:= $(BUILD_SYSTEM)/host_static_library.mk ./core/config.mk:BUILD_HOST_SHARED_LIBRARY:= $(BUILD_SYSTEM)/host_shared_library.mk ./core/config.mk:BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk ./core/config.mk:BUILD_RAW_STATIC_LIBRARY := $(BUILD_SYSTEM)/raw_static_library.mk ./core/config.mk:BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk ./core/config.mk:BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk ./core/config.mk:BUILD_RAW_EXECUTABLE:= $(BUILD_SYSTEM)/raw_executable.mk ./core/config.mk:BUILD_HOST_EXECUTABLE:= $(BUILD_SYSTEM)/host_executable.mk ./core/config.mk:BUILD_PACKAGE:= $(BUILD_SYSTEM)/package.mk ./core/config.mk:BUILD_HOST_PREBUILT:= $(BUILD_SYSTEM)/host_prebuilt.mk ./core/config.mk:BUILD_PREBUILT:= $(BUILD_SYSTEM)/prebuilt.mk ./core/config.mk:BUILD_MULTI_PREBUILT:= $(BUILD_SYSTEM)/multi_prebuilt.mk ./core/config.mk:BUILD_JAVA_LIBRARY:= $(BUILD_SYSTEM)/java_library.mk ./core/config.mk:BUILD_STATIC_JAVA_LIBRARY:= $(BUILD_SYSTEM)/static_java_library.mk ./core/config.mk:BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk ./core/config.mk:BUILD_DROIDDOC:= $(BUILD_SYSTEM)/droiddoc.mk ./core/config.mk:BUILD_COPY_HEADERS := $(BUILD_SYSTEM)/copy_headers.mk ./core/config.mk:BUILD_KEY_CHAR_MAP := $(BUILD_SYSTEM)/key_char_map.mk ./core/config.mk:HOST_JDK_TOOLS_JAR:= $(shell $(BUILD_SYSTEM)/find-jdk-tools-jar.sh) ./core/version_defaults.mk:INTERNAL_BUILD_ID_MAKEFILE := $(wildcard $(BUILD_SYSTEM)/build_id.mk) ./core/config.mk:include $(BUILD_SYSTEM)/envsetup.mk ./core/config.mk:include $(BUILD_SYSTEM)/combo/select.mk ./core/config.mk:include $(BUILD_SYSTEM)/combo/select.mk ./core/config.mk:include $(BUILD_SYSTEM)/combo/javac.mk ./core/product_config.mk:include $(BUILD_SYSTEM)/node_fns.mk ./core/product_config.mk:include $(BUILD_SYSTEM)/product.mk ./core/product_config.mk:include $(BUILD_SYSTEM)/device.mk ./core/dynamic_binary.mk:include $(BUILD_SYSTEM)/binary.mk ./core/host_static_library.mk:include $(BUILD_SYSTEM)/binary.mk ./core/java.mk:include $(BUILD_SYSTEM)/base_rules.mk ./core/host_shared_library.mk:include $(BUILD_SYSTEM)/binary.mk ./core/key_char_map.mk:include $(BUILD_SYSTEM)/base_rules.mk ./core/package.mk:include $(BUILD_SYSTEM)/java.mk ./core/static_library.mk:include $(BUILD_SYSTEM)/binary.mk ./core/definitions.mk:include $(BUILD_SYSTEM)/distdir.mk ./core/envsetup.mk:include $(BUILD_SYSTEM)/product_config.mk ./tools/apicheck/Android.mk:include $(BUILD_SYSTEM)/base_rules.mk ./tools/dexpreopt/Android.mk:include $(BUILD_SYSTEM)/host_prebuilt.mk COMMON_GLOBAL_CFLAGS:= -DANDROID-fmessage-length=0 -W-Wall -Wno-unused COMMON_DEBUG_CFLAGS:= COMMON_RELEASE_CFLAGS:= -DNDEBUG-UDEBUG COMMON_PACKAGE_SUFFIX:= .zip COMMON_JAVA_PACKAGE_SUFFIX:= .jar COMMON_ANDROID_PACKAGE_SUFFIX:= .apk ACP:= $(HOST_OUT_EXECUTABLES)/acp$(HOST_EXECUTABLE_SUFFIX) AIDL:= $(HOST_OUT_EXECUTABLES)/aidl$(HOST_EXECUTABLE_SUFFIX) MKBOOTFS:= $(HOST_OUT_EXECUTABLES)/mkbootfs$(HOST_EXECUTABLE_SUFFIX) MKBOOTIMG:= $(HOST_OUT_EXECUTABLES)/mkbootimg$(HOST_EXECUTABLE_SUFFIX) MKYAFFS2 := $(HOST_OUT_EXECUTABLES)/mkyaffs2image$(HOST_EXECUTABLE_SUFFIX) APICHECK:= $(HOST_OUT_EXECUTABLES)/apicheck$(HOST_EXECUTABLE_SUFFIX) FS_GET_STATS:= $(HOST_OUT_EXECUTABLES)/fs_get_stats$(HOST_EXECUTABLE_SUFFIX) MKEXT2IMG := $(HOST_OUT_EXECUTABLES)/genext2fs$(HOST_EXECUTABLE_SUFFIX) MKEXT2BOOTIMG := external/genext2fs/mkbootimg_ext2.sh MKTARBALL:= build/tools/mktarball.sh DX:= $(HOST_OUT_EXECUTABLES)/dx LOCALIZE:= $(HOST_OUT_EXECUTABLES)/localize$(HOST_EXECUTABLE_SUFFIX) HOST_GLOBAL_LDFLAGS TARGET_GLOBAL_LDFLAGS PRIVATE_LDFLAGS build/core/combo/linux-arm.mk:16:$(combo_target)NO_UNDEFINED_LDFLAGS := -Wl,--no- undefined save_CFLAGS="$CFLAGS -g -mabi=aapcs-linux" LDFLAGS='$LDFLAGS -lX11 -lxml2 -lXdmcp -lXau -lexpat -lXrender -lXft -lfontconfig - lfreetype -lz' --without-libtiff "#--with-gdktarget=directfb" LDFLAGS=" -Wl,-rpath-link=$LD_LIBRARY_PATH -L$PREFIX/lib ${env_LDFLAGS} ${save_LDFLAGS}" ./vendor/marvell/external/alsa/alsa-lib/src/Mdroid.mk:43:LOCAL_CFLAGS += -mabi=aapcs-linux ./vendor/marvell/external/alsa/alsa-tools/Mdroid.mk:8:LOCAL_CFLAGS += -mabi=aapcs-linux ./vendor/marvell/littleton/libaudio/Mdroid.mk:22:LOCAL_CPPFLAGS += -mabi=aapcs-linux ./external/wpa_supplicant/Android.mk:35:L_CFLAGS += -mabi=aapcs-linux ./system/wlan/ti/sta_dk_4_0_4_32/CUDK/tiwlan_loader/Android.mk:88:LOCAL_CFLAGS = -Wall - Wstrict-prototypes $(CLI_DEBUGFLAGS) -D__LINUX__ $(DK_DEFINES) -mabi=aapcs-linux ./kernel/arch/arm/Makefile ifeq ($(CONFIG_AEABI),y) CFLAGS_ABI:=-mabi=aapcs-linux -mno-thumb-interwork else CFLAGS_ABI:=$(call cc-option,-mapcs-32,-mabi=apcs-gnu) $(call cc-option,-mno-thumb- interwork,) endif # Need -Uarm for gcc < 3.x KBUILD_CFLAGS +=$(CFLAGS_ABI) $(arch-y) $(tune-y) $(call cc-option,-mshort-load- bytes,$(call cc-option, -malignment-traps,)) -msoft-float -Uarm KBUILD_AFLAGS +=$(CFLAGS_ABI) $(arch-y) $(tune-y) -msoft-float CFLAGS="${temp_CFLAGS} -I/include -I/usr/include -I/usr/X11R7/include" LDFLAGS="${temp_LDFLAGS} -L/lib -L/usr/lib -L/usr/X11R7/lib" Android Build System http://www.cublog.cn/u/8059/showart_1420446.html ==== ====== ====== ====== ====== ====== ====== = ==== ====== = ==== ====== ====== ====== ====== ====== ====== = ==== ====== ====== ====== ===== 2. 文件系统 分析 2.1 文件系统 概述 2.2 ext2 ,ext3 文件系统 2.3 jffs,jffs2 文件系统 2.4 yafss,yaffs2 文件系统 2.5 虚拟文件 系统( sysfs,proc,tsmpfs 等) 2.6 一些必要 重要的系统文 件 (/etc/fstab ,inittab,init.rc 等) 2.7 制作文件 系统 2.1 文件系统 概述 文件系统 ( File system)指代贮 存在计算机上 的文件和目录 。文件系统可 以有不同的格 式,叫做 文件系统类型 ( file system types)。 这些格式 决定信息是如 何被贮存为文 件和目录。 Linux 支持多种 文件系统,包 括 sysfs,proc, tmpfs,ext2,ext3,cramfs,ramfs,nfs, vfat,jffs,jffs2,yaffs,yaffs2 等,为了 对各类文件系 统进行统一管 理, Linux 引入了虚 拟文件系 统 VFS(Virtual File System), 为各类文 件系统提供一 个统一的操作 界面和应用编 程接口。 Linux 启动时, 第一个必须挂 载的 是根文件 系统;若系统 不能从指定设 备上挂载根文 件 系统,则 系统会出错而 退出启动。之 后可以自动或 手动挂载其他 的文件系统。 因此,一个系 统 中可以同 时存在不同的 文件系统。 不同的文 件系统类型有 不同的特点, 因而根据存储 设备的硬件特 性、系统需求 等有不同 的应用场 合。在嵌入式 Linux 应用中, 主要的存储设 备 为RAM(DRAM,SDRAM)和ROM(常采用 FLASH 存储器 ),常用的 基于存储设备 的文件系统 类型包括 : jffs2, yaffs, cramfs, romfs, ramdisk, ramfs/tmpfs 等。 2.2 ext2 ,ext3 文件系统 在异常断 电或系统崩溃 (又称不洁系 统关机, unclean system shutdown)发生时 ,每个在系统 上挂载了 的 ext2 文件系统 必须要使用 e2fsck 程序来检 查其一致性。 这是一个很费 时的过程,特 别是在检查包 含大量文件的 庞大文件卷 时,它会 大大耽搁引导 时间。在这期 间,文件卷上 的所有数据 都不能被 访问。由 ext3 文件系统 提供的登记报 表方式意味着 不洁系统关机 后没必要再进 行此 类文件系 统检查。使用 ext3 系统时, 一致性检查只 在 某些罕见 的硬件失效( 如硬盘驱动器 失效)情况下 才发生。 参考文档 : Linux ext2/ext3 文件系统 详解 http://www.blueidea.com/computer/system/2008/5536.asp Linux EXT2文件系统 结构分析 (详情见附 件 ) http://chenguang.blog.51cto.com/350944/69655 Ext2 文件系统 的硬盘布局 http://www.ibm.com/developerworks/cn/linux/filesystem/ext2/ 2.3 jffs,jffs2 文件系统 jffs2 文件系统 制作工具 mkfs.jffs2 1.从网上 下载: mkjffs2-arm.rar http://blogimg.chinaunix.net/blog/upfile2/080701192924.rar mkjffs2-pc.rar http://blogimg.chinaunix.net/blog/upfile2/080701193005.rar 2.通过源 代码获得 mkfs.jffs2 源码下载 地址 : ftp://ftp.infradead.org/pub/mtd-utils/mtd-utils-1.0.1.tar.gz 编译的过 程中缺少 sys/acl.h 文件, ubunt-8.10 通过下面 命令安装 sudo apt-get install libacl1-dev 制作 jffs2 文件系统 mkfs.jffs2 -r rootfs/ -o rootfs-jffs2.img -e 0x4000 --pad=0x500000 -s 0x200 -n 各参数的 意义: (1)-r :指定要 做成 image 的源文件 夹 . (2)-o : 指定输出 image 文档的文 件名 . (3)-e : 每一块要 抹除的 block size,默认值 是 64KB.要注意, 不同的 flash, 其block size 会不一 样 (4)--pad (-p): 用16 进制來表 示所要输出文 档的大小,也 就是 root.jffs2 的size。很重要 的是 , 为了不浪 费 flash 空间 , 這个值 最好符合 flash driver 所规划的 分区大小。 (5)如果挂载 后会出现类似 : CLEANMARKER node found at 0x0042c000 has totlen 0xc != normal 0x0 的警告, 则加上 -n 就会消失 。 在pc 上mount jffs2 镜像文件 首先确保 系统支持 jffs2 文件系统 ,通过命令 cat /proc/filesystems 查看 sudo modprobe mtdram sudo modprobe mtdblock 插入此模 块以后将会生 成节点: /dev/mtdblock0 sudo modprobe jffs2 在一些系 统 fedora core 5 ,linux 2.6.15.1 上的 mtdram 只有 4.2MB 所以最好 自己指定。 例如 : modprobe mtdram total_size=49152 erase_size=128 sudo dd if=rootfs-jffs2.img of=/dev/mtdblock0 sudo mount -t jffs2 /dev/mtdblock0 /mnt 更多参考 文档: mkfs.jffs2 参数详解 http://blog.sina.com.cn/s/blog_4a4163880100cogf.html~type=v5_one&label=rela_prevarticle 在linux pc 上挂载 jffs2 文件系 http://blog.sina.com.cn/s/blog_4a4163880100cozw.html 2.4 yafss,yaffs2 文件系统 2.4.1 yaffs2 文件系统 制作工具 mkyaffs2image 2.4.2 在pc 上挂载 yaffs2 文件系统 2.4.3 通过工具 释放 yaffs2 文件系统 YAFFS,Yet Another Flash File System ,是一种 类似于 JFFS/JFFS2 的专门为 Flash 设计的 嵌入式文 件系统。与 JFFS 相比, 它减少了 一些功能,因 此速度更快、 占用内存更少 。 YAFFS 和JFFS 都提供了 写均衡,垃 圾收集等 底层操作。它 们的不同之处 在于: 1 )、JFFS 是一种日 志文件系统, 通过日志机制 保证文件系统 的稳定性。 YAFFS 仅仅借 鉴了日志 系统的思想, 不提供日志机 能,所以稳定 性不如 JAFFS,但是资 源占用少。 2 )、JFFS 中使用多 级链表管理需 要回收的脏块 ,并且使用系 统生成伪随机 变量决定要回 收 的块,通 过这种方法能 提供较好的写 均衡,在 YAFFS 中是从头 到尾对块搜索 ,所以在垃圾 收集上 JFFS 的速度慢 ,但是能延长 NAND 的 寿命。 3 )、JFFS 支持文件 压缩,适合存 储容量较小的 系统; YAFFS 不支持压 缩,更适合存 储 容量大的 系统。 YAFFS 还带有 NAND 芯片驱动 ,并为嵌入式 系统提供了直 接访问文件系 统的 API,用户可 以不使用 Linux 中的 MTD 和VFS,直接对 文件 进行操作 。 NAND Flash 大多采用 MTD+YAFFS 的模式。 MTD(Memory Technology Devices ,内存技 术设备)是对 Flash 操作的 接口,提 供了一系列的 标准函数,将 硬件驱动设计 和系统程序设 计分开。 YAFFS2 是YAFFS 的升级版 ,能更好的支 持 NANDFLASH。 2.4.1 yaffs2 文件系统 制作工具 mkyaffs2image 1. android yaffs2 源代码 external/yaffs2/ 2. 从网上下 载 yaffs2 源码 下载: http://www.aleph1.co.uk/cgi-bin/viewcvs.cgi/yaffs/ 下载: http://www.aleph1.co.uk/cgi-bin/viewcvs.cgi/yaffs2/ //点击左下 角的 Download tarball 下整个 tar 包 cvs 下载 : export CVSROOT=:pserver:anonymous@cvs.aleph1.co.uk:/home/aleph1/cvs cvs logon cvs co yaffs2 tar -xvf yaffs2.tar.bz;cd yaffs2;make 为ubuntu 8.10 添加 yaffs 文件系统 支持 sudo mkdir -p /lib/modules/2.6.27-4-generic/kernel/fs/yaffs2 sudo cp yaffs2.ko /lib/modules/2.6.27-4-generic/kernel/fs/yaffs2/ sudo insmod /lib/modules/2.6.27-4-generic/kernel/fs/yaffs2/yaffs2.ko 制作 yaffs2 文件系统 mkyaffs2image /nfsroot/rootfs/system system.img /nfsroot/rootfs/system 为文件系 统所在的目录 system.img 为生成的 镜像文件 2.4.2 在pc 上挂载 yaffs2 文件系统 sudo mkdir -p /mnt/mtd/yaffs2 sudo modprobe mtdblock sudo modprobe mtdram total_size=100000 erase_size=256 sudo insmod /lib/modules/2.6.27-4-generic/kernel/fs/yaffs2/yaffs2.ko sudo dd if=rootfs.yaffs2 of=/dev/mtdblock0 sudo mount -t yaffs2 /dev/mtdblock0 /mnt/mtd/yaffs2 #modprobe mtdram total_size=49152 erase_size=128 #cat rootfs.yaffs2 >/dev/mtdblock0 2.4.3 通过工具 释放 yaffs2 文件系统 yaffs2 image 逆向工具 http://blog.csdn.net/absurd/archive/2008/11/05/3223825.aspx 获取源代 码: http://www.limodev.cn/bbs/download/file.php?id=1 2.5 虚拟文件 系统( sysfs,proc,tsmpfs 等) 2.5.1 虚拟文件 系统概述 2.5.2 proc 文件系统 2.5.3 sysfs 文件系统 2.5.4 tmpfs 文件系统 2.5.5 usbdevfs 文件系统 2.5.6 devpts 文件系统 2.5.1 虚拟文件 系统概述 虚拟内核 文件系统( Virtual Kernel File Systems),是指 那些是由内核 产生但并不存 在于硬盘 上(存在 于内存中)的 文件系统, 他们被用 来与内核进行 通信前面介绍 的 ext2,ext3,jffs2,yaffs2 等目录和 文件,都是真 真正 正、实实 在在的存储在 具体的外部存 储设备上 的,它们可能 是在本机的硬 盘、闪存、光 盘中,可能保 存在不只一个 磁盘分区中, 也 可能保存 在网络中其它 主机的存储设 备中的。 虚拟文件 系统,虽然它 们出现在根文 件系统中,但 它里面的内容 却无法在任何 外部存储设备 中 找到,因 为它们都在内 存中。 ==== ====== android 网络挂载 : rootfs / rootfs rw 0 0 /dev/root / nfs rw,vers=2,rsize=1024,wsize=1024,... tmpfs /dev tmpfs rw,mode=755 0 0 devpts /dev/pts devpts rw,mode=600 0 0 proc /proc proc rw 0 0 sysfs /sys sysfs rw 0 0 tmpfs /sqlite_stmt_journals tmpfs rw,size=4096k 0 0 /dev/block/mmcblk0p1 /sdcard vfat rw,... ==== ====== = android 本机挂载 (使用 flash 中的文件 系统) rootfs / rootfs ro 0 0 tmpfs /dev tmpfs rw,mode=755 0 0 devpts /dev/pts devpts rw,mode=600 0 0 proc /proc proc rw 0 0 sysfs /sys sysfs rw 0 0 tmpfs /sqlite_stmt_journals tmpfs rw,size=4096k 0 0 /dev/block/mtdblock2 /system yaffs2 ro 0 0 /dev/block/mtdblock3 /data yaffs2 rw,nosuid,nodev 0 0 /dev/block/mmcblk0p1 /sdcard vfat rw ==== ====== === ubuntu 系统: /dev/sda8 on / type ext3 (rw,relatime,errors=remount-ro) tmpfs on /lib/init/rw type tmpfs (rw,nosuid,mode=0755) /proc on /proc type proc (rw,noexec,nosuid,nodev) sysfs on /sys type sysfs (rw,noexec,nosuid,nodev) varrun on /var/run type tmpfs (rw,nosuid,mode=0755) tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev) devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=620) /dev/sda7 on /boot type ext3 (rw,relatime) /dev/sda11 on /home type ext3 (rw,relatime) /dev/sdb5 on /opt type ext3 (rw,relatime) /dev/sda9 on /usr/local type ext3 (rw,relatime) /dev/sda1 on /windows/c type vfat (rw,utf8,umask=007,gid=1000) /dev/sda5 on /windows/d type vfat (rw,utf8,umask=007,gid=1000) /dev/sda6 on /windows/e type vfat (rw,utf8,umask=007,gid=1000) ==== ====== ===== 2.5.2 proc 文件系统 proc 是一个重 要虚拟文件系 统,通过它里 面的一些文件 ,可以获取系 统状态信息并 修改某些系 统的配置 信息。 proc 文件系统 本身不占用 磁盘空间 ,它仅存在于 内存之中,为 操作系统本身 和应用程序之 间的通信提供 了一个安全的 接 口。当我 们在内核中添 加了新功能或 设备驱 动时,经 常需要得到一 些系统状态的 信息,一般这 样的功能可能 需要经过一些 象 ioctl()这样的 系统调用 来完成。系统 调用接口对于 一些 功能性的 信息可能是适 合的,因为应 用程序必须将 这些信息读出 后再做一定的 处理。但对于 一 些实时性 的系统信息, 例如内存的使 用状况, 或者是驱 动设备的统计 资料等,我们 更需要一个比 较简单易用的 接口来取得它 们。 proc 文件系 统就是这 样的一个接口 ,我们可以简 单的用 cat、strings 程序来查 看这些信息。 例如,执行下 面的命令: cat /proc/filesystems //操作系统 支持的文件系 统类型 cat /proc/meminfo //内存的实 时信息,内存 大小等 cat /proc/partitions //存储器分 区信息 cat /proc/cpuinfo //查看 cpu 信息 同样的, free、df、top、ps 等程序的 功能实现,强 烈依赖于 proc 文件系统 ,为了使用那 些程 序,一定 要使内核支持 proc 文件系统 , 并将其挂 接到根文件系 统的 /proc 目录下。 其他使用 /proc 文件系统 的例子: processor : 0 vendor_id : AuthenticAMD processor : 1 vendor_id : AuthenticAMD model name :AMD Athlon(tm) 64 X2 Dual Core CPU 5000+ 1.vmware 虚拟机无 法正常启动 在Linux 下,单个 进程的最大内 存使用量受 /proc/sys/kernel/shmmax 中设置的 数字限制 (单位为 字节 ), 例如 ubuntu 8.10 的shmmax 默认值为 33554432 字节 (33554432bytes/1024/1024=32MB)。 2.scratchbox 开发工具 不能登录 /scratchbox/login Inconsistency detected by ld.so: rtld.c: 1192: dl_main: Assertion `(void *) ph->p_vaddr == _rtld_local._dl_sysinfo_dso' failed! NOTE: on Ubuntu installation, you have to disable VDSO to make Scratchbox work fine, or you'll get errors like this: 在ubuntu 系统中, 我们必须关闭 VDSO 标记,以 便 scratchbox 能正常工 作 echo 0 | sudo tee /proc/sys/vm/vdso_enabled echo 4096 | sudo tee /proc/sys/vm/mmap_min_addr vm.vdso_enabled = 0 vm.mmap_min_addr = 4096 修改 /proc 文件系统 值的方法 1.直接修 改 echo "2147483648" | sudo tee /proc/sys/kernel/shmmax echo 0 | sudo tee /proc/sys/vm/vdso_enabled echo 4096 | sudo tee /proc/sys/vm/mmap_min_addr 2.将以下命 令放入 /etc/rc.local 启动文件 中: echo "2147483648" > /proc/sys/kernel/shmmax echo 0 > /proc/sys/vm/vdso_enabled echo 4096 > /proc/sys/vm/mmap_min_addr 3.使用 sysctl 命令来更 改 SHMMAX 的值: sysctl -w kernel.shmmax=2147483648 4.内核参数 插入到 /etc/sysctl.conf 启动文件 中,使这种更 改永久有效 echo "kernel.shmmax=2147483648" >> /etc/sysctl.conf sudo sysctl –p ./system/core/logcat/logcat.cpp:403: fd = open("/proc/cmdline", O_RDONLY); ./system/core/init/init.c:553: char cmdline[1024]; ./system/core/init/init.c:557: fd = open("/proc/cmdline", O_RDONLY); ./system/core/init/init.c:580: chmod("/proc/cmdline", 0440); ./system/core/init/bootchart.c:139: proc_read("/proc/cmdline", cmdline, sizeof(cmdline)); ./system/core/init/bootchart.c:319: proc_read( "/proc/cmdline", cmdline, sizeof(cmdline) ); ./system/core/init/bootchart.c:320: s = strstr(cmdline, KERNEL_OPTION); ./system/core/rootdir/init.rc:162: chown root radio /proc/cmdline 2.5.3 sysfs 文件系统 与proc 文件系统 类似, sysfs 文件系统 也是一个不占 有任何磁盘空 间的虚拟文件 系 统。它通 常被挂接在 /sys 目录下。 sysfs 文件系统 是 Linux2.6 内核引入 的,它把连接 在系 统上的设 备和总线组织 成为一个分级 的文件,使得 它们可以在用 户空间存取。 其实 sysfs 是从 proc 和devfs 中划分出 来的。 一、 devfs linux 下有专门 的文件系统用 来对设备进行 管理, devfs 和sysfs 就是其中 两种。 在2.6 内核以前 一直使用的是 devfs,devfs 挂载于 /dev 目录下, 提供了一种类 似于文件的方 法 来管理位 于 /dev 目录下的 所有设备,我 们知道 /dev 目录下的 每一个文件都 对应的是一个 设备,至于当 前该设备存在 与否先且不论 ,而且这 些特殊文 件是位于根文 件系统上的, 在制作文件 系统的时 候我们就已经 建立了这些设 备文件,因此 通过操作这些 特殊文件,可 以实现与内核 进 行交互。 但是 devfs 文件系统 有一些缺点, 例如: 不确定的 设备映射,有 时一个设备映 射的设备文件 可能不同,例 如我的 U盘可能对 应 sda 有可 能对应 sdb;没有足 够的主 /辅设备号 ,当设备过多 的时候, 显然这会成为 一个问题; /dev 目录下文 件太多而且不 能表示当前系 统上的实际设 备; 命名不够 灵活,不能任 意指定等等。 二、 sysfs 正因为上 述这些问题的 存在,在 linux2.6 内核以后 ,引入了一个 新的文件系统 sysfs,它 挂载于 /sys 目录下, 跟 devfs 一样它也 是一个 虚拟文件 系统,也是用 来对系统的设 备进行管理的 ,它把实际连 接到系统上的 设备和总线组 织 成一个分 级的文件,用 户空间的程序 同样可以利用 这些信息 以实现和内核 的交互,该文 件系统是当前 系统上实际设 备树的一个直 观反应,它是 通 过kobject 子系统来 建立这个信息 的,当一个 kobject 被创建的 时候,对应的 文件和目录也 就被创建了, 位于 /sys 下的相关 目录下,既然 每个 设备在 sysfs 中都有唯 一对应的目录 ,那么也 就可以被 用户空间读写 了。用户空间 的工具 udev 就是利用 了 sysfs 提供的信 息来实现所 有 devfs 的功能的 ,但不同的是 udev 运行在用 户空间中, 而devfs 却运行在 内核空间,而 且 udev 不存在 devfs 那些先天 的缺陷。很显 然, sysfs 将是未 来发展的 方向。 2.5.4 tmpfs 文件系统 tmpfs 是Linux 特有的文 件系统,唯一 的标准挂接点 是 /dev/shm。当然, 用户可以将其 挂接在 其他地方 。 tmpfs 有些像虚 拟磁盘( ramdisk), 但不是一 回事。说其像 虚拟磁盘,是 因为它可以使 用你的 RAM,但它也 可以使用你的 交换分 区。传统 的虚拟磁盘是 一个块设备, 而且需要一个 mkfs 之类的命 令格式化它才 能使用。 tmpfs 是一个独 立的文件系统 ,不是块设备 ,只要挂接, 立即 就可以使 用。 tmpfs 的大下是 不确定的,它 最初只有 很小的空 间,但随着文 件的复制和创 建,它的大小 就会不断变化 ,换句话说, 它会根据你的 实 际需要而 改变大小; tmpfs 的速度非 常惊人,毕竟 它 是驻留在 RAM 中的,即 使用了交换分 区,性能仍然 非常卓越;由 于 tmpfs 是驻留在 RAM 的,因此 它的内容是不 持久的,断电 后, tmpfs 的内容就 消 失了,这 也是被称作 tmpfs 的根本原 因。 tmpfs 是ramfs 的衍生物 ,用来限制缓 存大小、向 swap 空间写入 数据。它是用 来保存 VM所 有文件的 文件系统。 tmpfs 中缓存的 内容全部是临 时的。一旦卸 载,所有的内 容都会遗失。 它把所有的缓 存置于内 核,它的 规模随着 文件的规 模同步变化。 但是它规模有 大小限制,可 以修改。它可 以把当前不再 需要的页写入 到 swap 空间。 tmpfs 和ramfs 本身就是 一个文件系统 , 用的时候 只需要直接挂 载就可以 . tmpfs 可以使用 ram, 也可以使 用 swap 共享内存 的时候会使用 tmpfs 系统默认 共享内存是内 存的一半大小 ! /dev/shm 是挂载点 ! 通过 df -h 可以看出 ,默认状况下 它为内存大小 的一半: 文件系统 容量 已用 可用 已用 % 挂载点 tmpfs 1013M 12K 1013M 1% /dev/shm mount | grep tmpfs 显示当前 系统中的 tmpfs: tmpfs on /lib/init/rw type tmpfs (rw,nosuid,mode=0755) varrun on /var/run type tmpfs (rw,nosuid,mode=0755) varlock on /var/lock type tmpfs (rw,noexec,nosuid,nodev,mode=1777) udev on /dev type tmpfs (rw,mode=0755) tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev) lrm on /lib/modules/2.6.27-4-generic/volatile type tmpfs (rw,mode=755) 2.5.6 usbdevfs 文件系统 顾名思义 , usbdevfs 就是 USB 设备文件 系统,它是一 个动态生成的 文件系统,有 些类似于 proc 文件系统 。它的标准挂 接点是 /proc/bus/usb,当然, 也可以挂接到 其他 地方。它 主要用于:用 户级驱动、即 插即用、提供 USB 设备信息 、应用程序轮 询 USB 设备的变 化等。 2.5.7 devpts 文件系统 devpts 文件系统 为伪终端提供 了一个标准接 口,它的标准 挂接点是 /dev/pts。只要 pty 的主复合 设备 /dev/ptmx 被打开, 就会在 /dev/pts 下动态的 创建一个新的 pty 设备文 件。挂接 时, UID、GID及其工作 模式会指定给 devpts 文件系统 的所有 pty 文件。这 可 以保证伪 终端的安全性 。 讨论 devpts 文件系统 的详细内容, 已经超过本文 范围,还请读 者参考其他专 著。 2.6 一些必要 重要的系统文 件 (/etc/fstab ,inittab,init.rc 等) 2.6.1 /etc/inittab 2.6.2 /etc/init.d/rcS 2.6.3 /etc/fstab 文件 ==== ====== ====== 2.6.1 /etc/inittab initab 被init 使用 2.6.1.1 老平台 inittab 文件内容 2.6.1.1 gpephone 官方的 inittab 文件(与 redhat,federo 差不多) 2.6.1.1 ubuntu 中没有 inittab 文件 ==== ====== ====== = 2.6.1.1 老平台 inittab 文件内容 ---- ------ ------ ------ ------ ------ ------ - ::sysinit:/etc/init.d/rcS ::respawn:-/bin/sh ::restart:/sbin/init ::ctrlaltdel:/sbin/reboot ::shutdown:/bin/umount -a -r ::shutdown:/sbin/swapoff -a ---- ------ ------ ------ ------ ------ ------ - 2.6.1.2 gpephone 官方的 inittab 文件(与 redhat,federo 差不多 ---- ------ ------ ------ ------ ------ ------ - #/etc/inittab: init(8) configuration. # $Id: inittab,v 1.91 2002/01/25 13:35:21 miquels Exp $ # The default runlevel. id:5:initdefault: # Boot-time system configuration/initialization script. # This is run first except when booting in emergency (-b) mode. si::sysinit:/etc/init.d/rcS # What to do in single-user mode. ~~:S:wait:/sbin/sulogin #/etc/init.d executes the S and K scripts upon change # of runlevel. # # Runlevel 0 is halt. # Runlevel 1 is single-user. # Runlevels 2-5 are multi-user. # Runlevel 6 is reboot. l0:0:wait:/etc/init.d/rc 0 l1:1:wait:/etc/init.d/rc 1 l2:2:wait:/etc/init.d/rc 2 l3:3:wait:/etc/init.d/rc 3 l4:4:wait:/etc/init.d/rc 4 l5:5:wait:/etc/init.d/rc 5 l6:6:wait:/etc/init.d/rc 6 # Normally not reached, but fallthrough in case of emergency. z6:6:respawn:/sbin/sulogin 1:2345:respawn:/sbin/getty 38400 tty1 ---- ------ ------ ------ ------ ------ ------ - -- 2.6.1.3 ubuntu 中没有 inittab 文件 在unbutu 系统中我 们没看到此文 件,是因为 ubuntu 用的是 upstart ,lfs 中使用的 是 sysvinit ,嵌入式 系统中 一般使用 的是 busybox 中的 init ,android 系统使用 的是 system/core/init init: main() init_main() read_inittab(); gdm 运行后 /etc/rc5.d/S30gdm -> ../init.d/gdm /etc/init.d/gdm:19:DAEMON=/usr/sbin/gdm /etc/init.d/gdm:24: SSD_ARG="--startas $DAEMON" /etc/init.d/gdm:27: SSD_ARG="--exec $DAEMON" 启动 gdm: log_begin_msg "Starting GNOME Display Manager..." start-stop-daemon --start --quiet --oknodo --pidfile $PIDFILE --name gdm $SSD_ARG -- $CONFIG_FILE >/dev/null ==== ====== ====== 2.6.2 /etc/init.d/rcS ---- ------ ------ --- #!/bin/sh 挂在 /etc/fstab 中的文件 系统 /bin/mount -a ./etc/default/rcS #环境变量 ./etc/profile #屏幕叫准 备 ./etc/X11/run-calibrate #启动 X ./etc/X11/Xserver ./etc/scripts/testd-bus.sh #启动 dbus 消息总线 #启动 gpephone ---- ------ ------ --- ubuntu 系统 ---- ------ ----- exec /etc/init.d/rc S ---- ------ ----- 会依此执 行 /etc/rcS.d/ 下以 S01mountkernfs.sh S02hostname.sh S10udev S11mountdevsubfs.sh S20checkroot.sh S22mtab.sh S30checkfs.sh S35mountall.sh S40networking S43portmap S55bootmisc.sh ./rc3.d/S30gdm ./rc2.d/S30gdm ./rc4.d/S30gdm ./rc5.d/S30gdm /etc/rcS.d/S35mountall.sh -> ../init.d/mountall.sh mount -a -t nonfs,nfs4,smbfs,cifs,ncp,ncpfs,coda,ocfs2,gfs,gfs2 -O no_netdev mount 命令的一 些解析: mount -a [-t|-O] ...: mount all stuff from /etc/fstab mount -t type dev dir : ordinary mount command ==== ====== ====== 2.6.3 /etc/fstab 文件 Util-linux 软件包包 含许多工具。 其中比较重要 的是加载、卸 载、格式化、 分区和管理硬 盘驱 动器,打 开 tty 端口和得 到内核消息 arch 报告机器 的体系结构 blockdev 在命令行 中调用块设备 的 ioctl cal 显示一个 简单的日历。 cfdisk 处理指定 设备的分区表 column 把输出格 式化为几列 ctrlaltdel 设置 CTRL+ALT+DEL 组合键的 功能为硬重启 或软重启 dmesg 显示内核 的启动信息 fdisk 磁盘分区 管理程序 fsck.cramfs 对Cramfs 文件系统 的一致性进行 检查 getopt 在给出的 命令行进行选 项和参数解析 hexdump 用用户指 定的方式 (包括 ASCII, 十进制 , 十六进制 , 八进制 )显示一个 文件或者标 准输入的 数据 hwclock 查询和设 置硬件时钟 (也被称为 RTC 或BIOS 时钟 )。 ipcrm 删除给定 的进程间通信 (IPC)资源 mkfs 在一个设 备 (通常是一 个硬盘分区 )设备上建 立文件系统 mkfs.cramfs 创建 cramfs 文件系统 mkswap 初始化指 定设备或文件 ,以用做交换 分区 more 分屏显示 文件,但没有 less 好用 mount 把一个文 件系统从一个 设备挂载到一 个目录 ramsize 显示或者 改变 RAM disk 的大小 raw 将一个原 始的 Linux 字符设备 绑定到一个块 设备 rdev 查询和设 置内核的根设 备和其他信息 readprofile 显示内核 侧写文件 /proc/profile 的信息 rename 对文件进 行重命名 renice 修改正在 运行进程的优 先级 sfdisk 磁盘分区 表管理工具 umount 卸载一个 被挂载的文件 系统 mount 挂载与 /etc/fstab mount 源目录 目的目录 mount -a 自动挂载 /etc/fstab 中的文件 系统 根目录 / 是必须挂 载的﹐而且一 定要先于其它 mount point 被挂载进 来。 其它 mount point 必须为已 建立的目录﹐ 可任意指定﹐ 但一定要 遵守必须的系 统目录架构原 则 所有 mount point 在同一时 间之内﹐只能 挂载一 次。 所有 partition 在同一时 间之内﹐ 只能挂载 一次。 如若进行 卸载﹐您必须 先将工作目录 移到 mount point(及其子目 录 ) 之 外。 /etc/fstab 第一列: label 第二列: 挂载点 第三列: 分区的文件系 统 第四列: 文件系统挂载 选项 ,看附件啦 第五列: 是否被 dump 作用。 0代表不要 做 dump 备份, 1代表要每 天进行 dump 的动作。 2 也代表其 它不定日期的 dump 备份动作 ,通常这个数 值不是 0就是 1啦! 第六列: 是否以 fsck 检查分区 (开机时候检 查分区) 0为不检查 , 1为开机的 时候检查, 2为 在稍后的 时间检查 /dev/sda8 on / type ext3 (rw,relatime,errors=remount-ro) /proc on /proc type proc (rw,noexec,nosuid,nodev) sysfs on /sys type sysfs (rw,noexec,nosuid,nodev) tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev) devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=620) /dev/sda7 on /boot type ext3 (rw,relatime) /dev/sda11 on /home type ext3 (rw,relatime) /dev/sdb5 on /opt type ext3 (rw,relatime) /dev/sda9 on /usr/local type ext3 (rw,relatime) /dev/sda1 on /windows/c type vfat (rw,utf8,umask=007,gid=1000) /dev/sda5 on /windows/d type vfat (rw,utf8,umask=007,gid=1000) /dev/sda6 on /windows/e type vfat (rw,utf8,umask=007,gid=1000) 可以在 /etc/fstab 中进行指 定 proc /proc proc defaults 0 0 none /tmp ramfs defaults 0 0 sysfs /sys sysfs defaults 0 0 none /dev/pts devpts defaults 0 0 ./util-linux-2.12r/mount/mount.c main() result = do_mount_all (types, options, test_opts); mount --help 可以知道 mount -a 是mount 所有 /etc/fstab mount -a [-t|-O] ...: mount all stuff from /etc/fstab ==== ====== ====== ====== 2.7 制作文件 系统 2.7.1 原始方式 2.7.2 通过 scratchbox 等工具 2.7.3 通过 android 源码集成 开发环境 2.7.1 原始方式 创建基本 文件系统标准 目录(根据不 同的 linux 系统, ubuntu 跟android 目录结构 就完全不同) lfs 中的标准 目录: 创建修改 必要的配置文 件 /scratchbox/source2/source/busybox/busybox-1.1.2/examples/bootfloppy/etc/ vim ${CLFS_ROOTFS_DIR}/etc/profile vim ${CLFS_ROOTFS_DIR}/etc/inittab vim ${CLFS_ROOTFS_DIR}/etc/fstab vim ${CLFS_ROOTFS_DIR}/etc/init.d/rcS 创建帐号 以及密码文件 sudo vim ${CLFS_ROOTFS_DIR}/passwd 拷贝必须 的动态库文件 cd ${CLFS_ROOTFS_DIR}/lib cp -d $COMPILER_LIB/ld* ./ cp $COMPILER_LIB/libc-2.3.5.so ./ cp -d $COMPILER_LIB/libc.so.6 ./ cp $COMPILER_LIB/libm-* ./ cp -d $COMPILER_LIB/libm.s* ./ cp $COMPILER_LIB/libcrypt-* ./ cp -d $COMPILER_LIB/libcrypt.s* ./ 拷贝可选 的动态库文件 如果需要 域名解析: 1)增加 /etc/resolv.conf [root@lqm /etc]#cat resolv.conf nameserver 192.168.x.x //加入域名 解析器 2)增加相 应动态库的支 持 增加如下 : libnss_files libnss_dns libresolv.so find find .-name "libnss*" $COMPILER_LIB/ ./libnss_files.so.2 ./libnss_files.so ./libnss_dns-2.3.2.so ./libnss_dns.so ./libnss_files-2.3.2.so ./libnss_dns.so.2 find .-name "libresolv*" /scratchbox/compilers/arm-linux-gcc-3.4.4-glibc-2.3.5/arm-unknown- linux-gnu/lib/ ./libresolv.so ./libresolv.so.2 ./libresolv-2.3.2.so 2.7.2 通过 scratchbox 等工具 ==== ====== ====== === 2.7.3 通过 android 源码集成 开发环境 环境搭建 问题: 1.为什么拷 贝 cupcake 编译结果 out/target/product/littleton/root/ 到内核顶 层目录 ? 2.cupcake-jianping/make_image15.sh 中的 choosecombo 是什么作 用? 3.make_image15.sh 与make_env15.sh 只差一句 make -j2? 4.补充 shell 脚本知识 。 ==== ====== ====== ===== 2.7.4 配置 android 网络文件 系统 下面是曾 经用过的几种 开发板的命令 行参数: S3C2410 启动参数 : noinitrd root=/dev/nfs nfsroot=192.168.2.56:/nfsroot/rootfs ip=192.168.2.188:192.168.2.56:192.168.2.56:255.255.255.0::eth0:on console=ttySAC0 S3C2440 启动参数 : setenv bootargs console=ttySAC0 root=/dev/nfs nfsroot=192.168.2.56:/nfsroot/rootfs ip=192.168.2.175:192.168.2.56:192.168.2.201:255.255.255.0::eth0:on mem=64M init=/init marvell 310 启动参数 : boot root=/dev/nfs nfsroot=192.168.2.56:/nfsroot/rootfs,rsize=1024,wsize=1024 ip=192.168.2.176:192.168.2.201:192.168.2.201:255.255.255.0::eth0:-On console=ttyS2,115200 mem=64M init=/init 当前 android 内核的 .config 文件中的 命令行参数: CONFIG_CMDLINE="root=/dev/nfs nfsroot=192.168.1.100:/nfsroot/rootfs,rsize=1024,wsize=1024 ip=192.168.1.101:192.168.1.100:192.168.1.100:255.255.255.0::usb0:on console=ttyS1,115200 mem=128M init=/init android uart_dma=1" `root=' 参数 此参数告 诉内核启动时 以那个设备作 为根文件系统 使用。我的 pc 根文件系 统: /dev/sda8 9614116 6522156 2603588 72% / ubuntu 的/boot/grub/menu.lst 参数: kernel /vmlinuz-2.6.27-4-generic root=UUID=2ffa7dc6-2dc5-4b66-8661-1226c086951a ro locale=zh_CN quiet splash initrd /initrd.img-2.6.27-4-generic 其中 root 可以设置 为: root=/dev/sda8 /dev/nfs, 这并非真 的是个设备, 而是一个 告诉核心经由 网络取得根文 件系统 lfs 的/boot/grub/menu.lst 参数: title LFS 6.4 root (hd1,1) kernel /boot/lfskernel-2.6.27.4 root=/dev/sdb1 `nfsroot=' 参数 这个参数 告诉内核到哪 台 pc 的哪个目 录读取根文件 系统。此参数 的格式如下: nfsroot=[:][,] --pc 机的 ip 地址,如 果此字段没给 值,那么将使 用由 nfsaddrs 变量(见 下面)所 决定的值 。 -- pc 服务端上 要作为根挂入 的目录域名 (/nfsroot/rootfs) -- 标准的网 络文件系统选 项。所有选项 都以逗号分开 。如果没有给 定此选项字段 则使用下 列的缺省值: port = as given by server portmap daemon rsize = 1024 wsize = 1024 timeo = 7 retrans = 3 acregmin = 3 acregmax = 60 acdirmin = 30 acdirmax = 60 flags = hard, nointr, noposix, cto, ac `init=' 参数 内核启动 时缺省执行 `init' 程序,内 核将会到 /sbin/, /bin/ 等目录下 查找默认的 init,如果没 有 找到那么 就报告出错。 而最后它 会去试 /bin/sh (可能在 /etc/rc )。如果 说,例如,如 果你的 init 程序坏掉 了,只 要使用 init=/bin/sh 这个启动 参数就能让你 在启动时直接 跳到解译环境 (shell),使你能 够换掉坏掉的 程序。 `ip=' 参数 nfsaddrs=:::::: ip=192.168.1.101:192.168.1.100:192.168.1.100:255.255.255.0::usb0:on ip=192.168.2.175:192.168.2.56:192.168.2.201:255.255.255.0::eth0:on -- 板子的 ip 使用何种 协议端视配置 核心时打开的 选项以及 参数而定 。如果 设定此参 数,就不会使 用反向地址解 析协议或启动 协议。 -- 网络文件 系统服务端之 互联网地址。 -- 网关 (gateway), -- 本地网络 界面的网络掩 码。如果为空 白,则网络掩 码由客户端的 互联网地址导 出,除非 由启动协议接 收到值。 -- 客户端的 域名。如果空 白,则使用客 户端互联网地 址之 ASCII-标记法, 或由启动 协议接收 的值。 -- 要使用的 网络设备域名 。 -- 用以作为 自动配置的方 法。 参考文档 : ramfs, rootfs, initrd and initramfs http://blog.chinaunix.net/u2/89923/showart_1890405.html 嵌入式系 统文件系统比 较 http://blog.sina.com.cn/s/blog_53ad41a50100eptc.html LINUX 系统性能 调谐 http://www.host01.com/article/server/00070002/0621409052193755_2.htm 怎样限制 或者修改 /dev/shm 的大小 http://www.linuxfly.cn/html/65/t-665.html ==== ====== ====== ====== ====== ====== ====== = ==== ====== ====== ====== ===== ==== ====== ====== ====== ====== ====== ====== = ==== ====== ====== ====== ===== 3. 制作交叉 工具链 3.1 什么是工 具链 3.2 获取交叉 工具链的几种 途径 3.3 android 工具链与 gnu 工具链的 比较 每一个软 件,在编译的 过程中,都要 经过一系列的 处理,才能从 源代码变成可 执行的 目标代码 。这一系列处 理包括:预编 译,高级语言 编译, 汇编,连 接及重定位。 这一套流程里 面用到的每个 工具和相关的 库组成的集合 ,就称为工具 链 (tool chain)。以 GNU 的开发工 具 GCC 为例, 它就包括 了预编译器 cpp,c编译器 gcc,汇编器 as,和连接 器 ld 等。在 GNU 自己对工 具链定 义中,还 加进了一套额 外的用于处理 二进制包的 工具包 binutils,整个工 具链应该是 GCC+binutils+Glibc,binutils 其实与 Glibc 关系不是 很 大,它可 以被独立安装 的,所以 GNU 工具 链也可以 狭义地被理解 为 GCC+Glibc。 要构建出 一个交叉工具 链,需要解决 三个问题。一 是这个工具链 必须是可以运 行在原工作站 平 台上的。 二是我们需要 更换一个与目 标平台对应的 汇编器, 使得工具链能 产生对应的目 标代码,三是 要更换一套与 目标平台对应 的二进制库, 使 得工具链 在连接时能找 到正确的二进 制库。 3.2 获取交叉 工具链的几种 途径 3.2.1 利用源代 码制作交叉工 具链 网上直接 下载工具链或 者从方案商处 获取 (如: marvell) 下载地址 : http://www.angstrom-distribution.org/unstable/ 3.2.2 用脚本制 作工具链 3.2.2.1 croostool-0.43 http://www.kegel.com/crosstool/crosstool-0.43.tar.gz 制作工具 链的源码包搭 配情况 : http://www.kegel.com/crosstool/crosstool-0.43/buildlogs/ 3.2.2.2 buildroot http://buildroot.uclibc.org/downloads/snapshots/buildroot-snapshot.tar.bz2 若想详细 地了解 buildroot 可参考该 文档 http://buildroot.uclibc.org/buildroot.html 3.2.3 利用 OE制作工具 链 http://www.scratchbox.org/wiki/OpenEmbedded 3.3 android 工具链与 gnu 工具链的 比较 Android 所用的 Toolchain(即交叉 编译工具链) 可从下面的网 址下载: http://android.kernel.org/pub/android-toolchain-20081019.tar.bz2。如果下 载了完整的 Android 项目 的源代码 ,则可以在 “/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin”目录下找 到交叉编译工 具,比 如 Android 所用的 arm-eabi-gcc-4.2.1。Android 并没有采 用 glibc 作为 C库,而是 采用了 Google 自己开发 的 Bionic Libc,它的官 方 Toolchain 也是基于 Bionic Libc 而并非 glibc 的。这使 得使用或移植 其他 Toolchain 来用于 Android 要比较麻 烦: 在 Google 公布用于 Android 的官方 Toolchain 之前, 多数的 Android 爱好者使 用的 Toolchain 是在 http://www.codesourcery.com/gnu_toolchains/arm/download.html 下载的一 个通用的 Toolchain,它用来 编译和移植 Android 的Linux 内核是可 行的,因为内 核并不需要 C库,但 是开发 Android 的应用程 序时,直接采 用或者移植其 他 的Toolchain 都比较麻 烦,其他 Toolchain 编译的应 用程序只能采 用静态编译的 方式才能运行 于 Android 模拟器中 ,这显然是实 际开发中所不 能接 受的方式 。目前尚没有 看到说明成功 移植其他交叉 编译器来编译 Android 应用程序 的资料。 与glibc 相比, Bionic Libc 有如下一 些特点: - 采用 BSD License,而不是 glibc 的GPL License; - 大小只有 大约 200k,比 glibc 差不多小 一半,且比 glibc 更快; - 实现了一 个更小、更快 的 pthread; - 提供了一 些 Android 所需要的 重要函数,如 ”getprop”,“LOGI”等; - 不完全支 持 POSIX 标准,比 如 C++ exceptions,wide chars 等; - 不提供 libthread_db 和libm 的实现 另外, Android 中所用的 其他一些二进 制工具也比较 特殊: - 加载动态 库时使用的是 /system/bin/linker 而不是常 用的 /lib/ld.so; - prelink 工具不是 常用的 prelink 而是 apriori,其源代 码位于 ” /build/tools/apriori” - strip 工具也没 有采用常用的 strip,即 “/prebuilt/linux- x86/toolchain/arm-eabi-4.2.1/bin” 目录下的 arm-eabi-strip,而是位 于 /out/host/linux-x86/bin/的soslim 工具。 参考文档 : CLFS2.0 原理分析 http://www.linuxsir.org/bbs/showthread.php?t=267672 Cross-Compiled Linux From Scratch http://cross-lfs.org/view/clfs-sysroot/arm/ 全手工制 作 arm-linux 交叉编译 工具链《一》 http://blog.chinaunix.net/u2/62168/showart_1898748.html 自己制作 arm-linux 交叉编译 环境 (一)-scratch 篇 http://blog.csdn.net/chenzhixin/archive/2007/01/12/1481442.aspx 如何建立 交叉编译工具 链 http://www.decell.org/article.asp?id=53 Android Toolchain 与Bionic Libc http://www.top-e.org/jiaoshi/html/?151.html ndroid 编译环境 (2) - 手工编译 C模块 ==== ====== ====== ====== ====== ====== ====== = ==== ==== ==== ====== ====== ====== ====== ====== ====== = ==== ==== 4. 软件编译 常识 4.1 链接器和 加载器 4.2 android 的标准链 接器和加载器 4.3 Makefile 基本语法 何为链接 器和加载器? 链接器为 ld,加载为 ld-linux.so.2,两个的区 别很大,一个 编译时用 ,一个运行 时用 ,ld 负责在编 译 的搜索路 径里找到要求 的库 ,并查看 是否有提 供了需要的 符号 (如函数等 ),如果有 ,记录相关 信息到程序中 ,由ld-linux.so.2 在执行时 查找到该 库 ,并根据相 关信息进行需 要符号的 重定位等工作 .注意 这两者的 搜索库的方式 是不同的。 动态连接 器通常是指的 动态加载器 (不要与 Binutils 里的标准 连接器 ld 混淆了 )。动态连 接器 由Glibc 提供,用 来 找到并加 载一个程序运 行时所需的共 享库,在做好 程序运行的准 备之后,运行 这个程序。动 态 连接器的 名称通常是 ld-linux.so.2,标准连 接器 ld 由Binutils 这个包提 供。 标准连接 器 查看 gcc 使用的标 准连接器 mhf@mhf-desktop:/usr/local/marvell-arm-linux-4.1.1/bin$ arm-linux-gcc -print-prog-name=ld 编译时库 的搜索路径 ,以下几种 方式让连接器 去找需要的库 1. 编译的时 候明确指定, 如: gcc test.c ./say.so -o test 中的 ./say.so 2. 编译 Binutils 的时候通 过 LIB_PATH 变量指定 , 如: make -C ld LIB_PATH=/tools/lib -C ld LIB_PATH=/tools/lib 这个选项 重新编译 ld 子目录中 的所有文件。 在命令行中指 定 Makefile 的LIB_PATH 变量 值,使它 明确指向 /tools/lib 工具目录 , 以覆盖默 认值。这个变 量的值指定了 连接器的默认 库搜索路径。 来源: Linux From Scratch - 版本 6.4 第5 章构建临时 系统 5.4. Binutils-2.18 - 第一遍 http://www.bitctp.org/lfsbook-6.4/chapter05/binutils-pass1.html 3. 在源码包 configure 的时候通 过 --with-lib-path 指定,或 者 --lib- path 例如: binutils-2.18/configure --prefix=/tools --disable-nls --with-lib-path=/tools/lib 配置选项 的含义: --with-lib-path=/tools/lib 告诉配置 脚本在为编译 Binutils 的过程中 使用正确的库 搜索路径,也 就是将 /tools/lib 传 递给连接 器。这防止连 接器搜索宿主 系统中的库文 件目录。 来源: Linux From Scratch - 版本 6.4 第5 章构建临时 系统 lfs 5.13. Binutils-2.18 - 第二遍 http://www.bitctp.org/lfsbook-6.4/chapter05/binutils-pass2.html 4. 到ld –verbose | grep SEARCH 列出的默 认目录下去找 5. -L/usr/gpephone/lib 指定的目 录找 经常以 LDFLAGS=" -L/usr/gpephone/lib -L/lib -L/usr/lib -L/usr/X11R7/lib" 的方式传 入 参数 -rpath 与-rpath-link 如果使用 了 '-rpath'选项 , 那运行时 搜索路径就只 从 '-rpath'选项中得 到 'nodefaultlib'标志一个 对象 ,使在搜索 本对象所依赖 的库时 ,忽略所有 缺省库搜索路 径 . LDFLAGS="-Wl,-rpath-link=/usr/gpephone/lib/:/usr/gphone/lib:/usr/local/lib -L/usr/gpephone/lib -L/usr/gphone/lib" -rpath 与-rpath-link 的特性: 1. 在编译的 时候我们都可 以使用这两个 路径, 2. '-rpath'跟'-rpath_link'的不同之 处在于 ,由'-rpath'指定的路 径会被包含到 可执行程序中 ,并在运 行时使用 , 而'-rpath-link'选项仅仅 在链接时起作 用。 -dumpspecs Display all of the built in spec strings -dumpversion Display the version of the compiler -dumpmachine Display the compiler's target processor -print-search-dirs Display the directories in the compiler's search path -print-prog-name= Display the full path to compiler component -specs= Override built-in specs with the contents of -Wa, Pass comma-separated on to the assembler -Wp, Pass comma-separated on to the preprocessor -Wl, Pass comma-separated on to the linker 从工具链 内建的规范中 查看动态加载 器 gcc -dumpspecs | grep dynamic-linker //本机 查看编译 起所指定的动 态加载器 1. s3c2440 (arm9tdmi) 平台的工 具链 /scratchbox/compilers/arm-9tdmi-softfloat-linux-gcc-3.4.4-glibc-2.3.5/bin/arm-softfloat-linux-gnu-gcc -dumpspecs | grep dynamic-linker /scratchbox/compilers/arm-softfloat-linux-gcc-3.4.4-glibc-2.3.5/bin/arm-softfloat-linux-gnu-gcc - dumpspecs | grep dynamic-linker 2. marvell 的工具链 /scratchbox/compilers/marvell-arm-linux-4.1.1/bin/arm-linux-gcc -dumpspecs | grep dynamic- linker 3. scrathbox 中工具链 host-gcc /scratchbox/compilers/host-gcc/bin/host-gcc -dumpspecs | grep dynamic-linker 如果我们 在编译的时候 给编译起 gcc 指定 -specs=/scratchbox/compilers/host-gcc/host- gcc.spec ,那么 -specs 指定 的规范将 会覆盖工具链 内建的规范。 cat /scratchbox/compilers/host-gcc/host-gcc.specs | grep ld 有如下内 容: -dynamic-linker /scratchbox/host_shared/lib/ld.so /scratchbox/compilers/host-gcc/bin/gcc -specs=/scratchbox/compilers/host-gcc/host-gcc.specs mhf@mhf-desktop:/usr/local/marvell-arm-linux-4.1.1/arm-iwmmxt-linux-gnueabi/bin$ ./gcc - dumpspecs|grep dynamic-linker gcc -dumpspecs | sed 's@/lib/ld-linux.so.2@/tools&@g' | sudo tee `dirname $(gcc -print-libgcc- file-name)`/specs cat `dirname $(gcc -print-libgcc-file-name)`/specs | grep tools 查看本机 应用程序使用 的动态加载器 readelf -l /usr/bin/make | grep interpreter [Requesting program interpreter: /lib/ld-linux.so.2] 查看 scratchbox 中应用程 序使用的动态 加载器 readelf -l /scratchbox/tools/bin/make | grep interpreter [Requesting program interpreter: /scratchbox/host_shared/lib/ld.so] cd ~/svn/mohuifu.svn/trunk/mysource/compiler_test /scratchbox/compilers/host-gcc/bin/gcc -specs=/scratchbox/compilers/host-gcc/host-gcc.specs -o ld.so.test1 ld.so.test.c /scratchbox/compilers/host-gcc/bin/gcc -o ld.so.test2 ld.so.test.c readelf -l ./ld.so.test1 | grep interpreter readelf -l ./ld.so.test2 | grep interpreter 其他示例 : readelf -l /scratchbox/tools/bin/make | grep interpreter readelf -l /usr/bin/make | grep interpreter 分别显示 : [Requesting program interpreter: /scratchbox/host_shared/lib/ld.so] [Requesting program interpreter: /lib/ld-linux.so.2] 下面的方 式也可以查看 应用程序所使 用的加载器 strings /scratchbox/tools/bin/make |grep lib strings /usr/bin/make |grep lib 分别为: /scratchbox/host_shared/lib/ld.so /lib/ld-linux.so.2 查看应程 序加载器库的 搜索路径 显示 scratchbox 中加载器 的库搜索路径 strings /scratchbox/host_shared/lib/ld.so |grep lib display library search paths /scratchbox/host_shared/lib/ /scratchbox/tools/lib/ 显示本机 中加载器的库 搜索路径 strings /lib/ld-linux.so.2 |grep lib display library search paths /lib/ /usr/lib/ /lib/i486-linux-gnu/ /usr/lib/i486-linux-gnu/ ldd 验证应用 程序所使用动 态库 ldd /scratchbox/tools/bin/make libc.so.6 => /scratchbox/host_shared/lib/libc.so.6 (0xb7ef9000) /scratchbox/host_shared/lib/ld.so => /scratchbox/host_shared/lib/ld.so (0xb802f000) ldd /usr/bin/make librt.so.1 => /lib/tls/i686/cmov/librt.so.1 (0xb7fb9000) libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7e5b000) libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0xb7e42000) /lib/ld-linux.so.2 (0xb7fd5000) 参考文档 : 交叉编译 中 libtool 相关的问 题 http://hi.baidu.com/lieyu063/blog/item/9c99a2dd23e41f365882dd39.html 静态库和 共享库库的定 位搜索路径 http://blog.csdn.net/lwhsyit/archive/2008/08/26/2830783.aspx Linux 动态连接 原理 http://blog.chinaunix.net/u2/67984/showart_1359874.html 程序编译 链接运行时对 库关系的探讨 (原创) http://www.360doc.com/content/061107/09/13188_251964.html http://lamp.linux.gov.cn/Linux/LFS-6.2/chapter05/toolchaintechnotes.html [Linux 命令 ] ld 中文使用 手册完全版 (译) http://blog.csdn.net/rstevens/archive/2008/01/28/2070568.aspx scratchbox 是mameo (nokia) 提供的一 个集成开发环 境,可以去官 方网站: http://www.scratchbox.org/ http://www.scratchbox.org/download/ 4.2 android 的标准链 接器和加载器 android 的标准链 接器 ./prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi-ld android 中标准连 接器搜索库的 路径 ./prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi-ld -verbose | grep SEARCH SEARCH_DIR("/android/mathias/armdev/toolchain-eabi-4.2.1/arm-eabi/lib"); Android 编译环境 所用的交叉编 译工具链是 ./prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm- eabi-gcc, -I 和-L 参数指定 了所用的 C库头文件 和动态库文件 路径分别是 bionic/libc /include 和 out/target/product/generic/obj/lib, 其他还包 括很多编译选 项以及 -D 所定义的 预编译宏。这 里值得留意的 是参数 “-Wl,-dynamic- linker,/system/bin/linker”,它指定 了 Android 专用的动 态链接器 /system/bin/linker,而不是 通常所用的 ld.so。 上面的 “make clean-$(LOCAL_MODULE)”是Android 编译环境 提供的 make clean 的方式。 android 中应用程 序使用的加载 器 strings out/target/product/littleton/obj/EXECUTABLES/rild_intermediates/rild | grep link /system/bin/linker ./prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi-gcc -dumpspecs|grep dynamic-linker %{mbig-endian:-EB} %{mlittle-endian:-EL} %{static:-Bstatic} %{shared:-shared} %{symbolic:- Bsymbolic} %{!static:%{shared: -Bsymbolic} %{!shared:%{rdynamic:-export-dynamic} %{!dynamic-linker:- dynamic-linker /system/bin/linker}}} -X android 中加载器 搜索库的路径 strings /nfsroot/rootfs/system/bin/linker | grep lib /system/lib /lib 生成的可 执行程序可用 file 和readelf 命令来查 看一下: file out/target/product/littleton/obj/EXECUTABLES/rild_intermediates/rild out/target/product/littleton/obj/EXECUTABLES/rild_intermediates/rild: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped readelf -d out/target/product/littleton/obj/EXECUTABLES/rild_intermediates/rild |grep NEEDED 0x00000001 (NEEDED) Shared library: [liblog.so] 0x00000001 (NEEDED) Shared library: [libcutils.so] 0x00000001 (NEEDED) Shared library: [libril.so] 0x00000001 (NEEDED) Shared library: [libc.so] 0x00000001 (NEEDED) Shared library: [libstdc++.so] 0x00000001 (NEEDED) Shared library: [libm.so] 0x00000001 (NEEDED) Shared library: [libdl.so] 这是 ARM 格式的动 态链接可执行 文件,运行时 需要 libc.so 和libm.so。“not stripped”表示它还 没被 STRIP。嵌入式 系统中为节省 空间通常 将编译完 成的可执行文 件或动态库进 行 STRIP,即去掉 其中多余的符 号表信息。在 前面 “make helloworld showcommands”命令的最 后我们也 可以看到 , Android 编译环境 中使用了 out/host/linux-x86/bin/soslim 工具进行 STRIP。 4.3 Makefile 基本语法 Makefile 详解(超 级好) linux/Unix 环境下的 make 和makefile 详解 http://www.unlinux.com/doc/program/20051026/2365.html 跟我一起 写 Makefile http://dev.csdn.net/develop/article/20/20025.shtm ==== ====== ====== ====== ====== ====== ====== = ==== ==== ==== ====== ====== ====== ====== ====== ====== = ==== ==== 5. 设置模块 流程分析 rild 流程分析 5.1 设置 pin 状态, pin 认证 5.1.1 设置 pin 状态 5.1.2 修改 sim 卡pin 5.1.3 pin 认证流程 5.2 网络设置 5.3 屏幕背光 设置 5.4 获取,显 示电池状态 ==== ====== ====== EditPinPreference.java (packages\apps\settings\src\com\android\settings) private OnPinEnteredListener mPinListener; protected void onDialogClosed(boolean positiveResult) mPinListener.onPinEntered(this, positiveResult); 执行 SimLockSettings.java (packages\apps\settings\src\com\android\settings)中函数: public void onPinEntered(EditPinPreference preference, boolean positiveResult) 修改 pin 状态: tryChangeSimLockState(); 修改 pin: tryChangePin(); 5.1.1 设置 pin 状态 private void tryChangeSimLockState() Message callback = Message.obtain(mHandler, ENABLE_SIM_PIN_COMPLETE); mPhone.getSimCard().setSimLockEnabled(mToState, mPin, callback); 进入 sim lock 菜单会显 示初始化 pin 状态,是 通过下面语句 得到: mPinToggle.setChecked(mPhone.getSimCard().getSimLockEnabled()); mPhone.getSimCard().setSimLockEnabled(mToState, mPin, callback)调用的是 文件: GsmSimCard.java (frameworks\base\telephony\java\com\android\internal\telephony\gsm)中的函数 : public void setSimLockEnabled (boolean enabled,String password, Message onComplete) { int serviceClassX; serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + CommandsInterface.SERVICE_CLASS_DATA + CommandsInterface.SERVICE_CLASS_FAX; mDesiredPinLocked = enabled; phone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_SIM, enabled, password, serviceClassX, obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete)); phone.mCM.setFacilityLock 调用的是 文件: RIL.java (frameworks\base\telephony\java\com\android\internal\telephony\gsm)中的函数 : public void setFacilityLock (String facility, boolean lockState, String password, int serviceClass, Message response) { String lockString; RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_FACILITY_LOCK, response); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); // count strings rr.mp.writeInt(4); rr.mp.writeString(facility); lockString = (lockState)?"1":"0"; rr.mp.writeString(lockString); rr.mp.writeString(password); rr.mp.writeString(Integer.toString(serviceClass)); send(rr); } 设置应用 程序向 rild 发送 RIL_REQUEST_SET_FACILITY_LOCK 请求的 socket 消息, android 的初始源 代码中 RIL_REQUEST_SET_FACILITY_LOCK 请求,在 参考实现 Reference-ril.c (hardware\ril\reference-ril) 中没有实 现。 我们需要 做得工作是: ==== ====== 5.1.2 修改 sim 卡pin private void tryChangePin() mPhone.getSimCard().changeSimLockPassword(mOldPin,mNewPin, callback); mPhone.getSimCard 调用的是 文件: GsmSimCard.java (frameworks\base\telephony\java\com\android\internal\telephony\gsm)中的函数 : public void changeSimLockPassword(String oldPassword, String newPassword, Message onComplete) phone.mCM.changeSimPin(oldPassword, newPassword, obtainMessage(EVENT_CHANGE_SIM_PASSWORD_DONE, onComplete)); phone.mCM.changeSimPin 调用的是 文件: RIL.java (frameworks\base\telephony\java\com\android\internal\telephony\gsm)中的函数 : public void changeSimPin(String oldPin, String newPin, Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_CHANGE_SIM_PIN, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); rr.mp.writeInt(2); rr.mp.writeString(oldPin); rr.mp.writeString(newPin); send(rr); } rild 端处理流 程: 5.1.3 pin 认证流程 ==== ==== 5.2 网络设置 ==== === 5.3 屏幕背光 设置 packages/apps/Settings/src/com/android/settings/BrightnessPreference.java 背光设置 滚动条和关闭 按钮都会调用 setBrightness(mOldBrightness); public void onProgressChanged(SeekBar seekBar, int progress,boolean fromTouch) protected void onDialogClosed(boolean positiveResult) private void setBrightness(int brightness) { try { IHardwareService hardware = IHardwareService.Stub.asInterface( ServiceManager.getService("hardware")); if (hardware != null) { hardware.setBacklights(brightness); } } catch (RemoteException doe) { } } 调用硬件 服务器 HardwareService 的setBacklights 函数 HardwareService.java (frameworks\base\services\java\com\android\server): public void setBacklights(int brightness) { ... // Don't let applications turn the screen all the way off brightness = Math.max(brightness, Power.BRIGHTNESS_DIM); setLightBrightness_UNCHECKED(LIGHT_ID_BACKLIGHT, brightness); setLightBrightness_UNCHECKED(LIGHT_ID_KEYBOARD, brightness); setLightBrightness_UNCHECKED(LIGHT_ID_BUTTONS, brightness); ... } void setLightOff_UNCHECKED(int light) { //本地调用 setLight_native setLight_native(mNativePointer, light, 0, LIGHT_FLASH_NONE, 0, 0); } void setLightBrightness_UNCHECKED(int light, int brightness) { int b = brightness & 0x000000ff; b = 0xff000000 | (b << 16) | (b << 8) | b; setLight_native(mNativePointer, light, b, LIGHT_FLASH_NONE, 0, 0); } 因为有: com_android_server_HardwareService.cpp (frameworks\base\services\jni): static JNINativeMethod method_table[] = { {"init_native", "()I",(void*)init_native }, {"finalize_native", "(I)V",(void*)init_native }, {"setLight_native", "(IIIIII)V",(void*)setLight_native }, {"vibratorOn", "(J)V",(void*)vibratorOn }, {"vibratorOff", "()V",(void*)vibratorOff } }; 所以最终 调用的是文件 : com_android_server_HardwareService.cpp (frameworks\base\services\jni)中的函数 : static void setLight_native(JNIEnv *env, jobject clazz, int ptr, int light, int colorARGB, int flashMode, int onMS, int offMS) { Devices* devices = (Devices*)ptr; light_state_t state; if (light < 0 || light >= LIGHT_COUNT || devices->lights[light] == NULL){ return ; } memset(&state, 0, sizeof(light_state_t)); state.color = colorARGB; state.flashMode = flashMode; state.flashOnMS = onMS; state.flashOffMS = offMS; devices->lights[light]->set_light(devices->lights[light], &state); } Lights.h (hardware\libhardware\include\hardware):#define LIGHTS_HARDWARE_MODULE_ID "lights" com_android_server_HardwareService.cpp (frameworks\base\services\jni) err = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module); static const char *variant_keys[] = { "ro.hardware", /* This goes first so that it can pick up a different file on the emulator. */ "ro.product.board", "ro.board.platform", "ro.arch" }; int hw_get_module(const char *id, const struct hw_module_t **module) status = load(id, prop, &hmi); status = load(id, HAL_DEFAULT_VARIANT,&hmi); static int load(const char *id, const char *variant,const struct hw_module_t **pHmi) snprintf(path, sizeof(path), "%s/%s.%s.so", HAL_LIBRARY_PATH, id, variant); #define HAL_DEFAULT_VARIANT"default" #define HAL_LIBRARY_PATH"/system/lib/hw" 所以 path 等于: /system/lib/hw/light.marvell.so /system/lib/hw/light.default.so 我们编译 的 light 模块放在 /system/lib/hw/light.default.so 所以初始 化成功。 property_get(variant_keys[i], prop, NULL) 只有 ro.hardware 存在 [ro.hardware]: [marvell] static int lights_device_open(const struct hw_module_t* module, const char* name,struct hw_device_t** device) dev->set_light = set_light_backlight; static struct hw_module_methods_t lights_module_methods = { open: lights_device_open }; hardware/libhardware/modules/lights/Android.mk LOCAL_MODULE:= lights.default err = module->methods->open(module, name, &device); 执行的是 :lights_device_open const char * const brightness_file = "/sys/class/backlight/micco-bl/brightness"; static int set_light_backlight(struct light_device_t* dev, struct light_state_t const* state) { ... color = state->color; tmp = ((77*((color>>16)&0x00ff)) + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8; brightness = tmp/16; LOGD("---->calling %s(),line=%d state- >color=%d,brightness=%d\n",__FUNCTION__,__LINE__,state->color,brightness); len = sprintf(buf,"%d",brightness); len = write(fd, buf, len); ... } 上面的函 数完成了与内 核的交互 综上所述 ,程序调用流 程如下,上层 应用通过 /sys/class/leds/lcd-backlight/brightnes 于内核打 交道 设置模块 -> 硬件服务 器 -> 本地调用 ->功能库 -> 读写 /sys/class/leds/lcd- backlight/brightness 函数与内 核交互 Init.rc (vendor\marvell\littleton): chown system system /sys/class/leds/keyboard- backlight/brightness Init.rc (vendor\marvell\littleton): chown system system /sys/class/leds/lcd-backlight/brightness Init.rc (vendor\marvell\littleton): chown system system /sys/class/leds/button-backlight/brightness 5.4 获取,显 示电池状态 电池状态 (正在充电( AC)): Status.java String statusString; mBatteryStatus.setSummary(statusString); public static final int BATTERY_STATUS_UNKNOWN = 1; public static final int BATTERY_STATUS_CHARGING = 2; public static final int BATTERY_STATUS_DISCHARGING = 3; public static final int BATTERY_STATUS_NOT_CHARGING = 4; public static final int BATTERY_STATUS_FULL = 5; // values for "health" field in the ACTION_BATTERY_CHANGED Intent public static final int BATTERY_HEALTH_UNKNOWN = 1; public static final int BATTERY_HEALTH_GOOD = 2; public static final int BATTERY_HEALTH_OVERHEAT = 3; public static final int BATTERY_HEALTH_DEAD = 4; public static final int BATTERY_HEALTH_OVER_VOLTAGE = 5; public static final int BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6; public static final int BATTERY_PLUGGED_AC = 1; 电源充电 public static final int BATTERY_PLUGGED_USB = 2; USB 充电 BatteryInfo.java (packages\apps\settings\src\com\android\settings) 电池级别 ( 50%) BatteryService.java (frameworks\base\services\java\com\android\server) 电池服务 器: 构造函数 : public BatteryService(Context context) mUEventObserver.startObserving("SUBSYSTEM=power_supply"); ---- ------ UEventObserver.java (frameworks\base\core\java\android\os) void startObserving(String match) ensureThreadStarted(); sThread = new UEventThread(); sThread.start(); sThread.addObserver(match, this); ---- ------ - update() native_update(); sendIntent(); private final void sendIntent() Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); ... intent.putExtra("status", mBatteryStatus); intent.putExtra("health", mBatteryHealth); intent.putExtra("present", mBatteryPresent); intent.putExtra("level", mBatteryLevel); intent.putExtra("scale", BATTERY_SCALE); intent.putExtra("icon-small", icon); intent.putExtra("plugged", mPlugType); intent.putExtra("voltage", mBatteryVoltage); intent.putExtra("temperature", mBatteryTemperature); intent.putExtra("technology", mBatteryTechnology); ActivityManagerNative.broadcastStickyIntent(intent, null); 把读取的 电池信息通过 广播信息发送 给所有的应用 程序。 native_update 本地调用 的是文件 com_android_server_BatteryService.cpp (frameworks\base\services\jni) 中的函数 : static void android_server_BatteryService_update(JNIEnv* env, jobject obj) { setBooleanField(env, obj, AC_ONLINE_PATH, gFieldIds.mAcOnline); setBooleanField(env, obj, USB_ONLINE_PATH, gFieldIds.mUsbOnline); setBooleanField(env, obj, BATTERY_PRESENT_PATH, gFieldIds.mBatteryPresent); setIntField(env, obj, BATTERY_CAPACITY_PATH, gFieldIds.mBatteryLevel); setIntField(env, obj, BATTERY_VOLTAGE_PATH, gFieldIds.mBatteryVoltage); setIntField(env, obj, BATTERY_TEMPERATURE_PATH, gFieldIds.mBatteryTemperature); const int SIZE = 128; char buf[SIZE]; if (readFromFile(BATTERY_STATUS_PATH, buf, SIZE) > 0) env->SetIntField(obj, gFieldIds.mBatteryStatus, getBatteryStatus(buf)); if (readFromFile(BATTERY_HEALTH_PATH, buf, SIZE) > 0) env->SetIntField(obj, gFieldIds.mBatteryHealth, getBatteryHealth(buf)); if (readFromFile(BATTERY_TECHNOLOGY_PATH, buf, SIZE) > 0) env->SetObjectField(obj, gFieldIds.mBatteryTechnology, env->NewStringUTF(buf)); } #define AC_ONLINE_PATH"/sys/class/power_supply/ac/online" #define USB_ONLINE_PATH"/sys/class/power_supply/usb/online" #define BATTERY_STATUS_PATH"/sys/class/power_supply/battery/status" #define BATTERY_HEALTH_PATH"/sys/class/power_supply/battery/health" #define BATTERY_PRESENT_PATH"/sys/class/power_supply/battery/present" #define BATTERY_CAPACITY_PATH"/sys/class/power_supply/battery/capacity" #define BATTERY_VOLTAGE_PATH"/sys/class/power_supply/battery/batt_vol" #define BATTERY_TEMPERATURE_PATH"/sys/class/power_supply/battery/batt_temp" #define BATTERY_TECHNOLOGY_PATH"/sys/class/power_supply/battery/technology" ==== ====== ====== ====== ====== ====== ====== = ==== ==== ==== ====== ====== ====== ====== ====== ====== = ==== ==== 6. linux 系统启动 流程分析 6.1 桌面操作 系统启动流程 ( redhat,federa,ubuntu) 6.2 小型嵌入 式系统启动流 程 6.3 android 系统启动 流程 ==== ====== ==== 6.1 桌面操作 系统启动流程 ( redhat,federa,ubuntu) ubuntu 从6.10 开始逐步 用 upstart 代替原来 的 sysinit,进行服 务进程的管理 。为了对原有 的 init 实现向后 兼容, 目前 ubuntu 中与 init 相关的几 个目录和应用 程序,可以方 便后面的论述 。这些目录和 程序包 括: init telinit //字面理解 tell init runlevel /etc/event.d/ /etc/init.d/ /etc/rcX.d/ 首先是 /etc/event.d/目录,这 是 upstart 的核心, upstart 不同于原 有的 init 的地方就 在于它引入 了 event 机制。 Event 机制通俗 的 讲就是将 所有进程的触 发、停止等等 都看作 event(事件 )。/etc/event.d/中就存放 了目前 upstart 需要识别 的 event。这其中 主要有三种 rc-default, rcX(x=0,1,...6,S)以及 ttyX。这 rc-default 就类似于 inittab 文件,它 就是设置默认 运行 级别的 ,需要运 行程序的 脚本,而 ttyX 则是设置 伪终端数目的 ,也就是你 Ctrl+Alt+F(1~6)调出的那 个 Console。我们 以 rc2 为例, cat rc2: rc-default start on stopped rcS telinit 2 所以会依 次执行 /etc/event.d/rcS /etc/event.d/rc2 它们又会 分别执行: exec /etc/init.d/rc S exec /etc/init.d/rc 2 这样,我 们就可以自然 地过渡到下一 个重要的目录 , /etc/init.d/了。 /etc/init.d/中存放的 是服务 (services)或者任务 (tasks)的执行脚 本。可以这么 说,只要你安 装了一 个程序 (特别是服 务程序 daemon), 它可以在 系统启动的时 候运行,那么 它必定会在 /etc/init.d/中有一个 脚本文件。 执行了一 个 exec /etc/init.d/rc 2的命令。 也就是说,给 /etc/init.d/rc 脚本传递 了一个参数 "2",让 它执行。 rc 脚本 (很长,耐 心点 ),能看到 这样的一段: # Now run the START scripts for this runlevel. # Run all scripts with the same level in parallel ....... for s in /etc/rc$runlevel.d/S* ....... 将会开始 执行 /etc/rc2.d/下S开头的脚 本。这就过渡 到下一个目录 /etc/rc2.d/了。 /etc/rc2.d 都是一些 到 /etc/init.d/中脚本的 符号链接。不 同的是在开头 加上了 S和一个数 字, S 表示在启 动时运行,数 字则表示执行 的先后顺序。 /etc/rcS.d/S35mountall.sh K08vmware S19vmware S20nfs-common S20nfs-kernel-server S20samba S20xinetd S30gdm S98usplash S99rc.local 总结: 这样一来 , upstart 管理的 ubuntu 启动过程 应该就清楚了 。梳理一下: 1,内核启动 init 2,init 找到 /etc/event.d/rc-default 文件,确 定默认的运行 级别 (X) 3,触发相应 的 runlevel 事件,开 始运行 /etc/event.d/rcX 4,rcX 运行 /etc/init.d/rc,传入参 数 X 5,/etc/init.d/rc 脚本进行 一系列设置, 最后运行相应 的 /etc/rcX.d/中的脚本 6,/etc/rcX.d/中的脚本 按事先设定的 优先级依次启 动,直至最后 给出登录画面 (启动 X服务 器和 GDM) 理解了这 些,手动配置 开机服务的启 动与否就很简 单了。 Ubutnu 默认的启 动级别是 2,不 想启动的 程序,只要把 相应的符号链 接从 /etc/rc2.d/中删去即 可 注意: 想redat ,federa 这些系统 ,他们用的是 sysvinit ,有 /etc/inittab 文件,里 面定义了 : id:5:initdefault: si::sysinit:/etc/init.d/rcS init 直接解析 id:5:initdefault 字段,然 后执行 /etc/rc5.d/ 下面的脚 本 ==== ====== ====== 参考文档 : linux 教程 :upstart 和ubuntu 启动过程 原理介绍 http://www.zhiweinet.com/jiaocheng/2009-06/12500.htm 6.2 小型嵌入 式系统启动流 程 小型嵌入 式的 init 通常使用 busybox 中自带的 , 6.3 android 系统启动 流程 参考文档 : init 是内核进 入文件系统后 第一个运行的 程序,我们可 以在 linux 的命令行 中进行指定, 如果 没指定, 内核将会到 /sbin/, /bin/ 等目录下 查找默认 的 init,如果没 有找到那么就 报告出错。 init 源代码分 析 init 的mian 函数在文 件: ./system/core/init/init.c 中, init 会一步步 完成下面的任 务: 1.初始化 log 系统 2.解析 /init.rc 和/init.%hardware%.rc 文件 3. 执行 early-init action in the two files parsed in step 2. 4. 设备初始 化,例如:在 /dev 下面创建 所有设备节点 ,下载 firmwares. 5. 初始化属 性服务器, Actually the property system is working as a share memory. Logically it looks like a registry under Windows system. 6. 执行 init action in the two files parsed in step 2. 7. 开启 属性服务 。 8. 执行 early-boot and boot actions in the two files parsed in step 2. 9. 执行 Execute property action in the two files parsed in step 2. 10. 进入一个 无限循环 to wait for device/property set/child process exit events.例如 ,如果 SD 卡被 插入, init 会收到一 个设备插入事 件, 它会为这 个设备创建节 点。系统中比 较重要的进程 都是由 init 来fork 的,所以 如果他们他谁 崩 溃了,那 么 init 将会收到 一个 SIGCHLD 信号,把 这个信号转化 为子进程 退出事件, 所以在 loop 中, init 会操作进 程退出事件并 且执行 *.rc 文件中定 义的命 令。 例如,在 init.rc 中,因为 有: service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server socket zygote stream 666 onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on 所以,如 果 zygote 因为启动 某些服务导致 异常退出后, init 将会重新 去启动它。 int main(int argc, char **argv) { ... //需要在后 面的程序中看 打印信息的话 ,需要屏蔽 open_devnull_stdio()函数 open_devnull_stdio(); ... //初始化 log 系统 log_init(); //解析 /init.rc 和/init.%hardware%.rc 文件 parse_config_file("/init.rc"); ... snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware); parse_config_file(tmp); ... //执行 early-init action in the two files parsed in step 2. action_for_each_trigger("early-init", action_add_queue_tail); drain_action_queue(); ... /* execute all the boot actions to get us started */ /* 执行 init action in the two files parsed in step 2 */ action_for_each_trigger("init", action_add_queue_tail); drain_action_queue(); ... /* 执行 early-boot and boot actions in the two files parsed in step 2 */ action_for_each_trigger("early-boot", action_add_queue_tail); action_for_each_trigger("boot", action_add_queue_tail); drain_action_queue(); /* run all property triggers based on current state of the properties */ queue_all_property_triggers(); drain_action_queue(); /* enable property triggers */ property_triggers_enabled = 1; ... for(;;) { int nr, timeout = -1; ... drain_action_queue(); restart_processes(); if (process_needs_restart) { timeout = (process_needs_restart - gettime()) * 1000; if (timeout < 0) timeout = 0; } ... nr = poll(ufds, 3, timeout); if (nr <= 0) continue; if (ufds[2].revents == POLLIN){ /* we got a SIGCHLD- reap and restart as needed */ read(signal_recv_fd, tmp, sizeof(tmp)); while (!wait_for_one_process(0)) ; continue; } if (ufds[0].revents == POLLIN) handle_device_fd(device_fd); if (ufds[1].revents == POLLIN) { handle_property_set_fd(property_set_fd); } } return 0; } 解析 init.rc 脚本 init.rc 脚本的具 体语法可以参 考下面文档 http://www.kandroid.org/android_pdk/bring_up.html init.rc 脚本语法 Android 初始化語 言由四大类声 明组成:行为 类 (Actions),命令类 (Commands),服务类 (Services), 选项类 (Options). 初始化语 言以行为单位 ,由以空格间 隔的语言符号 組成。 C风格的反 斜杠转义符可 以用来插入 空白到语 言符号。双引 号也可以用来 防止 文本被空 格分成多个语 言符号。当反 斜杠在行末时 ,作为换行符 。 * 以#开始 (前面允许 空格 )的行为注 释。 * Actions 和Services 隐含声明 一个新的段落 。所有该段落 下 Commands 或Options 的声明属 于 该段落。 第一段落前的 Commands 或Options 被忽略。 * Actions 和Services 拥有唯一 的命名。在他 们之后声明相 同命名的类将 被当作错误并 忽略。 Actions 是一系列 命令的命名。 Actions 拥有一个 触发器 (trigger)用来決定 action 何時执行 。当一 个action 在符合触 发条件被执行 时, 如果它还 没被加入到待 执行队列中的 话,則加入到 队列最后。 队列中的 action 依次执行 , action 中的命令 也依次执行。 Init 在执行命 令的中间处理 其他活动 (设备创建 /销毁 ,property 设置,进 程重启 )。 Actions 的表现形 式 : on 重要的数 据结构 两个列表 ,一个队列。 static list_declare(service_list); static list_declare(action_list); static list_declare(action_queue); *.rc 脚本中所 有 service 关键字定 义的服务将会 添加到 service_list 列表中。 *.rc 脚本中所 有 on 关键开头 的项将会被会 添加到 action_list 列表中。 每个 action 列表项都 有一个列表, 此列表用来保 存该段落下的 Commands 脚本解析 过程 parse_config_file("/init.rc") int parse_config_file(const char *fn) { char *data; data = read_file(fn, 0); if (!data) return -1; parse_config(fn, data); DUMP(); return 0; } static void parse_config(const char *fn, char *s) { ... case T_NEWLINE: if (nargs) { int kw = lookup_keyword(args[0]); if (kw_is(kw, SECTION)){ state.parse_line(&state, 0, 0); parse_new_section(&state, kw, nargs, args); } else { state.parse_line(&state, nargs, args); } nargs = 0; } ... } parse_config 会逐行对 脚本进行解析 ,如果关键字 类型为 SECTION,那么将 会执行 parse_new_section() 类型为 SECTION 的关键字 有: on 和sevice 关键字类 型定义在 Parser.c (system\core\init) 文件中 Parser.c (system\core\init) #define SECTION 0x01 #define COMMAND 0x02 #define OPTION 0x04 关键字 属性 capability, OPTION, 0, 0) class, OPTION, 0, 0) class_start, COMMAND, 1, do_class_start) class_stop, COMMAND, 1, do_class_stop) console, OPTION, 0, 0) critical, OPTION, 0, 0) disabled, OPTION, 0, 0) domainname, COMMAND, 1, do_domainname) exec, COMMAND, 1, do_exec) export, COMMAND, 2, do_export) group, OPTION, 0, 0) hostname, COMMAND, 1, do_hostname) ifup, COMMAND, 1, do_ifup) insmod, COMMAND, 1, do_insmod) import, COMMAND, 1, do_import) keycodes, OPTION, 0, 0) mkdir, COMMAND, 1, do_mkdir) mount, COMMAND, 3, do_mount) on, SECTION, 0, 0) oneshot, OPTION, 0, 0) onrestart, OPTION, 0, 0) restart, COMMAND, 1, do_restart) service, SECTION, 0, 0) setenv, OPTION, 2, 0) setkey, COMMAND, 0, do_setkey) setprop, COMMAND, 2, do_setprop) setrlimit, COMMAND, 3, do_setrlimit) socket, OPTION, 0, 0) start, COMMAND, 1, do_start) stop, COMMAND, 1, do_stop) trigger, COMMAND, 1, do_trigger) symlink, COMMAND, 1, do_symlink) sysclktz, COMMAND, 1, do_sysclktz) user, OPTION, 0, 0) write, COMMAND, 2, do_write) chown, COMMAND, 2, do_chown) chmod, COMMAND, 2, do_chmod) loglevel, COMMAND, 1, do_loglevel) device, COMMAND, 4, do_device) parse_new_section()中再分别 对 service 或者 on 关键字开 头的内容进行 解析。 ... case K_service: state->context = parse_service(state, nargs, args); if (state->context) { state->parse_line = parse_line_service; return; } break; case K_on: state->context = parse_action(state, nargs, args); if (state->context) { state->parse_line = parse_line_action; return; } break; } ... 对on 关键字开 头的内容进行 解析 static void *parse_action(struct parse_state *state, int nargs, char **args) { ... act = calloc(1, sizeof(*act)); act->name = args[1]; list_init(&act->commands); list_add_tail(&action_list, &act->alist); ... } 对service 关键字开 头的内容进行 解析 static void *parse_service(struct parse_state *state, int nargs, char **args) { struct service *svc; if (nargs < 3) { parse_error(state, "services must have a name and a program\n"); return 0; } if (!valid_name(args[1])) { parse_error(state, "invalid service name '%s'\n", args[1]); return 0; } //如果服务 已经存在 service_list 列表中将 会被忽略 svc = service_find_by_name(args[1]); if (svc) { parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]); return 0; } nargs -= 2; svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs); if (!svc) { parse_error(state, "out of memory\n"); return 0; } svc->name = args[1]; svc->classname = "default"; memcpy(svc->args, args + 2, sizeof(char*) * nargs); svc->args[nargs] = 0; svc->nargs = nargs; svc->onrestart.name = "onrestart"; list_init(&svc->onrestart.commands); //添加该服 务到 service_list 列表 list_add_tail(&service_list, &svc->slist); return svc; } 服务的表 现形式 : service [ ]*
还剩70页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 8 金币 [ 分享pdf获得金币 ] 2 人已下载

下载pdf

pdf贡献者

安卓安安

贡献于2012-06-19

下载需要 8 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf