天天看點

linux ,Android基礎知識總結

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 list  svn://192.168.2.148/smartphone 檢視svn版本庫核心

更多資訊請參卡以下文檔:

http://192.168.2.148/svn/smartphone/

http://192.168.2.148/svn/smartphone/智能平台開發部資料管理手冊V1.0.doc

http://192.168.2.148/svn/smartphone/linux下svn操作指南及規範.doc

使用者名為各位的姓名拼音,密碼與使用者名相同

3. 編譯源碼

進入 cupcake 工作拷貝的頂層目錄,執行:

. ./make_image15.sh

部分執行結果:

out/target/product/littleton/root/   核心需要使用的 initramfs

out/target/product/littleton/system  檔案系統的系統分區

out/target/product/littleton/data/   檔案系統資料分區

4. 編譯核心

此處核心編譯主要針對驅動組之外的同僚

1> 設定工具鍊

核心的 linux-2.6.28-a1/Makefile 中設定了:

CROSS_COMPILE        ?= arm-linux-

是以設定PATH環境變量,保證能找到正确的工具鍊

假設工具鍊位于: /usr/local/marvell-arm-linux-4.1.1/ 設定為:

export PATH:=/usr/local/marvell-arm-linux-4.1.1/bin/:$PATH

2> 更改編譯選項(網絡啟動或者本機啟動)

核心頂層目錄執行:

make menuconfig

