android linux 基礎知識總結

===================================================
linux ,Android基礎知識總結
1. Android編譯系統分析
2. 文件系統分析
3. 製作交叉工具鏈
4. 軟件編譯常識
5. 設置模塊流程分析
6. linux系統啓動流程分析
7. linux下svn使用指南
8. LFS 相關
9. linux 內核的初步理解
====================================================
================
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 listsvn://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 ABSOLUTELY NO WARRANTY; read the GNU GPL for details.
This is free software, and you are welcome to redistribute it
under certain conditions; read the GNU GPL 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 OCAL_MODULE:= sh
./system/core/libcutils/Android.mk:71 OCAL_MODULE := libcutils
./system/core/cpio/Android.mk:9 OCAL_MODULE := mkbootfs
./system/core/mkbootimg/Android.mk:8 OCAL_MODULE := mkbootimg
./system/core/toolbox/Android.mk:61 OCAL_MODULE:= toolbox
./system/core/logcat/Android.mk:10 OCAL_MODULE:= logcat
./system/core/adb/Android.mk:65 OCAL_MODULE := adb
./system/core/adb/Android.mk:125 OCAL_MODULE := adbd
./system/core/init/Android.mk:20 OCAL_MODULE:= init
./system/core/vold/Android.mk:24 OCAL_MODULE:= vold
./system/core/mountd/Android.mk:13 OCAL_MODULE:= mountd
LOCAL_PACKAGE_NAME
Java 應用程序的名字用該變量定義
./packages/apps/Music/Android.mk:9 OCAL_PACKAGE_NAME := Music
./packages/apps/Browser/Android.mk:14 OCAL_PACKAGE_NAME := Browser
./packages/apps/Settings/Android.mk:8 OCAL_PACKAGE_NAME := Settings
./packages/apps/Stk/Android.mk:10 OCAL_PACKAGE_NAME := Stk
./packages/apps/Contacts/Android.mk:10 OCAL_PACKAGE_NAME := Contacts
./packages/apps/Mms/Android.mk:8 OCAL_PACKAGE_NAME := Mms
./packages/apps/Camera/Android.mk:8 OCAL_PACKAGE_NAME := Camera
./packages/apps/Phone/Android.mk:11 OCAL_PACKAGE_NAME := Phone
./packages/apps/VoiceDialer/Android.mk:8 OCAL_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 /
        $/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 RODUCT_NAME := littleton
vendor/marvell/littleton/littleton.mk:28 RODUCT_DEVICE := littleton
vendor/marvell/littleton/AndroidProducts.mk:13:    $(LOCAL_DIR)/littleton.mk
vendor/sample/products/sample_addon.mk:40 RODUCT_NAME := sample_addon
vendor/htc/dream-open/htc_dream.mk:6 RODUCT_NAME := htc_dream
./vendor/htc/dream-open/htc_dream.mk:7 RODUCT_DEVICE := dream-open
./vendor/htc/dream-open/AndroidProducts.mk:3:    $(LOCAL_DIR)/htc_dream.mk
build/target/product/generic.mk:26 RODUCT_NAME := generic
build/target/product/generic_with_google.mk:20 RODUCT_NAME := generic_with_google
build/target/product/min_dev.mk:6 RODUCT_NAME := min_dev
build/target/product/core.mk:2 RODUCT_NAME :=
build/target/product/sim.mk:7 RODUCT_NAME := sim
build/target/product/sdk.mk:37 RODUCT_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
lunchgeneric-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 OCAL_CFLAGS += -mabi=aapcs-linux
./vendor/marvell/external/alsa/alsa-tools/Mdroid.mk:8 OCAL_CFLAGS += -mabi=aapcs-linux
./vendor/marvell/littleton/libaudio/Mdroid.mk:22 OCAL_CPPFLAGS += -mabi=aapcs-linux
./external/wpa_supplicant/Android.mk:35 _CFLAGS += -mabi=aapcs-linux
./system/wlan/ti/sta_dk_4_0_4_32/CUDK/tiwlan_loader/Android.mk:88 OCAL_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 /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/ptsdevpts 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/rwtype 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/sda7on /boot type ext3 (rw,relatime)
/dev/sda11 on /home type ext3 (rw,relatime)
/dev/sdb5on /opt type ext3 (rw,relatime)
/dev/sda9on /usr/local type ext3 (rw,relatime)
/dev/sda1on /windows/c type vfat (rw,utf8,umask=007,gid=1000)
/dev/sda5on /windows/d type vfat (rw,utf8,umask=007,gid=1000)
/dev/sda6on /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 12K1013M 1%  /dev/shm
mount | grep tmpfs 顯示當前系統中的 tmpfs:
tmpfs on /lib/init/rw type tmpfs (rw,nosuid,mode=0755)
varrunon /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 AEMON=/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/nfsnfsroot=192.168.2.56:/nfsroot/rootfs
ip=192.168.2.188:192.168.2.56:192.168.2.56:255.255.255.0::eth0 n 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 n 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 n
console=ttyS1,115200 mem=128M init=/init android uart_dma=1"
`root=' 參數
此參數告訴內核啓動時以那個設備作爲根文件系統使用。我的pc根文件系統:
/dev/sda8    9614116 6522156 260358872% /
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 n
ip=192.168.2.175:192.168.2.56:192.168.2.201:255.255.255.0::eth0 n
-- 板子的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-separatedon to the assembler
-Wp,    Pass comma-separatedon to the preprocessor
-Wl,    Pass comma-separatedon to the linker
從工具鏈內建的規範中查看動態加載器
gcc -dumpspecs | grepdynamic-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 | grepdynamic-linker
/scratchbox/compilers/arm-softfloat-linux-gcc-3.4.4-glibc-2.3.5/bin/arm-softfloat-linux-gnu-gcc -dumpspecs | grepdynamic-linker
2. marvell 的工具鏈
/scratchbox/compilers/marvell-arm-linux-4.1.1/bin/arm-linux-gcc-dumpspecs | grepdynamic-linker
3. scrathbox 中工具鏈 host-gcc
/scratchbox/compilers/host-gcc/bin/host-gcc-dumpspecs | grepdynamic-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中應用程序使用的加載器
stringsout/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 = CommandsInte**ce.SERVICE_CLASS_VOICE +
      CommandsInte**ce.SERVICE_CLASS_DATA +
      CommandsInte**ce.SERVICE_CLASS_FAX;
mDesiredPinLocked = enabled;
phone.mCM.setFacilityLock(CommandsInte**ce.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.asInte**ce(
      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 = 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, 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 intset_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



重要的數據結構
兩個列表,一個隊列。
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 OPTION0x04
關鍵字  屬性   
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 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 []*
...
申請一個service結構體,然後掛接到service_list鏈表上,name 爲服務的名稱 pathname 爲執行的命令 argument
爲命令的參數。之後的 option 用來控制這個service結構體的屬性,parse_line_service 會對 service關鍵字後的
內容進行解析並填充到 service 結構中 ,當遇到下一個service或者on關鍵字的時候此service選項解析結束。
例如:
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
服務名稱爲:         zygote
啓動該服務執行的命令:     /system/bin/app_process
命令的參數:         -Xzygote /system/bin --zygote --start-system-server
socket zygote stream 666: 創建一個名爲:/dev/socket/zygote 的 socket ,類型爲:stream
當*.rc 文件解析完成以後:
action_list 列表項目如下:
on init
on boot
on property:ro.kernel.qemu=1
on property:persist.service.adb.enable=1
on property:persist.service.adb.enable=0
init.marvell.rc 文件
on early-init
on init
on early-boot
on boot
service_list 列表中的項有:
service console
service adbd
service servicemanager
service mountd
service debuggerd
service ril-daemon
service zygote
service media
service bootsound
service dbus
service hcid
service hfag
service hsag
service installd
service flash_recovery
設備初始化
early-init 初始化
初始化屬性服務器
在init.c 的main函數中啓動狀態服務器。
property_set_fd = start_property_service();
狀態讀取函數:
Property_service.c (system/core/init)
const char* property_get(const char *name)
Properties.c (system/core/libcutils)
int property_get(const char *key, char *value, const char *default_value)
狀態設置函數:
Property_service.c (system/core/init)
int property_set(const char *name, const char *value)
Properties.c (system/core/libcutils)
int property_set(const char *key, const char *value)
在終端模式下我們可以通過執行命令 setprop
setprop 工具源代碼所在文件: Setprop.c (system/core/toolbox)
Getprop.c (system/core/toolbox):  property_get(argv[1], value, default_value);
Property_service.c (system/core/init)
中定義的狀態讀取和設置函數僅供init進程調用,
handle_property_set_fd(property_set_fd);
property_set() //Property_service.c (system/core/init)
  property_changed(name, value) //Init.c (system/core/init)
  queue_property_triggers(name, value)
  drain_action_queue()
只要屬性一改變就會被觸發,然後執行相應的命令:
例如:
在init.rc 文件中有
on property:persist.service.adb.enable=1
start adbd
on property:persist.service.adb.enable=0
stop adbd
所以如果在終端下輸入:
setprop property:persist.service.adb.enable 1或者0
那麼將會開啓或者關閉adbd 程序。
執行action_list 中的命令:
從action_list 中取出 act->name 爲 early-init 的列表項,再調用 action_add_queue_tail(act)將其插入到
隊列 action_queue 尾部。drain_action_queue() 從action_list隊列中取出隊列項 ,然後執行act->commands
列表中的所有命令。
所以從./system/core/init/init.c mian()函數的程序片段:
action_for_each_trigger("early-init", action_add_queue_tail);
drain_action_queue();
action_for_each_trigger("init", action_add_queue_tail);
drain_action_queue();
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();
可以看出,在解析完init.rc init.marvell.rc 文件後,action 命令執行順序爲:
執行act->name 爲 early-init,act->commands列表中的所有命令
執行act->name 爲 init,    act->commands列表中的所有命令
執行act->name 爲 early-boot,act->commands列表中的所有命令
執行act->name 爲 boot,    act->commands列表中的所有命令
關鍵的幾個命令:
class_start default 啓動所有service 關鍵字定義的服務。
class_start 在act->name爲boot的 act->commands列表中,所以當 class_start 被觸發後,實際
上調用的是函數 do_class_start()
int do_class_start(int nargs, char **args)
{
  /* Starting a class does not start services
   * which are explicitly disabled.They must
   * be started individually.
   */
  service_for_each_class(args[1], service_start_if_not_disabled);
  return 0;
}
void service_for_each_class(const char *classname,
          void (*func)(struct service *svc))
{
  struct listnode *node;
  struct service *svc;
  list_for_each(node, &service_list) {
  svc = node_to_item(node, struct service, slist);
  if (!strcmp(svc->classname, classname)) {
    func(svc);
  }
  }
}
因爲在調用 parse_service() 添加服務列表的時候,所有服務 svc->classname 默認取值:"default",
所以 service_list 中的所有服務將會被執行。
參考文檔:
http://blog.chinaunix.net/u1/38994/showart_1775465.html
http://blog.chinaunix.net/u1/38994/showart_1168440.html
淺析kernel啓動的第1個用戶進程init如何解讀init.rc腳本
http://blog.chinaunix.net/u1/38994/showart_1168440.html
Zygote 服務概論:
Zygote 是android 系統中最重要的一個服務,它將一步一步完成下面的任務:
start Android Java Runtime and start system server. It’s the most important service. The source is in device/servers/app.
1. 創建JAVA 虛擬機
2. 爲JAVA 虛擬機註冊android 本地函數
3. 調用 com.android.internal.os.ZygoteInit 類中的main函數,android/com/android/internal/os/ZygoteInit.java.
a) 裝載ZygoteInit類
b) 註冊zygote socket
c) 裝載preload classes(the default file is device/java/android/preloaded-classes)
d) 裝載Load preload 資源
e) 調用 Zygote::forkSystemServer (定義在./dalvik/vm/InternalNative.c)來fork一個新的進程,在新進程中調用
com.android.server.SystemServer 的main函數。
a) 裝載 libandroid_servers.so庫
bb) 調用JNI native init1 函數 (device/libs/android_servers/com_android_server_SystemServers)
Load libandroid_servers.so
Call JNI native init1 function implemented in device/libs/android_servers/com_android_server_SystemServers.
It only calls system_init implemented in device/servers/system/library/system_init.cpp.
If running on simulator, instantiate AudioFlinger, MediaPlayerService and CameraService here.
Call init2 function in JAVA class named com.android.server.SystemServer, whose source is in
device/java/services/com/android/server. This function is very critical for Android because it start all of
Android JAVA services.
If not running on simulator, call IPCThreadState::self()->joinThreadPool() to enter into service dispatcher.
SystemServer::init2 將會啓動一個新的線程來啓動下面的所有JAVA服務:
Core 服務:
1.Starting Power Manager(電源管理)
2.Creating Activity Manager(活動服務)
3.Starting Telephony Registry(電話註冊服務)
4.Starting Package Manager(包管理器)
5.Set Activity Manager Service as System Process
6.Starting Context Manager
7.Starting System Context Providers
8.Starting Battery Service(電池服務)
9.Starting Alarm Manager(鬧鐘服務)
10. Starting Sensor Service
11. Starting Window Manager(啓動窗口管理器)
12. Starting Bluetooth Service(藍牙服務)
13. Starting Mount Service
其他services:
1.Starting Status Bar Service(狀態服務)
2.Starting Hardware Service(硬件服務)
3.Starting NetStat Service(網絡狀態服務)
4.Starting Connectivity Service
5.Starting Notification Manager
6.Starting DeviceStorageMonitor Service
7.Starting Location Manager
8.Starting Search Service(查詢服務)
9.Starting Clipboard Service
10. Starting Checkin Service
11. Starting Wallpaper Service
12. Starting Audio Service
13. Starting HeadsetObserver
14. Starting AdbSettingsObserver
最後SystemServer::init2 將會調用 ActivityManagerService.systemReady 通過發送
Intent.CATEGORY_HOME intent來啓動第一個 activity.還有另外一種啓動system server的方法是:
通過名爲 system_server的程序(源代碼:device/servers/system/system_main.cpp)它也是通過
調用 system_init 來啓動 system services,這時候就有個問題:爲什麼android 有兩種方式啓動system services?
我的猜想是:
My guess is that directly start system_server may have synchronous problem with zygote because
system_server will call JNI to start SystemServer::init2, while at that time zygote may not start
JAVA VM yet. So Android uses another method. After zynote is initialized, fork a new process to
start system services.
Zygote服務啓動的詳細過程:
通過啓動服務列表的 app_process 進程,實際上進入的是
App_main.cpp (frameworks/base/cmds/app_process)
main()
根據 init.rc 中的 --zygote --start-system-server
分別調用的是
runtime.start("com.android.internal.os.ZygoteInit",startSystemServer);
或者
runtime.start();
start()函數在 AndroidRuntime.cpp (frameworks/base/core/jni)文件中
從打印信息:
D/AndroidRuntime( 56): >>>>>>>>>>>>>> AndroidRuntime START GetStaticMethodID(startClass, "main","([Ljava/lang/String;)V");
從上面的調用可以看出一類引用的過程都是從 main方法
所以接着調用了 ZygoteInit 類的main方法
main方法主要完成:
1.Register zygote socket, Registers a server socket for zygote command connections
2.Load preload classes(the default file is device/java/android/preloaded-classes).
3.Load preload resources, Load in commonly used resources, so they can be shared across processes.
4.Start SystemServer, Prepare the arguments and fork for the system server process.
具體執行過程如下:
ZygoteInit.java (frameworks/base/core/java/com/android/internal/os)中的mian
main()
registerZygoteSocket()
preloadClasses()
  loadLibrary()
  Log.i(TAG, " reloading classes...");
  Runtime.loadLibrary
  Dalvik_java_lang_Runtime_nativeLoad()
  dvmLoadNativeCode()
    LOGD("Trying to load lib %s %p/n", pathName, classLoader);
    System.loadLibrary("media_jni");
preloadResources();
startSystemServer()
  Zygote.forkSystemServer(parsedArgs.uid, parsedArgs.gid,parsedArgs.gids, debugFlags, null);
  //Zygote.java (dalvik/libcore/dalvik/src/main/java/dalvik/system)
  forkSystemServer()
  forkAndSpecialize() //Zygote.java (dalvik/libcore/dalvik/src/main/java/dalvik/system)
    Dalvik_dalvik_system_Zygote_forkAndSpecialize() //dalvik_system_Zygote.c (dalvik/vm/native)
    Dalvik_dalvik_system_Zygote_forkAndSpecialize()
    setSignalHandler()
    fork()
  handleSystemServerProcess() //handleChildProc(parsedArgs, descriptors, newStderr);
  closeServerSocket();
  RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
  zygoteInit()   //RuntimeInit.java (frameworks/base/core/java/com/android/internal/os)
    zygoteInitNative()
    invokeStaticMain()
    System.loadLibrary("android_servers");
    //com.android.server.SystemServer startSystemServer() 函數中
    m = cl.getMethod("main", new Class[] { String[].class });
      //執行的是SystemServer 類的main函數 SystemServer.java (frameworks/base/services/java/com/android/server)
      init1() //SystemServer.java (frameworks/base/services/java/com/android/server)     
      //init1()實際上是調用android_server_SystemServer_init1(JNIEnv* env, jobject clazz)
      //com_android_server_SystemServer.cpp (frameworks/base/services/jni)
      android_server_SystemServer_init1()//JNI 調用
      system_init() //System_init.cpp (frameworks/base/cmds/system_server/library)
      // Start the Su**ceFlinger
      Su**ceFlinger::instantiate();
      //Start the AudioFlinger media playbackcamera service
        AudioFlinger::instantiate();
        MediaPlayerService::instantiate();
        CameraService::instantiate();
        //調用 SystemServer 類的init2
        runtime->callStatic("com/android/server/SystemServer", "init2");
        init2()//SystemServer.java (frameworks/base/services/java/com/android/server)
        ServerThread()
        run()//在run中啓動電源管理,藍牙,等核心服務以及狀態,查找等其他服務
         ((ActivityManagerService)ServiceManager.getService("activity")).setWindowManager(wm);
         ...
         ActivityManagerNative.getDefault().systemReady();   
runSelectLoopMode();
  done = peers.get(index).runOnce();
  forkAndSpecialize() //Zygote.java (dalvik/libcore/dalvik/src/main/java/dalvik/system)
  Dalvik_dalvik_system_Zygote_forkAndSpecialize() //dalvik_system_Zygote.c (dalvik/vm/native)
    forkAndSpecializeCommon()  
    setSignalHandler()
    RETURN_INT(pid);      
closeServerSocket();
見附A
主進程runSelectLoopMode()
5.Runs the zygote process's select loop runSelectLoopMode(), Accepts new connections as they happen, and
reads commands from connections one spawn-request's worth at a time.
如果運行正常,則zygote進程會在runSelectLoopMode()中循環:
zygote 被siganl(11)終止
在dalvik_system_Zygote.c (dalvik/vm/native)
的 static void sigchldHandler(int s) 函數中打印:   
" rocess %d terminated by signal (%d)/n",
"Exit zygote because system server (%d) has terminated/n",
startSystemServer() ZygoteInit.java (frameworks/base/core/java/com/android/internal/os)
SystemServer 的mian()函數會調用
SystemServer.java (frameworks/base/services/java/com/android/server)中的 init1()函數。
init1()實際執行的是com_android_server_SystemServer.cpp (frameworks/base/services/jni)
中的 android_server_SystemServer_init1()。
android_server_SystemServer_init1()調用的是
System_init.cpp (frameworks/base/cmds/system_server/library) 中的 system_init()函數
system_init()函數定義如下:
extern "C" status_t system_init()
{
  ...
  sp sm = defaultServiceManager();
  ...
  property_get("system_init.startsu**ceflinger", propBuf, "1");
  if (strcmp(propBuf, "1") == 0) {
  //讀取屬性服務器,開啓啓動 Su**ceFlinger服務
  //接着會開始顯示機器人圖標
  //BootAnimation.cpp (frameworks/base/libs/su**ceflinger):status_t BootAnimation::readyToRun()
  Su**ceFlinger::instantiate();
  }
  //在模擬器上 audioflinger 等幾個服務與設備上的啓動過程不一樣,所以
  //我們在這裏啓動他們。
  if (!proc->supportsProcesses()) {
  //啓動 AudioFlinger,media playback service,camera service服務
  AudioFlinger::instantiate();
  MediaPlayerService::instantiate();
  CameraService::instantiate();
  }
  //現在開始運行 the Android runtime ,我們這樣做的目的是因爲必須在 core system services
  //起來以後才能 Android runtime initialization,其他服務在調用他們自己的main()時,都會
  //調用 Android runtime
  //before calling the init function.
  LOGI("System server: starting Android runtime./n");
  AndroidRuntime* runtime = AndroidRuntime::getRuntime();
  LOGI("System server: starting Android services./n");
  //調用 SystemServer.java (frameworks/base/services/java/com/android/server)
  //中的init2函數
  runtime->callStatic("com/android/server/SystemServer", "init2");
   
  // If running in our own process, just go into the thread
  // pool.Otherwise, call the initialization finished
  // func to let this process continue its initilization.
  if (proc->supportsProcesses()) {
  LOGI("System server: entering thread pool./n");
  ProcessState::self()->startThreadPool();
  IPCThreadState::self()->joinThreadPool();
  LOGI("System server: exiting thread pool./n");
  }
  return NO_ERROR;
}
System server: entering thread pool 表明已經進入服務線程 ServerThread
在 ServerThread 類的run 服務中開啓核心服務:
  @Override
  public void run() {
  EventLog.writeEvent(LOG_BOOT_PROGRESS_SYSTEM_RUN,
    SystemClock.uptimeMillis());
  ActivityManagerService.prepareTraceFile(false); // create dir
  Looper.prepare();
  //設置線程的優先級
  android.os.Process.setThreadPriority(
      android.os.Process.THREAD_PRIORITY_FOREGROUND);
  ...
  //關鍵(核心)服務
  try {
    Log.i(TAG, "Starting Power Manager.");
    Log.i(TAG, "Starting activity Manager.");
    Log.i(TAG, "Starting telephony registry");
    Log.i(TAG, "Starting Package Manager.");
    Log.i(TAG, "tarting Content Manager.");
    Log.i(TAG, "Starting System Content Providers.");
    Log.i(TAG, "Starting Battery Service.");
    Log.i(TAG, "Starting Alarm Manager.");
    Log.i(TAG, "Starting Sensor Service.");
    Log.i(TAG, "Starting Window Manager.");
    Log.i(TAG, "Starting Bluetooth Service.");
    //如果是模擬器,那麼跳過藍牙服務。
    // Skip Bluetooth if we have an emulator kernel
   //其他的服務
    Log.i(TAG, "Starting Status Bar Service.");
    Log.i(TAG, "Starting Clipboard Service.");
    Log.i(TAG, "Starting Input Method Service.");
    Log.i(TAG, "Starting Hardware Service.");
    Log.i(TAG, "Starting NetStat Service.");
    Log.i(TAG, "Starting Connectivity Service.");
    Log.i(TAG, "Starting Notification Manager.");
    // MountService must start after NotificationManagerService
    Log.i(TAG, "Starting Mount Service.");
  Log.i(TAG, "Starting DeviceStorageMonitor service");
    Log.i(TAG, "Starting Location Manager.");
    Log.i(TAG, "Starting Search Service.");
    ...
    if (INCLUDE_DEMO) {
      Log.i(TAG, "Installing demo data...");
      (new DemoThread(context)).start();
    }
    try {
      Log.i(TAG, "Starting Checkin Service.");
      Intent intent = new Intent().setComponent(new ComponentName(
        "com.google.android.server.checkin",
        "com.google.android.server.checkin.CheckinService"));
      if (context.startService(intent) == null) {
      Log.w(TAG, "Using fallback Checkin Service.");
      ServiceManager.addService("checkin", new FallbackCheckinService(context));
      }
    } catch (Throwable e) {
      Log.e(TAG, "Failure starting Checkin Service", e);
    }
    Log.i(TAG, "Starting Wallpaper Service");
  Log.i(TAG, "Starting Audio Service");
    Log.i(TAG, "Starting HeadsetObserver");
    Log.i(TAG, "Starting AppWidget Service");
  ...
    try {
      com.android.server.status.StatusBarPolicy.installIcons(context, statusBar);
    } catch (Throwable e) {
      Log.e(TAG, "Failure installing status bar icons", e);
    }
  }
  // make sure the ADB_ENABLED setting value matches the secure property value
  Settings.Secure.putInt(mContentResolver, Settings.Secure.ADB_ENABLED,
      "1".equals(SystemProperties.get("persist.service.adb.enable")) ? 1 : 0);
  // register observer to listen for settings changes
  mContentResolver.registerContentObserver(Settings.Secure.getUriFor(Settings.Secure.ADB_ENABLED),
      false, new AdbSettingsObserver());
  // It is now time to start up the app processes...
  boolean safeMode = wm.detectSafeMode();
  if (statusBar != null) {
    statusBar.systemReady();
  }
  if (imm != null) {
    imm.systemReady();
  }
  wm.systemReady();
  power.systemReady();
  try {
    pm.systemReady();
  } catch (RemoteException e) {
  }
  if (appWidget != null) {
    appWidget.systemReady(safeMode);
  }
  // After making the following code, third party code may be running...
  try {
    ActivityManagerNative.getDefault().systemReady();
  } catch (RemoteException e) {
  }
  Watchdog.getInstance().start();
  Looper.loop();
  Log.d(TAG, "System ServerThread is exiting!");
  }
startActivity()
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);

ActivityManagerService.java 3136p (frameworks/base/services/java/com/android/server/am)
startActivity()
  startActivityLocked() //3184
  int res = startActivityLocked(caller, intent, resolvedType,grantedUriPermissions, grantedMode, aInfo,
      resultTo, resultWho, requestCode, -1, -1,
      onlyIfNeeded, componentSpecified);
public abstract class ActivityManagerNative extends Binder implements IActivityManager
ActivityManagerService.java 1071p(frameworks/base/services/java/com/android/server/am)
ActivityManagerService.main()
//ActivityManagerService.java 7375p (frameworks/base/services/java/com/android/server/am)
m.startRunning(null, null, null, null);
  //ActivityManagerService.java 7421p (frameworks/base/services/java/com/android/server/am)
  systemReady();
ActivityManagerService.java 3136p (frameworks/base/services/java/com/android/server/am)
startActivity(IApplicationThread caller,Intent intent,...)
  int startActivityLocked(caller, intent,...)  //3184L 定義:2691L
  void startActivityLocked()   //3132L 定義:2445L
  resumeTopActivityLocked(null); //2562p 定義:2176L
  if(next=NULL)
  {
    intent.addCategory(Intent.CATEGORY_HOME);
    startActivityLocked(null, intent, null, null, 0, aInfo,null, null, 0, 0, 0, false, false);
  }
  else
  {
    startSpecificActivityLocked(next, true, false); //2439L 定義:1628L
    realStartActivityLocked() //1640L  定義:1524L
    //1651L 定義:1654L
    startProcessLocked(r.processName, r.info.applicationInfo, true, 0,"activity", r.intent.getComponent());
    //1717L 定義:1721L
    startProcessLocked(app, hostingType, hostingNameStr);
      //1768L定義:Process.java 222L(frameworks/base/core/java/android/os)
      int pid = Process.start("android.app.ActivityThread",...)
      startViaZygote(processClass, niceName, uid, gid, gids,debugFlags, zygoteArgs);
      pid = zygoteSendArgsAndGetPid(argsForZygote);
        sZygoteWriter.write(Integer.toString(args.size()));
  }

runSelectLoopMode();
  done = peers.get(index).runOnce();
  forkAndSpecialize() //Zygote.java (dalvik/libcore/dalvik/src/main/java/dalvik/system)
  Dalvik_dalvik_system_Zygote_forkAndSpecialize() //dalvik_system_Zygote.c (dalvik/vm/native)
    forkAndSpecializeCommon()  
    setSignalHandler()
    RETURN_INT(pid);
   
   ActivityThread main()
   ActivityThread attach() //ActivityThread.java 3870p (frameworks/base/core/java/android/app)
   mgr.attachApplication(mAppThread)
   //ActivityManagerService.java 4677p (frameworks/base/services/java/com/android/server/am)
   attachApplication()
     //ActivityManagerService.java 4677p (frameworks/base/services/java/com/android/server/am)
     attachApplicationLocked()
     if (realStartActivityLocked(hr, app, true, true)) //ActivityManagerService.java 4609p
                       //(frameworks/base/services/java/com/android/server/am)
     realStartActivityLocked()
     //ActivityManagerService.java (frameworks/base/services/java/com/android/server/am)
     app.thread.scheduleLaunchActivity(new Intent(r.intent), r,r.info, r.icicle, results, newIntents, /
      !andResume,isNextTransitionForward());
     scheduleLaunchActivity()
       queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
       ActivityThread.H.handleMessage()
       handleLaunchActivity()  //ActivityThread.java (frameworks/base/core/java/android/app)
         performLaunchActivity() //ActivityThread.java (frameworks/base/core/java/android/app)
         activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);

     
/////////////////////////////////////////////////   
init 守護進程:
//andriod init 函數啓動過程分析:
在main循環中會重複調用
drain_action_queue();
restart_processes();
static void restart_processes()
{
  process_needs_restart = 0;
  service_for_each_flags(SVC_RESTARTING,
         restart_service_if_needed);
}
通過循環檢測服務列表service_list 中每個服務的 svc->flags 標記,如果爲 SVC_RESTARTING,
那麼在滿足條件的情況下調用:restart_service_if_needed
通過 service_start 來再次啓動該服務。
ActivityManagerService.main
I/SystemServer( 45): Starting Power Manager.
I/ServiceManager( 26): service 'Su**ceFlinger' died
D/Zygote( 30): Process 45 terminated by signal (11)
I/Zygote( 30): Exit zygote because system server (45) has terminated
通過錯誤信息發現程序在調用 Su**ceFlinger服務的時候被中止。
Service_manager.c (frameworks/base/cmds/servicemanager):
LOGI("service '%s' died/n", str8(si->name));
Binder.c (frameworks/base/cmds/servicemanager):
death->func(bs, death->ptr);
Binder.c (kernel/drivers/misc)中的函數
binder_thread_read()
struct binder_work *w;
switch (w->type)
爲 BINDER_WORK_DEAD_BINDER 的時候
binder_parse()中
當 cmd 爲 BR_DEAD_BINDER的時候
執行 death->func(bs, death->ptr)
因爲函數
int do_add_service(struct binder_state *bs,
       uint16_t *s, unsigned len,
       void *ptr, unsigned uid)
的 si->death.func = svcinfo_death;
所以 death->func(bs, death->ptr) 實際上執行的是
svcinfo_death()//Service_manager.c (frameworks/base/cmds/servicemanager)
================================================
=================================================
7. linux下svn使用指南
1.1 服務器端配置說明
1.1.3 配置用戶和權限
1.1.4 導入工程到倉庫中
1.2 客戶端操作指南及使用規範
1.2.1 檢出工作拷貝
1.2.2 svn update 更新別人做的更改
1.2.2.1 svn update 獲取最新版本
1.2.2.2 svn update-r 獲取特定的版本
1.2.3 svn st 查看文件狀態信息
1.2.4 svn log 查看log信息
1.2.5 svn diff 查看文件修改詳情
1.2.6 svn list 顯示版本庫的文件列表
1.2.8 svn add 增加目錄或者文件
1.2.9 svn delete 刪除目錄或者文件
1.2.10 svn revert 取消本地修改
1.2.11 svn commit 提交本地做的更改
1.2.12 文件更新,提交時的衝突處理
1.2.13 打標籤
1.2.14 清除緩存的認證信息,重新輸入用戶名和密碼
=================
1.1 服務器端配置說明
1.1.1 ubuntu-8.10 svn服務器安裝
sudo apt-get install subversion
1.1.2 建立版本庫(Repository)
運行Subversion服務器需要首先要建立一個版本庫(Repository),可以看作服務器上存放數據的數據庫,在安裝了Subversion服務器之後,可以直接運行
cd path_to_svn_root例如:/home/svn
svnadmin create --fs-type=fsfssmartphone
--fs-type 指定倉庫類型,可以爲fsfs或bdb 如果沒有指定默認創建爲fsfs類型smartphone爲倉庫名稱
1.1.3 配置用戶和權限
修改 path_to_svn_repos/conf/svnserve.conf 文件,打開下面配置項
---------------------------
#anon-access = read
anon-access = none
auth-access = write
password-db = passwd
authz-db = authz
anon-access 應設置等於 none ,否則沒有log信息
修改path_to_svn_repos/conf/passwd 文件,添加用戶和密碼
----------------------------
[users]
wanghui=wanghui

1.1.4 導入工程到倉庫中
svn importsmartphone/svn://192.168.2.148/smartphone
1.1.5 運行svn服務器
svnserve -d -rpath_to_svn_root例如:/home/svn
1.2 客戶端操作指南及使用規範
以我們服務器上 android 源代碼爲例,介紹svn常用操作。
1.2.1 檢出工作拷貝
檢出工作拷貝到 ~/svn/cupcake-jiangping
使用svn co url
cd ~/svn
svn co svn://192.168.2.148/smartphone/td0901/trunk/cupcake-jianpingcupcake-jianping
1.2.2 svn update 更新別人做的更改
1.2.2.1 svn update 獲取最新版本
svn update cupcake-jiangping
或者進入目錄更新
cd cupcake-jiangping
svn update
如果負責的應用與系統的關聯性不是很大,通常不建議頻繁進行更新。
1.2.2.2 svn update-r 獲取特定的版本
直接在某目錄下執行 svn update 獲取當前目錄下所有文件的最新版本,如果我們只需要獲取某個文件或者目錄的特定版本,可以通過-r 和 名稱進行指定:
svn update –r 5cupcake-jianping/packages/apps/Phone/src/com/android/phone/xxxx.java
1.2.3 svn st 查看文件狀態信息
Mcupcake-jianping/packages/apps/Phone/src/com/android/phone/xxxx.java
?cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java
M表明文件已經有修改
? 表明文件沒有受版本控制
1.2.4 svn log 查看log信息
svn log -r  查看所有版本的log信息
svn log -r 5  查看某一版本的log信息
svn log -r 5:19 查看某區間一系列版本的log信息
如果要查看log的詳細信息可以加上 –v 選項,如:
svn log –v -r 5
1.2.5 svn diff 查看文件修改詳情
顯示單個文件或者某目錄下所有文件的修改詳情
svn diff有三種不同的用法
1. 檢查本地修改
2. 比較工作拷貝與版本庫
3. 比較版本庫與版本庫
不使用任何參數調用時,svn diff將會比較你的工作文件與緩存在.svn的“原始”拷貝,如:
svn diff cupcake-jianping/packages/apps/Phone
svn diff cupcake-jianping/packages/apps/Phone/src/com/android/phone/zzzz.java
如果傳遞一個—revision –r 參數,你的工作拷貝會與指定的版本比較。
svn diff -r 3 cupcake-jianping/packages/apps/Phone
如果通過--revision –r 傳遞兩個通過冒號分開的版本號,這兩個版本會進行比較。
svn diff -r 2:3 cupcake-jianping/packages/apps/Phone
如果你在本機沒有工作拷貝,還是可以比較版本庫的修訂版本,只需要在命令行中輸入合適的URL:
svn diff -r 33 svn://192.168.2.148/smartphone/td0901/trunk/cupcake-jianping/packages/apps/Phone
1.2.6 svn list 顯示版本庫的文件列表
svn list svn://192.168.2.148/smartphone/td0901
design/
hedoc/
pm/
release/
tag/
trunk/
svn list svn://192.168.2.148/smartphone/td0901/trunk
3src/
boot-a1/
cupcake-jianping/
linux-2.6.28-a1/
svn list 類似本機的ls命令,它查看的是服務器端的目錄結構。
1.2.7 svn info 查看版本庫信息
cd ~/svn/cupcake-jianping
svn infos
路徑: .
URL: svn://192.168.2.148/smartphone/td0901/trunk/cupcake-jianping
版本庫根: svn://192.168.2.148/smartphone
版本庫 UUID: 1fac82c5-1665-442c-a8d6-2b3dd850438a
版本: 146
節點種類: 目錄
調度: 正常
最後修改的作者: tangligang
最後修改的版本: 145
最後修改的時間: 2009-07-31 15:40:50 +0800 (五, 2009-07-31)
1.2.8 svn add 增加目錄或者文件
svn add cupcake-jianping/packages/apps/Phone/src/com/android/phone/xxxx
svn add cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java
1.2.9 svn delete 刪除目錄或者文件
svn delete cupcake-jianping/packages/apps/Phone/src/com/android/phone/xxxx
svn delete cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java
在進行刪除操作的時候要非常小心,假設我們要添加一個文件:
cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java
但是在提交之前我們發現並不需要這個文件,這時候我們經常通過 svn delete 來撤銷之前添加的文件:
svn delete cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java
這樣操作的後果往往導致本地的文件yyyy.java 被誤刪除掉,所以我們正確的做法是:
svnn delete cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java –keep-local
1.2.10 svn revert 取消本地修改
1.當你發現對某個文件的所有修改都是錯誤的,或許你根本不應該修改這個文件,或者是從開頭重新修改會更加容易的時候可以用這個命令。
2.通過svn add 添加了一個項目,如果想取消可以通過該命令。
1.2.11 svn commit 提交本地做的更改
通常只對自己負責的模塊進行提交,如果負責電話模塊,那麼提交命令如下:
svn commit cupcake-jiangping/packages/apps/Phone
在提交之前建議用命令:
svn st cupcake-jiangping/packages/apps/Phone 查看狀態
M cupcake-jianping/packages/apps/Phone/src/com/android/phone/xxxx.java
?cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java
M表明文件已經有修改
? 表明文件沒有受版本控制
1. 如果有 “?”存在,並且該文件或者目錄是自己添加並且是工程的一部分,那麼在提交之前必須先執行svn add 操作:svn add cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java ;
2. 提交之前也必須解決衝突,否則會提交失敗。
3. 提交之前必須寫log
1.2.12 文件更新,提交時的衝突處理
$ svn update
Uxxxx
Gyyyy
Cxxxx.c
1. 更新的時候如果前面的狀態爲:C 表示有衝突存在。
2. 工作拷貝里做過修改,且服務器版本庫在修改前工作拷貝的版本後被提交過其他修改;那麼svn commit首先會失敗並要求update,此時便會出現版本衝突的情況。
當你Update出現了衝突時,Subversion會產生三個文件
filename.mine :你更新前的文件,沒有衝突標誌,只是你最新更改的內容。
Filename.roldrev:就是你在上次更新之後未作更改的版本。
Filename.rnewrev:客戶端從服務器剛剛收到的版本,這個文件對應版本庫的HEAD版本。
衝突的文件內容,在衝突的地方將被使用“>>>>”標誌出來,用戶自己進行合併的取捨。
解決衝突之後,svn resolved path_to_name,Subversion刪除衝突所產生三個文件刪除,此時你纔可以進行提交。( 也可以手動刪除此三個文件。)
1.2.13 打標籤
svn 的標籤是通過copy命令完成,但是操作的路徑必須是服務器的路徑,打標籤實際上類似於創建一個到特定版本的鏈接,如:
svn cp svn://192.168.2.148/smartphone/td0901/trunk/cupcake-jianping/
svn://192.168.2.148/smartphone/td0901/tags/cupcake-1.0.6
如果 svn://192.168.2.148/smartphone/td0901/trunk/cupcake-jianping 的當前版本爲 5 ,/
那麼 svn://192.168.2.148/smartphone/td0901/tags/cupcake-1.0.6 實際 /
上就是 svn://192.168.2.148/smartphone/td0901/trunk/cupcake-jianping 版本5的一個標籤。
1.2.14 清除緩存的認證信息,重新輸入用戶名和密碼
一個具有權限控制的 svn 版本庫在第一次 checkout 工作拷貝的時候會要求輸入用戶名和密碼:
認證領域:176512f1-51ee-4947-8c07-88c90ab77ac5
“$USER”的密碼:
認證領域:d3216b51-7915-4881-bf30-02e0672c61cd
用戶名: xxxxx
“xxxxx”的密碼:
這些信息被緩存在 ~/.subversion/auth/svn.simple/ 如果需要更換另一個用戶登錄,必須先清除緩存的認證信息:
rm ~/.subversion/auth/svn.simple/* -rf
1.3 爲規避風險,建議遵守以下規範
1.3.1 提交前審查修改情況, 用命令svn status瀏覽所做的修改,svn diff檢查修改的詳細信息
1.3.2 提交時,必須填寫註釋,註釋內容清晰描述本次提交內容,變動信息。
1.3.3 做較大修改時,和項目組其他同事的工作相關時,必須通知對方。
1.3.4 納入版本控制的項目必須定期提交,至少一週提交一次,避免意外事故導致代碼丟失。
1.3.5 每次提交後,必須確認工程可正常運行,即SVN裏保存的是可以正確運行的代碼,否則恢復至穩定版本。
1.3.6 編譯過程動態產生的東西不要提交到服務器
1.3.7 每次提交前先更新,這樣能在提交前發現是否和別人的衝突
filelist=`find ./ -name "*.conf"`;svn add $filelist; svn commit$filelist
filelist=`find ./ -name "*.conf"`;svn delete $filelist --force --keep-local
=================================================
================================================
8. LFS 相關
7.1 lfs 相關資源
7.2 LFS問題解答
=========
LFS──Linux from Scratch,就是一種從網上直接下載源碼,從頭編譯LINUX的安裝方式。它不是發行版,只是一個菜譜,
告訴你到哪裏去買菜(下載源碼),怎麼把這些生東西( raw code) 作成符合自己口味的菜餚──個性化的linux,不單單是
個性的桌面。
LFS 有什麼優勢呢?現在看來,它可以提供最快和最小的 Linux。但是最大的優勢就是,安裝LFS是菜鳥變成高手的捷徑。
第一次安裝,需要按照LFS文檔安裝,如果在此期間所有文檔內容你都認真的閱讀,保證你受益匪淺;然後發現很多地方可以
不按照別人的老路操作,這個時候用自己的方式參考第一次安裝的經驗,再一次建立linux,完成的時候,你會發現你在 LinuxSir.Org
上已經再也不是菜鳥了。
7.1 lfs 相關資源
官方網站:
http://www.linuxfromscratch.org/
lfs中文網站
http://lfs.linuxsir.org/main/
Linux From Scratch版本 6.2
http://lamp.linux.gov.cn/Linux/LFS-6.2/index.html
Linux From Scratch 版本 6.4
http://www.bitctp.org/lfsbook-6.4/index.html
Linux 發行版 LFS 討論區
http://www.linuxsir.org/bbs/forumdisplay.php?f=58
7.2 LFS問題解答
構建LFS的過程中遇到一些問題,總體來說還算順利,但是還有一些不明白的地方,這裏總結一下:
1./etc/fstab是否在開機就執行,是被誰調用執行的。
2.爲什麼系統啓動之後就要自動掛載/proc 和/sys,這兩個目錄有什麼作用;devpts和tmpfs有什麼作用。
參考章節:文件系統概述
3.關於文件系統:按照我的理解,文件系統是內核提供支持的,可以看作是一種協議,提供一種數據組織方式,每個設備必須有自己的文件系統。
不同文件系統的存儲設備的數據組織形式不同。mke2fs -jv /dev/默認在上面創建EXT3的文件系統嗎?既然這樣的話爲什麼
我們還需要把以ext3掛載到一個目錄呢?如果不是 的話,又是創建什麼文件系統呢?爲什麼第六章中掛載了虛擬內核文件系統之後才能
進入chroot環境呢?
參考章節:文件系統概述
4.虛擬文件系統.作用.什麼?
虛擬內核文件系統(Virtual Kernel File Systems),是指那些是由內核產生但並不存在於硬盤上(存在於內存中)的文件系統,他們
被用來與內核進行通信。
5.符號鏈接 和硬鏈接的區別是什麼?什麼是符號鏈接?什麼是硬鏈接?爲什麼liinux上都使用符號鏈接,而不是硬鏈接?linux上很多地方
使用了鏈接,是爲了組織清晰系統的結構和節省空間嗎?
硬連接和軟連接的區別, 硬連接和複製的區別?
硬連接記錄的是目標的 inode;軟連接記錄的是目標的 path。
hard link 由於 inode 的緣故,只能在本分區中做 link;soft link 可以做跨分區的 link。硬連接因爲記錄的是 inode,所以不怕改名,
比如ln aaa bbb, mv aaa ccc, 這時 bbb 仍然可以訪問;soft-link 就不行:source 的名字改變後,所有鏈接到這裏的 soft-link
全部變爲 broken。事實上,即使所有指向該 inode 的 hard-link 的文件名都變了,每一個仍然都可以訪問。我想這是它最大的優點吧。
硬連接和複製的區別:
幾個硬連接=幾個名字的同一個房子,這些名字可以相同或不同但地址(i-node)是一樣的, 所以硬連接被刪除只是把相應名字抹去,只有最
後一個名字被抹去你纔會找不到房子;而複製是建造一個一模一樣的房子,當然地址(i-node)就不同的了。
6.工作平臺中由Glibc提供的動態連接器與Binutils裏面的標準連接器有什麼區別?
參考章節: 鏈接器和加載器
7.$LFS/tools 目錄的所有者是僅存在於宿主環境中的 lfs 用戶。如果保留 $LFS/tools 目錄,那麼該目錄內文件的所有者的 user ID 就
沒有對應的賬號 ?爲什麼沒有帳戶,難道不是LFS?
查看 /etc/password /etc/group兩個文件 分別記錄 用戶和組的信息
如果用戶名和用戶ID 組名和組ID 的對應關係分別存在上面兩個文件中,那麼ls -ls 的時候就可以查看到用戶信息,而不再是ID等數字信息
8.系統的環境變量保存在哪個文件?
保存在tty中
9。配置參數腳本時[alias1] [alias2 ...]什麼時候用到?
別名的意思
alias ls='ls --color=auto'
/etc/skel/.bashrc:81:  #alias dir='dir --color=auto'
/etc/skel/.bashrc:82:  #alias vdir='vdir --color=auto'
/etc/skel/.bashrc:84:  #alias grep='grep --color=auto'
/etc/skel/.bashrc:85:  #alias fgrep='fgrep --color=auto'
/etc/skel/.bashrc:86:  #alias egrep='egrep --color=auto'
/etc/skel/.bashrc:89:# some more ls aliases
/etc/skel/.bashrc:90:#alias ll='ls -l'
/etc/skel/.bashrc:91:#alias la='ls -A'
/etc/skel/.bashrc:92:#alias l='ls -CF'
alias mohuifu='ls -l'
========================
9. linux 內核的初步理解
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
編譯好的內核:===================================================
linux ,Android基礎知識總結
1. Android編譯系統分析
2. 文件系統分析
3. 製作交叉工具鏈
4. 軟件編譯常識
5. 設置模塊流程分析
6. linux系統啓動流程分析
7. linux下svn使用指南
8. LFS 相關
9. linux 內核的初步理解
====================================================
================
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 listsvn://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 ABSOLUTELY NO WARRANTY; read the GNU GPL for details.
This is free software, and you are welcome to redistribute it
under certain conditions; read the GNU GPL 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 OCAL_MODULE:= sh
./system/core/libcutils/Android.mk:71 OCAL_MODULE := libcutils
./system/core/cpio/Android.mk:9 OCAL_MODULE := mkbootfs
./system/core/mkbootimg/Android.mk:8 OCAL_MODULE := mkbootimg
./system/core/toolbox/Android.mk:61 OCAL_MODULE:= toolbox
./system/core/logcat/Android.mk:10 OCAL_MODULE:= logcat
./system/core/adb/Android.mk:65 OCAL_MODULE := adb
./system/core/adb/Android.mk:125 OCAL_MODULE := adbd
./system/core/init/Android.mk:20 OCAL_MODULE:= init
./system/core/vold/Android.mk:24 OCAL_MODULE:= vold
./system/core/mountd/Android.mk:13 OCAL_MODULE:= mountd
LOCAL_PACKAGE_NAME
Java 應用程序的名字用該變量定義
./packages/apps/Music/Android.mk:9 OCAL_PACKAGE_NAME := Music
./packages/apps/Browser/Android.mk:14 OCAL_PACKAGE_NAME := Browser
./packages/apps/Settings/Android.mk:8 OCAL_PACKAGE_NAME := Settings
./packages/apps/Stk/Android.mk:10 OCAL_PACKAGE_NAME := Stk
./packages/apps/Contacts/Android.mk:10 OCAL_PACKAGE_NAME := Contacts
./packages/apps/Mms/Android.mk:8 OCAL_PACKAGE_NAME := Mms
./packages/apps/Camera/Android.mk:8 OCAL_PACKAGE_NAME := Camera
./packages/apps/Phone/Android.mk:11 OCAL_PACKAGE_NAME := Phone
./packages/apps/VoiceDialer/Android.mk:8 OCAL_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 /
        $/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 RODUCT_NAME := littleton
vendor/marvell/littleton/littleton.mk:28 RODUCT_DEVICE := littleton
vendor/marvell/littleton/AndroidProducts.mk:13:    $(LOCAL_DIR)/littleton.mk
vendor/sample/products/sample_addon.mk:40 RODUCT_NAME := sample_addon
vendor/htc/dream-open/htc_dream.mk:6 RODUCT_NAME := htc_dream
./vendor/htc/dream-open/htc_dream.mk:7 RODUCT_DEVICE := dream-open
./vendor/htc/dream-open/AndroidProducts.mk:3:    $(LOCAL_DIR)/htc_dream.mk
build/target/product/generic.mk:26 RODUCT_NAME := generic
build/target/product/generic_with_google.mk:20 RODUCT_NAME := generic_with_google
build/target/product/min_dev.mk:6 RODUCT_NAME := min_dev
build/target/product/core.mk:2 RODUCT_NAME :=
build/target/product/sim.mk:7 RODUCT_NAME := sim
build/target/product/sdk.mk:37 RODUCT_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
lunchgeneric-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 OCAL_CFLAGS += -mabi=aapcs-linux
./vendor/marvell/external/alsa/alsa-tools/Mdroid.mk:8 OCAL_CFLAGS += -mabi=aapcs-linux
./vendor/marvell/littleton/libaudio/Mdroid.mk:22 OCAL_CPPFLAGS += -mabi=aapcs-linux
./external/wpa_supplicant/Android.mk:35 _CFLAGS += -mabi=aapcs-linux
./system/wlan/ti/sta_dk_4_0_4_32/CUDK/tiwlan_loader/Android.mk:88 OCAL_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 /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/ptsdevpts 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/rwtype 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/sda7on /boot type ext3 (rw,relatime)
/dev/sda11 on /home type ext3 (rw,relatime)
/dev/sdb5on /opt type ext3 (rw,relatime)
/dev/sda9on /usr/local type ext3 (rw,relatime)
/dev/sda1on /windows/c type vfat (rw,utf8,umask=007,gid=1000)
/dev/sda5on /windows/d type vfat (rw,utf8,umask=007,gid=1000)
/dev/sda6on /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 12K1013M 1%  /dev/shm
mount | grep tmpfs 顯示當前系統中的 tmpfs:
tmpfs on /lib/init/rw type tmpfs (rw,nosuid,mode=0755)
varrunon /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 AEMON=/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/nfsnfsroot=192.168.2.56:/nfsroot/rootfs
ip=192.168.2.188:192.168.2.56:192.168.2.56:255.255.255.0::eth0 n 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 n 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 n
console=ttyS1,115200 mem=128M init=/init android uart_dma=1"
`root=' 參數
此參數告訴內核啓動時以那個設備作爲根文件系統使用。我的pc根文件系統:
/dev/sda8    9614116 6522156 260358872% /
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 n
ip=192.168.2.175:192.168.2.56:192.168.2.201:255.255.255.0::eth0 n
-- 板子的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-separatedon to the assembler
-Wp,    Pass comma-separatedon to the preprocessor
-Wl,    Pass comma-separatedon to the linker
從工具鏈內建的規範中查看動態加載器
gcc -dumpspecs | grepdynamic-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 | grepdynamic-linker
/scratchbox/compilers/arm-softfloat-linux-gcc-3.4.4-glibc-2.3.5/bin/arm-softfloat-linux-gnu-gcc -dumpspecs | grepdynamic-linker
2. marvell 的工具鏈
/scratchbox/compilers/marvell-arm-linux-4.1.1/bin/arm-linux-gcc-dumpspecs | grepdynamic-linker
3. scrathbox 中工具鏈 host-gcc
/scratchbox/compilers/host-gcc/bin/host-gcc-dumpspecs | grepdynamic-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中應用程序使用的加載器
stringsout/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 = CommandsInte**ce.SERVICE_CLASS_VOICE +
      CommandsInte**ce.SERVICE_CLASS_DATA +
      CommandsInte**ce.SERVICE_CLASS_FAX;