General setup  --->

  • Initial RAM filesystem and RAM disk (initramfs/initrd) support

        ()    Initramfs source file(s) (NEW)

    如果需要支援網絡啟動反選  [] Initial RAM filesystem and RAM disk (initramfs/initrd) support

    如果需要支援本地啟動選中  

  • Initial RAM filesystem and RAM disk (initramfs/initrd) support

    設定 ()    Initramfs source file(s) (NEW) 為 root

    拷貝  cupcake 編譯結果  out/target/product/littleton/root/  到核心頂層目錄

    3> 編譯

    核心頂層目錄執行 make zImage

    編譯好的核心:

    arch/arm/boot/zImage

    5. 搭建網絡開發環境

    1>  安裝nfs伺服器

    sudo apt-get install nfs-kernel-server nfs-common

    2> 修改nfs伺服器配置檔案/etc/exports ,確定有以下配置項

    /nfsroot/rootfs *(rw,no_root_squash,sync)

    我們在核心中已經固定,手機通過網絡方式啟動,預設從 /nfsroot/rootfs

    讀取檔案系統,修改配置項後需要重新開機nfs伺服器:

    sudo /etc/init.d/nfs-kernel-server restart

    3> 配置網絡根檔案系統

    拷貝  out/target/product/littleton/root/  内容到  /nfsroot/rootfs 目錄

    拷貝  out/target/product/littleton/system 内容到  /nfsroot/rootfs/system

    修改  /nfsroot/rootfs/init.rc 去掉幾個mount指令

    為了使大家的過程,結果統一,可以使用腳本 mkfs.cupcake 完成

    在執行 mkfs.cupcake.nfs  腳本前先到  cupcake-jianping 目錄下執行: . ./make_env15.sh設定環境變量,

    擷取通過手動輸入android源碼的位置,讓腳本來設定環境變量。

    二   ubuntu下燒錄核心和檔案系統

    1. 硬體:

    手機一台

    usb轉序列槽線一根

    usb轉網卡線一根

    2. 軟體環境

    1> tftp 伺服器

    執行腳本: setup_tftpd.sh 安裝和配置tftp伺服器,我們預設以 /tftpboot

    為 tftp伺服器的根目錄,需要下載下傳的檔案都放在該目錄下。

    2> 擷取待燒錄的鏡像檔案

    svn list svn://192.168.2.148/smartphone/td0901/release/images 檢視伺服器上的

    版本情況,通常我們下載下傳最新的,例如,下載下傳9月18号釋出的版本:

    svn co svn://192.168.2.148/smartphone/td0901/release/images/images20090918

    3> 燒錄鏡像檔案

    用以下檔案為例,示範通過tftp燒寫核心和檔案系統

    核心           zImage0917

    系統分區: system0918.img  

    資料分區    data0918.img

    待燒寫的以上檔案必須存在于tftp伺服器根目錄/tftpboot下。

    具體步驟:

    首先連接配接好硬體裝置進入blob下載下傳模式

    1> blob 起來後按任意鍵

    Processing obm parameters...

    Can\'t detect micco. Set PMIC as normal I2C mode.

    NAND flash(Manu=0x98 Device=0xba) detected!

    Slot 0 Found

    get relocation table

    Found Main Bad block table at address 0x0f000000, version 0x01

    Found Mirror Bad block table at address 0x0efc0000, version 0x01

    Consider yourself BLOBed!

    blob version 2.0.5-pre3 for Marvell Littleton

    Copyright (C) 1999 2000 2001 2002 2003 Jan-Derk Bakker and Erik Mouw

    blob comes with 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:LOCAL_MODULE:= sh

    ./system/core/libcutils/Android.mk:71:LOCAL_MODULE := libcutils

    ./system/core/cpio/Android.mk:9:LOCAL_MODULE := mkbootfs

    ./system/core/mkbootimg/Android.mk:8:LOCAL_MODULE := mkbootimg

    ./system/core/toolbox/Android.mk:61:LOCAL_MODULE:= toolbox

    ./system/core/logcat/Android.mk:10:LOCAL_MODULE:= logcat

    ./system/core/adb/Android.mk:65:LOCAL_MODULE := adb

    ./system/core/adb/Android.mk:125:LOCAL_MODULE := adbd

    ./system/core/init/Android.mk:20:LOCAL_MODULE:= init

    ./system/core/vold/Android.mk:24:LOCAL_MODULE:= vold

    ./system/core/mountd/Android.mk:13:LOCAL_MODULE:= mountd

    LOCAL_PACKAGE_NAME

    Java 應用程式的名字用該變量定義

    ./packages/apps/Music/Android.mk:9:LOCAL_PACKAGE_NAME := Music

    ./packages/apps/Browser/Android.mk:14:LOCAL_PACKAGE_NAME := Browser

    ./packages/apps/Settings/Android.mk:8:LOCAL_PACKAGE_NAME := Settings

    ./packages/apps/Stk/Android.mk:10:LOCAL_PACKAGE_NAME := Stk

    ./packages/apps/Contacts/Android.mk:10:LOCAL_PACKAGE_NAME := Contacts

    ./packages/apps/Mms/Android.mk:8:LOCAL_PACKAGE_NAME := Mms

    ./packages/apps/Camera/Android.mk:8:LOCAL_PACKAGE_NAME := Camera

    ./packages/apps/Phone/Android.mk:11:LOCAL_PACKAGE_NAME := Phone

    ./packages/apps/VoiceDialer/Android.mk:8:LOCAL_PACKAGE_NAME := VoiceDialer

    BUILD_SHARED_LIBRARY - 指明要編譯成動态庫。

    編譯的目标,用include 操作符

    UILD_STATIC_LIBRARY來指明要編譯成靜态庫。

    如果是java檔案的話,會用到系統的編譯腳本host_java_library.mk,用BUILD_PACKAGE來指明。三個編譯

    -------------------

    include $(BUILD_STATIC_LIBRARY)

    BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk

    -------------------

    include $(BUILD_SHARED_LIBRARY)

    ./build/core/config.mk:50:BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk

    -------------------

    include $(BUILD_HOST_SHARED_LIBRARY)

    BUILD_HOST_SHARED_LIBRARY:= $(BUILD_SYSTEM)/host_shared_library.mk

    -------------------

    include $(BUILD_EXECUTABLE)

    build/core/config.mk:51:BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk

    -------------------

    include $(BUILD_HOST_EXECUTABLE)

    ./build/core/config.mk:53:BUILD_HOST_EXECUTABLE:= $(BUILD_SYSTEM)/host_executable.mk

    -------------------

    BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk

    -------------------

    BUILD_JAVA_LIBRARY

    ./build/core/config.mk:58:BUILD_JAVA_LIBRARY:= $(BUILD_SYSTEM)/java_library.mk

    ------------------

    BUILD_STATIC_JAVA_LIBRARY 編譯靜态JAVA庫

    ./build/core/config.mk:59:BUILD_STATIC_JAVA_LIBRARY:= $(BUILD_SYSTEM)/static_java_library.mk

    ------------------

    BUILD_HOST_JAVA_LIBRARY   編譯本機用的JAVA庫

    ./build/core/config.mk:60:BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk

    ------------------

    BUILD_HOST_STATIC_LIBRARY:= $(BUILD_SYSTEM)/host_static_library.mk

    BUILD_HOST_SHARED_LIBRARY:= $(BUILD_SYSTEM)/host_shared_library.mk

    BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk

    BUILD_RAW_STATIC_LIBRARY := $(BUILD_SYSTEM)/raw_static_library.mk

    BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk

    BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk

    BUILD_RAW_EXECUTABLE:= $(BUILD_SYSTEM)/raw_executable.mk

    BUILD_HOST_EXECUTABLE:= $(BUILD_SYSTEM)/host_executable.mk

    BUILD_PACKAGE:= $(BUILD_SYSTEM)/package.mk

    BUILD_HOST_PREBUILT:= $(BUILD_SYSTEM)/host_prebuilt.mk

    BUILD_PREBUILT:= $(BUILD_SYSTEM)/prebuilt.mk

    BUILD_MULTI_PREBUILT:= $(BUILD_SYSTEM)/multi_prebuilt.mk

    BUILD_JAVA_LIBRARY:= $(BUILD_SYSTEM)/java_library.mk

    BUILD_STATIC_JAVA_LIBRARY:= $(BUILD_SYSTEM)/static_java_library.mk

    BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk

    BUILD_DROIDDOC:= $(BUILD_SYSTEM)/droiddoc.mk

    BUILD_COPY_HEADERS := $(BUILD_SYSTEM)/copy_headers.mk

    BUILD_KEY_CHAR_MAP := $(BUILD_SYSTEM)/key_char_map.mk

    ============

    LOCAL_PRELINK_MODULE

            Prelink利用事先連結代替運作時連結的方法來加速共享庫的加載,它不僅可以加快起動速度,還可以減少部分記憶體開銷,

    是各種Linux架構上用于減少程式加載時間、縮短系統啟動時間和加快應用程式啟動的很受歡迎的一個工具。程式運作時的

    動态連結尤其是重定位(relocation)的開銷對于大型系統來說是很大的。

            動态連結和加載的過程開銷很大,并且在大多數的系統上, 函數庫并不會常常被更動, 每次程式被執行時所進行的連結

    動作都是完全相同的,對于嵌入式系統來說尤其如此。是以,這一過程可以改在運作時之前就可以預先處理好,即花一些時間

    利用Prelink工具對動态共享庫和可執行檔案進行處理,修改這些二進制檔案并加入相應的重定位等資訊,節約了本來在程式

    啟動時的比較耗時的查詢函數位址等工作,這樣可以減少程式啟動的時間,同時也減少了記憶體的耗用。

            Prelink的這種做法當然也有代價:每次更新動态共享庫時,相關的可執行檔案都需要重新執行一遍Prelink才能保

    證有效,因為新的共享庫中的符号資訊、位址等很可能與原來的已經不同了,這就是為什麼 android framework代碼一改動,

    這時候就會導緻相關的應用程式重新被編譯。

    這種代價對于嵌入式系統的開發者來說可能稍微帶來一些複雜度,不過好在對使用者來說幾乎是可以忽略的。

    --------------------

    變量設定為false那麼将不做prelink操作

    LOCAL_PRELINK_MODULE := false

    預設是需要prlink的,同時需要在 build/core/prelink-linux-arm.map 中加入

    libhellod.so      0x96000000

    這個map檔案好像是制定動态庫的位址的,在前面注釋上面有一些位址範圍的資訊,注意庫與庫之間的間隔數,

    如果指定不好的話編譯的時候會提示說位址空間沖突的問題。另外,注意排序,這裡要把數大的放到前面去,

    按照大小降序排序。

    解析 LOCAL_PRELINK_MODULE 變量

    build/core/dynamic_binary.mk:94:ifeq ($(LOCAL_PRELINK_MODULE),true)

    ifeq ($(LOCAL_PRELINK_MODULE),true)

    $(prelink_output): $(prelink_input) $(TARGET_PRELINKER_MAP) $(APRIORI)

            $(transform-to-prelinked)

    transform-to-prelinked定義:

    ./build/core/definitions.mk:1002:define transform-to-prelinked

    define transform-to-prelinked

    @mkdir -p $(dir $@)

    @echo "target Prelink: $(PRIVATE_MODULE) ($@)"

    $(hide) $(APRIORI) \

                    --prelinkmap $(TARGET_PRELINKER_MAP) \

                    --locals-only \

                    --quiet \

                    $/build/tools/apriori”

    參考文檔:

    動态庫優化——Prelink(預連接配接)技術

    http://www.eefocus.com/article/09-04/71629s.html

    ===============

    LOCAL_ARM_MODE := arm

    目前Android大部分都是基于Arm處理器的,Arm指令用兩種模式Thumb(每條指令兩個位元組)和arm指令(每條指令四個位元組)

    LOCAL_CFLAGS += -O3 -fstrict-aliasing -fprefetch-loop-arrays

    通過設定編譯器操作,優化級别,-O0表示沒有優化,-O1為預設值,-O3優化級别最高

    LOCAL_CFLAGS += -W -Wall

    LOCAL_CFLAGS += -fPIC -DPIC

    LOCAL_CFLAGS += -O2 -g -DADB_HOST=1  -Wall -Wno-unused-parameter

    LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE -DSH_HISTORY

    LOCAL_CFLAGS += -DUSEOVERLAY2

    根據條件選擇相應的編譯參數

    ifeq ($(TARGET_ARCH),arm)

    LOCAL_CFLAGS += -DANDROID_GADGET=1

    LOCAL_CFLAGS :=   $(PV_CFLAGS)

    endif

    ifeq ($(TARGET_BUILD_TYPE),release)

            LOCAL_CFLAGS += -O2

    endif

    LOCAL_LDLIBS := -lpthread

    LOCAL_LDLIBS += -ldl

    ifdef USE_MARVELL_MVED

    LOCAL_WHOLE_STATIC_LIBRARIES += lib_il_mpeg4aspdecmved_wmmx2lnx lib_il_h264decmved_wmmx2lnx

    LOCAL_SHARED_LIBRARIES += libMrvlMVED

    else

    LOCAL_WHOLE_STATIC_LIBRARIES += lib_il_h264dec_wmmx2lnx lib_il_mpeg4aspdec_wmmx2lnx

    endif

    ====================

    其他一些變量和腳本:

    HOST_JNILIB_SUFFIX

    LOCAL_MODULE_SUFFIX

    LOCAL_MODULE_SUFFIX := $(HOST_JNILIB_SUFFIX)

    HOST_GLOBAL_LDFLAGS

    TARGET_GLOBAL_LDFLAGS

    PRIVATE_LDFLAGS

    LOCAL_LDLIBS

    LOCAL_C_INCLUDES

    LOCAL_STATIC_LIBRARIES

    LOCAL_STATIC_LIBRARIES += codecJPDec_WMMX2LNX miscGen_WMMX2LNX

    LOCAL_SHARED_LIBRARIES

    LOCAL_SHARED_LIBRARIES += libMrvlIPP

    LOCAL_SHARED_LIBRARIES += $(common_SHARED_LIBRARIES)

    LOCAL_SHARED_LIBRARIES += libMrvlIPP

    LOCAL_SHARED_LIBRARIES += libdl

    ifeq ($(TARGET_PRODUCT),littleton)

    LOCAL_C_INCLUDES += vendor/marvell/littleton/m2d \

    LOCAL_SHARED_LIBRARIES += libOmxCore

    endif

    vendor/marvell/littleton/littleton.mk:27:PRODUCT_NAME := littleton

    vendor/marvell/littleton/littleton.mk:28:PRODUCT_DEVICE := littleton

    vendor/marvell/littleton/AndroidProducts.mk:13:        $(LOCAL_DIR)/littleton.mk

    vendor/sample/products/sample_addon.mk:40:PRODUCT_NAME := sample_addon

    vendor/htc/dream-open/htc_dream.mk:6:PRODUCT_NAME := htc_dream

    ./vendor/htc/dream-open/htc_dream.mk:7:PRODUCT_DEVICE := dream-open

    ./vendor/htc/dream-open/AndroidProducts.mk:3:        $(LOCAL_DIR)/htc_dream.mk

    build/target/product/generic.mk:26:PRODUCT_NAME := generic

    build/target/product/generic_with_google.mk:20:PRODUCT_NAME := generic_with_google

    build/target/product/min_dev.mk:6:PRODUCT_NAME := min_dev

    build/target/product/core.mk:2:PRODUCT_NAME :=

    build/target/product/sim.mk:7:PRODUCT_NAME := sim

    build/target/product/sdk.mk:37:PRODUCT_NAME := sdk

    build/tools/buildinfo.sh:20:echo "ro.product.name=$PRODUCT_NAME"

    lunch sample_addon-eng

    lunch htc_dream-eng

    lunch generic-eng

    lunch 1

    lunch sim-eng

    TARGET_BUILD_TYPE=release

    lunch 2

    TARGET_BUILD_TYPE=debug

    lunch  generic-user

    .PHONY: systemtarball-nodeps

    systemtarball-nodeps: $(FS_GET_STATS) \

                          $(filter-out systemtarball-nodeps stnod,$(MAKECMDGOALS))

            $(build-systemtarball-target)

    .PHONY: stnod

    stnod: systemtarball-nodeps

    systemimage-nodeps snod

    ./core/main.mk:BUILD_SYSTEM := $(TOPDIR)build/core

    ./core/main.mk:include $(BUILD_SYSTEM)/config.mk

    ./core/main.mk:include $(BUILD_SYSTEM)/cleanbuild.mk

    ./core/main.mk:include $(BUILD_SYSTEM)/version_defaults.mk

    ./core/main.mk:include $(BUILD_SYSTEM)/definitions.mk

    ./core/main.mk:include $(BUILD_SYSTEM)/Makefile

    ./core/static_java_library.mk:include $(BUILD_SYSTEM)/java_library.mk

    ./core/host_java_library.mk:include $(BUILD_SYSTEM)/base_rules.mk

    ./core/executable.mk:include $(BUILD_SYSTEM)/dynamic_binary.mk

    ./core/java_library.mk:include $(BUILD_SYSTEM)/java.mk

    ./core/binary.mk:include $(BUILD_SYSTEM)/base_rules.mk

    ./core/raw_executable.mk:include $(BUILD_SYSTEM)/binary.mk

    ./core/prebuilt.mk:include $(BUILD_SYSTEM)/base_rules.mk

    ./core/host_executable.mk:include $(BUILD_SYSTEM)/binary.mk

    ./core/combo/select.mk:$(combo_target)PRELINKER_MAP := $(BUILD_SYSTEM)/prelink-$(combo_os_arch).map

    ./core/shared_library.mk:include $(BUILD_SYSTEM)/dynamic_binary.mk

    ./core/config.mk:include $(BUILD_SYSTEM)/pathmap.mk

    ./core/config.mk:BUILD_COMBOS:= $(BUILD_SYSTEM)/combo

    ./core/config.mk:CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk

    ./core/config.mk:BUILD_HOST_STATIC_LIBRARY:= $(BUILD_SYSTEM)/host_static_library.mk

    ./core/config.mk:BUILD_HOST_SHARED_LIBRARY:= $(BUILD_SYSTEM)/host_shared_library.mk

    ./core/config.mk:BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk

    ./core/config.mk:BUILD_RAW_STATIC_LIBRARY := $(BUILD_SYSTEM)/raw_static_library.mk

    ./core/config.mk:BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk

    ./core/config.mk:BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk

    ./core/config.mk:BUILD_RAW_EXECUTABLE:= $(BUILD_SYSTEM)/raw_executable.mk

    ./core/config.mk:BUILD_HOST_EXECUTABLE:= $(BUILD_SYSTEM)/host_executable.mk

    ./core/config.mk:BUILD_PACKAGE:= $(BUILD_SYSTEM)/package.mk

    ./core/config.mk:BUILD_HOST_PREBUILT:= $(BUILD_SYSTEM)/host_prebuilt.mk

    ./core/config.mk:BUILD_PREBUILT:= $(BUILD_SYSTEM)/prebuilt.mk

    ./core/config.mk:BUILD_MULTI_PREBUILT:= $(BUILD_SYSTEM)/multi_prebuilt.mk

    ./core/config.mk:BUILD_JAVA_LIBRARY:= $(BUILD_SYSTEM)/java_library.mk

    ./core/config.mk:BUILD_STATIC_JAVA_LIBRARY:= $(BUILD_SYSTEM)/static_java_library.mk

    ./core/config.mk:BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk

    ./core/config.mk:BUILD_DROIDDOC:= $(BUILD_SYSTEM)/droiddoc.mk

    ./core/config.mk:BUILD_COPY_HEADERS := $(BUILD_SYSTEM)/copy_headers.mk

    ./core/config.mk:BUILD_KEY_CHAR_MAP := $(BUILD_SYSTEM)/key_char_map.mk

    ./core/config.mk:HOST_JDK_TOOLS_JAR:= $(shell $(BUILD_SYSTEM)/find-jdk-tools-jar.sh)

    ./core/version_defaults.mk:INTERNAL_BUILD_ID_MAKEFILE := $(wildcard $(BUILD_SYSTEM)/build_id.mk)

    ./core/config.mk:include $(BUILD_SYSTEM)/envsetup.mk

    ./core/config.mk:include $(BUILD_SYSTEM)/combo/select.mk

    ./core/config.mk:include $(BUILD_SYSTEM)/combo/select.mk

    ./core/config.mk:include $(BUILD_SYSTEM)/combo/javac.mk

    ./core/product_config.mk:include $(BUILD_SYSTEM)/node_fns.mk

    ./core/product_config.mk:include $(BUILD_SYSTEM)/product.mk

    ./core/product_config.mk:include $(BUILD_SYSTEM)/device.mk

    ./core/dynamic_binary.mk:include $(BUILD_SYSTEM)/binary.mk

    ./core/host_static_library.mk:include $(BUILD_SYSTEM)/binary.mk

    ./core/java.mk:include $(BUILD_SYSTEM)/base_rules.mk

    ./core/host_shared_library.mk:include $(BUILD_SYSTEM)/binary.mk

    ./core/key_char_map.mk:include $(BUILD_SYSTEM)/base_rules.mk

    ./core/package.mk:include $(BUILD_SYSTEM)/java.mk

    ./core/static_library.mk:include $(BUILD_SYSTEM)/binary.mk

    ./core/definitions.mk:include $(BUILD_SYSTEM)/distdir.mk

    ./core/envsetup.mk:include $(BUILD_SYSTEM)/product_config.mk

    ./tools/apicheck/Android.mk:include $(BUILD_SYSTEM)/base_rules.mk

    ./tools/dexpreopt/Android.mk:include $(BUILD_SYSTEM)/host_prebuilt.mk

    COMMON_GLOBAL_CFLAGS:= -DANDROID -fmessage-length=0 -W -Wall -Wno-unused

    COMMON_DEBUG_CFLAGS:=

    COMMON_RELEASE_CFLAGS:= -DNDEBUG -UDEBUG

    COMMON_PACKAGE_SUFFIX := .zip

    COMMON_JAVA_PACKAGE_SUFFIX := .jar

    COMMON_ANDROID_PACKAGE_SUFFIX := .apk

    ACP := $(HOST_OUT_EXECUTABLES)/acp$(HOST_EXECUTABLE_SUFFIX)

    AIDL := $(HOST_OUT_EXECUTABLES)/aidl$(HOST_EXECUTABLE_SUFFIX)

    MKBOOTFS := $(HOST_OUT_EXECUTABLES)/mkbootfs$(HOST_EXECUTABLE_SUFFIX)

    MKBOOTIMG := $(HOST_OUT_EXECUTABLES)/mkbootimg$(HOST_EXECUTABLE_SUFFIX)

    MKYAFFS2 := $(HOST_OUT_EXECUTABLES)/mkyaffs2image$(HOST_EXECUTABLE_SUFFIX)

    APICHECK := $(HOST_OUT_EXECUTABLES)/apicheck$(HOST_EXECUTABLE_SUFFIX)

    FS_GET_STATS := $(HOST_OUT_EXECUTABLES)/fs_get_stats$(HOST_EXECUTABLE_SUFFIX)

    MKEXT2IMG := $(HOST_OUT_EXECUTABLES)/genext2fs$(HOST_EXECUTABLE_SUFFIX)

    MKEXT2BOOTIMG := external/genext2fs/mkbootimg_ext2.sh

    MKTARBALL := build/tools/mktarball.sh

    DX := $(HOST_OUT_EXECUTABLES)/dx

    LOCALIZE := $(HOST_OUT_EXECUTABLES)/localize$(HOST_EXECUTABLE_SUFFIX)

    HOST_GLOBAL_LDFLAGS

    TARGET_GLOBAL_LDFLAGS

    PRIVATE_LDFLAGS

    build/core/combo/linux-arm.mk:16:$(combo_target)NO_UNDEFINED_LDFLAGS := -Wl,--no-undefined

    save_CFLAGS="$CFLAGS -g  -mabi=aapcs-linux"

    LDFLAGS=\'$LDFLAGS  -lX11 -lxml2 -lXdmcp -lXau -lexpat -lXrender -lXft  -lfontconfig -lfreetype -lz\'  

    --without-libtiff "   # --with-gdktarget=directfb"

    LDFLAGS=" -Wl,-rpath-link=$LD_LIBRARY_PATH  -L$PREFIX/lib  ${env_LDFLAGS} ${save_LDFLAGS}"

    ./vendor/marvell/external/alsa/alsa-lib/src/Mdroid.mk:43:LOCAL_CFLAGS += -mabi=aapcs-linux

    ./vendor/marvell/external/alsa/alsa-tools/Mdroid.mk:8:LOCAL_CFLAGS += -mabi=aapcs-linux

    ./vendor/marvell/littleton/libaudio/Mdroid.mk:22:LOCAL_CPPFLAGS += -mabi=aapcs-linux

    ./external/wpa_supplicant/Android.mk:35:L_CFLAGS += -mabi=aapcs-linux

    ./system/wlan/ti/sta_dk_4_0_4_32/CUDK/tiwlan_loader/Android.mk:88:LOCAL_CFLAGS = -Wall -Wstrict-prototypes

    $(CLI_DEBUGFLAGS) -D__LINUX__ $(DK_DEFINES) -mabi=aapcs-linux

    ./kernel/arch/arm/Makefile

    ifeq ($(CONFIG_AEABI),y)

    CFLAGS_ABI        :=-mabi=aapcs-linux -mno-thumb-interwork

    else

    CFLAGS_ABI        :=$(call cc-option,-mapcs-32,-mabi=apcs-gnu) $(call cc-option,-mno-thumb-interwork,)

    endif

    # Need -Uarm for gcc /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等目錄和檔案,都是真真正正、實實在在的存儲在具體的外部存

    儲裝置上的,它們可能是在本機的硬碟、閃存、CD光牒中,可能儲存在不隻一個磁盤分區中,也可能儲存在網絡中其它主機的儲存設備中的。

    虛拟檔案系統,雖然它們出現在根檔案系統中,但它裡面的内容卻無法在任何外部儲存設備中找到,因為它們都在記憶體中。

    ==========

    android 網絡挂載:

    rootfs    /         rootfs rw 0 0

    /dev/root /         nfs rw,vers=2,rsize=1024,wsize=1024,...

    tmpfs     /dev      tmpfs rw,mode=755 0 0

    devpts    /dev/pts  devpts rw,mode=600 0 0

    proc      /proc     proc rw 0 0

    sysfs     /sys      sysfs rw 0 0

    tmpfs                   /sqlite_stmt_journals   tmpfs rw,size=4096k 0 0

    /dev/block/mmcblk0p1    /sdcard                 vfat rw,...

    ===========

    android 本機挂載(使用flash中的檔案系統)

    rootfs / rootfs ro 0 0

    tmpfs /dev tmpfs rw,mode=755 0 0

    devpts /dev/pts devpts rw,mode=600 0 0

    proc /proc proc rw 0 0

    sysfs /sys sysfs rw 0 0

    tmpfs /sqlite_stmt_journals tmpfs rw,size=4096k 0 0

    /dev/block/mtdblock2 /system yaffs2 ro 0 0

    /dev/block/mtdblock3 /data yaffs2 rw,nosuid,nodev 0 0

    /dev/block/mmcblk0p1 /sdcard vfat rw

    =============

    ubuntu 系統:

    /dev/sda8 on /             type ext3  (rw,relatime,errors=remount-ro)

    tmpfs     on /lib/init/rw  type tmpfs (rw,nosuid,mode=0755)

    /proc     on /proc         type proc  (rw,noexec,nosuid,nodev)

    sysfs     on /sys          type sysfs (rw,noexec,nosuid,nodev)

    varrun    on /var/run      type tmpfs (rw,nosuid,mode=0755)

    tmpfs     on /dev/shm      type tmpfs (rw,nosuid,nodev)

    devpts    on /dev/pts      type devpts (rw,noexec,nosuid,gid=5,mode=620)

    /dev/sda7  on /boot type ext3 (rw,relatime)

    /dev/sda11 on /home type ext3 (rw,relatime)

    /dev/sdb5  on /opt type ext3 (rw,relatime)

    /dev/sda9  on /usr/local type ext3 (rw,relatime)

    /dev/sda1  on /windows/c type vfat (rw,utf8,umask=007,gid=1000)

    /dev/sda5  on /windows/d type vfat (rw,utf8,umask=007,gid=1000)

    /dev/sda6  on /windows/e type vfat (rw,utf8,umask=007,gid=1000)

    ===============

    2.5.2 proc 檔案系統

    proc是一個重要虛拟檔案系統,通過它裡面的一些檔案,可以擷取系統狀态資訊并修改某些系統的配置資訊。proc檔案系統本身不占用

    磁盤空間,它僅存在于記憶體之中,為作業系統本身和應用程式之間的通信提供了一個安全的接口。當我們在核心中添加了新功能或裝置驅

    動時,經常需要得到一些系統狀态的資訊,一般這樣的功能可能需要經過一些象ioctl()這樣的系統調用來完成。系統調用接口對于一些

    功能性的資訊可能是适合的,因為應用程式必須将這些資訊讀出後再做一定的處理。但對于一些實時性的系統資訊,例如記憶體的使用狀況,

    或者是驅動裝置的統計資料等,我們更需要一個比較簡單易用的接口來取得它們。proc檔案系統就是這樣的一個接口,我們可以簡單的用

    cat、strings程式來檢視這些資訊。例如,執行下面的指令:

    cat /proc/filesystems    //作業系統支援的檔案系統類型

    cat /proc/meminfo        //記憶體的實時資訊,記憶體大小等

    cat /proc/partitions     //存儲器分區資訊

    cat /proc/cpuinfo        //檢視cpu資訊

    同樣的,free、df、top、ps等程式的功能實作,強烈依賴于proc檔案系統,為了使用那些程式,一定要使核心支援proc檔案系統,

    并将其挂接到根檔案系統的/proc目錄下。

    其他使用 /proc 檔案系統的例子:

    processor        : 0

    vendor_id        : AuthenticAMD

    processor        : 1

    vendor_id        : AuthenticAMD

    model name        : AMD Athlon(tm) 64 X2 Dual Core CPU 5000+

    1.vmware 虛拟機無法正常啟動

    在Linux下,單個程序的最大記憶體使用量受/proc/sys/kernel/shmmax中設定的數字限制(機關為位元組),

    例如 ubuntu 8.10 的shmmax預設值為33554432位元組(33554432bytes/1024/1024=32MB)。

    2.scratchbox 開發工具不能登入

    /scratchbox/login

    Inconsistency detected by ld.so: rtld.c: 1192: dl_main: Assertion `(void *) ph->p_vaddr ==

    _rtld_local._dl_sysinfo_dso\' failed!

    NOTE: on Ubuntu installation, you have to disable VDSO to make Scratchbox work fine,

    or you\'ll get errors like this:

    在 ubuntu 系統中,我們必須關閉 VDSO 标記,以便scratchbox能正常工作

    echo 0 | sudo tee /proc/sys/vm/vdso_enabled

    echo 4096 | sudo tee /proc/sys/vm/mmap_min_addr

    vm.vdso_enabled = 0

    vm.mmap_min_addr = 4096

    修改 /proc 檔案系統值的方法

    1.直接修改

    echo "2147483648" | sudo tee /proc/sys/kernel/shmmax

    echo 0 | sudo tee /proc/sys/vm/vdso_enabled

    echo 4096 | sudo tee /proc/sys/vm/mmap_min_addr

    2.将以下指令放入 /etc/rc.local 啟動檔案中:

    echo "2147483648" > /proc/sys/kernel/shmmax

    echo 0            > /proc/sys/vm/vdso_enabled

    echo 4096         > /proc/sys/vm/mmap_min_addr

    3.使用 sysctl 指令來更改 SHMMAX 的值:

    sysctl -w kernel.shmmax=2147483648

    4.核心參數插入到 /etc/sysctl.conf 啟動檔案中,使這種更改永久有效

    echo "kernel.shmmax=2147483648" >> /etc/sysctl.conf

    sudo sysctl –p

    ./system/core/logcat/logcat.cpp:403:   fd = open("/proc/cmdline", O_RDONLY);

    ./system/core/init/init.c:553:    char cmdline[1024];

    ./system/core/init/init.c:557:    fd = open("/proc/cmdline", O_RDONLY);

    ./system/core/init/init.c:580:    chmod("/proc/cmdline", 0440);

    ./system/core/init/bootchart.c:139:   proc_read("/proc/cmdline", cmdline, sizeof(cmdline));

    ./system/core/init/bootchart.c:319:   proc_read( "/proc/cmdline", cmdline, sizeof(cmdline) );

    ./system/core/init/bootchart.c:320:   s = strstr(cmdline, KERNEL_OPTION);

    ./system/core/rootdir/init.rc:162:    chown root radio /proc/cmdline

    2.5.3 sysfs檔案系統

    與proc檔案系統類似,sysfs檔案系統也是一個不占有任何磁盤空間的虛拟檔案系

    統。它通常被挂接在/sys目錄下。sysfs檔案系統是Linux2.6核心引入的,它把連接配接在系

    統上的裝置和總線組織成為一個分級的檔案,使得它們可以在使用者空間存取。其實

    sysfs是從proc和devfs中劃分出來的。

    一、devfs

       linux下有專門的檔案系統用來對裝置進行管理,devfs和sysfs就是其中兩種。

    在2.6核心以前一直使用的是devfs,devfs挂載于/dev目錄下,提供了一種類似于檔案的方法來管理位于/dev目錄下的所有裝置,我們知道

    /dev目錄下的每一個檔案都對應的是一個裝置,至于目前該裝置存在與否先且不論,而且這些特殊檔案是位于根檔案系統上的,在制作檔案

    系統的時候我們就已經建立了這些裝置檔案,是以通過操作這些特殊檔案,可以實作與核心進行互動。但是devfs檔案系統有一些缺點,例如:

    不确定的裝置映射,有時一個裝置映射的裝置檔案可能不同,例如我的U盤可能對應sda有可能對應sdb;沒有足夠的主/輔裝置号,當裝置過多

    的時候,顯然這會成為一個問題;/dev目錄下檔案太多而且不能表示目前系統上的實際裝置;命名不夠靈活,不能任意指定等等。

    二、sysfs

          正因為上述這些問題的存在,在linux2.6核心以後,引入了一個新的檔案系統sysfs,它挂載于/sys目錄下,跟devfs一樣它也是一個

    虛拟檔案系統,也是用來對系統的裝置進行管理的,它把實際連接配接到系統上的裝置和總線組織成一個分級的檔案,使用者空間的程式同樣可以利用

    這些資訊以實作和核心的互動,該檔案系統是目前系統上實際裝置樹的一個直覺反應,它是通過kobject子系統來建立這個資訊的,當一個

    kobject被建立的時候,對應的檔案和目錄也就被建立了,位于/sys下的相關目錄下,既然每個裝置在sysfs中都有唯一對應的目錄,那麼也

    就可以被使用者空間讀寫了。使用者空間的工具udev 就是利用了sysfs提供的資訊來實作所有devfs的功能的,但不同的是udev運作在使用者空間中,

    而devfs卻運作在核心空間,而且udev不存在 devfs那些先天的缺陷。很顯然,sysfs将是未來發展的方向。

    2.5.4 tmpfs檔案系統

    tmpfs 是Linux特有的檔案系統,唯一的标準挂接點是/dev/shm。當然,使用者可以将其挂接在其他地方。tmpfs有些像虛拟磁盤(ramdisk),

    但不是一回事。說其像虛拟磁盤,是因為它可以使用你的RAM,但它也可以使用你的交換分區。傳統的虛拟磁盤是一個塊裝置,而且需要一個mkfs

    之類的指令格式化它才能使用。tmpfs是一個獨立的檔案系統,不是塊裝置,隻要挂接,立即就可以使用。tmpfs的大下是不确定的,它最初隻有

    很小的空間,但随着檔案的複制和建立,它的大小就會不斷變化,換句話說,它會根據你的實際需要而改變大小;tmpfs的速度非常驚人,畢竟它

    是駐留在RAM中的,即使用了交換分區,性能仍然非常卓越;由于tmpfs是駐留在RAM的,是以它的内容是不持久的,斷電後,tmpfs的内容就消

    失了,這也是被稱作tmpfs的根本原因。

    tmpfs 是ramfs的衍生物,用來限制緩存大小、向swap空間寫入資料。它是用來儲存VM所有檔案的檔案系統。

    tmpfs中緩存的内容全部是臨時的。一旦解除安裝,所有的内容都會遺失。它把所有的緩存置于核心,它的規模随着

    檔案的規模同步變化。但是它規模有大小限制,可以修改。它可以把目前不再需要的頁寫入到 swap空間。

    tmpfs 和 ramfs 本身就是一個檔案系統, 用的時候隻需要直接挂載就可以. tmpfs可以使用ram, 也可以使用swap

    共享記憶體的時候會使用tmpfs

    系統預設共享記憶體是記憶體的一半大小! /dev/shm是挂載點!

    通過 df -h 可以看出,預設狀況下它為記憶體大小的一半:

    檔案系統        容量      已用      可用     已用%    挂載點

    tmpfs    1013M   12K  1013M   1%    /dev/shm

    mount | grep tmpfs 顯示目前系統中的 tmpfs:

    tmpfs   on /lib/init/rw   type   tmpfs (rw,nosuid,mode=0755)

    varrun  on /var/run       type   tmpfs (rw,nosuid,mode=0755)

    varlock on /var/lock      type   tmpfs (rw,noexec,nosuid,nodev,mode=1777)

    udev    on /dev           type   tmpfs (rw,mode=0755)

    tmpfs   on /dev/shm       type   tmpfs (rw,nosuid,nodev)

    lrm     on /lib/modules/2.6.27-4-generic/volatile type tmpfs (rw,mode=755)

    2.5.6 usbdevfs檔案系統

    顧名思義,usbdevfs就是USB裝置檔案系統,它是一個動态生成的檔案系統,有

    些類似于proc檔案系統。它的标準挂接點是/proc/bus/usb,當然,也可以挂接到其他

    地方。它主要用于:使用者級驅動、即插即用、提供USB裝置資訊、應用程式輪詢

    USB裝置的變化等。

    2.5.7 devpts檔案系統

    devpts檔案系統為僞終端提供了一個标準接口,它的标準挂接點是/dev/pts。隻要

    pty的主複合裝置/dev/ptmx被打開,就會在/dev/pts下動态的建立一個新的pty裝置文

    件。挂接時,UID、GID及其工作模式會指定給devpts檔案系統的所有pty檔案。這可

    以保證僞終端的安全性。

    讨論devpts檔案系統的詳細内容,已經超過本文範圍,還請讀者參考其他專

    著。

    2.6 一些必要重要的系統檔案 ( /etc/fstab ,inittab,init.rc等)

    2.6.1 /etc/inittab

    2.6.2 /etc/init.d/rcS

    2.6.3 /etc/fstab 檔案

    ================

    2.6.1 /etc/inittab

    initab  被 init 使用

    2.6.1.1 老平台 inittab檔案内容

    2.6.1.1 gpephone 官方的inittab 檔案(與redhat,federo差不多)

    2.6.1.1 ubuntu中沒有inittab檔案

    =================

    2.6.1.1 老平台 inittab檔案内容

    -----------------------------------------

    ::sysinit:/etc/init.d/rcS

    ::respawn:-/bin/sh

    ::restart:/sbin/init

    ::ctrlaltdel:/sbin/reboot

    ::shutdown:/bin/umount -a -r

    ::shutdown:/sbin/swapoff -a

    -----------------------------------------

    2.6.1.2 gpephone 官方的inittab 檔案(與redhat,federo差不多

    -----------------------------------------

    # /etc/inittab: init(8) configuration.

    # $Id: inittab,v 1.91 2002/01/25 13:35:21 miquels Exp $

    # The default runlevel.

    id:5:initdefault:

    # Boot-time system configuration/initialization script.

    # This is run first except when booting in emergency (-b) mode.

    si::sysinit:/etc/init.d/rcS

    # What to do in single-user mode.

    ~~:S:wait:/sbin/sulogin

    # /etc/init.d executes the S and K scripts upon change

    # of runlevel.

    #

    # Runlevel 0 is halt.

    # Runlevel 1 is single-user.

    # Runlevels 2-5 are multi-user.

    # Runlevel 6 is reboot.

    l0:0:wait:/etc/init.d/rc 0

    l1:1:wait:/etc/init.d/rc 1

    l2:2:wait:/etc/init.d/rc 2

    l3:3:wait:/etc/init.d/rc 3

    l4:4:wait:/etc/init.d/rc 4

    l5:5:wait:/etc/init.d/rc 5

    l6:6:wait:/etc/init.d/rc 6

    # Normally not reached, but fallthrough in case of emergency.

    z6:6:respawn:/sbin/sulogin

    1:2345:respawn:/sbin/getty 38400 tty1

    -------------------------------------------

    2.6.1.3 ubuntu中沒有inittab檔案

    在unbutu系統中我們沒看到此檔案,是因為ubuntu用的是 upstart ,lfs中使用的是 sysvinit ,嵌入式系統中

    一般使用的是 busybox 中的 init ,android 系統使用的是 system/core/init

    init:

    main()

      init_main()

        read_inittab();

    gdm運作後

    /etc/rc5.d/S30gdm -> ../init.d/gdm

    /etc/init.d/gdm:19:DAEMON=/usr/sbin/gdm

    /etc/init.d/gdm:24:        SSD_ARG="--startas $DAEMON"

    /etc/init.d/gdm:27:        SSD_ARG="--exec $DAEMON"

    啟動gdm:

    log_begin_msg "Starting GNOME Display Manager..."

    start-stop-daemon --start --quiet --oknodo --pidfile $PIDFILE --name gdm $SSD_ARG -- $CONFIG_FILE >/dev/null

    ================

    2.6.2 /etc/init.d/rcS

    -------------------

    #!/bin/sh

    挂在 /etc/fstab 中的檔案系統

    /bin/mount -a

    . /etc/default/rcS

    #環境變量

    . /etc/profile

    #螢幕叫準備

    . /etc/X11/run-calibrate

    #啟動X

    . /etc/X11/Xserver

    . /etc/scripts/testd-bus.sh

    #啟動dbus消息總線

    #啟動gpephone

    -------------------

    ubuntu 系統

    ---------------

    exec /etc/init.d/rc S

    ---------------

    會依此執行 /etc/rcS.d/ 下以

    S01mountkernfs.sh

    S02hostname.sh

    S10udev

    S11mountdevsubfs.sh

    S20checkroot.sh

    S22mtab.sh

    S30checkfs.sh

    S35mountall.sh

    S40networking

    S43portmap

    S55bootmisc.sh

    ./rc3.d/S30gdm

    ./rc2.d/S30gdm

    ./rc4.d/S30gdm

    ./rc5.d/S30gdm

    /etc/rcS.d/S35mountall.sh -> ../init.d/mountall.sh

    mount -a -t nonfs,nfs4,smbfs,cifs,ncp,ncpfs,coda,ocfs2,gfs,gfs2 -O no_netdev

    mount指令的一些解析:

    mount -a [-t|-O] ...     : mount all stuff from /etc/fstab

    mount -t type dev dir    : ordinary mount command

    ================

    2.6.3 /etc/fstab 檔案

    Util-linux 軟體包包含許多工具。其中比較重要的是加載、解除安裝、格式化、分區和管理硬碟驅動器,打開 tty 端口和得到核心消息

    arch         報告機器的體系結構

    blockdev         在指令行中調用塊裝置的ioctl

    cal         顯示一個簡單的月曆。

    cfdisk         處理指定裝置的分區表

    column         把輸出格式化為幾列

    ctrlaltdel         設定CTRL+ALT+DEL組合鍵的功能為硬重新開機或軟重新開機

    dmesg         顯示核心的啟動資訊

    fdisk         磁盤分區管理程式

    fsck.cramfs         對Cramfs檔案系統的一緻性進行檢查

    getopt         在給出的指令行進行選項和參數解析

    hexdump         用使用者指定的方式(包括ASCII, 十進制, 十六進制, 八進制)顯示一個檔案或者标準輸入的資料

    hwclock         查詢和設定硬體時鐘(也被稱為RTC或BIOS時鐘)。

    ipcrm         删除給定的程序間通信(IPC)資源

    mkfs         在一個裝置(通常是一個硬碟分區)裝置上建立檔案系統

    mkfs.cramfs         建立cramfs檔案系統

    mkswap         初始化指定裝置或檔案,以用做交換分區

    more         分屏顯示檔案,但沒有less好用

    mount         把一個檔案系統從一個裝置挂載到一個目錄

    ramsize         顯示或者改變 RAM disk 的大小

    raw 将一個原始的Linux字元裝置綁定到一個塊裝置

    rdev  查詢和設定核心的根裝置和其他資訊

    readprofile         顯示核心側寫檔案/proc/profile的資訊

    rename         對檔案進行重命名

    renice         修改正在運作程序的優先級

    sfdisk         磁盤分區表管理工具

    umount         解除安裝一個被挂載的檔案系統

    mount挂載與/etc/fstab

    mount 源目錄 目的目錄

    mount -a 自動挂載/etc/fstab中的檔案系統     

    根目錄 / 是必須挂載的﹐而且一定要先于其它 mount point 被挂載進來。     其它 mount point 必須為已建立的目錄﹐可任意指定﹐

    但一定要遵守必須的系統目錄架構原則     所有 mount point 在同一時間之内﹐隻能挂載一次。     所有 partition 在同一時間之内﹐

    隻能挂載一次。     如若進行解除安裝﹐您必須先将工作目錄移到 mount point(及其子目錄) 之外。

    /etc/fstab

    第一列:label

    第二列:挂載點

    第三列:分區的檔案系統

    第四列:檔案系統挂載選項,看附件啦

    第五列:是否被dump作用。0代表不要做dump 備份,1代表要每天進行dump的動作。 2 也代表其它不定日期的dump備份動作,通常這個數值不是0就是1啦!

    第六列:是否以fsck檢查分區(開機時候檢查分區)0為不檢查,1為開機的時候檢查,2為在稍後的時間檢查

    /dev/sda8 on / type ext3 (rw,relatime,errors=remount-ro)

    /proc on /proc type proc (rw,noexec,nosuid,nodev)

    sysfs on /sys type sysfs (rw,noexec,nosuid,nodev)

    tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)

    devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=620)

    /dev/sda7 on /boot type ext3 (rw,relatime)

    /dev/sda11 on /home type ext3 (rw,relatime)

    /dev/sdb5 on  /opt type ext3 (rw,relatime)

    /dev/sda9 on  /usr/local type ext3 (rw,relatime)

    /dev/sda1 on  /windows/c type vfat (rw,utf8,umask=007,gid=1000)

    /dev/sda5 on  /windows/d type vfat (rw,utf8,umask=007,gid=1000)

    /dev/sda6 on  /windows/e type vfat (rw,utf8,umask=007,gid=1000)

    可以在/etc/fstab 中進行指定

    proc        /proc         proc        defaults    0        0

    none        /tmp         ramfs        defaults        0        0

    sysfs        /sys         sysfs        defaults        0        0

    none    /dev/pts devpts defaults        0        0

    ./util-linux-2.12r/mount/mount.c

    main()

    result = do_mount_all (types, options, test_opts);

    mount --help 可以知道 mount -a 是mount所有/etc/fstab

    mount -a [-t|-O] ...     : mount all stuff from /etc/fstab

    ======================

    2.7 制作檔案系統

    2.7.1 原始方式

    2.7.2 通過scratchbox等工具

    2.7.3 通過 android 源碼內建開發環境

    2.7.1 原始方式

    建立基本檔案系統标準目錄(根據不同的linux系統,ubuntu跟android目錄結構就完全不同)

    lfs中的标準目錄:

    建立修改必要的配置檔案

    /scratchbox/source2/source/busybox/busybox-1.1.2/examples/bootfloppy/etc/

    vim  ${CLFS_ROOTFS_DIR}/etc/profile

    vim  ${CLFS_ROOTFS_DIR}/etc/inittab

    vim  ${CLFS_ROOTFS_DIR}/etc/fstab

    vim  ${CLFS_ROOTFS_DIR}/etc/init.d/rcS

    建立帳号以及密碼檔案

    sudo vim ${CLFS_ROOTFS_DIR}/passwd

    拷貝必須的動态庫檔案

    cd  ${CLFS_ROOTFS_DIR}/lib

    cp -d  $COMPILER_LIB/ld* ./

    cp      $COMPILER_LIB/libc-2.3.5.so ./

    cp -d  $COMPILER_LIB/libc.so.6 ./

    cp      $COMPILER_LIB/libm-* ./

    cp -d  $COMPILER_LIB/libm.s* ./

    cp      $COMPILER_LIB/libcrypt-* ./

    cp -d  $COMPILER_LIB/libcrypt.s* ./

    拷貝可選的動态庫檔案

    如果需要域名解析:

    1)增加/etc/resolv.conf

    [root@lqm /etc]#cat resolv.conf

    nameserver 192.168.x.x  //加入域名解析器

    2)增加相應動态庫的支援

    增加如下:

    libnss_files

    libnss_dns

    libresolv.so

    find find . -name "libnss*"  $COMPILER_LIB/

    ./libnss_files.so.2

    ./libnss_files.so

    ./libnss_dns-2.3.2.so

    ./libnss_dns.so

    ./libnss_files-2.3.2.so

    ./libnss_dns.so.2

    find . -name "libresolv*"  /scratchbox/compilers/arm-linux-gcc-3.4.4-glibc-2.3.5/arm-unknown-linux-gnu/lib/

    ./libresolv.so

    ./libresolv.so.2

    ./libresolv-2.3.2.so

    2.7.2 通過scratchbox等工具

    ===================

    2.7.3 通過 android 源碼內建開發環境

    環境搭建問題:

            1.為什麼拷貝  cupcake 編譯結果  out/target/product/littleton/root/  到核心頂層目錄?

            2.cupcake-jianping/make_image15.sh中的choosecombo是什麼作用?

            3.make_image15.sh 與 make_env15.sh隻差一句make -j2?

            4.補充shell腳本知識。

    =====================

    2.7.4 配置android網絡檔案系統

    下面是曾經用過的幾種開發闆的指令行參數:

    S3C2410 啟動參數:

    noinitrd root=/dev/nfs  nfsroot=192.168.2.56:/nfsroot/rootfs  

    ip=192.168.2.188:192.168.2.56:192.168.2.56:255.255.255.0::eth0:on console=ttySAC0

    S3C2440 啟動參數:

    setenv bootargs console=ttySAC0 root=/dev/nfs nfsroot=192.168.2.56:/nfsroot/rootfs

    ip=192.168.2.175:192.168.2.56:192.168.2.201:255.255.255.0::eth0:on mem=64M init=/init         

    marvell 310 啟動參數:

    boot root=/dev/nfs nfsroot=192.168.2.56:/nfsroot/rootfs,rsize=1024,wsize=1024

    ip=192.168.2.176:192.168.2.201:192.168.2.201:255.255.255.0::eth0:-On  

    console=ttyS2,115200 mem=64M init=/init

    目前android核心的.config檔案中的指令行參數:

    CONFIG_CMDLINE="root=/dev/nfs nfsroot=192.168.1.100:/nfsroot/rootfs,rsize=1024,wsize=1024

    ip=192.168.1.101:192.168.1.100:192.168.1.100:255.255.255.0::usb0:on

    console=ttyS1,115200 mem=128M init=/init android uart_dma=1"

    `root=\' 參數

    此參數告訴核心啟動時以那個裝置作為根檔案系統使用。我的pc根檔案系統:

    /dev/sda8              9614116   6522156   2603588  72% /

    ubuntu 的/boot/grub/menu.lst參數:

    kernel                /vmlinuz-2.6.27-4-generic root=UUID=2ffa7dc6-2dc5-4b66-8661-1226c086951a

                    ro locale=zh_CN quiet splash

    initrd                /initrd.img-2.6.27-4-generic

    其中 root可以設定為:root=/dev/sda8

    /dev/nfs, 這并非真的是個裝置, 而是一個告訴核心經由網絡取得根檔案系統

    lfs的/boot/grub/menu.lst參數:

    title LFS 6.4

    root (hd1,1)

    kernel /boot/lfskernel-2.6.27.4 root=/dev/sdb1

    `nfsroot=\' 參數

    這個參數告訴核心到哪台pc的哪個目錄讀取根檔案系統。此參數的格式如下:

    nfsroot=[:][,]

    --pc機的ip位址,如果此字段沒給值,那麼将使用由 nfsaddrs 變量(見下面)所決定的值。

    -- pc服務端上要作為根挂入的目錄域名(/nfsroot/rootfs)

    -- 标準的網絡檔案系統選項。所有選項都以逗号分開。如果沒有給定此選項字段則使用下列的預設值:

            port            = as given by server portmap daemon

            rsize           = 1024

            wsize           = 1024

            timeo           = 7

            retrans         = 3

            acregmin        = 3

            acregmax        = 60

            acdirmin        = 30

            acdirmax        = 60

            flags           = hard, nointr, noposix, cto, ac

    `init=\' 參數

    核心啟動時預設執行 `init\' 程式,核心将會到/sbin/, /bin/ 等目錄下查找預設的init,如果沒有找到那麼就報告出錯。

    而最後它會去試 /bin/sh (可能在 /etc/rc )。如果說,例如,如果你的 init 程式壞掉了,隻要使用 init=/bin/sh

    這個啟動參數就能讓你在啟動時直接跳到解譯環境(shell),使你能夠換掉壞掉的程式。

    `ip=\' 參數

    nfsaddrs=::::::

    ip=192.168.1.101:192.168.1.100:192.168.1.100:255.255.255.0::usb0:on

    ip=192.168.2.175:192.168.2.56:192.168.2.201:255.255.255.0::eth0:on

    -- 闆子的ip 使用何種協定端視配置核心時打開的選項以及  參數而定。如果設定此參數,就不會使用反向位址解析協定或啟動協定。

    -- 網絡檔案系統服務端之網際網路位址。

    -- 網關(gateway),

    -- 本地網絡界面的網絡掩碼。如果為空白,則網絡掩碼由用戶端的網際網路位址導出,除非由啟動協定接收到值。

    -- 用戶端的域名。如果空白,則使用用戶端網際網路位址之 ASCII-标記法,或由啟動協定接收的值。

    -- 要使用的網絡裝置域名。

    -- 用以作為自動配置的方法。

    參考文檔:

    ramfs, rootfs, initrd and initramfs

    http://blog.chinaunix.net/u2/89923/showart_1890405.html

    嵌入式系統檔案系統比較

    http://blog.sina.com.cn/s/blog_53ad41a50100eptc.html

    LINUX系統性能調諧

    http://www.host01.com/article/server/00070002/0621409052193755_2.htm

    怎樣限制或者修改/dev/shm的大小

    http://www.linuxfly.cn/html/65/t-665.html

    ====================================================================

    ====================================================================

    3. 制作交叉工具鍊

    3.1 什麼是工具鍊

    3.2 擷取交叉工具鍊的幾種途徑

    3.3 android工具鍊與gnu工具鍊的比較

           每一個軟體,在編譯的過程中,都要經過一系列的處理,才能從源代碼變成可執行的目标代碼。這一系列處理包括:預編譯,進階語言編譯,

    彙編,連接配接及重定位。這一套流程裡面用到的每個工具和相關的庫組成的集合,就稱為工具鍊(tool chain)。以GNU的開發工具GCC為例,

    它就包括了預編譯器cpp,c編譯器gcc,彙編器as,和連接配接器ld等。在GNU自己對工具鍊定義中,還加進了一套額外的用于處理二進制包的

    工具包binutils,整個工具鍊應該是GCC+binutils+Glibc, binutils其實與Glibc關系不是很大,它可以被獨立安裝的,是以GNU工具

    鍊也可以狹義地被了解為GCC+Glibc。

    要建構出一個交叉工具鍊,需要解決三個問題。一是這個工具鍊必須是可以運作在原工作站平台上的。二是我們需要更換一個與目标平台對應的

    彙編器,使得工具鍊能産生對應的目标代碼,三是要更換一套與目标平台對應的二進制庫,使得工具鍊在連接配接時能找到正确的二進制庫。

    3.2 擷取交叉工具鍊的幾種途徑

    3.2.1 利用源代碼制作交叉工具鍊

    網上直接下載下傳工具鍊或者從方案商處擷取(如:marvell)

    下載下傳位址:

    http://www.angstrom-distribution.org/unstable/

    3.2.2 用腳本制作工具鍊

    3.2.2.1 croostool-0.43

    http://www.kegel.com/crosstool/crosstool-0.43.tar.gz

    制作工具鍊的源碼包搭配情況: http://www.kegel.com/crosstool/crosstool-0.43/buildlogs/

    3.2.2.2 buildroot

    http://buildroot.uclibc.org/downloads/snapshots/buildroot-snapshot.tar.bz2

    若想詳細地了解buildroot可參考該文檔http://buildroot.uclibc.org/buildroot.html

    3.2.3 利用OE制作工具鍊

    http://www.scratchbox.org/wiki/OpenEmbedded

    3.3 android工具鍊與gnu工具鍊的比較

    Android所用的Toolchain(即交叉編譯工具鍊)可從下面的網址下載下傳:

    http://android.kernel.org/pub/android-toolchain-20081019.tar.bz2。如果下載下傳了完整的Android項目的源代碼,則可以在

    “/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin”目錄下找到交叉編譯工具,比如Android所用的

    arm-eabi-gcc-4.2.1。Android并沒有采用glibc作為C庫,而是采用了Google自己開發的Bionic Libc,它的官方Toolchain也是基于

    Bionic Libc而并非glibc的。這使得使用或移植其他Toolchain來用于Android要比較麻煩:在Google公布用于Android的官方Toolchain之前,

    多數的Android愛好者使用的Toolchain是在http://www.codesourcery.com/gnu_toolchains/arm/download.html 下載下傳的一個通用的

    Toolchain,它用來編譯和移植Android 的Linux核心是可行的,因為核心并不需要C庫,但是開發Android的應用程式時,直接采用或者移植其他

    的Toolchain都比較麻煩,其他Toolchain編譯的應用程式隻能采用靜态編譯的方式才能運作于Android模拟器中,這顯然是實際開發中所不能接

    受的方式。目前尚沒有看到說明成功移植其他交叉編譯器來編譯Android應用程式的資料。

    與glibc相比,Bionic Libc有如下一些特點:

    -          采用BSD License,而不是glibc的GPL License;

    -          大小隻有大約200k,比glibc差不多小一半,且比glibc更快;

    -          實作了一個更小、更快的pthread;

    -          提供了一些Android所需要的重要函數,如”getprop”, “LOGI”等;

    -          不完全支援POSIX标準,比如C++ exceptions,wide chars等;

    -          不提供libthread_db 和 libm的實作

    另外,Android中所用的其他一些二進制工具也比較特殊:

    -          加載動态庫時使用的是/system/bin/linker而不是常用的/lib/ld.so;

    -          prelink工具不是常用的prelink而是apriori,其源代碼位于” /build/tools/apriori”

    -          strip工具也沒有采用常用的strip,即“/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin”

    目錄下的arm-eabi-strip,而是位于/out/host/linux-x86/bin/的soslim工具。

    參考文檔:

    CLFS2.0原理分析

    http://www.linuxsir.org/bbs/showthread.php?t=267672

    Cross-Compiled Linux From Scratch

    http://cross-lfs.org/view/clfs-sysroot/arm/

    全手工制作arm-linux交叉編譯工具鍊《一》

    http://blog.chinaunix.net/u2/62168/showart_1898748.html

    自己制作arm-linux交叉編譯環境(一)-scratch篇

    http://blog.csdn.net/chenzhixin/archive/2007/01/12/1481442.aspx

    如何建立交叉編譯工具鍊

    http://www.decell.org/article.asp?id=53

    Android Toolchain與Bionic Libc

    http://www.top-e.org/jiaoshi/html/?151.html

    ndroid編譯環境(2) - 手工編譯C子產品

    =================================================

    =================================================

    4. 軟體編譯常識

    4.1 連結器和加載器

    4.2 android 的标準連結器和加載器

    4.3 Makefile基本文法

    何為連結器和加載器?

    連結器為ld,加載為ld-linux.so.2,兩個的差別很大,一個編譯時用,一個運作時用,ld負責在編譯的搜尋路徑裡找到要求的庫,并檢視

    是否有提供了需要的 符号(如函數等),如果有,記錄相關資訊到程式中,由ld-linux.so.2在執行時查找到該庫,并根據相關資訊進行需

    要符号的重定位等工作.注意 這兩者的搜尋庫的方式是不同的。

    動态連接配接器通常是指的動态加載器(不要與 Binutils 裡的标準連接配接器 ld 混淆了)。動态連接配接器由 Glibc 提供,用來

    找到并加載一個程式運作時所需的共享庫,在做好程式運作的準備之後,運作這個程式。動态連接配接器的名稱通常是

    ld-linux.so.2,标準連接配接器 ld 由 Binutils 這個包提供。

    标準連接配接器

    檢視gcc使用的标準連接配接器

    mhf@mhf-desktop:/usr/local/marvell-arm-linux-4.1.1/bin$ arm-linux-gcc -print-prog-name=ld

    編譯時庫的搜尋路徑,以下幾種方式讓連接配接器去找需要的庫

    1. 編譯的時候明确指定,如: gcc test.c  ./say.so -o test中的   ./say.so

    2. 編譯 Binutils 的時候通過LIB_PATH 變量指定,

    如:make -C ld LIB_PATH=/tools/lib

    -C ld LIB_PATH=/tools/lib

    這個選項重新編譯 ld 子目錄中的所有檔案。在指令行中指定 Makefile 的 LIB_PATH 變量值,使它明确指向/tools/lib工具目錄,

    以覆寫預設值。這個變量的值指定了連接配接器的預設庫搜尋路徑。

    來源:Linux From Scratch - 版本 6.4第 5 章 建構臨時系統  5.4. Binutils-2.18 - 第一遍

    http://www.bitctp.org/lfsbook-6.4/chapter05/binutils-pass1.html

    3. 在源碼包configure的時候通過  --with-lib-path 指定,或者 --lib- path

    例如:

    binutils-2.18/configure --prefix=/tools --disable-nls --with-lib-path=/tools/lib

    配置選項的含義:

    --with-lib-path=/tools/lib

        告訴配置腳本在為編譯 Binutils 的過程中使用正确的庫搜尋路徑,也就是将 /tools/lib 傳遞給連接配接器。這防止連接配接器搜尋宿主系統中的庫檔案目錄。

    來源: Linux From Scratch - 版本 6.4 第 5 章 建構臨時系統  lfs 5.13. Binutils-2.18 - 第二遍

    http://www.bitctp.org/lfsbook-6.4/chapter05/binutils-pass2.html

    4. 到 ld –verbose | grep SEARCH 列出的預設目錄下去找

    5. -L/usr/gpephone/lib 指定的目錄找

    經常以 LDFLAGS=" -L/usr/gpephone/lib  -L/lib -L/usr/lib -L/usr/X11R7/lib" 的方式傳入

    參數 -rpath 與  -rpath-link

    如果使用了\'-rpath\'選項, 那運作時搜尋路徑就隻從\'-rpath\'選項中得到

    \'nodefaultlib\'标志一個對象,使在搜尋本對象所依賴的庫時,忽略所有預設庫搜尋路徑.

    LDFLAGS="-Wl,-rpath-link=/usr/gpephone/lib/:/usr/gphone/lib:/usr/local/lib  -L/usr/gpephone/lib  -L/usr/gphone/lib"

    -rpath 與  -rpath-link 的特性:

    1. 在編譯的時候我們都可以使用這兩個路徑,

    2. \'-rpath\'跟\'-rpath_link\'的不同之處在于,由\'-rpath\'指定的路徑會被包含到可執行程式中,并在運作時使用,

    而\'-rpath-link\'選項僅僅在連結時起作用。

    -dumpspecs               Display all of the built in spec strings

      -dumpversion             Display the version of the compiler

      -dumpmachine             Display the compiler\'s target processor

      -print-search-dirs       Display the directories in the compiler\'s search path

      -print-prog-name=  Display the full path to compiler component

      -specs=            Override built-in specs with the contents of

      -Wa,            Pass comma-separated  on to the assembler

      -Wp,            Pass comma-separated  on to the preprocessor

      -Wl,            Pass comma-separated  on to the linker

    從工具鍊内建的規範中檢視動态加載器

    gcc -dumpspecs | grep  dynamic-linker  //本機

    檢視編譯起所指定的動态加載器

    1. s3c2440 (arm9tdmi) 平台的工具鍊

    /scratchbox/compilers/arm-9tdmi-softfloat-linux-gcc-3.4.4-glibc-2.3.5/bin/arm-softfloat-linux-gnu-gcc -dumpspecs | grep  dynamic-linker

    /scratchbox/compilers/arm-softfloat-linux-gcc-3.4.4-glibc-2.3.5/bin/arm-softfloat-linux-gnu-gcc -dumpspecs | grep  dynamic-linker

    2. marvell 的工具鍊

    /scratchbox/compilers/marvell-arm-linux-4.1.1/bin/arm-linux-gcc  -dumpspecs | grep  dynamic-linker

    3. scrathbox 中工具鍊 host-gcc

    /scratchbox/compilers/host-gcc/bin/host-gcc  -dumpspecs | grep  dynamic-linker

    如果我們在編譯的時候給編譯起 gcc 指定 -specs=/scratchbox/compilers/host-gcc/host-gcc.spec ,那麼-specs指定

    的規範将會覆寫工具鍊内建的規範。

    cat /scratchbox/compilers/host-gcc/host-gcc.specs  | grep ld 有如下内容:

    -dynamic-linker /scratchbox/host_shared/lib/ld.so

    /scratchbox/compilers/host-gcc/bin/gcc -specs=/scratchbox/compilers/host-gcc/host-gcc.specs

    mhf@mhf-desktop:/usr/local/marvell-arm-linux-4.1.1/arm-iwmmxt-linux-gnueabi/bin$ ./gcc -dumpspecs|grep dynamic-linker

    gcc -dumpspecs | sed \'s@/lib/ld-linux.so.2@/tools&@g\'  | sudo tee  `dirname $(gcc -print-libgcc-file-name)`/specs

    cat `dirname $(gcc -print-libgcc-file-name)`/specs | grep tools

    檢視本機應用程式使用的動态加載器

    readelf -l /usr/bin/make | grep interpreter

    [Requesting program interpreter: /lib/ld-linux.so.2]

    檢視 scratchbox 中應用程式使用的動态加載器

    readelf -l /scratchbox/tools/bin/make | grep interpreter

    [Requesting program interpreter: /scratchbox/host_shared/lib/ld.so]

    cd ~/svn/mohuifu.svn/trunk/mysource/compiler_test

    /scratchbox/compilers/host-gcc/bin/gcc -specs=/scratchbox/compilers/host-gcc/host-gcc.specs -o ld.so.test1 ld.so.test.c

    /scratchbox/compilers/host-gcc/bin/gcc -o ld.so.test2 ld.so.test.c

    readelf -l ./ld.so.test1 | grep interpreter

    readelf -l ./ld.so.test2 | grep interpreter

    其他示例:

    readelf -l /scratchbox/tools/bin/make | grep interpreter

    readelf -l /usr/bin/make | grep interpreter

    分别顯示:

    [Requesting program interpreter: /scratchbox/host_shared/lib/ld.so]

    [Requesting program interpreter: /lib/ld-linux.so.2]

    下面的方式也可以檢視應用程式所使用的加載器

    strings  /scratchbox/tools/bin/make  |grep lib

    strings  /usr/bin/make  |grep lib

    分别為:

    /scratchbox/host_shared/lib/ld.so

    /lib/ld-linux.so.2

    檢視應程式加載器庫的搜尋路徑

    顯示 scratchbox 中加載器的庫搜尋路徑

    strings /scratchbox/host_shared/lib/ld.so |grep lib

    display library search paths

    /scratchbox/host_shared/lib/

    /scratchbox/tools/lib/

    顯示本機中加載器的庫搜尋路徑

    strings  /lib/ld-linux.so.2 |grep lib

    display library search paths

    /lib/

    /usr/lib/

    /lib/i486-linux-gnu/

    /usr/lib/i486-linux-gnu/

    ldd 驗證應用程式所使用動态庫

    ldd /scratchbox/tools/bin/make

            libc.so.6 => /scratchbox/host_shared/lib/libc.so.6 (0xb7ef9000)

            /scratchbox/host_shared/lib/ld.so => /scratchbox/host_shared/lib/ld.so (0xb802f000)

    ldd /usr/bin/make

            librt.so.1 => /lib/tls/i686/cmov/librt.so.1 (0xb7fb9000)

            libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7e5b000)

            libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0xb7e42000)

            /lib/ld-linux.so.2 (0xb7fd5000)

    參考文檔:

    交叉編譯中libtool相關的問題

    http://hi.baidu.com/lieyu063/blog/item/9c99a2dd23e41f365882dd39.html

    靜态庫和共享庫庫的定位搜尋路徑

    http://blog.csdn.net/lwhsyit/archive/2008/08/26/2830783.aspx

    Linux動态連接配接原理

    http://blog.chinaunix.net/u2/67984/showart_1359874.html

    程式編譯連結運作時對庫關系的探讨(原創)

    http://www.360doc.com/content/061107/09/13188_251964.html

    http://lamp.linux.gov.cn/Linux/LFS-6.2/chapter05/toolchaintechnotes.html

    [Linux指令] ld 中文使用手冊完全版(譯)

    http://blog.csdn.net/rstevens/archive/2008/01/28/2070568.aspx

    scratchbox 是mameo (nokia) 提供的一個內建開發環境,可以去官方網站:

    http://www.scratchbox.org/

    http://www.scratchbox.org/download/

    4.2 android 的标準連結器和加載器

    android的标準連結器 ./prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi-ld

    android 中标準連接配接器搜尋庫的路徑

    ./prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi-ld -verbose | grep SEARCH

    SEARCH_DIR("/android/mathias/armdev/toolchain-eabi-4.2.1/arm-eabi/lib");

    Android編譯環境所用的交叉編譯工具鍊是./prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi-gcc,

    -I和-L參數指定了所用的C庫頭檔案和動态庫檔案路徑分别是bionic/libc /include 和out/target/product/generic/obj/lib,

    其他還包括很多編譯選項以及-D所定義的預編譯宏。這裡值得留意的是參數“-Wl,-dynamic-linker,/system/bin/linker”,它指定了

    Android專用的動态連結器/system/bin/linker,而不是通常所用的ld.so。

    上面的“make clean-$(LOCAL_MODULE)”是Android編譯環境提供的make clean的方式。

    android中應用程式使用的加載器

    strings  out/target/product/littleton/obj/EXECUTABLES/rild_intermediates/rild  | grep link

    /system/bin/linker

    ./prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi-gcc -dumpspecs|grep dynamic-linker

    %{mbig-endian:-EB} %{mlittle-endian:-EL} %{static:-Bstatic} %{shared:-shared} %{symbolic:-Bsymbolic}

    %{!static:%{shared: -Bsymbolic} %{!shared:%{rdynamic:-export-dynamic} %{!dynamic-linker:-dynamic-linker /system/bin/linker}}} -X

    android中加載器搜尋庫的路徑

    strings /nfsroot/rootfs/system/bin/linker | grep lib

    /system/lib

    /lib

    生成的可執行程式可用file和readelf指令來檢視一下:

    file out/target/product/littleton/obj/EXECUTABLES/rild_intermediates/rild

    out/target/product/littleton/obj/EXECUTABLES/rild_intermediates/rild: ELF 32-bit LSB executable,

    ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped

    readelf -d out/target/product/littleton/obj/EXECUTABLES/rild_intermediates/rild  |grep NEEDED

    0x00000001 (NEEDED)                     Shared library: [liblog.so]

    0x00000001 (NEEDED)                     Shared library: [libcutils.so]

    0x00000001 (NEEDED)                     Shared library: [libril.so]

    0x00000001 (NEEDED)                     Shared library: [libc.so]

    0x00000001 (NEEDED)                     Shared library: [libstdc++.so]

    0x00000001 (NEEDED)                     Shared library: [libm.so]

    0x00000001 (NEEDED)                     Shared library: [libdl.so]

    這是ARM格式的動态連結可執行檔案,運作時需要libc.so和libm.so。“not stripped”表示它還沒被STRIP。嵌入式系統中為節省空間通常

    将編譯完成的可執行檔案或動态庫進行STRIP,即去掉其中多餘的符号表資訊。在前面“make helloworld showcommands”指令的最後我們也

    可以看到,Android編譯環境中使用了out/host/linux-x86/bin/soslim工具進行STRIP。

    4.3 Makefile基本文法

    Makefile詳解(超級好)

    linux/Unix環境下的make和makefile詳解

    http://www.unlinux.com/doc/program/20051026/2365.html

    跟我一起寫 Makefile

    http://dev.csdn.net/develop/article/20/20025.shtm

    =================================================

    =================================================

    5. 設定子產品流程分析

    rild 流程分析

    5.1 設定 pin 狀态,pin認證

    5.1.1 設定pin狀态

    5.1.2 修改sim卡pin

    5.1.3 pin認證流程

    5.2 網絡設定

    5.3 螢幕背光設定

    5.4 擷取,顯示電池狀态

    ================

    EditPinPreference.java (packages\apps\settings\src\com\android\settings)

    private OnPinEnteredListener mPinListener;

    protected void onDialogClosed(boolean positiveResult)

      mPinListener.onPinEntered(this, positiveResult);

    執行  SimLockSettings.java (packages\apps\settings\src\com\android\settings)中函數:

    public void onPinEntered(EditPinPreference preference, boolean positiveResult)

    修改pin狀态: tryChangeSimLockState();

    修改pin:        tryChangePin();

    5.1.1 設定pin狀态

    private void tryChangeSimLockState()

      Message callback = Message.obtain(mHandler, ENABLE_SIM_PIN_COMPLETE);

      mPhone.getSimCard().setSimLockEnabled(mToState, mPin, callback);

    進入sim lock 菜單會顯示初始化pin狀态,是通過下面語句得到:

    mPinToggle.setChecked(mPhone.getSimCard().getSimLockEnabled());

    mPhone.getSimCard().setSimLockEnabled(mToState, mPin, callback)調用的是檔案:

    GsmSimCard.java (frameworks\base\telephony\java\com\android\internal\telephony\gsm)中的函數:

    public void setSimLockEnabled (boolean enabled,String password, Message onComplete) {

      int serviceClassX;

      serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +

                    CommandsInterface.SERVICE_CLASS_DATA +

                    CommandsInterface.SERVICE_CLASS_FAX;

      mDesiredPinLocked = enabled;

      phone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_SIM,

                    enabled, password, serviceClassX,

                    obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete));

    phone.mCM.setFacilityLock 調用的是檔案:

    RIL.java (frameworks\base\telephony\java\com\android\internal\telephony\gsm)中的函數:

        public void

        setFacilityLock (String facility, boolean lockState, String password,

                            int serviceClass, Message response)

        {

            String lockString;

             RILRequest rr

                    = RILRequest.obtain(RIL_REQUEST_SET_FACILITY_LOCK, response);

            if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));

            // count strings

            rr.mp.writeInt(4);

            rr.mp.writeString(facility);

            lockString = (lockState)?"1":"0";

            rr.mp.writeString(lockString);

            rr.mp.writeString(password);

            rr.mp.writeString(Integer.toString(serviceClass));

            send(rr);

        }

    設定應用程式向 rild 發送 RIL_REQUEST_SET_FACILITY_LOCK 請求的 socket消息,

    android的初始源代碼中 RIL_REQUEST_SET_FACILITY_LOCK 請求,在參考實作 Reference-ril.c

    (hardware\ril\reference-ril) 中沒有實作。

    我們需要做得工作是:

    ==========

    5.1.2 修改sim卡pin

    private void tryChangePin()

      mPhone.getSimCard().changeSimLockPassword(mOldPin,mNewPin, callback);

    mPhone.getSimCard 調用的是檔案:

    GsmSimCard.java (frameworks\base\telephony\java\com\android\internal\telephony\gsm)中的函數:

    public void changeSimLockPassword(String oldPassword, String newPassword,

                Message onComplete)

      phone.mCM.changeSimPin(oldPassword, newPassword,

                    obtainMessage(EVENT_CHANGE_SIM_PASSWORD_DONE, onComplete));

    phone.mCM.changeSimPin 調用的是檔案:

    RIL.java (frameworks\base\telephony\java\com\android\internal\telephony\gsm)中的函數:

        public void

        changeSimPin(String oldPin, String newPin, Message result)

        {

            RILRequest rr = RILRequest.obtain(RIL_REQUEST_CHANGE_SIM_PIN, result);

            if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));

            rr.mp.writeInt(2);

            rr.mp.writeString(oldPin);

            rr.mp.writeString(newPin);

            send(rr);

        }

    rild端處理流程:

    5.1.3 pin認證流程

    ========

    5.2 網絡設定

    =======

    5.3 螢幕背光設定

    packages/apps/Settings/src/com/android/settings/BrightnessPreference.java

    背光設定滾動條和關閉按鈕都會調用  setBrightness(mOldBrightness);

    public void onProgressChanged(SeekBar seekBar, int progress,boolean fromTouch)

    protected void onDialogClosed(boolean positiveResult)

        private void setBrightness(int brightness) {

            try {

                IHardwareService hardware = IHardwareService.Stub.asInterface(

                        ServiceManager.getService("hardware"));

                if (hardware != null) {

                    hardware.setBacklights(brightness);

                }

            } catch (RemoteException doe) {        

            }        

        }

    調用硬體伺服器 HardwareService 的 setBacklights 函數

    HardwareService.java (frameworks\base\services\java\com\android\server):   

    public void setBacklights(int brightness)

    {

            . . .

            // Don\'t let applications turn the screen all the way off

            brightness = Math.max(brightness, Power.BRIGHTNESS_DIM);

            setLightBrightness_UNCHECKED(LIGHT_ID_BACKLIGHT, brightness);

            setLightBrightness_UNCHECKED(LIGHT_ID_KEYBOARD, brightness);

            setLightBrightness_UNCHECKED(LIGHT_ID_BUTTONS, brightness);

            . . .

    }

    void setLightOff_UNCHECKED(int light)

    {

            //本地調用 setLight_native

            setLight_native(mNativePointer, light, 0, LIGHT_FLASH_NONE, 0, 0);

    }

        void setLightBrightness_UNCHECKED(int light, int brightness) {

            int b = brightness & 0x000000ff;

            b = 0xff000000 | (b = 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 int  set_light_backlight(struct light_device_t* dev,

                struct light_state_t const* state)

       . .  .

       color = state->color;

        tmp = ((77*((color>>16)&0x00ff)) + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8;

        brightness = tmp/16;

        LOGD("---->calling %s(),line=%d state->color=%d,brightness=%d\n",__FUNCTION__,__LINE__,state->color,brightness);

        len = sprintf(buf,"%d",brightness);

        len = write(fd, buf, len);

        . . .

    上面的函數完成了與核心的互動

    綜上所述,程式調用流程如下,上層應用通過 /sys/class/leds/lcd-backlight/brightnes 于核心打交道

    設定子產品 -> 硬體伺服器 -> 本地調用 ->功能庫 -> 讀寫  /sys/class/leds/lcd-backlight/brightness 函數與核心互動

    Init.rc (vendor\marvell\littleton):    chown system system /sys/class/leds/keyboard-backlight/brightness

    Init.rc (vendor\marvell\littleton):    chown system system /sys/class/leds/lcd-backlight/brightness

    Init.rc (vendor\marvell\littleton):    chown system system /sys/class/leds/button-backlight/brightness

    5.4 擷取,顯示電池狀态

    電池狀态(正在充電(AC)):

    Status.java

    String statusString;

    mBatteryStatus.setSummary(statusString);

        public static final int BATTERY_STATUS_UNKNOWN = 1;

        public static final int BATTERY_STATUS_CHARGING = 2;

        public static final int BATTERY_STATUS_DISCHARGING = 3;

        public static final int BATTERY_STATUS_NOT_CHARGING = 4;

        public static final int BATTERY_STATUS_FULL = 5;

        // values for "health" field in the ACTION_BATTERY_CHANGED Intent

        public static final int BATTERY_HEALTH_UNKNOWN = 1;

        public static final int BATTERY_HEALTH_GOOD = 2;

        public static final int BATTERY_HEALTH_OVERHEAT = 3;

        public static final int BATTERY_HEALTH_DEAD = 4;

        public static final int BATTERY_HEALTH_OVER_VOLTAGE = 5;

        public static final int BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6;

    public static final int BATTERY_PLUGGED_AC = 1;  電源充電

    public static final int BATTERY_PLUGGED_USB = 2; USB充電

    BatteryInfo.java (packages\apps\settings\src\com\android\settings)

    電池級别(50%)

    BatteryService.java (frameworks\base\services\java\com\android\server)

    電池伺服器:

    構造函數:

    public BatteryService(Context context)

      mUEventObserver.startObserving("SUBSYSTEM=power_supply");

    ----------

    UEventObserver.java (frameworks\base\core\java\android\os)

    void startObserving(String match)

      ensureThreadStarted();

        sThread = new UEventThread();

        sThread.start();

      sThread.addObserver(match, this);

    -----------

      update()

        native_update();

        sendIntent();

    private final void sendIntent()

      Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);

      intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);

      ...

      intent.putExtra("status", mBatteryStatus);

      intent.putExtra("health", mBatteryHealth);

      intent.putExtra("present", mBatteryPresent);

      intent.putExtra("level", mBatteryLevel);

      intent.putExtra("scale", BATTERY_SCALE);

      intent.putExtra("icon-small", icon);

      intent.putExtra("plugged", mPlugType);

      intent.putExtra("voltage", mBatteryVoltage);

      intent.putExtra("temperature", mBatteryTemperature);

      intent.putExtra("technology", mBatteryTechnology);

    ActivityManagerNative.broadcastStickyIntent(intent, null);

    把讀取的電池資訊通過廣播資訊發送給所有的應用程式。

    native_update 本地調用的是檔案 com_android_server_BatteryService.cpp (frameworks\base\services\jni) 中的函數:

    static void android_server_BatteryService_update(JNIEnv* env, jobject obj)

    {

        setBooleanField(env, obj, AC_ONLINE_PATH, gFieldIds.mAcOnline);

        setBooleanField(env, obj, USB_ONLINE_PATH, gFieldIds.mUsbOnline);

        setBooleanField(env, obj, BATTERY_PRESENT_PATH, gFieldIds.mBatteryPresent);

        setIntField(env, obj, BATTERY_CAPACITY_PATH, gFieldIds.mBatteryLevel);

        setIntField(env, obj, BATTERY_VOLTAGE_PATH, gFieldIds.mBatteryVoltage);

        setIntField(env, obj, BATTERY_TEMPERATURE_PATH, gFieldIds.mBatteryTemperature);

        const int SIZE = 128;

        char buf[SIZE];

        if (readFromFile(BATTERY_STATUS_PATH, buf, SIZE) > 0)

            env->SetIntField(obj, gFieldIds.mBatteryStatus, getBatteryStatus(buf));

        if (readFromFile(BATTERY_HEALTH_PATH, buf, SIZE) > 0)

            env->SetIntField(obj, gFieldIds.mBatteryHealth, getBatteryHealth(buf));

        if (readFromFile(BATTERY_TECHNOLOGY_PATH, buf, SIZE) > 0)

            env->SetObjectField(obj, gFieldIds.mBatteryTechnology, env->NewStringUTF(buf));

    }

    #define AC_ONLINE_PATH "/sys/class/power_supply/ac/online"

    #define USB_ONLINE_PATH "/sys/class/power_supply/usb/online"

    #define BATTERY_STATUS_PATH "/sys/class/power_supply/battery/status"

    #define BATTERY_HEALTH_PATH "/sys/class/power_supply/battery/health"

    #define BATTERY_PRESENT_PATH "/sys/class/power_supply/battery/present"

    #define BATTERY_CAPACITY_PATH "/sys/class/power_supply/battery/capacity"

    #define BATTERY_VOLTAGE_PATH "/sys/class/power_supply/battery/batt_vol"

    #define BATTERY_TEMPERATURE_PATH "/sys/class/power_supply/battery/batt_temp"

    #define BATTERY_TECHNOLOGY_PATH "/sys/class/power_supply/battery/technology"

    =================================================

    =================================================

    6. linux系統啟動流程分析

    6.1 桌面作業系統啟動流程(redhat,federa,ubuntu)

    6.2 小型嵌入式系統啟動流程

    6.3 android 系統啟動流程

    ==============

    6.1 桌面作業系統啟動流程(redhat,federa,ubuntu)

    ubuntu從6.10開始逐漸用upstart代替原來的sysinit,進行服務程序的管理。為了對原有的init實作向後相容,

    目前ubuntu中與init相關的幾個目錄和應用程式,可以友善後面的論述。這些目錄和程式包括:

    init

    telinit  //字面了解 tell init

    runlevel

    /etc/event.d/

    /etc/init.d/

    /etc/rcX.d/

    首先是/etc/event.d/目錄,這是upstart的核心,upstart不同于原有的init的地方就在于它引入了event機制。Event 機制通俗的

    講就是将所有程序的觸發、停止等等都看作event(事件)。/etc/event.d/中就存放了目前upstart需要識别的event。這其中主要有三種

    rc-default, rcX(x=0,1,...6,S)以及ttyX。這rc-default就類似于 inittab檔案,它就是設定預設運作級别的 ,需要運作程式的

    腳本,而ttyX則是設定僞終端數目的,也就是你Ctrl+Alt+F(1~6)調出的那個Console。我們以rc2為例,cat rc2:

    rc-default

    start on stopped rcS

    telinit 2

    是以會依次執行 /etc/event.d/rcS /etc/event.d/rc2

    它們又會分别執行:

    exec /etc/init.d/rc S

    exec /etc/init.d/rc 2

    這樣,我們就可以自然地過渡到下一個重要的目錄,/etc/init.d/了。

    /etc/init.d/中存放的是服務(services)或者任務(tasks)的執行腳本。可以這麼說,隻要你安裝了一個程式(特别是服務程式daemon),

    它可以在系統啟動的時候運作,那麼它必定會在/etc/init.d/中有一個腳本檔案。

    執行了一個exec /etc/init.d/rc 2的指令。也就是說,給/etc/init.d/rc腳本傳遞了一個參數"2",讓它執行。

    rc腳本(很長,耐心點),能看到這樣的一段:

    # Now run the START scripts for this runlevel.

    # Run all scripts with the same level in parallel

    .......

    for s in /etc/rc$runlevel.d/S*

    .......

    将會開始執行/etc/rc2.d/下S開頭的腳本。這就過渡到下一個目錄/etc/rc2.d/了。

    /etc/rc2.d 都是一些到/etc/init.d/中腳本的符号連結。不同的是在開頭加上了S和一個數字,S表示在啟動時運作,數字則表示執行的先後順序。

    /etc/rcS.d/S35mountall.sh

    K08vmware

    S19vmware

    S20nfs-common

    S20nfs-kernel-server

    S20samba

    S20xinetd

    S30gdm

    S98usplash

    S99rc.local

    總結:

        這樣一來,upstart管理的ubuntu啟動過程應該就清楚了。梳理一下:

        1,核心啟動init

        2,init找到/etc/event.d/rc-default檔案,确定預設的運作級别(X)

        3,觸發相應的runlevel事件,開始運作/etc/event.d/rcX

        4,rcX運作/etc/init.d/rc,傳入參數X

        5,/etc/init.d/rc腳本進行一系列設定,最後運作相應的/etc/rcX.d/中的腳本

        6,/etc/rcX.d/中的腳本按事先設定的優先級依次啟動,直至最後給出登入畫面(啟動X伺服器和GDM)

        了解了這些,手動配置開機服務的啟動與否就很簡單了。Ubutnu預設的啟動級别是2,不想啟動的程式,隻要把相應的符号連結從/etc/rc2.d/中删去即可

    注意:

    想redat ,federa 這些系統,他們用的是sysvinit ,有 /etc/inittab 檔案,裡面定義了 :

    id:5:initdefault:

    si::sysinit:/etc/init.d/rcS

    init 直接解析  id:5:initdefault 字段,然後執行 /etc/rc5.d/ 下面的腳本

    ================

    參考文檔:

    linux教程:upstart 和ubuntu啟動過程原理介紹

    http://www.zhiweinet.com/jiaocheng/2009-06/12500.htm

    6.2 小型嵌入式系統啟動流程

    小型嵌入式的 init 通常使用busybox中自帶的,

    6.3 android 系統啟動流程

    參考文檔:

    init 是核心進入檔案系統後第一個運作的程式,我們可以在linux的指令行中進行指定,如果沒指定,核心将會到/sbin/, /bin/ 等目錄下

    查找預設的init,如果沒有找到那麼就報告出錯。

    init 源代碼分析

    init的mian函數在檔案:./system/core/init/init.c 中,init會一步步完成下面的任務:

    1.初始化log系統

    2.解析/init.rc和/init.%hardware%.rc檔案  

    3. 執行 early-init action in the two files parsed in step 2.  

    4. 裝置初始化,例如:在 /dev 下面建立所有裝置節點,下載下傳 firmwares.  

    5. 初始化屬性伺服器,Actually the property system is working as a share memory. Logically it looks like a registry under Windows system.  

    6. 執行 init action in the two files parsed in step 2.  

    7. 開啟 屬性服務。

    8. 執行 early-boot and boot actions in the two files parsed in step 2.  

    9. 執行 Execute property action in the two files parsed in step 2.  

    10. 進入一個無限循環 to wait for device/property set/child process exit events.例如,如果SD卡被插入,init會收到一個裝置插入事件,

    它會為這個裝置建立節點。系統中比較重要的程序都是由init來fork的,是以如果他們他誰崩潰了,那麼init 将會收到一個 SIGCHLD 信号,把這個信号轉化

    為子程序退出事件, 是以在loop中,init 會操作程序退出事件并且執行 *.rc 檔案中定義的指令。

    例如,在init.rc中,因為有:

    service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server

        socket zygote stream 666

        onrestart write /sys/android_power/request_state wake

        onrestart write /sys/power/state on

    是以,如果zygote因為啟動某些服務導緻異常退出後,init将會重新去啟動它。

    int main(int argc, char **argv)

    {

        ...

        //需要在後面的程式中看列印資訊的話,需要屏蔽open_devnull_stdio()函數

        open_devnull_stdio();

        ...

        //初始化log系統

        log_init();

        //解析/init.rc和/init.%hardware%.rc檔案

        parse_config_file("/init.rc");

        ...

        snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);

        parse_config_file(tmp);

        ...

        //執行 early-init action in the two files parsed in step 2.

        action_for_each_trigger("early-init", action_add_queue_tail);

        drain_action_queue();

        ...

        /* execute all the boot actions to get us started */

        /* 執行 init action in the two files parsed in step 2 */

        action_for_each_trigger("init", action_add_queue_tail);

        drain_action_queue();

        ...

        /* 執行 early-boot and boot actions in the two files parsed in step 2 */

        action_for_each_trigger("early-boot", action_add_queue_tail);

        action_for_each_trigger("boot", action_add_queue_tail);

        drain_action_queue();

        /* run all property triggers based on current state of the properties */

        queue_all_property_triggers();

        drain_action_queue();

        /* enable property triggers */  

        property_triggers_enabled = 1;   

        ...

        for(;;) {

            int nr, timeout = -1;

        ...

            drain_action_queue();

            restart_processes();

            if (process_needs_restart) {

                timeout = (process_needs_restart - gettime()) * 1000;

                if (timeout

    重要的資料結構

    兩個清單,一個隊列。

    static list_declare(service_list);

    static list_declare(action_list);

    static list_declare(action_queue);

    *.rc 腳本中所有 service關鍵字定義的服務将會添加到 service_list 清單中。

    *.rc 腳本中所有 on     關鍵開頭的項将會被會添加到 action_list 清單中。

    每個action清單項都有一個清單,此清單用來儲存該段落下的 Commands

    腳本解析過程

    parse_config_file("/init.rc")

    int parse_config_file(const char *fn)

    {

        char *data;

        data = read_file(fn, 0);

        if (!data) return -1;

        parse_config(fn, data);

        DUMP();

        return 0;

    }

    static void parse_config(const char *fn, char *s)

        ...

        case T_NEWLINE:

            if (nargs) {

                int kw = lookup_keyword(args[0]);

                if (kw_is(kw, SECTION)) {

                    state.parse_line(&state, 0, 0);

                    parse_new_section(&state, kw, nargs, args);

                } else {

                    state.parse_line(&state, nargs, args);

                }

                nargs = 0;

            }

       ...

    parse_config會逐行對腳本進行解析,如果關鍵字類型為  SECTION ,那麼将會執行 parse_new_section()

    類型為 SECTION 的關鍵字有: on 和 sevice

    關鍵字類型定義在 Parser.c (system\core\init) 檔案中

    Parser.c (system\core\init)

    #define SECTION 0x01

    #define COMMAND 0x02

    #define OPTION  0x04

    關鍵字        屬性      

    capability,  OPTION,  0, 0)

    class,       OPTION,  0, 0)

    class_start, COMMAND, 1, do_class_start)

    class_stop,  COMMAND, 1, do_class_stop)

    console,     OPTION,  0, 0)

    critical,    OPTION,  0, 0)

    disabled,    OPTION,  0, 0)

    domainname,  COMMAND, 1, do_domainname)

    exec,        COMMAND, 1, do_exec)

    export,      COMMAND, 2, do_export)

    group,       OPTION,  0, 0)

    hostname,    COMMAND, 1, do_hostname)

    ifup,        COMMAND, 1, do_ifup)

    insmod,      COMMAND, 1, do_insmod)

    import,      COMMAND, 1, do_import)

    keycodes,    OPTION,  0, 0)

    mkdir,       COMMAND, 1, do_mkdir)

    mount,       COMMAND, 3, do_mount)

    on,          SECTION, 0, 0)

    oneshot,     OPTION,  0, 0)

    onrestart,   OPTION,  0, 0)

    restart,     COMMAND, 1, do_restart)

    service,     SECTION, 0, 0)

    setenv,      OPTION,  2, 0)

    setkey,      COMMAND, 0, do_setkey)

    setprop,     COMMAND, 2, do_setprop)

    setrlimit,   COMMAND, 3, do_setrlimit)

    socket,      OPTION,  0, 0)

    start,       COMMAND, 1, do_start)

    stop,        COMMAND, 1, do_stop)

    trigger,     COMMAND, 1, do_trigger)

    symlink,     COMMAND, 1, do_symlink)

    sysclktz,    COMMAND, 1, do_sysclktz)

    user,        OPTION,  0, 0)

    write,       COMMAND, 2, do_write)

    chown,       COMMAND, 2, do_chown)

    chmod,       COMMAND, 2, do_chmod)

    loglevel,    COMMAND, 1, do_loglevel)

    device,      COMMAND, 4, do_device)

    parse_new_section()中再分别對 service 或者 on 關鍵字開頭的内容進行解析。

        ...

        case K_service:

            state->context = parse_service(state, nargs, args);

            if (state->context) {

                state->parse_line = parse_line_service;

                return;

            }

            break;

        case K_on:

            state->context = parse_action(state, nargs, args);

            if (state->context) {

                state->parse_line = parse_line_action;

                return;

            }

            break;

        }

        ...

    對 on 關鍵字開頭的内容進行解析

    static void *parse_action(struct parse_state *state, int nargs, char **args)

    {

        ...

        act = calloc(1, sizeof(*act));

        act->name = args[1];

        list_init(&act->commands);

        list_add_tail(&action_list, &act->alist);

        ...

    }

    對 service 關鍵字開頭的内容進行解析

    static void *parse_service(struct parse_state *state, int nargs, char **args)

    {

        struct service *svc;

        if (nargs 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, "Preloading 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 SurfaceFlinger

                        SurfaceFlinger::instantiate();

                        //Start the AudioFlinger media playback  camera 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) 函數中列印:              

    "Process %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.startsurfaceflinger", propBuf, "1");

        if (strcmp(propBuf, "1") == 0) {

            //讀取屬性伺服器,開啟啟動 SurfaceFlinger服務

            //接着會開始顯示機器人圖示

            //BootAnimation.cpp (frameworks\base\libs\surfaceflinger):status_t BootAnimation::readyToRun()

            SurfaceFlinger::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 \'SurfaceFlinger\' died

    D/Zygote  (   30): Process 45 terminated by signal (11)

    I/Zygote  (   30): Exit zygote because system server (45) has terminated

    通過錯誤資訊發現程式在調用 SurfaceFlinger服務的時候被中止。

    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=fsfs  smartphone

    --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 import  smartphone/  svn://192.168.2.148/smartphone

    1.1.5 運作svn伺服器

    svnserve -d -r  path_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-jianping  cupcake-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 5  cupcake-jianping/packages/apps/Phone/src/com/android/phone/xxxx.java

    1.2.3 svn st 檢視檔案狀态資訊

    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.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

    U  xxxx

    G  yyyy

    C  xxxx.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 ========================

    本文來自ChinaUnix部落格,如果檢視原文請點:http://blog.chinaunix.net/u1/49742/showart_2077813.html

  • linux ,Android基礎知識總結