mDesiredPinLocked = enabled;
phone.mCM.setFacilityLock(CommandsInte**ce.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.asInte**ce(
      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 = 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, 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 intset_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



重要的數據結構
兩個列表,一個隊列。
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 OPTION0x04
關鍵字  屬性   
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 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 []*
...
申請一個service結構體,然後掛接到service_list鏈表上,name 爲服務的名稱 pathname 爲執行的命令 argument
爲命令的參數。之後的 option 用來控制這個service結構體的屬性,parse_line_service 會對 service關鍵字後的
內容進行解析並填充到 service 結構中 ,當遇到下一個service或者on關鍵字的時候此service選項解析結束。
例如:
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
服務名稱爲:         zygote
啓動該服務執行的命令:     /system/bin/app_process
命令的參數:         -Xzygote /system/bin --zygote --start-system-server
socket zygote stream 666: 創建一個名爲:/dev/socket/zygote 的 socket ,類型爲:stream
當*.rc 文件解析完成以後:
action_list 列表項目如下:
on init
on boot
on property:ro.kernel.qemu=1
on property:persist.service.adb.enable=1
on property:persist.service.adb.enable=0
init.marvell.rc 文件
on early-init
on init
on early-boot
on boot
service_list 列表中的項有:
service console
service adbd
service servicemanager
service mountd
service debuggerd
service ril-daemon
service zygote
service media
service bootsound
service dbus
service hcid
service hfag
service hsag
service installd
service flash_recovery
設備初始化
early-init 初始化
初始化屬性服務器
在init.c 的main函數中啓動狀態服務器。
property_set_fd = start_property_service();
狀態讀取函數:
Property_service.c (system/core/init)
const char* property_get(const char *name)
Properties.c (system/core/libcutils)
int property_get(const char *key, char *value, const char *default_value)
狀態設置函數:
Property_service.c (system/core/init)
int property_set(const char *name, const char *value)
Properties.c (system/core/libcutils)
int property_set(const char *key, const char *value)
在終端模式下我們可以通過執行命令 setprop
setprop 工具源代碼所在文件: Setprop.c (system/core/toolbox)
Getprop.c (system/core/toolbox):  property_get(argv[1], value, default_value);
Property_service.c (system/core/init)
中定義的狀態讀取和設置函數僅供init進程調用,
handle_property_set_fd(property_set_fd);
property_set() //Property_service.c (system/core/init)
  property_changed(name, value) //Init.c (system/core/init)
  queue_property_triggers(name, value)
  drain_action_queue()
只要屬性一改變就會被觸發,然後執行相應的命令:
例如:
在init.rc 文件中有
on property:persist.service.adb.enable=1
start adbd
on property:persist.service.adb.enable=0
stop adbd
所以如果在終端下輸入:
setprop property:persist.service.adb.enable 1或者0
那麼將會開啓或者關閉adbd 程序。
執行action_list 中的命令:
從action_list 中取出 act->name 爲 early-init 的列表項,再調用 action_add_queue_tail(act)將其插入到
隊列 action_queue 尾部。drain_action_queue() 從action_list隊列中取出隊列項 ,然後執行act->commands
列表中的所有命令。
所以從./system/core/init/init.c mian()函數的程序片段:
action_for_each_trigger("early-init", action_add_queue_tail);
drain_action_queue();
action_for_each_trigger("init", action_add_queue_tail);
drain_action_queue();
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();
可以看出,在解析完init.rc init.marvell.rc 文件後,action 命令執行順序爲:
執行act->name 爲 early-init,act->commands列表中的所有命令
執行act->name 爲 init,    act->commands列表中的所有命令
執行act->name 爲 early-boot,act->commands列表中的所有命令
執行act->name 爲 boot,    act->commands列表中的所有命令
關鍵的幾個命令:
class_start default 啓動所有service 關鍵字定義的服務。
class_start 在act->name爲boot的 act->commands列表中,所以當 class_start 被觸發後,實際
上調用的是函數 do_class_start()
int do_class_start(int nargs, char **args)
{
  /* Starting a class does not start services
   * which are explicitly disabled.They must
   * be started individually.
   */
  service_for_each_class(args[1], service_start_if_not_disabled);
  return 0;
}
void service_for_each_class(const char *classname,
          void (*func)(struct service *svc))
{
  struct listnode *node;
  struct service *svc;
  list_for_each(node, &service_list) {
  svc = node_to_item(node, struct service, slist);
  if (!strcmp(svc->classname, classname)) {
    func(svc);
  }
  }
}
因爲在調用 parse_service() 添加服務列表的時候,所有服務 svc->classname 默認取值:"default",
所以 service_list 中的所有服務將會被執行。
參考文檔:
http://blog.chinaunix.net/u1/38994/showart_1775465.html
http://blog.chinaunix.net/u1/38994/showart_1168440.html
淺析kernel啓動的第1個用戶進程init如何解讀init.rc腳本
http://blog.chinaunix.net/u1/38994/showart_1168440.html
Zygote 服務概論:
Zygote 是android 系統中最重要的一個服務,它將一步一步完成下面的任務:
start Android Java Runtime and start system server. It’s the most important service. The source is in device/servers/app.
1. 創建JAVA 虛擬機
2. 爲JAVA 虛擬機註冊android 本地函數
3. 調用 com.android.internal.os.ZygoteInit 類中的main函數,android/com/android/internal/os/ZygoteInit.java.
a) 裝載ZygoteInit類
b) 註冊zygote socket
c) 裝載preload classes(the default file is device/java/android/preloaded-classes)
d) 裝載Load preload 資源
e) 調用 Zygote::forkSystemServer (定義在./dalvik/vm/InternalNative.c)來fork一個新的進程,在新進程中調用
com.android.server.SystemServer 的main函數。
a) 裝載 libandroid_servers.so庫
bb) 調用JNI native init1 函數 (device/libs/android_servers/com_android_server_SystemServers)
Load libandroid_servers.so
Call JNI native init1 function implemented in device/libs/android_servers/com_android_server_SystemServers.
It only calls system_init implemented in device/servers/system/library/system_init.cpp.
If running on simulator, instantiate AudioFlinger, MediaPlayerService and CameraService here.
Call init2 function in JAVA class named com.android.server.SystemServer, whose source is in
device/java/services/com/android/server. This function is very critical for Android because it start all of
Android JAVA services.
If not running on simulator, call IPCThreadState::self()->joinThreadPool() to enter into service dispatcher.
SystemServer::init2 將會啓動一個新的線程來啓動下面的所有JAVA服務:
Core 服務:
1.Starting Power Manager(電源管理)
2.Creating Activity Manager(活動服務)
3.Starting Telephony Registry(電話註冊服務)
4.Starting Package Manager(包管理器)
5.Set Activity Manager Service as System Process
6.Starting Context Manager
7.Starting System Context Providers
8.Starting Battery Service(電池服務)
9.Starting Alarm Manager(鬧鐘服務)
10. Starting Sensor Service
11. Starting Window Manager(啓動窗口管理器)
12. Starting Bluetooth Service(藍牙服務)
13. Starting Mount Service
其他services:
1.Starting Status Bar Service(狀態服務)
2.Starting Hardware Service(硬件服務)
3.Starting NetStat Service(網絡狀態服務)
4.Starting Connectivity Service
5.Starting Notification Manager
6.Starting DeviceStorageMonitor Service
7.Starting Location Manager
8.Starting Search Service(查詢服務)
9.Starting Clipboard Service
10. Starting Checkin Service
11. Starting Wallpaper Service
12. Starting Audio Service
13. Starting HeadsetObserver
14. Starting AdbSettingsObserver
最後SystemServer::init2 將會調用 ActivityManagerService.systemReady 通過發送
Intent.CATEGORY_HOME intent來啓動第一個 activity.還有另外一種啓動system server的方法是:
通過名爲 system_server的程序(源代碼:device/servers/system/system_main.cpp)它也是通過
調用 system_init 來啓動 system services,這時候就有個問題:爲什麼android 有兩種方式啓動system services?
我的猜想是:
My guess is that directly start system_server may have synchronous problem with zygote because
system_server will call JNI to start SystemServer::init2, while at that time zygote may not start
JAVA VM yet. So Android uses another method. After zynote is initialized, fork a new process to
start system services.
Zygote服務啓動的詳細過程:
通過啓動服務列表的 app_process 進程,實際上進入的是
App_main.cpp (frameworks/base/cmds/app_process)
main()
根據 init.rc 中的 --zygote --start-system-server
分別調用的是
runtime.start("com.android.internal.os.ZygoteInit",startSystemServer);
或者
runtime.start();
start()函數在 AndroidRuntime.cpp (frameworks/base/core/jni)文件中
從打印信息:
D/AndroidRuntime( 56): >>>>>>>>>>>>>> AndroidRuntime START GetStaticMethodID(startClass, "main","([Ljava/lang/String;)V");
從上面的調用可以看出一類引用的過程都是從 main方法
所以接着調用了 ZygoteInit 類的main方法
main方法主要完成:
1.Register zygote socket, Registers a server socket for zygote command connections
2.Load preload classes(the default file is device/java/android/preloaded-classes).
3.Load preload resources, Load in commonly used resources, so they can be shared across processes.
4.Start SystemServer, Prepare the arguments and fork for the system server process.
具體執行過程如下:
ZygoteInit.java (frameworks/base/core/java/com/android/internal/os)中的mian
main()
registerZygoteSocket()
preloadClasses()
  loadLibrary()
  Log.i(TAG, " reloading classes...");
  Runtime.loadLibrary
  Dalvik_java_lang_Runtime_nativeLoad()
  dvmLoadNativeCode()
    LOGD("Trying to load lib %s %p/n", pathName, classLoader);
    System.loadLibrary("media_jni");
preloadResources();
startSystemServer()
  Zygote.forkSystemServer(parsedArgs.uid, parsedArgs.gid,parsedArgs.gids, debugFlags, null);
  //Zygote.java (dalvik/libcore/dalvik/src/main/java/dalvik/system)
  forkSystemServer()
  forkAndSpecialize() //Zygote.java (dalvik/libcore/dalvik/src/main/java/dalvik/system)
    Dalvik_dalvik_system_Zygote_forkAndSpecialize() //dalvik_system_Zygote.c (dalvik/vm/native)
    Dalvik_dalvik_system_Zygote_forkAndSpecialize()
    setSignalHandler()
    fork()
  handleSystemServerProcess() //handleChildProc(parsedArgs, descriptors, newStderr);
  closeServerSocket();
  RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
  zygoteInit()   //RuntimeInit.java (frameworks/base/core/java/com/android/internal/os)
    zygoteInitNative()
    invokeStaticMain()
    System.loadLibrary("android_servers");
    //com.android.server.SystemServer startSystemServer() 函數中
    m = cl.getMethod("main", new Class[] { String[].class });
      //執行的是SystemServer 類的main函數 SystemServer.java (frameworks/base/services/java/com/android/server)
      init1() //SystemServer.java (frameworks/base/services/java/com/android/server)     
      //init1()實際上是調用android_server_SystemServer_init1(JNIEnv* env, jobject clazz)
      //com_android_server_SystemServer.cpp (frameworks/base/services/jni)
      android_server_SystemServer_init1()//JNI 調用
      system_init() //System_init.cpp (frameworks/base/cmds/system_server/library)
      // Start the Su**ceFlinger
      Su**ceFlinger::instantiate();
      //Start the AudioFlinger media playbackcamera service
        AudioFlinger::instantiate();
        MediaPlayerService::instantiate();
        CameraService::instantiate();
        //調用 SystemServer 類的init2
        runtime->callStatic("com/android/server/SystemServer", "init2");
        init2()//SystemServer.java (frameworks/base/services/java/com/android/server)
        ServerThread()
        run()//在run中啓動電源管理,藍牙,等核心服務以及狀態,查找等其他服務
         ((ActivityManagerService)ServiceManager.getService("activity")).setWindowManager(wm);
         ...
         ActivityManagerNative.getDefault().systemReady();   
runSelectLoopMode();
  done = peers.get(index).runOnce();
  forkAndSpecialize() //Zygote.java (dalvik/libcore/dalvik/src/main/java/dalvik/system)
  Dalvik_dalvik_system_Zygote_forkAndSpecialize() //dalvik_system_Zygote.c (dalvik/vm/native)
    forkAndSpecializeCommon()  
    setSignalHandler()
    RETURN_INT(pid);      
closeServerSocket();
見附A
主進程runSelectLoopMode()
5.Runs the zygote process's select loop runSelectLoopMode(), Accepts new connections as they happen, and
reads commands from connections one spawn-request's worth at a time.
如果運行正常,則zygote進程會在runSelectLoopMode()中循環:
zygote 被siganl(11)終止
在dalvik_system_Zygote.c (dalvik/vm/native)
的 static void sigchldHandler(int s) 函數中打印:   
" rocess %d terminated by signal (%d)/n",
"Exit zygote because system server (%d) has terminated/n",
startSystemServer() ZygoteInit.java (frameworks/base/core/java/com/android/internal/os)
SystemServer 的mian()函數會調用
SystemServer.java (frameworks/base/services/java/com/android/server)中的 init1()函數。
init1()實際執行的是com_android_server_SystemServer.cpp (frameworks/base/services/jni)
中的 android_server_SystemServer_init1()。
android_server_SystemServer_init1()調用的是
System_init.cpp (frameworks/base/cmds/system_server/library) 中的 system_init()函數
system_init()函數定義如下:
extern "C" status_t system_init()
{
  ...
  sp sm = defaultServiceManager();
  ...
  property_get("system_init.startsu**ceflinger", propBuf, "1");
  if (strcmp(propBuf, "1") == 0) {
  //讀取屬性服務器,開啓啓動 Su**ceFlinger服務
  //接着會開始顯示機器人圖標
  //BootAnimation.cpp (frameworks/base/libs/su**ceflinger):status_t BootAnimation::readyToRun()
  Su**ceFlinger::instantiate();
  }
  //在模擬器上 audioflinger 等幾個服務與設備上的啓動過程不一樣,所以
  //我們在這裏啓動他們。
  if (!proc->supportsProcesses()) {
  //啓動 AudioFlinger,media playback service,camera service服務
  AudioFlinger::instantiate();
  MediaPlayerService::instantiate();
  CameraService::instantiate();
  }
  //現在開始運行 the Android runtime ,我們這樣做的目的是因爲必須在 core system services
  //起來以後才能 Android runtime initialization,其他服務在調用他們自己的main()時,都會
  //調用 Android runtime
  //before calling the init function.
  LOGI("System server: starting Android runtime./n");
  AndroidRuntime* runtime = AndroidRuntime::getRuntime();
  LOGI("System server: starting Android services./n");
  //調用 SystemServer.java (frameworks/base/services/java/com/android/server)
  //中的init2函數
  runtime->callStatic("com/android/server/SystemServer", "init2");
   
  // If running in our own process, just go into the thread
  // pool.Otherwise, call the initialization finished
  // func to let this process continue its initilization.
  if (proc->supportsProcesses()) {
  LOGI("System server: entering thread pool./n");
  ProcessState::self()->startThreadPool();
  IPCThreadState::self()->joinThreadPool();
  LOGI("System server: exiting thread pool./n");
  }
  return NO_ERROR;
}
System server: entering thread pool 表明已經進入服務線程 ServerThread
在 ServerThread 類的run 服務中開啓核心服務:
  @Override
  public void run() {
  EventLog.writeEvent(LOG_BOOT_PROGRESS_SYSTEM_RUN,
    SystemClock.uptimeMillis());
  ActivityManagerService.prepareTraceFile(false); // create dir
  Looper.prepare();
  //設置線程的優先級
  android.os.Process.setThreadPriority(
      android.os.Process.THREAD_PRIORITY_FOREGROUND);
  ...
  //關鍵(核心)服務
  try {
    Log.i(TAG, "Starting Power Manager.");
    Log.i(TAG, "Starting activity Manager.");
    Log.i(TAG, "Starting telephony registry");
    Log.i(TAG, "Starting Package Manager.");
    Log.i(TAG, "tarting Content Manager.");
    Log.i(TAG, "Starting System Content Providers.");
    Log.i(TAG, "Starting Battery Service.");
    Log.i(TAG, "Starting Alarm Manager.");
    Log.i(TAG, "Starting Sensor Service.");
    Log.i(TAG, "Starting Window Manager.");
    Log.i(TAG, "Starting Bluetooth Service.");
    //如果是模擬器,那麼跳過藍牙服務。
    // Skip Bluetooth if we have an emulator kernel
   //其他的服務
    Log.i(TAG, "Starting Status Bar Service.");
    Log.i(TAG, "Starting Clipboard Service.");
    Log.i(TAG, "Starting Input Method Service.");
    Log.i(TAG, "Starting Hardware Service.");
    Log.i(TAG, "Starting NetStat Service.");
    Log.i(TAG, "Starting Connectivity Service.");
    Log.i(TAG, "Starting Notification Manager.");
    // MountService must start after NotificationManagerService
    Log.i(TAG, "Starting Mount Service.");
  Log.i(TAG, "Starting DeviceStorageMonitor service");
    Log.i(TAG, "Starting Location Manager.");
    Log.i(TAG, "Starting Search Service.");
    ...
    if (INCLUDE_DEMO) {
      Log.i(TAG, "Installing demo data...");
      (new DemoThread(context)).start();
    }
    try {
      Log.i(TAG, "Starting Checkin Service.");
      Intent intent = new Intent().setComponent(new ComponentName(
        "com.google.android.server.checkin",
        "com.google.android.server.checkin.CheckinService"));
      if (context.startService(intent) == null) {
      Log.w(TAG, "Using fallback Checkin Service.");
      ServiceManager.addService("checkin", new FallbackCheckinService(context));
      }
    } catch (Throwable e) {
      Log.e(TAG, "Failure starting Checkin Service", e);
    }
    Log.i(TAG, "Starting Wallpaper Service");
  Log.i(TAG, "Starting Audio Service");
    Log.i(TAG, "Starting HeadsetObserver");
    Log.i(TAG, "Starting AppWidget Service");
  ...
    try {
      com.android.server.status.StatusBarPolicy.installIcons(context, statusBar);
    } catch (Throwable e) {
      Log.e(TAG, "Failure installing status bar icons", e);
    }
  }
  // make sure the ADB_ENABLED setting value matches the secure property value
  Settings.Secure.putInt(mContentResolver, Settings.Secure.ADB_ENABLED,
      "1".equals(SystemProperties.get("persist.service.adb.enable")) ? 1 : 0);
  // register observer to listen for settings changes
  mContentResolver.registerContentObserver(Settings.Secure.getUriFor(Settings.Secure.ADB_ENABLED),
      false, new AdbSettingsObserver());
  // It is now time to start up the app processes...
  boolean safeMode = wm.detectSafeMode();
  if (statusBar != null) {
    statusBar.systemReady();
  }
  if (imm != null) {
    imm.systemReady();
  }
  wm.systemReady();
  power.systemReady();
  try {
    pm.systemReady();
  } catch (RemoteException e) {
  }
  if (appWidget != null) {
    appWidget.systemReady(safeMode);
  }
  // After making the following code, third party code may be running...
  try {
    ActivityManagerNative.getDefault().systemReady();
  } catch (RemoteException e) {
  }
  Watchdog.getInstance().start();
  Looper.loop();
  Log.d(TAG, "System ServerThread is exiting!");
  }
startActivity()
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);

ActivityManagerService.java 3136p (frameworks/base/services/java/com/android/server/am)
startActivity()
  startActivityLocked() //3184
  int res = startActivityLocked(caller, intent, resolvedType,grantedUriPermissions, grantedMode, aInfo,
      resultTo, resultWho, requestCode, -1, -1,
      onlyIfNeeded, componentSpecified);
public abstract class ActivityManagerNative extends Binder implements IActivityManager
ActivityManagerService.java 1071p(frameworks/base/services/java/com/android/server/am)
ActivityManagerService.main()
//ActivityManagerService.java 7375p (frameworks/base/services/java/com/android/server/am)
m.startRunning(null, null, null, null);
  //ActivityManagerService.java 7421p (frameworks/base/services/java/com/android/server/am)
  systemReady();
ActivityManagerService.java 3136p (frameworks/base/services/java/com/android/server/am)
startActivity(IApplicationThread caller,Intent intent,...)
  int startActivityLocked(caller, intent,...)  //3184L 定義:2691L
  void startActivityLocked()   //3132L 定義:2445L
  resumeTopActivityLocked(null); //2562p 定義:2176L
  if(next=NULL)
  {
    intent.addCategory(Intent.CATEGORY_HOME);
    startActivityLocked(null, intent, null, null, 0, aInfo,null, null, 0, 0, 0, false, false);
  }
  else
  {
    startSpecificActivityLocked(next, true, false); //2439L 定義:1628L
    realStartActivityLocked() //1640L  定義:1524L
    //1651L 定義:1654L
    startProcessLocked(r.processName, r.info.applicationInfo, true, 0,"activity", r.intent.getComponent());
    //1717L 定義:1721L
    startProcessLocked(app, hostingType, hostingNameStr);
      //1768L定義:Process.java 222L(frameworks/base/core/java/android/os)
      int pid = Process.start("android.app.ActivityThread",...)
      startViaZygote(processClass, niceName, uid, gid, gids,debugFlags, zygoteArgs);
      pid = zygoteSendArgsAndGetPid(argsForZygote);
        sZygoteWriter.write(Integer.toString(args.size()));
  }

runSelectLoopMode();
  done = peers.get(index).runOnce();
  forkAndSpecialize() //Zygote.java (dalvik/libcore/dalvik/src/main/java/dalvik/system)
  Dalvik_dalvik_system_Zygote_forkAndSpecialize() //dalvik_system_Zygote.c (dalvik/vm/native)
    forkAndSpecializeCommon()  
    setSignalHandler()
    RETURN_INT(pid);
   
   ActivityThread main()
   ActivityThread attach() //ActivityThread.java 3870p (frameworks/base/core/java/android/app)
   mgr.attachApplication(mAppThread)
   //ActivityManagerService.java 4677p (frameworks/base/services/java/com/android/server/am)
   attachApplication()
     //ActivityManagerService.java 4677p (frameworks/base/services/java/com/android/server/am)
     attachApplicationLocked()
     if (realStartActivityLocked(hr, app, true, true)) //ActivityManagerService.java 4609p
                       //(frameworks/base/services/java/com/android/server/am)
     realStartActivityLocked()
     //ActivityManagerService.java (frameworks/base/services/java/com/android/server/am)
     app.thread.scheduleLaunchActivity(new Intent(r.intent), r,r.info, r.icicle, results, newIntents, /
      !andResume,isNextTransitionForward());
     scheduleLaunchActivity()
       queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
       ActivityThread.H.handleMessage()
       handleLaunchActivity()  //ActivityThread.java (frameworks/base/core/java/android/app)
         performLaunchActivity() //ActivityThread.java (frameworks/base/core/java/android/app)
         activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);

     
/////////////////////////////////////////////////   
init 守護進程:
//andriod init 函數啓動過程分析:
在main循環中會重複調用
drain_action_queue();
restart_processes();
static void restart_processes()
{
  process_needs_restart = 0;
  service_for_each_flags(SVC_RESTARTING,
         restart_service_if_needed);
}
通過循環檢測服務列表service_list 中每個服務的 svc->flags 標記,如果爲 SVC_RESTARTING,
那麼在滿足條件的情況下調用:restart_service_if_needed
通過 service_start 來再次啓動該服務。
ActivityManagerService.main
I/SystemServer( 45): Starting Power Manager.
I/ServiceManager( 26): service 'Su**ceFlinger' died
D/Zygote( 30): Process 45 terminated by signal (11)
I/Zygote( 30): Exit zygote because system server (45) has terminated
通過錯誤信息發現程序在調用 Su**ceFlinger服務的時候被中止。
Service_manager.c (frameworks/base/cmds/servicemanager):
LOGI("service '%s' died/n", str8(si->name));
Binder.c (frameworks/base/cmds/servicemanager):
death->func(bs, death->ptr);
Binder.c (kernel/drivers/misc)中的函數
binder_thread_read()
struct binder_work *w;
switch (w->type)
爲 BINDER_WORK_DEAD_BINDER 的時候
binder_parse()中
當 cmd 爲 BR_DEAD_BINDER的時候
執行 death->func(bs, death->ptr)
因爲函數
int do_add_service(struct binder_state *bs,
       uint16_t *s, unsigned len,
       void *ptr, unsigned uid)
的 si->death.func = svcinfo_death;
所以 death->func(bs, death->ptr) 實際上執行的是
svcinfo_death()//Service_manager.c (frameworks/base/cmds/servicemanager)
================================================
=================================================
7. linux下svn使用指南
1.1 服務器端配置說明
1.1.3 配置用戶和權限
1.1.4 導入工程到倉庫中
1.2 客戶端操作指南及使用規範
1.2.1 檢出工作拷貝
1.2.2 svn update 更新別人做的更改
1.2.2.1 svn update 獲取最新版本
1.2.2.2 svn update-r 獲取特定的版本
1.2.3 svn st 查看文件狀態信息
1.2.4 svn log 查看log信息
1.2.5 svn diff 查看文件修改詳情
1.2.6 svn list 顯示版本庫的文件列表
1.2.8 svn add 增加目錄或者文件
1.2.9 svn delete 刪除目錄或者文件
1.2.10 svn revert 取消本地修改
1.2.11 svn commit 提交本地做的更改
1.2.12 文件更新,提交時的衝突處理
1.2.13 打標籤
1.2.14 清除緩存的認證信息,重新輸入用戶名和密碼
=================
1.1 服務器端配置說明
1.1.1 ubuntu-8.10 svn服務器安裝
sudo apt-get install subversion
1.1.2 建立版本庫(Repository)
運行Subversion服務器需要首先要建立一個版本庫(Repository),可以看作服務器上存放數據的數據庫,在安裝了Subversion服務器之後,可以直接運行
cd path_to_svn_root例如:/home/svn
svnadmin create --fs-type=fsfssmartphone
--fs-type 指定倉庫類型,可以爲fsfs或bdb 如果沒有指定默認創建爲fsfs類型smartphone爲倉庫名稱
1.1.3 配置用戶和權限
修改 path_to_svn_repos/conf/svnserve.conf 文件,打開下面配置項
---------------------------
#anon-access = read
anon-access = none
auth-access = write
password-db = passwd
authz-db = authz
anon-access 應設置等於 none ,否則沒有log信息
修改path_to_svn_repos/conf/passwd 文件,添加用戶和密碼
----------------------------
[users]
wanghui=wanghui

1.1.4 導入工程到倉庫中
svn importsmartphone/svn://192.168.2.148/smartphone
1.1.5 運行svn服務器
svnserve -d -rpath_to_svn_root例如:/home/svn
1.2 客戶端操作指南及使用規範
以我們服務器上 android 源代碼爲例,介紹svn常用操作。
1.2.1 檢出工作拷貝
檢出工作拷貝到 ~/svn/cupcake-jiangping
使用svn co url
cd ~/svn
svn co svn://192.168.2.148/smartphone/td0901/trunk/cupcake-jianpingcupcake-jianping
1.2.2 svn update 更新別人做的更改
1.2.2.1 svn update 獲取最新版本
svn update cupcake-jiangping
或者進入目錄更新
cd cupcake-jiangping
svn update
如果負責的應用與系統的關聯性不是很大,通常不建議頻繁進行更新。
1.2.2.2 svn update-r 獲取特定的版本
直接在某目錄下執行 svn update 獲取當前目錄下所有文件的最新版本,如果我們只需要獲取某個文件或者目錄的特定版本,可以通過-r 和 名稱進行指定:
svn update –r 5cupcake-jianping/packages/apps/Phone/src/com/android/phone/xxxx.java
1.2.3 svn st 查看文件狀態信息
Mcupcake-jianping/packages/apps/Phone/src/com/android/phone/xxxx.java
?cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java
M表明文件已經有修改
? 表明文件沒有受版本控制
1.2.4 svn log 查看log信息
svn log -r  查看所有版本的log信息
svn log -r 5  查看某一版本的log信息
svn log -r 5:19 查看某區間一系列版本的log信息
如果要查看log的詳細信息可以加上 –v 選項,如:
svn log –v -r 5
1.2.5 svn diff 查看文件修改詳情
顯示單個文件或者某目錄下所有文件的修改詳情
svn diff有三種不同的用法
1. 檢查本地修改
2. 比較工作拷貝與版本庫
3. 比較版本庫與版本庫
不使用任何參數調用時,svn diff將會比較你的工作文件與緩存在.svn的“原始”拷貝,如:
svn diff cupcake-jianping/packages/apps/Phone
svn diff cupcake-jianping/packages/apps/Phone/src/com/android/phone/zzzz.java
如果傳遞一個—revision –r 參數,你的工作拷貝會與指定的版本比較。
svn diff -r 3 cupcake-jianping/packages/apps/Phone
如果通過--revision –r 傳遞兩個通過冒號分開的版本號,這兩個版本會進行比較。
svn diff -r 2:3 cupcake-jianping/packages/apps/Phone
如果你在本機沒有工作拷貝,還是可以比較版本庫的修訂版本,只需要在命令行中輸入合適的URL:
svn diff -r 33 svn://192.168.2.148/smartphone/td0901/trunk/cupcake-jianping/packages/apps/Phone
1.2.6 svn list 顯示版本庫的文件列表
svn list svn://192.168.2.148/smartphone/td0901
design/
hedoc/
pm/
release/
tag/
trunk/
svn list svn://192.168.2.148/smartphone/td0901/trunk
3src/
boot-a1/
cupcake-jianping/
linux-2.6.28-a1/
svn list 類似本機的ls命令,它查看的是服務器端的目錄結構。
1.2.7 svn info 查看版本庫信息
cd ~/svn/cupcake-jianping
svn infos
路徑: .
URL: svn://192.168.2.148/smartphone/td0901/trunk/cupcake-jianping
版本庫根: svn://192.168.2.148/smartphone
版本庫 UUID: 1fac82c5-1665-442c-a8d6-2b3dd850438a
版本: 146
節點種類: 目錄
調度: 正常
最後修改的作者: tangligang
最後修改的版本: 145
最後修改的時間: 2009-07-31 15:40:50 +0800 (五, 2009-07-31)
1.2.8 svn add 增加目錄或者文件
svn add cupcake-jianping/packages/apps/Phone/src/com/android/phone/xxxx
svn add cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java
1.2.9 svn delete 刪除目錄或者文件
svn delete cupcake-jianping/packages/apps/Phone/src/com/android/phone/xxxx
svn delete cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java
在進行刪除操作的時候要非常小心,假設我們要添加一個文件:
cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java
但是在提交之前我們發現並不需要這個文件,這時候我們經常通過 svn delete 來撤銷之前添加的文件:
svn delete cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java
這樣操作的後果往往導致本地的文件yyyy.java 被誤刪除掉,所以我們正確的做法是:
svnn delete cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java –keep-local
1.2.10 svn revert 取消本地修改
1.當你發現對某個文件的所有修改都是錯誤的,或許你根本不應該修改這個文件,或者是從開頭重新修改會更加容易的時候可以用這個命令。
2.通過svn add 添加了一個項目,如果想取消可以通過該命令。
1.2.11 svn commit 提交本地做的更改
通常只對自己負責的模塊進行提交,如果負責電話模塊,那麼提交命令如下:
svn commit cupcake-jiangping/packages/apps/Phone
在提交之前建議用命令:
svn st cupcake-jiangping/packages/apps/Phone 查看狀態
M cupcake-jianping/packages/apps/Phone/src/com/android/phone/xxxx.java
?cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java
M表明文件已經有修改
? 表明文件沒有受版本控制
1. 如果有 “?”存在,並且該文件或者目錄是自己添加並且是工程的一部分,那麼在提交之前必須先執行svn add 操作:svn add cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java ;
2. 提交之前也必須解決衝突,否則會提交失敗。
3. 提交之前必須寫log
1.2.12 文件更新,提交時的衝突處理
$ svn update
Uxxxx
Gyyyy
Cxxxx.c
1. 更新的時候如果前面的狀態爲:C 表示有衝突存在。
2. 工作拷貝里做過修改,且服務器版本庫在修改前工作拷貝的版本後被提交過其他修改;那麼svn commit首先會失敗並要求update,此時便會出現版本衝突的情況。
當你Update出現了衝突時,Subversion會產生三個文件
filename.mine :你更新前的文件,沒有衝突標誌,只是你最新更改的內容。
Filename.roldrev:就是你在上次更新之後未作更改的版本。
Filename.rnewrev:客戶端從服務器剛剛收到的版本,這個文件對應版本庫的HEAD版本。
衝突的文件內容,在衝突的地方將被使用“>>>>”標誌出來,用戶自己進行合併的取捨。
解決衝突之後,svn resolved path_to_name,Subversion刪除衝突所產生三個文件刪除,此時你纔可以進行提交。( 也可以手動刪除此三個文件。)
1.2.13 打標籤
svn 的標籤是通過copy命令完成,但是操作的路徑必須是服務器的路徑,打標籤實際上類似於創建一個到特定版本的鏈接,如:
svn cp svn://192.168.2.148/smartphone/td0901/trunk/cupcake-jianping/
svn://192.168.2.148/smartphone/td0901/tags/cupcake-1.0.6
如果 svn://192.168.2.148/smartphone/td0901/trunk/cupcake-jianping 的當前版本爲 5 ,/
那麼 svn://192.168.2.148/smartphone/td0901/tags/cupcake-1.0.6 實際 /
上就是 svn://192.168.2.148/smartphone/td0901/trunk/cupcake-jianping 版本5的一個標籤。
1.2.14 清除緩存的認證信息,重新輸入用戶名和密碼
一個具有權限控制的 svn 版本庫在第一次 checkout 工作拷貝的時候會要求輸入用戶名和密碼:
認證領域:176512f1-51ee-4947-8c07-88c90ab77ac5
“$USER”的密碼:
認證領域:d3216b51-7915-4881-bf30-02e0672c61cd
用戶名: xxxxx
“xxxxx”的密碼:
這些信息被緩存在 ~/.subversion/auth/svn.simple/ 如果需要更換另一個用戶登錄,必須先清除緩存的認證信息:
rm ~/.subversion/auth/svn.simple/* -rf
1.3 爲規避風險,建議遵守以下規範
1.3.1 提交前審查修改情況, 用命令svn status瀏覽所做的修改,svn diff檢查修改的詳細信息
1.3.2 提交時,必須填寫註釋,註釋內容清晰描述本次提交內容,變動信息。
1.3.3 做較大修改時,和項目組其他同事的工作相關時,必須通知對方。
1.3.4 納入版本控制的項目必須定期提交,至少一週提交一次,避免意外事故導致代碼丟失。
1.3.5 每次提交後,必須確認工程可正常運行,即SVN裏保存的是可以正確運行的代碼,否則恢復至穩定版本。
1.3.6 編譯過程動態產生的東西不要提交到服務器
1.3.7 每次提交前先更新,這樣能在提交前發現是否和別人的衝突
filelist=`find ./ -name "*.conf"`;svn add $filelist; svn commit$filelist
filelist=`find ./ -name "*.conf"`;svn delete $filelist --force --keep-local
=================================================
================================================
8. LFS 相關
7.1 lfs 相關資源
7.2 LFS問題解答
=========
LFS──Linux from Scratch,就是一種從網上直接下載源碼,從頭編譯LINUX的安裝方式。它不是發行版,只是一個菜譜,
告訴你到哪裏去買菜(下載源碼),怎麼把這些生東西( raw code) 作成符合自己口味的菜餚──個性化的linux,不單單是
個性的桌面。
LFS 有什麼優勢呢?現在看來,它可以提供最快和最小的 Linux。但是最大的優勢就是,安裝LFS是菜鳥變成高手的捷徑。
第一次安裝,需要按照LFS文檔安裝,如果在此期間所有文檔內容你都認真的閱讀,保證你受益匪淺;然後發現很多地方可以
不按照別人的老路操作,這個時候用自己的方式參考第一次安裝的經驗,再一次建立linux,完成的時候,你會發現你在 LinuxSir.Org
上已經再也不是菜鳥了。
7.1 lfs 相關資源
官方網站:
http://www.linuxfromscratch.org/
lfs中文網站
http://lfs.linuxsir.org/main/
Linux From Scratch版本 6.2
http://lamp.linux.gov.cn/Linux/LFS-6.2/index.html
Linux From Scratch 版本 6.4
http://www.bitctp.org/lfsbook-6.4/index.html
Linux 發行版 LFS 討論區
http://www.linuxsir.org/bbs/forumdisplay.php?f=58
7.2 LFS問題解答
構建LFS的過程中遇到一些問題,總體來說還算順利,但是還有一些不明白的地方,這裏總結一下:
1./etc/fstab是否在開機就執行,是被誰調用執行的。
2.爲什麼系統啓動之後就要自動掛載/proc 和/sys,這兩個目錄有什麼作用;devpts和tmpfs有什麼作用。
參考章節:文件系統概述
3.關於文件系統:按照我的理解,文件系統是內核提供支持的,可以看作是一種協議,提供一種數據組織方式,每個設備必須有自己的文件系統。
不同文件系統的存儲設備的數據組織形式不同。mke2fs -jv /dev/默認在上面創建EXT3的文件系統嗎?既然這樣的話爲什麼
我們還需要把以ext3掛載到一個目錄呢?如果不是 的話,又是創建什麼文件系統呢?爲什麼第六章中掛載了虛擬內核文件系統之後才能
進入chroot環境呢?
參考章節:文件系統概述
4.虛擬文件系統.作用.什麼?
虛擬內核文件系統(Virtual Kernel File Systems),是指那些是由內核產生但並不存在於硬盤上(存在於內存中)的文件系統,他們
被用來與內核進行通信。
5.符號鏈接 和硬鏈接的區別是什麼?什麼是符號鏈接?什麼是硬鏈接?爲什麼liinux上都使用符號鏈接,而不是硬鏈接?linux上很多地方
使用了鏈接,是爲了組織清晰系統的結構和節省空間嗎?
硬連接和軟連接的區別, 硬連接和複製的區別?
硬連接記錄的是目標的 inode;軟連接記錄的是目標的 path。
hard link 由於 inode 的緣故,只能在本分區中做 link;soft link 可以做跨分區的 link。硬連接因爲記錄的是 inode,所以不怕改名,
比如ln aaa bbb, mv aaa ccc, 這時 bbb 仍然可以訪問;soft-link 就不行:source 的名字改變後,所有鏈接到這裏的 soft-link
全部變爲 broken。事實上,即使所有指向該 inode 的 hard-link 的文件名都變了,每一個仍然都可以訪問。我想這是它最大的優點吧。
硬連接和複製的區別:
幾個硬連接=幾個名字的同一個房子,這些名字可以相同或不同但地址(i-node)是一樣的, 所以硬連接被刪除只是把相應名字抹去,只有最
後一個名字被抹去你纔會找不到房子;而複製是建造一個一模一樣的房子,當然地址(i-node)就不同的了。
6.工作平臺中由Glibc提供的動態連接器與Binutils裏面的標準連接器有什麼區別?
參考章節: 鏈接器和加載器
7.$LFS/tools 目錄的所有者是僅存在於宿主環境中的 lfs 用戶。如果保留 $LFS/tools 目錄,那麼該目錄內文件的所有者的 user ID 就
沒有對應的賬號 ?爲什麼沒有帳戶,難道不是LFS?
查看 /etc/password /etc/group兩個文件 分別記錄 用戶和組的信息
如果用戶名和用戶ID 組名和組ID 的對應關係分別存在上面兩個文件中,那麼ls -ls 的時候就可以查看到用戶信息,而不再是ID等數字信息
8.系統的環境變量保存在哪個文件?
保存在tty中
9。配置參數腳本時[alias1] [alias2 ...]什麼時候用到?
別名的意思
alias ls='ls --color=auto'
/etc/skel/.bashrc:81:  #alias dir='dir --color=auto'
/etc/skel/.bashrc:82:  #alias vdir='vdir --color=auto'
/etc/skel/.bashrc:84:  #alias grep='grep --color=auto'
/etc/skel/.bashrc:85:  #alias fgrep='fgrep --color=auto'
/etc/skel/.bashrc:86:  #alias egrep='egrep --color=auto'
/etc/skel/.bashrc:89:# some more ls aliases
/etc/skel/.bashrc:90:#alias ll='ls -l'
/etc/skel/.bashrc:91:#alias la='ls -A'
/etc/skel/.bashrc:92:#alias l='ls -CF'
alias mohuifu='ls -l'
========================
9. linux 內核的初步理解
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
編譯好的內核:===================================================
linux ,Android基礎知識總結
1. Android編譯系統分析
2. 文件系統分析
3. 製作交叉工具鏈
4. 軟件編譯常識
5. 設置模塊流程分析
6. linux系統啓動流程分析
7. linux下svn使用指南
8. LFS 相關
9. linux 內核的初步理解
====================================================
================
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 listsvn://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 ABSOLUTELY NO WARRANTY; read the GNU GPL for details.
This is free software, and you are welcome to redistribute it
under certain conditions; read the GNU GPL 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 OCAL_MODULE:= sh
./system/core/libcutils/Android.mk:71 OCAL_MODULE := libcutils
./system/core/cpio/Android.mk:9 OCAL_MODULE := mkbootfs
./system/core/mkbootimg/Android.mk:8 OCAL_MODULE := mkbootimg
./system/core/toolbox/Android.mk:61 OCAL_MODULE:= toolbox
./system/core/logcat/Android.mk:10 OCAL_MODULE:= logcat
./system/core/adb/Android.mk:65 OCAL_MODULE := adb
./system/core/adb/Android.mk:125 OCAL_MODULE := adbd
./system/core/init/Android.mk:20 OCAL_MODULE:= init
./system/core/vold/Android.mk:24 OCAL_MODULE:= vold
./system/core/mountd/Android.mk:13 OCAL_MODULE:= mountd
LOCAL_PACKAGE_NAME
Java 應用程序的名字用該變量定義
./packages/apps/Music/Android.mk:9 OCAL_PACKAGE_NAME := Music
./packages/apps/Browser/Android.mk:14 OCAL_PACKAGE_NAME := Browser
./packages/apps/Settings/Android.mk:8 OCAL_PACKAGE_NAME := Settings
./packages/apps/Stk/Android.mk:10 OCAL_PACKAGE_NAME := Stk
./packages/apps/Contacts/Android.mk:10 OCAL_PACKAGE_NAME := Contacts
./packages/apps/Mms/Android.mk:8 OCAL_PACKAGE_NAME := Mms
./packages/apps/Camera/Android.mk:8 OCAL_PACKAGE_NAME := Camera
./packages/apps/Phone/Android.mk:11 OCAL_PACKAGE_NAME := Phone
./packages/apps/VoiceDialer/Android.mk:8 OCAL_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 /
        $/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 RODUCT_NAME := littleton
vendor/marvell/littleton/littleton.mk:28 RODUCT_DEVICE := littleton
vendor/marvell/littleton/AndroidProducts.mk:13:    $(LOCAL_DIR)/littleton.mk
vendor/sample/products/sample_addon.mk:40 RODUCT_NAME := sample_addon
vendor/htc/dream-open/htc_dream.mk:6 RODUCT_NAME := htc_dream
./vendor/htc/dream-open/htc_dream.mk:7 RODUCT_DEVICE := dream-open
./vendor/htc/dream-open/AndroidProducts.mk:3:    $(LOCAL_DIR)/htc_dream.mk
build/target/product/generic.mk:26 RODUCT_NAME := generic
build/target/product/generic_with_google.mk:20 RODUCT_NAME := generic_with_google
build/target/product/min_dev.mk:6 RODUCT_NAME := min_dev
build/target/product/core.mk:2 RODUCT_NAME :=
build/target/product/sim.mk:7 RODUCT_NAME := sim
build/target/product/sdk.mk:37 RODUCT_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
lunchgeneric-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 OCAL_CFLAGS += -mabi=aapcs-linux
./vendor/marvell/external/alsa/alsa-tools/Mdroid.mk:8 OCAL_CFLAGS += -mabi=aapcs-linux
./vendor/marvell/littleton/libaudio/Mdroid.mk:22 OCAL_CPPFLAGS += -mabi=aapcs-linux
./external/wpa_supplicant/Android.mk:35 _CFLAGS += -mabi=aapcs-linux
./system/wlan/ti/sta_dk_4_0_4_32/CUDK/tiwlan_loader/Android.mk:88 OCAL_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 /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/ptsdevpts 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/rwtype 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/sda7on /boot type ext3 (rw,relatime)
/dev/sda11 on /home type ext3 (rw,relatime)
/dev/sdb5on /opt type ext3 (rw,relatime)
/dev/sda9on /usr/local type ext3 (rw,relatime)
/dev/sda1on /windows/c type vfat (rw,utf8,umask=007,gid=1000)
/dev/sda5on /windows/d type vfat (rw,utf8,umask=007,gid=1000)
/dev/sda6on /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 12K1013M 1%  /dev/shm
mount | grep tmpfs 顯示當前系統中的 tmpfs:
tmpfs on /lib/init/rw type tmpfs (rw,nosuid,mode=0755)
varrunon /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 AEMON=/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/nfsnfsroot=192.168.2.56:/nfsroot/rootfs
ip=192.168.2.188:192.168.2.56:192.168.2.56:255.255.255.0::eth0 n 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 n 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 n
console=ttyS1,115200 mem=128M init=/init android uart_dma=1"
`root=' 參數
此參數告訴內核啓動時以那個設備作爲根文件系統使用。我的pc根文件系統:
/dev/sda8    9614116 6522156 260358872% /
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 n
ip=192.168.2.175:192.168.2.56:192.168.2.201:255.255.255.0::eth0 n
-- 板子的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-separatedon to the assembler
-Wp,    Pass comma-separatedon to the preprocessor
-Wl,    Pass comma-separatedon to the linker
從工具鏈內建的規範中查看動態加載器
gcc -dumpspecs | grepdynamic-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 | grepdynamic-linker
/scratchbox/compilers/arm-softfloat-linux-gcc-3.4.4-glibc-2.3.5/bin/arm-softfloat-linux-gnu-gcc -dumpspecs | grepdynamic-linker
2. marvell 的工具鏈
/scratchbox/compilers/marvell-arm-linux-4.1.1/bin/arm-linux-gcc-dumpspecs | grepdynamic-linker
3. scrathbox 中工具鏈 host-gcc
/scratchbox/compilers/host-gcc/bin/host-gcc-dumpspecs | grepdynamic-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中應用程序使用的加載器
stringsout/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 = CommandsInte**ce.SERVICE_CLASS_VOICE +
      CommandsInte**ce.SERVICE_CLASS_DATA +
      CommandsInte**ce.SERVICE_CLASS_FAX;
mDesiredPinLocked = enabled;
phone.mCM.setFacilityLock(CommandsInte**ce.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.asInte**ce(
      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 = 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, 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 intset_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



重要的數據結構
兩個列表,一個隊列。
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 OPTION0x04
關鍵字  屬性   
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 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 []*
...
申請一個service結構體,然後掛接到service_list鏈表上,name 爲服務的名稱 pathname 爲執行的命令 argument
爲命令的參數。之後的 option 用來控制這個service結構體的屬性,parse_line_service 會對 service關鍵字後的
內容進行解析並填充到 service 結構中 ,當遇到下一個service或者on關鍵字的時候此service選項解析結束。
例如:
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
服務名稱爲:         zygote
啓動該服務執行的命令:     /system/bin/app_process
命令的參數:         -Xzygote /system/bin --zygote --start-system-server
socket zygote stream 666: 創建一個名爲:/dev/socket/zygote 的 socket ,類型爲:stream
當*.rc 文件解析完成以後:
action_list 列表項目如下:
on init
on boot
on property:ro.kernel.qemu=1
on property:persist.service.adb.enable=1
on property:persist.service.adb.enable=0
init.marvell.rc 文件
on early-init
on init
on early-boot
on boot
service_list 列表中的項有:
service console
service adbd
service servicemanager
service mountd
service debuggerd
service ril-daemon
service zygote
service media
service bootsound
service dbus
service hcid
service hfag
service hsag
service installd
service flash_recovery
設備初始化
early-init 初始化
初始化屬性服務器
在init.c 的main函數中啓動狀態服務器。
property_set_fd = start_property_service();
狀態讀取函數:
Property_service.c (system/core/init)
const char* property_get(const char *name)
Properties.c (system/core/libcutils)
int property_get(const char *key, char *value, const char *default_value)
狀態設置函數:
Property_service.c (system/core/init)
int property_set(const char *name, const char *value)
Properties.c (system/core/libcutils)
int property_set(const char *key, const char *value)
在終端模式下我們可以通過執行命令 setprop
setprop 工具源代碼所在文件: Setprop.c (system/core/toolbox)
Getprop.c (system/core/toolbox):  property_get(argv[1], value, default_value);
Property_service.c (system/core/init)
中定義的狀態讀取和設置函數僅供init進程調用,
handle_property_set_fd(property_set_fd);
property_set() //Property_service.c (system/core/init)
  property_changed(name, value) //Init.c (system/core/init)
  queue_property_triggers(name, value)
  drain_action_queue()
只要屬性一改變就會被觸發,然後執行相應的命令:
例如:
在init.rc 文件中有
on property:persist.service.adb.enable=1
start adbd
on property:persist.service.adb.enable=0
stop adbd
所以如果在終端下輸入:
setprop property:persist.service.adb.enable 1或者0
那麼將會開啓或者關閉adbd 程序。
執行action_list 中的命令:
從action_list 中取出 act->name 爲 early-init 的列表項,再調用 action_add_queue_tail(act)將其插入到
隊列 action_queue 尾部。drain_action_queue() 從action_list隊列中取出隊列項 ,然後執行act->commands
列表中的所有命令。
所以從./system/core/init/init.c mian()函數的程序片段:
action_for_each_trigger("early-init", action_add_queue_tail);
drain_action_queue();
action_for_each_trigger("init", action_add_queue_tail);
drain_action_queue();
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();
可以看出,在解析完init.rc init.marvell.rc 文件後,action 命令執行順序爲:
執行act->name 爲 early-init,act->commands列表中的所有命令
執行act->name 爲 init,    act->commands列表中的所有命令
執行act->name 爲 early-boot,act->commands列表中的所有命令
執行act->name 爲 boot,    act->commands列表中的所有命令
關鍵的幾個命令:
class_start default 啓動所有service 關鍵字定義的服務。
class_start 在act->name爲boot的 act->commands列表中,所以當 class_start 被觸發後,實際
上調用的是函數 do_class_start()
int do_class_start(int nargs, char **args)
{
  /* Starting a class does not start services
   * which are explicitly disabled.They must
   * be started individually.
   */
  service_for_each_class(args[1], service_start_if_not_disabled);
  return 0;
}
void service_for_each_class(const char *classname,
          void (*func)(struct service *svc))
{
  struct listnode *node;
  struct service *svc;
  list_for_each(node, &service_list) {
  svc = node_to_item(node, struct service, slist);
  if (!strcmp(svc->classname, classname)) {
    func(svc);
  }
  }
}
因爲在調用 parse_service() 添加服務列表的時候,所有服務 svc->classname 默認取值:"default",
所以 service_list 中的所有服務將會被執行。
參考文檔:
http://blog.chinaunix.net/u1/38994/showart_1775465.html
http://blog.chinaunix.net/u1/38994/showart_1168440.html
淺析kernel啓動的第1個用戶進程init如何解讀init.rc腳本
http://blog.chinaunix.net/u1/38994/showart_1168440.html
Zygote 服務概論:
Zygote 是android 系統中最重要的一個服務,它將一步一步完成下面的任務:
start Android Java Runtime and start system server. It’s the most important service. The source is in device/servers/app.
1. 創建JAVA 虛擬機
2. 爲JAVA 虛擬機註冊android 本地函數
3. 調用 com.android.internal.os.ZygoteInit 類中的main函數,android/com/android/internal/os/ZygoteInit.java.
a) 裝載ZygoteInit類
b) 註冊zygote socket
c) 裝載preload classes(the default file is device/java/android/preloaded-classes)
d) 裝載Load preload 資源
e) 調用 Zygote::forkSystemServer (定義在./dalvik/vm/InternalNative.c)來fork一個新的進程,在新進程中調用
com.android.server.SystemServer 的main函數。
a) 裝載 libandroid_servers.so庫
bb) 調用JNI native init1 函數 (device/libs/android_servers/com_android_server_SystemServers)
Load libandroid_servers.so
Call JNI native init1 function implemented in device/libs/android_servers/com_android_server_SystemServers.
It only calls system_init implemented in device/servers/system/library/system_init.cpp.
If running on simulator, instantiate AudioFlinger, MediaPlayerService and CameraService here.
Call init2 function in JAVA class named com.android.server.SystemServer, whose source is in
device/java/services/com/android/server. This function is very critical for Android because it start all of
Android JAVA services.
If not running on simulator, call IPCThreadState::self()->joinThreadPool() to enter into service dispatcher.
SystemServer::init2 將會啓動一個新的線程來啓動下面的所有JAVA服務:
Core 服務:
1.Starting Power Manager(電源管理)
2.Creating Activity Manager(活動服務)
3.Starting Telephony Registry(電話註冊服務)
4.Starting Package Manager(包管理器)
5.Set Activity Manager Service as System Process
6.Starting Context Manager
7.Starting System Context Providers
8.Starting Battery Service(電池服務)
9.Starting Alarm Manager(鬧鐘服務)
10. Starting Sensor Service
11. Starting Window Manager(啓動窗口管理器)
12. Starting Bluetooth Service(藍牙服務)
13. Starting Mount Service
其他services:
1.Starting Status Bar Service(狀態服務)
2.Starting Hardware Service(硬件服務)
3.Starting NetStat Service(網絡狀態服務)
4.Starting Connectivity Service
5.Starting Notification Manager
6.Starting DeviceStorageMonitor Service
7.Starting Location Manager
8.Starting Search Service(查詢服務)
9.Starting Clipboard Service
10. Starting Checkin Service
11. Starting Wallpaper Service
12. Starting Audio Service
13. Starting HeadsetObserver
14. Starting AdbSettingsObserver
最後SystemServer::init2 將會調用 ActivityManagerService.systemReady 通過發送
Intent.CATEGORY_HOME intent來啓動第一個 activity.還有另外一種啓動system server的方法是:
通過名爲 system_server的程序(源代碼:device/servers/system/system_main.cpp)它也是通過
調用 system_init 來啓動 system services,這時候就有個問題:爲什麼android 有兩種方式啓動system services?
我的猜想是:
My guess is that directly start system_server may have synchronous problem with zygote because
system_server will call JNI to start SystemServer::init2, while at that time zygote may not start
JAVA VM yet. So Android uses another method. After zynote is initialized, fork a new process to
start system services.
Zygote服務啓動的詳細過程:
通過啓動服務列表的 app_process 進程,實際上進入的是
App_main.cpp (frameworks/base/cmds/app_process)
main()
根據 init.rc 中的 --zygote --start-system-server
分別調用的是
runtime.start("com.android.internal.os.ZygoteInit",startSystemServer);
或者
runtime.start();
start()函數在 AndroidRuntime.cpp (frameworks/base/core/jni)文件中
從打印信息:
D/AndroidRuntime( 56): >>>>>>>>>>>>>> AndroidRuntime START GetStaticMethodID(startClass, "main","([Ljava/lang/String;)V");
從上面的調用可以看出一類引用的過程都是從 main方法
所以接着調用了 ZygoteInit 類的main方法
main方法主要完成:
1.Register zygote socket, Registers a server socket for zygote command connections
2.Load preload classes(the default file is device/java/android/preloaded-classes).
3.Load preload resources, Load in commonly used resources, so they can be shared across processes.
4.Start SystemServer, Prepare the arguments and fork for the system server process.
具體執行過程如下:
ZygoteInit.java (frameworks/base/core/java/com/android/internal/os)中的mian
main()
registerZygoteSocket()
preloadClasses()
  loadLibrary()
  Log.i(TAG, " reloading classes...");
  Runtime.loadLibrary
  Dalvik_java_lang_Runtime_nativeLoad()
  dvmLoadNativeCode()
    LOGD("Trying to load lib %s %p/n", pathName, classLoader);
    System.loadLibrary("media_jni");
preloadResources();
startSystemServer()
  Zygote.forkSystemServer(parsedArgs.uid, parsedArgs.gid,parsedArgs.gids, debugFlags, null);
  //Zygote.java (dalvik/libcore/dalvik/src/main/java/dalvik/system)
  forkSystemServer()
  forkAndSpecialize() //Zygote.java (dalvik/libcore/dalvik/src/main/java/dalvik/system)
    Dalvik_dalvik_system_Zygote_forkAndSpecialize() //dalvik_system_Zygote.c (dalvik/vm/native)
    Dalvik_dalvik_system_Zygote_forkAndSpecialize()
    setSignalHandler()
    fork()
  handleSystemServerProcess() //handleChildProc(parsedArgs, descriptors, newStderr);
  closeServerSocket();
  RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
  zygoteInit()   //RuntimeInit.java (frameworks/base/core/java/com/android/internal/os)
    zygoteInitNative()
    invokeStaticMain()
    System.loadLibrary("android_servers");
    //com.android.server.SystemServer startSystemServer() 函數中
    m = cl.getMethod("main", new Class[] { String[].class });
      //執行的是SystemServer 類的main函數 SystemServer.java (frameworks/base/services/java/com/android/server)
      init1() //SystemServer.java (frameworks/base/services/java/com/android/server)     
      //init1()實際上是調用android_server_SystemServer_init1(JNIEnv* env, jobject clazz)
      //com_android_server_SystemServer.cpp (frameworks/base/services/jni)
      android_server_SystemServer_init1()//JNI 調用
      system_init() //System_init.cpp (frameworks/base/cmds/system_server/library)
      // Start the Su**ceFlinger
      Su**ceFlinger::instantiate();
      //Start the AudioFlinger media playbackcamera service
        AudioFlinger::instantiate();
        MediaPlayerService::instantiate();
        CameraService::instantiate();
        //調用 SystemServer 類的init2
        runtime->callStatic("com/android/server/SystemServer", "init2");
        init2()//SystemServer.java (frameworks/base/services/java/com/android/server)
        ServerThread()
        run()//在run中啓動電源管理,藍牙,等核心服務以及狀態,查找等其他服務
         ((ActivityManagerService)ServiceManager.getService("activity")).setWindowManager(wm);
         ...
         ActivityManagerNative.getDefault().systemReady();   
runSelectLoopMode();
  done = peers.get(index).runOnce();
  forkAndSpecialize() //Zygote.java (dalvik/libcore/dalvik/src/main/java/dalvik/system)
  Dalvik_dalvik_system_Zygote_forkAndSpecialize() //dalvik_system_Zygote.c (dalvik/vm/native)
    forkAndSpecializeCommon()  
    setSignalHandler()
    RETURN_INT(pid);      
closeServerSocket();
見附A
主進程runSelectLoopMode()
5.Runs the zygote process's select loop runSelectLoopMode(), Accepts new connections as they happen, and
reads commands from connections one spawn-request's worth at a time.
如果運行正常,則zygote進程會在runSelectLoopMode()中循環:
zygote 被siganl(11)終止
在dalvik_system_Zygote.c (dalvik/vm/native)
的 static void sigchldHandler(int s) 函數中打印:   
" rocess %d terminated by signal (%d)/n",
"Exit zygote because system server (%d) has terminated/n",
startSystemServer() ZygoteInit.java (frameworks/base/core/java/com/android/internal/os)
SystemServer 的mian()函數會調用
SystemServer.java (frameworks/base/services/java/com/android/server)中的 init1()函數。
init1()實際執行的是com_android_server_SystemServer.cpp (frameworks/base/services/jni)
中的 android_server_SystemServer_init1()。
android_server_SystemServer_init1()調用的是
System_init.cpp (frameworks/base/cmds/system_server/library) 中的 system_init()函數
system_init()函數定義如下:
extern "C" status_t system_init()
{
  ...
  sp sm = defaultServiceManager();
  ...
  property_get("system_init.startsu**ceflinger", propBuf, "1");
  if (strcmp(propBuf, "1") == 0) {
  //讀取屬性服務器,開啓啓動 Su**ceFlinger服務
  //接着會開始顯示機器人圖標
  //BootAnimation.cpp (frameworks/base/libs/su**ceflinger):status_t BootAnimation::readyToRun()
  Su**ceFlinger::instantiate();
  }
  //在模擬器上 audioflinger 等幾個服務與設備上的啓動過程不一樣,所以
  //我們在這裏啓動他們。
  if (!proc->supportsProcesses()) {
  //啓動 AudioFlinger,media playback service,camera service服務
  AudioFlinger::instantiate();
  MediaPlayerService::instantiate();
  CameraService::instantiate();
  }
  //現在開始運行 the Android runtime ,我們這樣做的目的是因爲必須在 core system services
  //起來以後才能 Android runtime initialization,其他服務在調用他們自己的main()時,都會
  //調用 Android runtime
  //before calling the init function.
  LOGI("System server: starting Android runtime./n");
  AndroidRuntime* runtime = AndroidRuntime::getRuntime();
  LOGI("System server: starting Android services./n");
  //調用 SystemServer.java (frameworks/base/services/java/com/android/server)
  //中的init2函數
  runtime->callStatic("com/android/server/SystemServer", "init2");
   
  // If running in our own process, just go into the thread
  // pool.Otherwise, call the initialization finished
  // func to let this process continue its initilization.
  if (proc->supportsProcesses()) {
  LOGI("System server: entering thread pool./n");
  ProcessState::self()->startThreadPool();
  IPCThreadState::self()->joinThreadPool();
  LOGI("System server: exiting thread pool./n");
  }
  return NO_ERROR;
}
System server: entering thread pool 表明已經進入服務線程 ServerThread
在 ServerThread 類的run 服務中開啓核心服務:
  @Override
  public void run() {
  EventLog.writeEvent(LOG_BOOT_PROGRESS_SYSTEM_RUN,
    SystemClock.uptimeMillis());
  ActivityManagerService.prepareTraceFile(false); // create dir
  Looper.prepare();
  //設置線程的優先級
  android.os.Process.setThreadPriority(
      android.os.Process.THREAD_PRIORITY_FOREGROUND);
  ...
  //關鍵(核心)服務
  try {
    Log.i(TAG, "Starting Power Manager.");
    Log.i(TAG, "Starting activity Manager.");
    Log.i(TAG, "Starting telephony registry");
    Log.i(TAG, "Starting Package Manager.");
    Log.i(TAG, "tarting Content Manager.");
    Log.i(TAG, "Starting System Content Providers.");
    Log.i(TAG, "Starting Battery Service.");
    Log.i(TAG, "Starting Alarm Manager.");
    Log.i(TAG, "Starting Sensor Service.");
    Log.i(TAG, "Starting Window Manager.");
    Log.i(TAG, "Starting Bluetooth Service.");
    //如果是模擬器,那麼跳過藍牙服務。
    // Skip Bluetooth if we have an emulator kernel
   //其他的服務
    Log.i(TAG, "Starting Status Bar Service.");
    Log.i(TAG, "Starting Clipboard Service.");
    Log.i(TAG, "Starting Input Method Service.");
    Log.i(TAG, "Starting Hardware Service.");
    Log.i(TAG, "Starting NetStat Service.");
    Log.i(TAG, "Starting Connectivity Service.");
    Log.i(TAG, "Starting Notification Manager.");
    // MountService must start after NotificationManagerService
    Log.i(TAG, "Starting Mount Service.");
  Log.i(TAG, "Starting DeviceStorageMonitor service");
    Log.i(TAG, "Starting Location Manager.");
    Log.i(TAG, "Starting Search Service.");
    ...
    if (INCLUDE_DEMO) {
      Log.i(TAG, "Installing demo data...");
      (new DemoThread(context)).start();
    }
    try {
      Log.i(TAG, "Starting Checkin Service.");
      Intent intent = new Intent().setComponent(new ComponentName(
        "com.google.android.server.checkin",
        "com.google.android.server.checkin.CheckinService"));
      if (context.startService(intent) == null) {
      Log.w(TAG, "Using fallback Checkin Service.");
      ServiceManager.addService("checkin", new FallbackCheckinService(context));
      }
    } catch (Throwable e) {
      Log.e(TAG, "Failure starting Checkin Service", e);
    }
    Log.i(TAG, "Starting Wallpaper Service");
  Log.i(TAG, "Starting Audio Service");
    Log.i(TAG, "Starting HeadsetObserver");
    Log.i(TAG, "Starting AppWidget Service");
  ...
    try {
      com.android.server.status.StatusBarPolicy.installIcons(context, statusBar);
    } catch (Throwable e) {
      Log.e(TAG, "Failure installing status bar icons", e);
    }
  }
  // make sure the ADB_ENABLED setting value matches the secure property value
  Settings.Secure.putInt(mContentResolver, Settings.Secure.ADB_ENABLED,
      "1".equals(SystemProperties.get("persist.service.adb.enable")) ? 1 : 0);
  // register observer to listen for settings changes
  mContentResolver.registerContentObserver(Settings.Secure.getUriFor(Settings.Secure.ADB_ENABLED),
      false, new AdbSettingsObserver());
  // It is now time to start up the app processes...
  boolean safeMode = wm.detectSafeMode();
  if (statusBar != null) {
    statusBar.systemReady();
  }
  if (imm != null) {
    imm.systemReady();
  }
  wm.systemReady();
  power.systemReady();
  try {
    pm.systemReady();
  } catch (RemoteException e) {
  }
  if (appWidget != null) {
    appWidget.systemReady(safeMode);
  }
  // After making the following code, third party code may be running...
  try {
    ActivityManagerNative.getDefault().systemReady();
  } catch (RemoteException e) {
  }
  Watchdog.getInstance().start();
  Looper.loop();
  Log.d(TAG, "System ServerThread is exiting!");
  }
startActivity()
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);

ActivityManagerService.java 3136p (frameworks/base/services/java/com/android/server/am)
startActivity()
  startActivityLocked() //3184
  int res = startActivityLocked(caller, intent, resolvedType,grantedUriPermissions, grantedMode, aInfo,
      resultTo, resultWho, requestCode, -1, -1,
      onlyIfNeeded, componentSpecified);
public abstract class ActivityManagerNative extends Binder implements IActivityManager
ActivityManagerService.java 1071p(frameworks/base/services/java/com/android/server/am)
ActivityManagerService.main()
//ActivityManagerService.java 7375p (frameworks/base/services/java/com/android/server/am)
m.startRunning(null, null, null, null);
  //ActivityManagerService.java 7421p (frameworks/base/services/java/com/android/server/am)
  systemReady();
ActivityManagerService.java 3136p (frameworks/base/services/java/com/android/server/am)
startActivity(IApplicationThread caller,Intent intent,...)
  int startActivityLocked(caller, intent,...)  //3184L 定義:2691L
  void startActivityLocked()   //3132L 定義:2445L
  resumeTopActivityLocked(null); //2562p 定義:2176L
  if(next=NULL)
  {
    intent.addCategory(Intent.CATEGORY_HOME);
    startActivityLocked(null, intent, null, null, 0, aInfo,null, null, 0, 0, 0, false, false);
  }
  else
  {
    startSpecificActivityLocked(next, true, false); //2439L 定義:1628L
    realStartActivityLocked() //1640L  定義:1524L
    //1651L 定義:1654L
    startProcessLocked(r.processName, r.info.applicationInfo, true, 0,"activity", r.intent.getComponent());
    //1717L 定義:1721L
    startProcessLocked(app, hostingType, hostingNameStr);
      //1768L定義:Process.java 222L(frameworks/base/core/java/android/os)
      int pid = Process.start("android.app.ActivityThread",...)
      startViaZygote(processClass, niceName, uid, gid, gids,debugFlags, zygoteArgs);
      pid = zygoteSendArgsAndGetPid(argsForZygote);
        sZygoteWriter.write(Integer.toString(args.size()));
  }

runSelectLoopMode();
  done = peers.get(index).runOnce();
  forkAndSpecialize() //Zygote.java (dalvik/libcore/dalvik/src/main/java/dalvik/system)
  Dalvik_dalvik_system_Zygote_forkAndSpecialize() //dalvik_system_Zygote.c (dalvik/vm/native)
    forkAndSpecializeCommon()  
    setSignalHandler()
    RETURN_INT(pid);
   
   ActivityThread main()
   ActivityThread attach() //ActivityThread.java 3870p (frameworks/base/core/java/android/app)
   mgr.attachApplication(mAppThread)
   //ActivityManagerService.java 4677p (frameworks/base/services/java/com/android/server/am)
   attachApplication()
     //ActivityManagerService.java 4677p (frameworks/base/services/java/com/android/server/am)
     attachApplicationLocked()
     if (realStartActivityLocked(hr, app, true, true)) //ActivityManagerService.java 4609p
                       //(frameworks/base/services/java/com/android/server/am)
     realStartActivityLocked()
     //ActivityManagerService.java (frameworks/base/services/java/com/android/server/am)
     app.thread.scheduleLaunchActivity(new Intent(r.intent), r,r.info, r.icicle, results, newIntents, /
      !andResume,isNextTransitionForward());
     scheduleLaunchActivity()
       queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
       ActivityThread.H.handleMessage()
       handleLaunchActivity()  //ActivityThread.java (frameworks/base/core/java/android/app)
         performLaunchActivity() //ActivityThread.java (frameworks/base/core/java/android/app)
         activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);

     
/////////////////////////////////////////////////   
init 守護進程:
//andriod init 函數啓動過程分析:
在main循環中會重複調用
drain_action_queue();
restart_processes();
static void restart_processes()
{
  process_needs_restart = 0;
  service_for_each_flags(SVC_RESTARTING,
         restart_service_if_needed);
}
通過循環檢測服務列表service_list 中每個服務的 svc->flags 標記,如果爲 SVC_RESTARTING,
那麼在滿足條件的情況下調用:restart_service_if_needed
通過 service_start 來再次啓動該服務。
ActivityManagerService.main
I/SystemServer( 45): Starting Power Manager.
I/ServiceManager( 26): service 'Su**ceFlinger' died
D/Zygote( 30): Process 45 terminated by signal (11)
I/Zygote( 30): Exit zygote because system server (45) has terminated
通過錯誤信息發現程序在調用 Su**ceFlinger服務的時候被中止。
Service_manager.c (frameworks/base/cmds/servicemanager):
LOGI("service '%s' died/n", str8(si->name));
Binder.c (frameworks/base/cmds/servicemanager):
death->func(bs, death->ptr);
Binder.c (kernel/drivers/misc)中的函數
binder_thread_read()
struct binder_work *w;
switch (w->type)
爲 BINDER_WORK_DEAD_BINDER 的時候
binder_parse()中
當 cmd 爲 BR_DEAD_BINDER的時候
執行 death->func(bs, death->ptr)
因爲函數
int do_add_service(struct binder_state *bs,
       uint16_t *s, unsigned len,
       void *ptr, unsigned uid)
的 si->death.func = svcinfo_death;
所以 death->func(bs, death->ptr) 實際上執行的是
svcinfo_death()//Service_manager.c (frameworks/base/cmds/servicemanager)
================================================
=================================================
7. linux下svn使用指南
1.1 服務器端配置說明
1.1.3 配置用戶和權限
1.1.4 導入工程到倉庫中
1.2 客戶端操作指南及使用規範
1.2.1 檢出工作拷貝
1.2.2 svn update 更新別人做的更改
1.2.2.1 svn update 獲取最新版本
1.2.2.2 svn update-r 獲取特定的版本
1.2.3 svn st 查看文件狀態信息
1.2.4 svn log 查看log信息
1.2.5 svn diff 查看文件修改詳情
1.2.6 svn list 顯示版本庫的文件列表
1.2.8 svn add 增加目錄或者文件
1.2.9 svn delete 刪除目錄或者文件
1.2.10 svn revert 取消本地修改
1.2.11 svn commit 提交本地做的更改
1.2.12 文件更新,提交時的衝突處理
1.2.13 打標籤
1.2.14 清除緩存的認證信息,重新輸入用戶名和密碼
=================
1.1 服務器端配置說明
1.1.1 ubuntu-8.10 svn服務器安裝
sudo apt-get install subversion
1.1.2 建立版本庫(Repository)
運行Subversion服務器需要首先要建立一個版本庫(Repository),可以看作服務器上存放數據的數據庫,在安裝了Subversion服務器之後,可以直接運行
cd path_to_svn_root例如:/home/svn
svnadmin create --fs-type=fsfssmartphone
--fs-type 指定倉庫類型,可以爲fsfs或bdb 如果沒有指定默認創建爲fsfs類型smartphone爲倉庫名稱
1.1.3 配置用戶和權限
修改 path_to_svn_repos/conf/svnserve.conf 文件,打開下面配置項
---------------------------
#anon-access = read
anon-access = none
auth-access = write
password-db = passwd
authz-db = authz
anon-access 應設置等於 none ,否則沒有log信息
修改path_to_svn_repos/conf/passwd 文件,添加用戶和密碼
----------------------------
[users]
wanghui=wanghui

1.1.4 導入工程到倉庫中
svn importsmartphone/svn://192.168.2.148/smartphone
1.1.5 運行svn服務器
svnserve -d -rpath_to_svn_root例如:/home/svn
1.2 客戶端操作指南及使用規範
以我們服務器上 android 源代碼爲例,介紹svn常用操作。
1.2.1 檢出工作拷貝
檢出工作拷貝到 ~/svn/cupcake-jiangping
使用svn co url
cd ~/svn
svn co svn://192.168.2.148/smartphone/td0901/trunk/cupcake-jianpingcupcake-jianping
1.2.2 svn update 更新別人做的更改
1.2.2.1 svn update 獲取最新版本
svn update cupcake-jiangping
或者進入目錄更新
cd cupcake-jiangping
svn update
如果負責的應用與系統的關聯性不是很大,通常不建議頻繁進行更新。
1.2.2.2 svn update-r 獲取特定的版本
直接在某目錄下執行 svn update 獲取當前目錄下所有文件的最新版本,如果我們只需要獲取某個文件或者目錄的特定版本,可以通過-r 和 名稱進行指定:
svn update –r 5cupcake-jianping/packages/apps/Phone/src/com/android/phone/xxxx.java
1.2.3 svn st 查看文件狀態信息
Mcupcake-jianping/packages/apps/Phone/src/com/android/phone/xxxx.java
?cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java
M表明文件已經有修改
? 表明文件沒有受版本控制
1.2.4 svn log 查看log信息
svn log -r  查看所有版本的log信息
svn log -r 5  查看某一版本的log信息
svn log -r 5:19 查看某區間一系列版本的log信息
如果要查看log的詳細信息可以加上 –v 選項,如:
svn log –v -r 5
1.2.5 svn diff 查看文件修改詳情
顯示單個文件或者某目錄下所有文件的修改詳情
svn diff有三種不同的用法
1. 檢查本地修改
2. 比較工作拷貝與版本庫
3. 比較版本庫與版本庫
不使用任何參數調用時,svn diff將會比較你的工作文件與緩存在.svn的“原始”拷貝,如:
svn diff cupcake-jianping/packages/apps/Phone
svn diff cupcake-jianping/packages/apps/Phone/src/com/android/phone/zzzz.java
如果傳遞一個—revision –r 參數,你的工作拷貝會與指定的版本比較。
svn diff -r 3 cupcake-jianping/packages/apps/Phone
如果通過--revision –r 傳遞兩個通過冒號分開的版本號,這兩個版本會進行比較。
svn diff -r 2:3 cupcake-jianping/packages/apps/Phone
如果你在本機沒有工作拷貝,還是可以比較版本庫的修訂版本,只需要在命令行中輸入合適的URL:
svn diff -r 33 svn://192.168.2.148/smartphone/td0901/trunk/cupcake-jianping/packages/apps/Phone
1.2.6 svn list 顯示版本庫的文件列表
svn list svn://192.168.2.148/smartphone/td0901
design/
hedoc/
pm/
release/
tag/
trunk/
svn list svn://192.168.2.148/smartphone/td0901/trunk
3src/
boot-a1/
cupcake-jianping/
linux-2.6.28-a1/
svn list 類似本機的ls命令,它查看的是服務器端的目錄結構。
1.2.7 svn info 查看版本庫信息
cd ~/svn/cupcake-jianping
svn infos
路徑: .
URL: svn://192.168.2.148/smartphone/td0901/trunk/cupcake-jianping
版本庫根: svn://192.168.2.148/smartphone
版本庫 UUID: 1fac82c5-1665-442c-a8d6-2b3dd850438a
版本: 146
節點種類: 目錄
調度: 正常
最後修改的作者: tangligang
最後修改的版本: 145
最後修改的時間: 2009-07-31 15:40:50 +0800 (五, 2009-07-31)
1.2.8 svn add 增加目錄或者文件
svn add cupcake-jianping/packages/apps/Phone/src/com/android/phone/xxxx
svn add cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java
1.2.9 svn delete 刪除目錄或者文件
svn delete cupcake-jianping/packages/apps/Phone/src/com/android/phone/xxxx
svn delete cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java
在進行刪除操作的時候要非常小心,假設我們要添加一個文件:
cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java
但是在提交之前我們發現並不需要這個文件,這時候我們經常通過 svn delete 來撤銷之前添加的文件:
svn delete cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java
這樣操作的後果往往導致本地的文件yyyy.java 被誤刪除掉,所以我們正確的做法是:
svnn delete cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java –keep-local
1.2.10 svn revert 取消本地修改
1.當你發現對某個文件的所有修改都是錯誤的,或許你根本不應該修改這個文件,或者是從開頭重新修改會更加容易的時候可以用這個命令。
2.通過svn add 添加了一個項目,如果想取消可以通過該命令。
1.2.11 svn commit 提交本地做的更改
通常只對自己負責的模塊進行提交,如果負責電話模塊,那麼提交命令如下:
svn commit cupcake-jiangping/packages/apps/Phone
在提交之前建議用命令:
svn st cupcake-jiangping/packages/apps/Phone 查看狀態
M cupcake-jianping/packages/apps/Phone/src/com/android/phone/xxxx.java
?cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java
M表明文件已經有修改
? 表明文件沒有受版本控制
1. 如果有 “?”存在,並且該文件或者目錄是自己添加並且是工程的一部分,那麼在提交之前必須先執行svn add 操作:svn add cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java ;
2. 提交之前也必須解決衝突,否則會提交失敗。
3. 提交之前必須寫log
1.2.12 文件更新,提交時的衝突處理
$ svn update
Uxxxx
Gyyyy
Cxxxx.c
1. 更新的時候如果前面的狀態爲:C 表示有衝突存在。
2. 工作拷貝里做過修改,且服務器版本庫在修改前工作拷貝的版本後被提交過其他修改;那麼svn commit首先會失敗並要求update,此時便會出現版本衝突的情況。
當你Update出現了衝突時,Subversion會產生三個文件
filename.mine :你更新前的文件,沒有衝突標誌,只是你最新更改的內容。
Filename.roldrev:就是你在上次更新之後未作更改的版本。
Filename.rnewrev:客戶端從服務器剛剛收到的版本,這個文件對應版本庫的HEAD版本。
衝突的文件內容,在衝突的地方將被使用“>>>>”標誌出來,用戶自己進行合併的取捨。
解決衝突之後,svn resolved path_to_name,Subversion刪除衝突所產生三個文件刪除,此時你纔可以進行提交。( 也可以手動刪除此三個文件。)
1.2.13 打標籤
svn 的標籤是通過copy命令完成,但是操作的路徑必須是服務器的路徑,打標籤實際上類似於創建一個到特定版本的鏈接,如:
svn cp svn://192.168.2.148/smartphone/td0901/trunk/cupcake-jianping/
svn://192.168.2.148/smartphone/td0901/tags/cupcake-1.0.6
如果 svn://192.168.2.148/smartphone/td0901/trunk/cupcake-jianping 的當前版本爲 5 ,/
那麼 svn://192.168.2.148/smartphone/td0901/tags/cupcake-1.0.6 實際 /
上就是 svn://192.168.2.148/smartphone/td0901/trunk/cupcake-jianping 版本5的一個標籤。
1.2.14 清除緩存的認證信息,重新輸入用戶名和密碼
一個具有權限控制的 svn 版本庫在第一次 checkout 工作拷貝的時候會要求輸入用戶名和密碼:
認證領域:176512f1-51ee-4947-8c07-88c90ab77ac5
“$USER”的密碼:
認證領域:d3216b51-7915-4881-bf30-02e0672c61cd
用戶名: xxxxx
“xxxxx”的密碼:
這些信息被緩存在 ~/.subversion/auth/svn.simple/ 如果需要更換另一個用戶登錄,必須先清除緩存的認證信息:
rm ~/.subversion/auth/svn.simple/* -rf
1.3 爲規避風險,建議遵守以下規範
1.3.1 提交前審查修改情況, 用命令svn status瀏覽所做的修改,svn diff檢查修改的詳細信息
1.3.2 提交時,必須填寫註釋,註釋內容清晰描述本次提交內容,變動信息。
1.3.3 做較大修改時,和項目組其他同事的工作相關時,必須通知對方。
1.3.4 納入版本控制的項目必須定期提交,至少一週提交一次,避免意外事故導致代碼丟失。
1.3.5 每次提交後,必須確認工程可正常運行,即SVN裏保存的是可以正確運行的代碼,否則恢復至穩定版本。
1.3.6 編譯過程動態產生的東西不要提交到服務器
1.3.7 每次提交前先更新,這樣能在提交前發現是否和別人的衝突
filelist=`find ./ -name "*.conf"`;svn add $filelist; svn commit$filelist
filelist=`find ./ -name "*.conf"`;svn delete $filelist --force --keep-local
=================================================
================================================
8. LFS 相關
7.1 lfs 相關資源
7.2 LFS問題解答
=========
LFS──Linux from Scratch,就是一種從網上直接下載源碼,從頭編譯LINUX的安裝方式。它不是發行版,只是一個菜譜,
告訴你到哪裏去買菜(下載源碼),怎麼把這些生東西( raw code) 作成符合自己口味的菜餚──個性化的linux,不單單是
個性的桌面。
LFS 有什麼優勢呢?現在看來,它可以提供最快和最小的 Linux。但是最大的優勢就是,安裝LFS是菜鳥變成高手的捷徑。
第一次安裝,需要按照LFS文檔安裝,如果在此期間所有文檔內容你都認真的閱讀,保證你受益匪淺;然後發現很多地方可以
不按照別人的老路操作,這個時候用自己的方式參考第一次安裝的經驗,再一次建立linux,完成的時候,你會發現你在 LinuxSir.Org
上已經再也不是菜鳥了。
7.1 lfs 相關資源
官方網站:
http://www.linuxfromscratch.org/
lfs中文網站
http://lfs.linuxsir.org/main/
Linux From Scratch版本 6.2
http://lamp.linux.gov.cn/Linux/LFS-6.2/index.html
Linux From Scratch 版本 6.4
http://www.bitctp.org/lfsbook-6.4/index.html
Linux 發行版 LFS 討論區
http://www.linuxsir.org/bbs/forumdisplay.php?f=58
7.2 LFS問題解答
構建LFS的過程中遇到一些問題,總體來說還算順利,但是還有一些不明白的地方,這裏總結一下:
1./etc/fstab是否在開機就執行,是被誰調用執行的。
2.爲什麼系統啓動之後就要自動掛載/proc 和/sys,這兩個目錄有什麼作用;devpts和tmpfs有什麼作用。
參考章節:文件系統概述
3.關於文件系統:按照我的理解,文件系統是內核提供支持的,可以看作是一種協議,提供一種數據組織方式,每個設備必須有自己的文件系統。
不同文件系統的存儲設備的數據組織形式不同。mke2fs -jv /dev/默認在上面創建EXT3的文件系統嗎?既然這樣的話爲什麼
我們還需要把以ext3掛載到一個目錄呢?如果不是 的話,又是創建什麼文件系統呢?爲什麼第六章中掛載了虛擬內核文件系統之後才能
進入chroot環境呢?
參考章節:文件系統概述
4.虛擬文件系統.作用.什麼?
虛擬內核文件系統(Virtual Kernel File Systems),是指那些是由內核產生但並不存在於硬盤上(存在於內存中)的文件系統,他們
被用來與內核進行通信。
5.符號鏈接 和硬鏈接的區別是什麼?什麼是符號鏈接?什麼是硬鏈接?爲什麼liinux上都使用符號鏈接,而不是硬鏈接?linux上很多地方
使用了鏈接,是爲了組織清晰系統的結構和節省空間嗎?
硬連接和軟連接的區別, 硬連接和複製的區別?
硬連接記錄的是目標的 inode;軟連接記錄的是目標的 path。
hard link 由於 inode 的緣故,只能在本分區中做 link;soft link 可以做跨分區的 link。硬連接因爲記錄的是 inode,所以不怕改名,
比如ln aaa bbb, mv aaa ccc, 這時 bbb 仍然可以訪問;soft-link 就不行:source 的名字改變後,所有鏈接到這裏的 soft-link
全部變爲 broken。事實上,即使所有指向該 inode 的 hard-link 的文件名都變了,每一個仍然都可以訪問。我想這是它最大的優點吧。
硬連接和複製的區別:
幾個硬連接=幾個名字的同一個房子,這些名字可以相同或不同但地址(i-node)是一樣的, 所以硬連接被刪除只是把相應名字抹去,只有最
後一個名字被抹去你纔會找不到房子;而複製是建造一個一模一樣的房子,當然地址(i-node)就不同的了。
6.工作平臺中由Glibc提供的動態連接器與Binutils裏面的標準連接器有什麼區別?
參考章節: 鏈接器和加載器
7.$LFS/tools 目錄的所有者是僅存在於宿主環境中的 lfs 用戶。如果保留 $LFS/tools 目錄,那麼該目錄內文件的所有者的 user ID 就
沒有對應的賬號 ?爲什麼沒有帳戶,難道不是LFS?
查看 /etc/password /etc/group兩個文件 分別記錄 用戶和組的信息
如果用戶名和用戶ID 組名和組ID 的對應關係分別存在上面兩個文件中,那麼ls -ls 的時候就可以查看到用戶信息,而不再是ID等數字信息
8.系統的環境變量保存在哪個文件?
保存在tty中
9。配置參數腳本時[alias1] [alias2 ...]什麼時候用到?
別名的意思
alias ls='ls --color=auto'
/etc/skel/.bashrc:81:  #alias dir='dir --color=auto'
/etc/skel/.bashrc:82:  #alias vdir='vdir --color=auto'
/etc/skel/.bashrc:84:  #alias grep='grep --color=auto'
/etc/skel/.bashrc:85:  #alias fgrep='fgrep --color=auto'
/etc/skel/.bashrc:86:  #alias egrep='egrep --color=auto'
/etc/skel/.bashrc:89:# some more ls aliases
/etc/skel/.bashrc:90:#alias ll='ls -l'
/etc/skel/.bashrc:91:#alias la='ls -A'
/etc/skel/.bashrc:92:#alias l='ls -CF'
alias mohuifu='ls -l'
========================
9. linux 內核的初步理解
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
initramfs與initrd
1. initrd是一個單獨的文件;initramfs和Linux內核鏈接在一起(/usr目錄下的程序負責生成initramfs文檔)。
2. initrd是一個壓縮的文件系統映像(可以是ext2等,需要內核的驅動);initramfs是類似tar的cpio壓縮文檔。
內核中的cpio解壓縮代碼很小,而且init數據在boot後可以丟棄。
3. initrd運行的程序(initd,不是init)進行部分setup後返回內核;initramfs執行的init程序不返回內核
(如果/init需要向內核傳遞控制權,可以再次安裝在/目錄下一個新的root設備並且啓動一個新的init程序)。
編譯腳本及系統變量
initramfs與initrd的區別
1. initrd是一個單獨的文件;initramfs和Linux內核鏈接在一起(/usr目錄下的程序負責生成initramfs文檔)。
2. initrd是一個壓縮的文件系統映像(可以是ext2等,需要內核的驅動);initramfs是類似tar的cpio壓縮文檔。
內核中的cpio解壓縮代碼很小,而且init數據在boot後可以丟棄。
3. initrd運行的程序(initd,不是init)進行部分setup後返回內核;initramfs執行的init程序不返回內核
(如果/init需要向內核傳遞控制權,可以再次安裝在/目錄下一個新的root設備並且啓動一個新的init程序)。
4. 切換到另一個root設備時,initrd執行pivot_root後,卸載ramdisk;initramfs是rootfs,既不能
pivot_root,也不能卸載。initramfs會刪掉rootfs的所有內容(find -xdev / -exec rm '{}' ';'),
再次安裝root到rootfs(cd /newmount; mount --move . /; chroot .),把stdin/sdout/stderr掛在
新的/dev/console上,重新執行init。由於這是一個相當困難的實現過程(包括在使用一個命令之前把它刪除),所以
klibc工具包引入一個幫助程序/utils/run_init.c來執行上述過程。其他大部分工具包(包括busybox) 把這個命令
稱爲"switch_root"。
======================= end ========================
arch/arm/boot/zImage
initramfs與initrd
1. initrd是一個單獨的文件;initramfs和Linux內核鏈接在一起(/usr目錄下的程序負責生成initramfs文檔)。
2. initrd是一個壓縮的文件系統映像(可以是ext2等,需要內核的驅動);initramfs是類似tar的cpio壓縮文檔。
內核中的cpio解壓縮代碼很小,而且init數據在boot後可以丟棄。
3. initrd運行的程序(initd,不是init)進行部分setup後返回內核;initramfs執行的init程序不返回內核
(如果/init需要向內核傳遞控制權,可以再次安裝在/目錄下一個新的root設備並且啓動一個新的init程序)。
編譯腳本及系統變量
initramfs與initrd的區別
1. initrd是一個單獨的文件;initramfs和Linux內核鏈接在一起(/usr目錄下的程序負責生成initramfs文檔)。
2. initrd是一個壓縮的文件系統映像(可以是ext2等,需要內核的驅動);initramfs是類似tar的cpio壓縮文檔。
內核中的cpio解壓縮代碼很小,而且init數據在boot後可以丟棄。
3. initrd運行的程序(initd,不是init)進行部分setup後返回內核;initramfs執行的init程序不返回內核
(如果/init需要向內核傳遞控制權,可以再次安裝在/目錄下一個新的root設備並且啓動一個新的init程序)。
4. 切換到另一個root設備時,initrd執行pivot_root後,卸載ramdisk;initramfs是rootfs,既不能
pivot_root,也不能卸載。initramfs會刪掉rootfs的所有內容(find -xdev / -exec rm '{}' ';'),
再次安裝root到rootfs(cd /newmount; mount --move . /; chroot .),把stdin/sdout/stderr掛在
新的/dev/console上,重新執行init。由於這是一個相當困難的實現過程(包括在使用一個命令之前把它刪除),所以
klibc工具包引入一個幫助程序/utils/run_init.c來執行上述過程。其他大部分工具包(包括busybox) 把這個命令
稱爲"switch_root"。
======================= end ========================
arch/arm/boot/zImage
initramfs與initrd
1. initrd是一個單獨的文件;initramfs和Linux內核鏈接在一起(/usr目錄下的程序負責生成initramfs文檔)。
2. initrd是一個壓縮的文件系統映像(可以是ext2等,需要內核的驅動);initramfs是類似tar的cpio壓縮文檔。
內核中的cpio解壓縮代碼很小,而且init數據在boot後可以丟棄。
3. initrd運行的程序(initd,不是init)進行部分setup後返回內核;initramfs執行的init程序不返回內核
(如果/init需要向內核傳遞控制權,可以再次安裝在/目錄下一個新的root設備並且啓動一個新的init程序)。
編譯腳本及系統變量
initramfs與initrd的區別
1. initrd是一個單獨的文件;initramfs和Linux內核鏈接在一起(/usr目錄下的程序負責生成initramfs文檔)。
2. initrd是一個壓縮的文件系統映像(可以是ext2等,需要內核的驅動);initramfs是類似tar的cpio壓縮文檔。
內核中的cpio解壓縮代碼很小,而且init數據在boot後可以丟棄。
3. initrd運行的程序(initd,不是init)進行部分setup後返回內核;initramfs執行的init程序不返回內核
(如果/init需要向內核傳遞控制權,可以再次安裝在/目錄下一個新的root設備並且啓動一個新的init程序)。
4. 切換到另一個root設備時,initrd執行pivot_root後,卸載ramdisk;initramfs是rootfs,既不能
pivot_root,也不能卸載。initramfs會刪掉rootfs的所有內容(find -xdev / -exec rm '{}' ';'),
再次安裝root到rootfs(cd /newmount; mount --move . /; chroot .),把stdin/sdout/stderr掛在
新的/dev/console上,重新執行init。由於這是一個相當困難的實現過程(包括在使用一個命令之前把它刪除),所以
klibc工具包引入一個幫助程序/utils/run_init.c來執行上述過程。其他大部分工具包(包括busybox) 把這個命令
稱爲"switch_root"。
======================= end ========================

http://www.x4hack.com/x/?name-main-tid-7034.html

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章