Android系統(tǒng)移植技術詳解【強烈推薦,非常經典】_第1頁
Android系統(tǒng)移植技術詳解【強烈推薦,非常經典】_第2頁
Android系統(tǒng)移植技術詳解【強烈推薦,非常經典】_第3頁
Android系統(tǒng)移植技術詳解【強烈推薦,非常經典】_第4頁
Android系統(tǒng)移植技術詳解【強烈推薦,非常經典】_第5頁
已閱讀5頁,還剩68頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

Android系統(tǒng)開發(fā)編譯環(huán)境配置 主機系統(tǒng): Ubuntu9.04 (1)安裝如下軟件包 sudo apt-get install git-core sudo apt-get install gnupg sudo apt-get install sun-java5-jdk sudo apt-get install flex sudo apt-get install bison sudo apt-get install gperf sudo apt-get install libsdl-dev sudo apt-get install libesd0-dev sudo apt-get install build-essential sudo apt-get install zip sudo apt-get install curl sudo apt-get install libncurses5-dev sudo apt-get install zlib1g-dev android編譯對 java的需求只支持 jdk5.0低版本, jdk5.0 update 12版本和 java 6不支持。 (2)下載 repo工具 curl /repo /bin/repo chmod a+x /bin/repo (3)創(chuàng)建源代碼下載目錄: mkdir /work/android-froyo-r2 (4)用 repo工具初始化一個版本 (以 android2.2r2為例 ) cd /work/android-froyo-r2 repo init -u git://platform/manifest.git -b froyo 初始化過程中會顯 示相關的版本的 TAG 信息,同時會提示你輸入用戶名和郵箱地址,以上面的方式初始化的是 android2.2 froyo的最新版本, android2.2本身也會有很多個版本,這可以從 TAG信息中看出來,當前 froyo的所有版本如下: * new tag android-2.2.1_r1 - android-2.2.1_r1 * new tag android-2.2_r1 - android-2.2_r1 * new tag android-2.2_r1.1 - android-2.2_r1.1 * new tag android-2.2_r1.2 - android-2.2_r1.2 * new tag android-2.2_r1.3 - android-2.2_r1.3 * new tag android-cts-2.2_r1 - android-cts-2.2_r1 * new tag android-cts-2.2_r2 - android-cts-2.2_r2 * new tag android-cts-2.2_r3 - android-cts-2.2_r3 這樣每次下載的都是最新的版本,當然我們也可以根據(jù) TAG信息下載某一特定的版本如下: repo init -u git://platform/manifest.git -b android-cts-2.2_r3 (5)下載代碼 repo sync froyo版本的代碼大小超過 2G,漫長的下載過程。 (6)編譯代碼 cd /work/android-froyo-r2 make Ubuntu下使用 Simba服務實現(xiàn)局域網內文件共享 Ubuntu下安裝 Simba服務器將 linux電腦上的內容共享,同一局域網內的另外一臺 Windows PC即可訪問其共享內容, 從而實現(xiàn) Windows電腦向訪問本地文件一樣訪問 Linux文件系統(tǒng)的內容。 (1)安裝 Simaba服務器 sudo apt-get install samba (2)安裝 samba圖形化配置軟件 sudo apt-get install system-config-samba (3)創(chuàng)建一個 Simba專用用戶 從“系統(tǒng)” “系統(tǒng)管理” “用戶和組”,來創(chuàng)建。如圖,先點擊“解鎖”,然后“添加新用戶” 然后輸入新用 戶名字 (如 Simba)和密碼 (如 111111),然后在“高級”里面,選擇“主組”為 sambashare后點擊 確定 即可 一句話來概括,就是創(chuàng)建一個主組為 sambashare的用戶 (4)配置 samba共享 從“系統(tǒng)” “系統(tǒng)管理 ” samba“,運行配置界面 然后”首選項“ ”服務器設置“。點擊:安全性,在最后的”來賓帳號“里面, 選擇我們新建立的那個用戶 simba后點擊確定 (5)修改 samba配置文件 打開 /etc/samba/smb.conf,修改 valid users = XXXX為 valid users = simba (6)重啟 samba服務 sudo /etc/init.d/samba restart (7)添加共享文件 從“系統(tǒng)” “系統(tǒng)管理 ” samba“,運行配置界面 點擊 添加 來添加共享文件夾 ,點擊 瀏覽 來選擇需要共享的文件夾,選擇 可擦寫 和 顯示 ,點擊 訪問 可以設置訪問權限,最好設置成 允許所有用戶訪問 本文來自 CSDN博客,轉載請標明出處: /jiajie961/archive/2010/11/04/5987821.aspx Ubuntu下 tftp服務器的創(chuàng)建 實驗平臺: Ubuntu9.04 (1)安裝 tftp服務 sudo apt-get install tftp tftpd openbsd-inetd (2)在根目錄下創(chuàng)建文件夾 tftpboot文件夾并修改權限 cd / sudo mkdir tftpboot sudo chmod 777 tftpboot (3)修改 /etc/inetd.conf文件如下: tftp dgram udp wait nobody /usr/sbin/tcpd /usr/sbin/in.tftpd /tftpboot (4)開啟 tftp服務 sudo /etc/init.d/openbsd-inetd reload sudo in.tftpd -l /tftpboot (5)重啟電腦,然后將測試文件放入 /tftpboot目錄下即可開始測試,出現(xiàn)問題可能一般都是權限問題 /tftpboot目錄下的文件訪問權限改成 0777 本文來自 CSDN博客,轉載請標明出處: /jiajie961/archive/2010/11/05/5989328.aspx 創(chuàng)建一個新的 Android產品項目 從 google網站上下載的 android源代碼編譯時默認是編譯 google設定的產品,如果要開發(fā)自己的產 品, 則需要重新定義一個產品項目,過程如下: 首先我們定義產品的規(guī)格,舉例如下: 公司名稱 ardent 產品名稱 MTP 主板名稱 merlin 然后安裝下面的步驟新建產品項目: (1)在源代碼目錄下創(chuàng)建一個用戶目錄 mkdir vendor (2)在用戶目錄下創(chuàng)建一個公司目錄 mkdir vendor/merlin (3)在公司目錄下創(chuàng)建一個 products目錄 mkdir vendor/merlin/products (4)在上面創(chuàng)建的 products下創(chuàng)建一個產品 makefile文件 MTP.mk,內容如下: PRODUCT_PACKAGES := AlarmClock Email Fallback Launcher2 Music Camera Settings LatinIME NotePad SoundRecorder Bluetooth CertInstaller DeskClock $(call inherit-product, $(SRC_TARGET_DIR)/product/core.mk) # # Overrides PRODUCT_MANUFACTURER := ardent PRODUCT_BRAND := ardent PRODUCT_NAME := MTP PRODUCT_MODEL := MultiMedia Touch Phone PRODUCT_DEVICE := merlin PRODUCT_LOCALES := zh_CN 產品 makefile文件的編寫有一套規(guī)則,詳細情況見此文后面的補充內容。 (5)在 vendor/merlin/products目錄下創(chuàng)建一個 AndroidProducts.mk文件,定義 Android產品配置文件的路徑,具體如下: PRODUCT_MAKEFILES := $(LOCAL_DIR)/MTP.mk (6)在公司目錄下創(chuàng)建一個主板目錄 mkdir vendor/ardent/merlin (7)在主板目錄下新建一個主板配置文件 BoardConfig.mk,內容如下: TARGET_NO_BOOTLOADER := true TARGET_NO_KERNEL := true TARGET_CPU_ABI := armeabi BOARD_USES_GENERIC_AUDIO := true USE_CAMERA_STUB := true (8)如果你希望修改系統(tǒng)屬性,則可以在主板目錄下新建一個 p 文件,該文件中可以修改系統(tǒng)屬性,舉例如下: # p for # This overrides settings in the products/generic/p file # # rild.libpath=/system/lib/libreference-ril.so # rild.libargs=-d /dev/ttyS0 (9)在主板目錄下建議一個 Android 的主板配置文件 AndroidBoard.mk,此文件是編譯系統(tǒng)接口文件,內容如下: # make file for new hardware from # LOCAL_PATH := $(call my-dir) # # this is here to use the pre-built kernel ifeq ($(TARGET_PREBUILT_KERNEL),) TARGET_PREBUILT_KERNEL := $(LOCAL_PATH)/kernel endif file := $(INSTALLED_KERNEL_TARGET) ALL_PREBUILT += $(file) $(file): $(TARGET_PREBUILT_KERNEL) | $(ACP) $(transform-prebuilt-to-target) # # no boot loader, so we dont need any of that stuff. # LOCAL_PATH := vendor/ardent/merlin include $(CLEAR_VARS) # # include more board specific stuff here? Such as Audio parameters. # (10)編譯新的項目 . build/envsetup.sh make PRODUCT-MTP-user 補充內容: (1)上面的新建的幾個文件的編寫可以參考 build/target/board/generic 目錄下的 AndroidBoard.mk,BoardConfig.mk和 p (2)產品 makefile的編寫規(guī)則,變量定義解釋如下: PRODUCT_NAME 終端用戶可見的產品名稱,對應到“ Settings“中的“ About the phone”信息 PRODUCT_MODEL End-user-visible name for the end product PRODUCT_LOCALES 1個以空格分隔開的兩個字母的語言碼加上 2字節(jié)的國家碼的列表,影響到 Settings中的語言,時間,日期和貨幣格式設置, 舉例: en_GB de_DE es_ES fr_CA PRODUCT_PACKAGES 需要安裝的 APK應用程序列表 PRODUCT_DEVICE 工作設計名稱,即主 板名稱 PRODUCT_MANUFACTURER 生產廠家 PRODUCT_BRAND 軟件設計針對的客戶品牌 PRODUCT_PROPERTY_OVERRIDES 以 key=value為格式的屬性列表 PRODUCT_COPY_FILES 文件復制列表,格式為“原文件路徑:目的文件路徑”,編譯過程中會按照此規(guī)則復制文件 PRODUCT_OTA_PUBLIC_KEYS 產品的 OTA公共密匙列表 PRODUCT_POLICY 聲明此產品使用的政策 PRODUCT_PACKAGE_OVERLAYS 指示是否使用默認資源或添加任何產品特定的資源,例如:vendor/acme/overlay PRODUCT_CONTRIBUTORS_FILE HTML文件中包含項目的貢獻者 PRODUCT_TAGS 以空格分隔開的指定產品關鍵詞列表 本文來自 CSDN博客,轉載請標明出處: ttp://jiajie961/archive/2010/11/07/5993126.aspx 制作 ubifs文件系統(tǒng) 1,安裝相關的軟件包 apt-get install liblzo2-dev 2,獲取相關的工具 mkfs.ubifs和 ubinize 這兩個工具是制作 ubifs 文件系統(tǒng)的時候用到,它們是 mtd-utils 工具包中的內容, mtd-utils 工具包你可以從下面的網站下載和編譯出來: 官方網站: /index.html 資源下載網站: / 3,創(chuàng)建一個 create-ubifs.sh腳本,主要是調用 mkfs.ubifs和 ubinize工具和相關參數(shù)來制作 ubifs文件系統(tǒng),內容如下: #!/bin/bash # # Script to generate ubifs filesystem image. # # # ubinize configuration file config_file=rootfs_ubinize.cfg # Function to check result of the command check_result() if $? -ne 0 then echo FAILED else echo SUCCESSFUL fi # Function to check whether an application exists check_program() for cmd in $ do which $cmd /dev/null 2&1 if $? -ne 0 then echo echo Cannot find command $cmd echo exit 1 fi done if $# -ne 5 then echo echo Usage: create-ubifs.sh page_size_in_bytes pages_per_block partition_size_in_bytes blocks_per_device path_to_rootfs echo exit fi page_size_in_bytes=$1 echo Page size $page_size_in_bytesbytes. pages_per_block=$2 echo Pages per block $pages_per_block partition_size_in_bytes=$3 echo File-system partition size $partition_size_in_bytesbytes. blocks_per_device=$4 echo Blocks per device $blocks_per_device path_to_rootfs=$5 # wear_level_reserved_blocks is 1% of total blcoks per device wear_level_reserved_blocks=expr $blocks_per_device / 100 echo Reserved blocks for wear level $wear_level_reserved_blocks #logical_erase_block_size is physical erase block size minus 2 pages for UBI logical_pages_per_block=expr $pages_per_block - 2 logical_erase_block_size=expr $page_size_in_bytes * $logical_pages_per_block echo Logical erase block size $logical_erase_block_sizebytes. #Block size = page_size * pages_per_block block_size=expr $page_size_in_bytes * $pages_per_block echo Block size $block_sizebytes. #physical blocks on a partition = partition size / block size partition_physical_blocks=expr $partition_size_in_bytes / $block_size echo Physical blocks in a partition $partition_physical_blocks #Logical blocks on a partition = physical blocks on a partitiion - reserved for wear level patition_logical_blocks=expr $partition_physical_blocks - $wear_level_reserved_blocks echo Logical blocks in a partition $patition_logical_blocks #File-system volume = Logical blocks in a partition * Logical erase block size fs_vol_size=expr $patition_logical_blocks * $logical_erase_block_size echo File-system volume $fs_vol_sizebytes. echo echo Generating configuration file. echo rootfs-volume $config_file echo mode=ubi $config_file echo image=rootfs_ubifs.img $config_file echo vol_id=0 $config_file echo vol_size=$fs_vol_size $config_file echo vol_type=dynamic $config_file echo vol_name=system $config_file echo # Note: Check necessary program for installation #echo -n Checking necessary program for installation. #check_program mkfs.ubifs ubinize #echo Done #Generate ubifs image echo -n Generating ubifs. ./mkfs.ubifs -x lzo -m $page_size_in_bytes -e $logical_erase_block_size -c $patition_logical_blocks -o rootfs_ubifs.img -d $path_to_rootfs check_result echo -n Generating ubi image out of the ubifs. ./ubinize -o ubi.img -m $page_size_in_bytes -p $block_size -s $page_size_in_bytes $config_file -v check_result rm -f rootfs_ubifs.img rm -f $config_file (4)將 mkfs.ubifs 和 ubinize 以及 create-ubifs.sh 放置在同一目錄下,然后調用 create-ubifs.sh 即可創(chuàng)建 ubifs文件系統(tǒng), create-ubifs.sh用法如下: create-ubifs.sh page_size_in_bytes(頁大小 ) pages_per_block(每個扇區(qū)的頁數(shù)量 ) partition_size_in_bytes(分區(qū)大小 ) blocks_per_device(扇區(qū)數(shù)量 ) path_to_rootfs(文件系統(tǒng)路徑 ) 舉例如下: ./create-ubifs.sh 2048 64 83886080 4096 ./rootfs 上面命令的意思是調用 create-ubifs.sh將當前目錄下的 rootfs文件夾的內容制作成 ubifs文件系統(tǒng), nand flash的頁大小為 2k,每個扇區(qū)有 64頁, 總共有 4096個扇區(qū),要制作的文件系統(tǒng)的大小為 83886080字節(jié)。 本文來自 CSDN博客,轉載請標明出處: /jiajie961/archive/2010/11/08/5994713.aspx android編譯系統(tǒng) makefile(Android.mk)寫法 android編譯系統(tǒng)的 makefile文件 Android.mk寫法如下 (1)Android.mk文件首先需要指定 LOCAL_PATH變量,用于查找源文件。由于一般情況下 Android.mk和需要編譯的源文件在同一目錄下,所以定義成如下形式: LOCAL_PATH:=$(call my-dir) 上面的語句的意思是將 LOCAL_PATH變量定義成本文件所在目錄路徑。 (2)Android.mk中可以定義多個編譯模塊,每個編譯模塊都是以 include $(CLEAR_VARS)開始 以 include $(BUILD_XXX)結束。 include $(CLEAR_VARS) CLEAR_VARS 由編譯系統(tǒng)提供,指定讓 GNU MAKEFILE 為你清除除 LOCAL_PATH 以外的所有LOCAL_XXX變量, 如 LOCAL_MODULE , LOCAL_SRC_FILES , LOCAL_SHARED_LIBRARIES ,LOCAL_STATIC_LIBRARIES 等。 include $(BUILD_STATIC_LIBRARY)表示編譯成靜態(tài)庫 include $(BUILD_SHARED_LIBRARY)表示編譯成動態(tài)庫。 include $(BUILD_EXECUTABLE)表示編譯成可執(zhí)行程序 (3)舉例如下 (frameworks/base/libs/audioflinger/Android.mk): LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) 模塊一 ifeq ($(AUDIO_POLICY_TEST),true) ENABLE_AUDIO_DUMP := true endif LOCAL_SRC_FILES:= AudioHardwareGeneric.cpp AudioHardwareStub.cpp AudioHardwareInterface.cpp ifeq ($(ENABLE_AUDIO_DUMP),true) LOCAL_SRC_FILES += AudioDumpInterface.cpp LOCAL_CFLAGS += -DENABLE_AUDIO_DUMP endif LOCAL_SHARED_LIBRARIES := libcutils libutils libbinder libmedia libhardware_legacy ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO),true) LOCAL_CFLAGS += -DGENERIC_AUDIO endif LOCAL_MODULE:= libaudiointerface ifeq ($(BOARD_HAVE_BLUETOOTH),true) LOCAL_SRC_FILES += A2dpAudioInterface.cpp LOCAL_SHARED_LIBRARIES += liba2dp LOCAL_CFLAGS += -DWITH_BLUETOOTH -DWITH_A2DP LOCAL_C_INCLUDES += $(call include-path-for, bluez) endif include $(BUILD_STATIC_LIBRARY) 模塊一編譯成靜態(tài)庫 include $(CLEAR_VARS) 模塊二 LOCAL_SRC_FILES:= AudioPolicyManagerBase.cpp LOCAL_SHARED_LIBRARIES := libcutils libutils libmedia ifeq ($(TARGET_SIMULATOR),true) LOCAL_LDLIBS += -ldl else LOCAL_SHARED_LIBRARIES += libdl endif LOCAL_MODULE:= libaudiopolicybase ifeq ($(BOARD_HAVE_BLUETOOTH),true) LOCAL_CFLAGS += -DWITH_A2DP endif ifeq ($(AUDIO_POLICY_TEST),true) LOCAL_CFLAGS += -DAUDIO_POLICY_TEST endif include $(BUILD_STATIC_LIBRARY) 模塊二編譯成靜態(tài)庫 include $(CLEAR_VARS) 模塊三 LOCAL_SRC_FILES:= AudioFlinger.cpp AudioMixer.cpp.arm AudioResampler.cpp.arm AudioResamplerSinc.cpp.arm AudioResamplerCubic.cpp.arm AudioPolicyService.cpp LOCAL_SHARED_LIBRARIES := libcutils libutils libbinder libmedia libhardware_legacy ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO),true) LOCAL_STATIC_LIBRARIES += libaudiointerface libaudiopolicybase LOCAL_CFLAGS += -DGENERIC_AUDIO else LOCAL_SHARED_LIBRARIES += libaudio libaudiopolicy endif ifeq ($(TARGET_SIMULATOR),true) LOCAL_LDLIBS += -ldl else LOCAL_SHARED_LIBRARIES += libdl endif LOCAL_MODULE:= libaudioflinger ifeq ($(BOARD_HAVE_BLUETOOTH),true) LOCAL_CFLAGS += -DWITH_BLUETOOTH -DWITH_A2DP LOCAL_SHARED_LIBRARIES += liba2dp endif ifeq ($(AUDIO_POLICY_TEST),true) LOCAL_CFLAGS += -DAUDIO_POLICY_TEST endif ifeq ($(TARGET_SIMULATOR),true) ifeq ($(HOST_OS),linux) LOCAL_LDLIBS += -lrt -lpthread endif endif ifeq ($(BOARD_USE_LVMX),true) LOCAL_CFLAGS += -DLVMX LOCAL_C_INCLUDES += vendor/nxp LOCAL_STATIC_LIBRARIES += liblifevibes LOCAL_SHARED_LIBRARIES += liblvmxservice # LOCAL_SHARED_LIBRARIES += liblvmxipc endif include $(BUILD_SHARED_LIBRARY) 模塊三編譯成動態(tài)庫 (4)編譯一個應用程序 (APK) LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # Build all java files in the java subdirectory LOCAL_SRC_FILES := $(call all-subdir-java-files) # Name of the APK to build LOCAL_PACKAGE_NAME := LocalPackage # Tell it to build an APK include $(BUILD_PACKAGE) (5)編譯一個依賴于靜態(tài) Java庫 (static.jar)的應用程序 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # List of static libraries to include in the package LOCAL_STATIC_JAVA_LIBRARIES := static-library # Build all java files in the java subdirectory LOCAL_SRC_FILES := $(call all-subdir-java-files) # Name of the APK to build LOCAL_PACKAGE_NAME := LocalPackage # Tell it to build an APK include $(BUILD_PACKAGE) (6)編譯一個需要用平臺的 key簽名的應用程序 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # Build all java files in the java subdirectory LOCAL_SRC_FILES := $(call all-subdir-java-files) # Name of the APK to build LOCAL_PACKAGE_NAME := LocalPackage LOCAL_CERTIFICATE := platform # Tell it to build an APK include $(BUILD_PACKAGE) (7)編譯一個需要用特定 key前面的應用程序 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # Build all java files in the java subdirectory LOCAL_SRC_FILES := $(call all-subdir-java-files) # Name of the APK to build LOCAL_PACKAGE_NAME := LocalPackage LOCAL_CERTIFICATE := vendor/example/certs/app # Tell it to build an APK include $(BUILD_PACKAGE) (8)添加一個預編譯應用程序 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # Module name should match apk name to be installed. LOCAL_MODULE := LocalModuleName LOCAL_SRC_FILES := $(LOCAL_MODULE).apk LOCAL_MODULE_CLASS := APPS LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX) include $(BUILD_PREBUILT) (9)添加一個靜態(tài) JAVA庫 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # Build all java files in the java subdirectory LOCAL_SRC_FILES := $(call all-subdir-java-files) # Any libraries that this library depends on LOCAL_JAVA_LIBRARIES := android.test.runner # The name of the jar file to create LOCAL_MODULE := sample # Build a static jar file. include $(BUILD_STATIC_JAVA_LIBRARY) (10)Android.mk的編譯模塊中間可以定義相關的編譯內容,也就是指定相關的變量如下: LOCAL_AAPT_FLAGS LOCAL_ACP_UNAVAILABLE LOCAL_ADDITIONAL_JAVA_DIR LOCAL_AIDL_INCLUDES LOCAL_ALLOW_UNDEFINED_SYMBOLS LOCAL_ARM_MODE LOCAL_ASFLAGS LOCAL_ASSET_DIR LOCAL_ASSET_FILES 在 Android.mk 文件中編譯應用程序 (BUILD_PACKAGE)時設置此變量,表示資源文件, 通常會定義成 LOCAL_ASSET_FILES += $(call find-subdir-assets) LOCAL_BUILT_MODULE_STEM LOCAL_C_INCLUDES 額外的 C/C+編譯頭文件路徑,用 LOCAL_PATH表示本文件所在目錄 舉例如下: LOCAL_C_INCLUDES += extlibs/zlib-1.2.3 LOCAL_C_INCLUDES += $(LOCAL_PATH)/src LOCAL_CC 指定 C編譯器 LOCAL_CERTIFICATE 簽名認證 LOCAL_CFLAGS 為 C/C+編譯器定義額外的標志 (如宏定義 ),舉例: LOCAL_CFLAGS += -DLIBUTILS_NATIVE=1 LOCAL_CLASSPATH LOCAL_COMPRESS_MODULE_SYMBOLS LOCAL_COPY_HEADERS install 應 用 程 序 時 需 要 復 制 的 頭 文 件 , 必 須 同 時 定 義LOCAL_COPY_HEADERS_TO LOCAL_COPY_HEADERS_TO install應用程序時復制頭文件的 目的路徑 LOCAL_CPP_EXTENSION 如果你的 C+ 文件不是 以 cpp 為文件后綴,你可以通過LOCAL_CPP_EXTENSION指定 C+文件后綴名 如: LOCAL_CPP_EXTENSION := .cc 注意統(tǒng)一模塊中 C+文件后綴必須保持一致。 LOCAL_CPPFLAGS 傳遞額外的標志給 C+編譯器,如: LOCAL_CPPFLAGS += -ffriend-injection LOCAL_CXX 指 定 C+編譯器 LOCAL_DX_FLAGS LOCAL_EXPORT_PACKAGE_RESOURCES LOCAL_FORCE_STATIC_EXECUTABLE 如果編譯的可執(zhí)行程序要進行靜態(tài)鏈接 (執(zhí)行時不依賴于任何動態(tài)庫 ),則設置 LOCAL_FORCE_STATIC_EXECUTABLE:=true 目前只有 libc有靜態(tài)庫形式,這個只有文件系統(tǒng)中 /sbin目錄下的應用程序會用到,這個目錄下的應用程序在運行時通常 文件系統(tǒng)的其它部分還沒有加載,所以必須進行靜態(tài)鏈接。 LOCAL_GENERATED_SOURCES LOCAL_INSTRUMENTATION_FOR LOCAL_INSTRUMENTATION_FOR_PACKAGE_NAME LOCAL_INTERMEDIATE_SOURCES LOCAL_INTERMEDIATE_TARGETS LOCAL_IS_HOST_MODULE LOCAL_JAR_MANIFEST LOCAL_JARJAR_RULES LOCAL_JAVA_LIBRARIES 編譯 java應用程序和庫的時候指定包含的 java類庫,目前有 core和 framework兩種 多數(shù)情況下定義成: LOCAL_JAVA_LIBRARIES := core framework 注意 LOCAL_JAVA_LIBRARIES 不是必須的,而且編譯 APK 時不允許定義 (系統(tǒng)會自動添加 ) LOCAL_JAVA_RESOURCE_DIRS LOCAL_JAVA_RESOURCE_FILES LOCAL_JNI_SHARED_LIBRARIES LOCAL_LDFLAGS 傳遞額外的參數(shù)給連接器 (務必注意參數(shù)的順序 ) LOCAL_LDLIBS 為可執(zhí)行程序或者庫的編譯指定額外的庫,指定庫以 -lxxx格式,舉例: LOCAL_LDLIBS += -lcurses -lpthread LOCAL_LDLIBS += -Wl,-z,origin LOCAL_MODULE 生成的模塊的名稱 (注意應 用程序名稱用 LOCAL_PACKAGE_NAME 而不是LOCAL_MODULE) LOCAL_MODULE_PATH 生成模塊的路徑 LOCAL_MODULE_STEM LOCAL_MODULE_TAGS 生成模塊的標記 LOCAL_NO_DEFAULT_COMPILER_FLAGS LOCAL_NO_EMMA_COMPILE LOCAL_NO_EMMA_INSTRUMENT LOCAL_NO_STANDARD_LIBRARIES LOCAL_OVERRIDES_PACKAGES LOCAL_PACKAGE_NAME APK應用程序的名稱 LOCAL_POST_PROCESS_COMMAND LOCAL_PREBUILT_EXECUTABLES 預 編 譯 including $(BUILD_PREBUILT) 或者$(BUILD_HOST_PREBUILT)時所用 ,指定需要復制的可執(zhí)行文件 LOCAL_PREBUILT_JAVA_LIBRARIES LOCAL_PREBUILT_LIBS 預編譯 including $(BUILD_PREBUILT)或者 $(BUILD_HOST_PREBUILT)時所用 , 指定需要復制的庫 . LOCAL_PREBUILT_OBJ_FILES LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES LOCAL_PRELINK_MODULE 是否需要預連接處理 (默認需要,用來做動態(tài)庫優(yōu)化 ) LOCAL_REQUIRED_MODULES 指定模塊運行所依賴的模塊 (模塊安裝時將會同步安裝它所依賴的模塊 ) LOCAL_RESOURCE_DIR LOCAL_SDK_VERSION LOCAL_SHARED_LIBRARIES 可鏈接動態(tài)庫 LOCAL_SRC_FILES 編譯源文件 LOCAL_STATIC_JAVA_LIBRARIES LOCAL_STATIC_LIBRARIES 可鏈接靜態(tài)庫 LOCAL_UNINSTALLABLE_MODULE LOCAL_UNSTRIPPED_PATH LOCAL_WHOLE_STATIC_LIBRARIES 指定模塊所需要載入的完整靜態(tài)庫 (這些精通庫在鏈接是不允許鏈接器刪除其中無用的代碼 ) LOCAL_YACCFLAGS OVERRIDE_BUILT_MODULE_PATH 本文來自 CSDN博客,轉載請標明出處: /jiajie961/archive/2010/11/09/5997147.aspx Android 系統(tǒng)移植 (一 )-讓 android 系統(tǒng)在目標平臺上運行起來 Android系統(tǒng)由于用的是 linux內 核,因此內核移植和嵌入式 linux內核移植差異不大,過程如下: (1)移植 boot-loader和 linux2.6內核到目標平臺上,讓 linux內核可以啟動起來,基本的驅動允許正常。 此過程完全是嵌入式 linux的開發(fā),這里直接跳過。需要注意的是,由于 android已經被 linux官方開除,因此從 網站上 (如 /)下載的最新 linux內核源代碼已經不包含 android的專有驅動,因此建議 從 google網上下下載 Linux內核, android源代碼瀏覽網站如下: / 從該網站上發(fā)現(xiàn)內核相關的包如下: kernel/common.git 通用 android內核項目 kernel/experimental.git 實驗性內核項目 kernel/linux-2.6.git 這個是標準的 Linux內核,沒有 android的驅動 kernel/lk.git 微內核項目 kernel/msm.git 這個是高通 msm7xxx系列芯片所用內核 kernel/omap.git kernel/tegra.git NVIDIA Tegra系列芯片所用內核 下載內核代碼的方法如下: git clone git://kernel/common.git 下載完后用 git branch -a查看所有 git分支 ,結果如下: android-2.6.27 origin/HEAD origin/android-2.6.25 origin/android-2.6.27 origin/android-2.6.29 origin/android-2.6.32 origin/android-2.6.35 origin/android-2.6.36 origin/android-goldfish-2.6.27 origin/android-goldfish-2.6.29 然后切換到最新分支 git checkout origin/android-2.6.36 (2)修改內核配置文件,打開 Android必須的驅動 (日志和 BINDER)如下: CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y CONFIG_ANDROID_LOGGER=y 此部分的代碼在內核 drivers/staging/android目錄下。 (3)為了提高啟動速度,采用 ramdisk,將 android文件系統(tǒng)的部分內容壓縮到內核中。 首先打開內核驅動: CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE=root CONFIG_INITRAMFS_ROOT_UID=0 CONFIG_INITRAMFS_ROOT_GID=0 然后在 android源代碼編譯出來的 out/target/product/merlin/root目 錄復制到內核目錄下。 (4)根據(jù) android文件系統(tǒng)的要求對 nand flash進行重新分區(qū),舉例如下: 將 nand flash分區(qū)以下 8個分區(qū) NTIM OBM U-boot Kernel System UserData Mass Storage BBT (5)根據(jù)分區(qū)表修改內核啟動參數(shù)如下: CONFIG_CMDLINE=ubi.mtd=4 ubi.mtd=5 ubi.mtd=6 root=ubi0_0 rootfstype=ubifs console=ttyS1,115200 uart_dma init=/init 參數(shù)的意思是:載入的文件系統(tǒng)部分有 3個分區(qū),分別為 nand flash的第 4,5,6分區(qū) (從 0編號 ),文件系統(tǒng)采用 ubifs格式,控制臺設備為 ttyS1,波特率為 115200 啟動的第一個應用程序是 /init (6)確保控制臺的設置和硬件保持一致,如:硬件上串口用的是 UART1,則內核啟動參數(shù)中設置有console=ttyS1,而且 android的啟動過程中設要設置正確,修改 部分位于 android源代碼 system/core/init/init.c文件中,將 static char *console_name = /dev/console; 修改成 static char *console_name = /dev/ttyS1; (7)修改 android源代碼 system/core/rootdir目錄下的 init.rc文件,作如下修改 (android默認 yaffs2文件系統(tǒng) ): 首先將 android文件系統(tǒng)修改成可讀寫,將 mount rootfs rootfs / ro remount 修改成 mount rootfs rootfs / rw remount 然后修改掛載 system和 userdata部分的代碼,將 # Mount /system rw first to give the filesystem a chance to save a checkpoint mount yaffs2 mtdsystem /system mount yaffs2 mtdsystem /system ro remount # We chown/chmod /data again so because mount is run as root + defaults mount yaffs2 mtduserdata /data nosuid nodev chown system system /data chmod 0771 /data 改成 # Mount /system rw first to give the filesystem a chance to save a checkpoint mount ubifs ubi0_0 /system ro # We chown/chmod /data again so because mount is run as root + defaults mount ubifs ubi1_0 /data nosuid nodev chown system system /data chmod 0771 /data (8)完成后編譯內核,可以啟動文件系統(tǒng),控制臺可用,但是沒有顯示啟動 log,而且不停的重啟。 (9)系統(tǒng)不停的重啟,因此控制臺已經可用了,自然而然的想到看到 logcat 日志,一看,發(fā)現(xiàn) logcat 設備居然沒 起來,配置文件里面都定義了 居然沒起來,查看了下內核 drivers/staging/android 目錄,沒有 .o 文件,證明是沒編譯到,在看內核目錄下的 .config文件,發(fā)現(xiàn)居然沒有了 logcat和 binder的宏定義,配置文件里面有定義而 .config文件中無定義,肯定是相關 Kconfig文件的問題,通過分析 drivers/staging目錄下的 Kconfig 文件發(fā)現(xiàn)是因為 STAGING_EXCLUDE_BUILD 宏默認是 y,在配置文件中否定此宏即可,在配置文件中 CONFIG_STAGING定義后加上 即可,如下: CONFIG_STAGING=y # CONFIG_STAGING_EXCLUDE_BUILD is not set 修改后重新編譯發(fā)現(xiàn)系統(tǒng)完成正常啟動,啟動過程中啟動 log也顯示正常。 至此, android初步移植工作已經完成,當然,系統(tǒng)還有很多問題,需要下一步繼續(xù)修改。 總結: android的移植按如下流程: (1)android linux內核的普通驅動移植,讓內核可以在目標平臺上運行起來。 (2)正確掛載文件系統(tǒng),確保內核啟動參數(shù)和 android源代碼 system/core/rootdir目錄下的 init.rc中的文件系統(tǒng)掛載正確。 (3)調試控制臺,讓內核啟動參數(shù)中的 console參數(shù)以及 android源代碼 system/core/init/init.c中的console_name設置和硬件保持一致 (4)打開 android相關的驅動 (logger,binder等 ),串口輸入 logcat看 logger驅動起來,沒有的話調試logger驅動。 說明: ARM的內核配置文件定義在內核 arch/arm/configs目錄下 Android系統(tǒng)移植 (二 )-按鍵移植 這一部分主要是移植 android的鍵盤和按鍵 (1)Android 使用標準的 linux 輸入事件設備 (/dev/input 目錄下 )和驅動,按鍵定義在內核include/linux/input.h文件中, 按鍵定義形式如下: #define KEY_ESC 1 #define KEY_1 2 #define KEY_2 3 (2)內核中 (我的平臺是 arch/arm/mach-mmp/merlin.c文件 )中按鍵的定義如下形式: static struct gpio_keys_button btn_button_table = 0 = .code = KEY_F1, .gpio = MFP_PIN_GPIO2, .active_low = 1, /* 0 for down 0, up 1; 1 for down 1, up 0 */ .desc = H_BTN button, .type = EV_KEY, /* .wakeup = */ .debounce_interval = 10, /* 10 msec jitter elimination */ , 1 = .code = KEY_F2, .gpio = MFP_PIN_GPIO3, .active_low = 1, /* 0 for down 0, up 1; 1 for down 1, up 0 */ .desc = O_BTN button, .type = EV_KEY, /* .wakeup = */ .debounce_interval = 10, /* 10 msec jitter elimination */ , 2 = .code = KEY_F4, .gpio = MFP_PIN_GPIO1, .active_low = 1, /* 0 for down 0, up 1; 1 for down 1, up 0 */ .desc = S_BTN button, .type = EV_KEY, /* .wakeup = */ .debounce_interval = 10, /* 10 msec jitter elimination */ , ; static struct gpio_keys_platform_data gpio_keys_data = .buttons = btn_button_table, .nbuttons = ARRAY_SIZE(btn_button_table), ; static struct platform_device gpio_keys = .name = gpio-keys, .dev = .platform_data = &gpio_keys_data, , .id = -1, ; 上面定義是將 MFP_PIN_GPIO2這個 GPIO口的按鍵映射到 Linux的 KEY_F1按鍵, MPF_PIN_GPIO3映射到 KEY_F2, MFP_PIN_GPIO1映射到 KEY_F4 (3)上面 (2)步實現(xiàn)了從硬件 GPIO口到內核標準按鍵的映射 ,但是 android并沒有直接使用映射后的鍵值,而且對其再進行了一次映射,從內核標準鍵值 到 android所用鍵值的映射表定義在 android文件系統(tǒng)的 /system/usr/keylayout目錄下。標準的映射文件為 qwerty.kl,定義如下: key 399 GRAVE key 2 1 key 3 2 key 4 3 key 5 4 key 6 5 key 7 6 key 8 7 key 9 8 key 10 9 key 11 0 key 158 BACK WAKE_DROPPED key 230 SOFT_RIGHT WAKE key 60 SOFT_RIGHT WAKE key 107 ENDCALL WAKE_DROPPED key 62 ENDCALL WAKE_DROPPED key 229 MENU WAKE_DROPPED key 139 MENU WAKE_DROPPED key 59 MENU WAKE_DROPPED key 127 SEARCH WAKE_DROPPED key 217 SEARCH WAKE_DROPPED key 228 POUND key 227 STAR key 231 CALL WAKE_DROPPED key 61 CALL WAKE_DROPPED key 232 DPAD_CENTER WAKE_DROPPED key 108 DPAD_DOWN WAKE_DROPPED key 103 DPAD_UP WAKE_DROPPED key 102 HOME WAKE key 105 DPAD_LEFT WAKE_DROPPED key 106 DPAD_RIGHT WAKE_DROPPED key 115 VOLUME_UP key 114 VOLUME_DOWN key 116 POWER WAKE key 212 CAMERA key 16 Q key 17 W key 18 E key 19 R key 20 T key 21 Y key 22 U key 23 I key 24 O key 25 P key 26 LEFT_BRACKET key 27 RIGHT_BRACKET key 43 BACKSLASH key 30 A key 31 S key 32 D key 33 F key 34 G key 35 H key 36 J key 37 K key 38 L key 39 SEMICOLON key 40 APOSTROPHE key 14 DEL key 44 Z key 45 X key 46 C key 47 V key 48 B key 49 N key 50 M key 51 COMMA key 52 PERIOD key 53 SLASH key 28 ENTER key 56 ALT_LEFT key 100 ALT_RIGHT key 42 SHIFT_LEFT key 54 SHIFT_RIGHT key 15 TAB key 57 SPACE key 150 EXPLORER key 155 ENVELOPE key 12 MINUS key 13 EQUALS key 215 AT (4)android對底層按鍵的處理方法 android 按鍵的處理是 Window Manager 負責,主要的映射轉換實現(xiàn)在 android 源代碼frameworks/base/libs/ui/EventHub.cpp 此文件處理來自底層的所有輸入事件,并根據(jù)來源對事件進行分類處理,對于按鍵事件,處理過程如下: (a)記錄驅動名稱為 (b)獲取環(huán)境變量 ANDROID_ROOT 為系統(tǒng)路徑 (默認是 /system,定義在 android 源代碼/system/core/rootdir/init.rc文件中 ) (c)查找路徑為 系統(tǒng)路徑 /usr/keylayout/驅動名稱 .kl的按鍵映射文件,如果不存在則默認用路徑為 系統(tǒng)路徑 /usr/keylayout/qwerty.kl 這個默認的按鍵映射文件,映射完成后再把經 映射得到的 android按鍵碼值發(fā)給上層應用程序。 所以我們可以在內核中定義多個按鍵設備,然后為每個設備設定不同的按鍵映射文件,不定義則會默認用qwerty.kl (5)舉例 上面 (2)步我們在內核中聲明了一個名為 gpio-keys的按鍵設備,此設備定義在內核drivers/input/keyboard/gpio_keys.c文件中 然后我們在內核啟動過程中注冊此設備: platform_device_register(&gpio_keys); 然后我們可以自己定義一個名為 gpio-keys.kl 的 android 按鍵映射文件,此文件的定義可以參考querty.kl的內容,比如說我們想將 MPF_PIN_GPIO3 對應的按鍵作 android 中的 MENU 鍵用,首先我們在內核中將 MPF_PIN_GPIO3 映射到 KEY_F2,在內核 include/linux/input.h中查找 KEY_F2發(fā)現(xiàn) #define KEY_F2 60 參照 KEY_F2的值我們在 gpio-keys.kl中加入如下映射即可 key 60 MENU WAKE 其它按鍵也照此添加,完 成后將按鍵表放置到 /system/usr/keylayout目錄下即可。 補充: (1)android按鍵設備的映射關系可以在 logcat開機日志中找的到 (查找 EventHub即可 ) (2)android按鍵設備由 Window Manager負責, Window Manager從按鍵驅動讀取內核按鍵碼,然后將內核按鍵碼轉換成 android按鍵碼,轉換完成 后 Window Manager會將內核按鍵碼和 android按鍵碼一起發(fā)給應用程序來使用,這一點一定要注意。 Android系統(tǒng)開發(fā)小知識 -在 android產品開發(fā)中添加新的編譯模塊 Android 開發(fā)中 用戶 內容定 義在 vendor 目 錄下, 而用戶 產品的 內容都定義 在vendor/目錄下 如果需要添加新的內容,可以在該目錄下新建子目錄,同時修改 AndroidBoard.mk文件即可。比如說要添加一個按鍵映射文件: (1)在 vendor/目錄下建立一個 keymaps子目錄 (2)將我們需要的按鍵映射文件 gpio-keys.kl和 power-button.kl復制到 keymaps目錄下 (3)在 keymaps目錄下新建一個 Mdroid.mk文件,內容如下: LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) file := $(TARGET_OUT_KEYLAYOUT)/gpio-keys.kl ALL_PREBUILT += $(file) $(file): $(LOCAL_PATH)/gpio-keys.kl | $(ACP) $(transform-prebuilt-to-target) file := $(TARGET_OUT_KEYLAYOUT)/power-button.kl ALL_PREBUILT += $(file) $(file): $(LOCAL_PATH)/power-button.kl | $(ACP) $(transform-prebuilt-to-target) (4)在 vendor/目錄下的 AndroidBoard.mk添加如下內容: include $(LOCAL_PATH)/keymaps/Mdroid.mk Android系統(tǒng)移植 (三 )-按鍵字符表 上節(jié)講 android的 Window Manager將內核按鍵碼通過按鍵映射表轉換成 android按鍵碼, 這節(jié)講的是 android按鍵碼向 android字符的轉換,轉換也是通過 Window Manager來完成的 (1)原始按鍵字符表,我們知道一個按鍵是可以顯示多個字符的,決定顯示字符的是 CAPS(大小寫 ),FN,NUNMBER等按鍵 舉例如下: type=QWERTY # keycode display number base caps fn caps_fn A A 2 a A # 0x00 B B 2 b B 0x0303 O O 6 o O ( 0x00 P P 7 p P ) 0x00 Q Q 7 q Q * 0x0300 R R 7 r R 3 0x20AC S S 7 s S 4 0x00DF T T 8 t T + 0x00A3 U U 8 u U & 0x0308 V V 8 v V = W W 9 w W 1 0x00 X X 9 x X 8 0xEF00 Y Y 9 y Y % 0x00A1 Z Z 9 z Z 7 0x00 # on pc keyboards COMMA , , , ; ; | PERIOD . . . : : 0x2026 AT 0 0 0 0x2022 SLASH / / / ? ? SPACE 0x20 0x20 0x20 0x20 0xEF01 0xEF01 ENTER 0xa 0xa 0xa 0xa 0xa 0xa TAB 0x9 0x9 0x9 0x9 0x9 0x9 0 0 0 0 ) ) ) 1 1 1 1 ! ! ! 2 2 2 2 3 3 3 3 # # # 4 4 4 4 $ $ $ 5 5 5 5 % % % 6 6 6 6 7 7 7 7 & & & 8 8 8 8 * * * 9 9 9 9 ( ( ( GRAVE MINUS - - - _ - _ EQUALS = = = + = + LEFT_BRACKET RIGHT_BRACKET BACKSLASH | | SEMICOLON ; ; ; : ; : APOSTROPHE STAR * * * * * * POUND # # # # # # PLUS + + + + + + (2)android為了減少載入時間,并沒有使用原始按鍵表文件,而是將其轉換成二進制文件 轉換的工具源代碼在 android源代碼 build/tools/kcm目錄下, android在編譯過程中會 首先編譯轉換工具,然后利用轉換工具將 android源代碼 sdk/emulator/keymaps目錄下 的 qwerty.kcm和 qwerty2.kcm文件分別轉換成 qwerty.kcm.bin和 qwerty2.kcm.bin 轉換后的二進制文件復制到 out/target/product/system/usr/keychars 目錄下,也就是目標平臺的 /system/usr/keychars目錄中。 (3)Window Manager對按鍵的處理在 android源代碼 frameworks/base/libs/ui/EventHub.cpp文件中 Window Manager 從內核接收到一個按鍵輸入事件后會首先調用按鍵映射表將內核按鍵碼映射成android按鍵碼 (這部分上節(jié)已講 ),然后會 將 android按鍵碼轉換成字符,具體過程如下: (a)設置系統(tǒng)系統(tǒng)屬性 hw.keyboards.設備號 .devname的值為設備名 以上節(jié)的 gpio-keys設備為例,會設置系統(tǒng)屬性 hw.keyboards.65539.devname的值為 gpio-keys (b)載入按鍵字符表,首先載入 /system/usr/keychars 目錄下的設備名 .kcm.bin 文件 (此例即gpio-keys.kcm.bin文件 ),如果載入失敗 則載入該目錄下的 querty.kcm.bin. (c)利用載入的按鍵字符表將 android按鍵轉換成按鍵字符發(fā)給上層應用程序。 (4)一般情況下一個控制按鍵是不需要作按鍵字符表的,系統(tǒng)會調用默認的去處理,但是如果要開發(fā)一個全功能鍵盤 (包含了字母和數(shù)字 ),那可能就需要 自己作一個專用的按鍵字符表了。 android系統(tǒng)開發(fā)小問題啟動過程中 android字符沒有顯示出來 android目標平臺可以正常啟動,但是啟動過程中的 android字符沒有顯示出來,這個是 linux內核配置的問題 打開內核 framebuffer控制臺即可。 (1)make menuconifg 后選擇 Device Drivers-Graphics support-Console display driver support-Framebuffer Console support 然后打開相關的幾個配置選項即可。 (2)直接修改內核配置文件,如下: CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y # CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set CONFIG_FONTS=y CONFIG_FONT_8x8=y CONFIG_FONT_8x16=y CONFIG_FONT_6x11=y # CONFIG_FONT_7x14 is not set # CONFIG_FONT_PEARL_8x8 is not set # CONFIG_FONT_ACORN_8x8 is not set # CONFIG_FONT_MINI_4x6 is not set # CONFIG_FONT_SUN8x16 is not set # CONFIG_FONT_SUN12x22 is not set # CONFIG_FONT_10x18 is not set (3)android啟動過程中的 android字符顯示在源代碼的 system/core/init.c中,如下: if( load_565rle_image(INIT_IMAGE_FILE) ) fd = open(/dev/tty0, O_WRONLY); if (fd = 0) const char *msg; msg = n n n n n n n / console is 40 cols x 30 lines n n n n n n n A N D R O I D ; write(fd, msg, strlen(msg); close(fd); android啟動過程配置文件的解析與語法 (1)android 啟動文件系統(tǒng)后調用的第一個應用程序是 /init,此文件的很重要的內容是解析了 init.rc 和init.xxx.rc 兩個配置文件,然后執(zhí)行解析出來的任務。相關代碼在 android源代碼 /system/core/init/init.c文件中,如下: parse_config_file(/init.rc); /* pull the kernel commandline and ramdisk properties file in */ qemu_init(); import_kernel_cmdline(0); get_hardware_name(); snprintf(tmp, sizeof(tmp), /init.%s.rc, hardware); parse_config_file(tmp); (2)從上面代碼可以看到,第一個配置文件名稱固定為 init.rc,而第二個配置文件格式為 init.xxx.rc,其中xxx部分的內容 是從內核讀取的,具體是讀取文件 /proc/cpuinfo中的 Hardware部分,然后截取其部分內容。 Hardware部分是定義在內核的 主板定義文件中,我的平臺是定義在內核 arch/arm/mach-mmp/merlin.c中,我的平臺定義如下: MACHINE_START(ARDENT_MERLIN, PXA168-based Merlin Platform) .phys_io = APB_PHYS_BASE, .boot_params = 0x00000100, .io_pg_offst = (APB_VIRT_BASE 18) & 0xfffc, .map_io = pxa_map_io, .init_irq = pxa168_init_irq, .timer = &pxa168_timer, .init_machine = merlin_init, MACHINE_END 這樣截取到的 hardware 部分的內容就為 pxa168-based,也就是說我的平臺的第二個配置文件應該命名為 init.pxa168-based.rc (3)從上面看 init.xxx.rc中的 xxx內容是取決是內核中主板的定義 的,如果覺得麻煩,可以將其在代碼中寫死,例如: parse_config_file(“init.merlin.rc”); (4)配置文件的語法如下: (a)配置文件的內容包含有 4種: 動作 (Action) 命令 (Commands) 服務 (Services) 選項 (Options) (b)動作和命令一起使用,形式如下: on 其中 trigger是觸發(fā)條件,也就是說在滿足 觸發(fā)條件的情況下執(zhí)行 1個或多個相應的命令,舉例如下: on property:persist.service.adb.enable=1 start adbd (c)服務和選項一起使用,形式如下: service * . 上面內容解釋為: service 服務名稱 服務對應的命令的路徑 命令的參數(shù) 選項 選項 . 舉例如下: service ril-daemon /system/bin/rild socket rild stream 660 root radio socket rild-debug stream 660 radio system user root group radio cache inet misc audio 上面的服務對應到 /system/bin/rild 命令,沒有參數(shù),服務名稱為 ril-daemon,后面的內容都是服務的選項。 (d)選項是影響服務啟動和運行的參數(shù),主要的選項如下: disabled 禁用服務,此服務開機時不會自動啟動,但是可以在應用程序中手動啟動它。 socket 套接字 類型 名稱 權限 用戶 組 創(chuàng)建一個名為 /dev/socket/,然后把它的 fd傳給啟動程序 類型 type的值為 dgram或者 stream perm表示該套接字的訪問權限 ,user和 group表示改套接字所屬的用戶和組,這兩個參數(shù) 默認都是 0,因此可以不設置。 user 執(zhí)行服務前切換到用戶 ,此選項默認是 root,因此可以不設置。 group * 執(zhí)行服務前切換到組 ,此選項默認是 root,因此可以不設置 capability + 執(zhí)行服務前設置 linux capability,沒什么用。 oneshot 服務只啟動一次,一旦關閉就不能再啟動。 class 為服務指 定一個類別,默認為 default,同一類別的服務必須一起啟動和停止 (e)動作觸發(fā)條件 boot 首個觸發(fā)條件,初始化開始 (載入配置文件 )的時候觸發(fā) = 當名為 的屬性 (property)的值為 的時候觸發(fā) device-added- 路徑為 的設置添加的時候觸發(fā) device-removed- 路徑為 的設置移除的時候觸發(fā) service-exited- 名為 的服務關閉的時候觸發(fā) (f)命令 (Command)的形式 exec * 復制 (fork)和執(zhí)行路徑為 的應用程序, 為該應用程序的參數(shù),在該應用程序執(zhí)行完前,此命令會屏蔽, export 聲明名為 的環(huán)境變量的值為 ,聲明的環(huán)境變量是系統(tǒng)環(huán)境變量,啟動后一直有效。 ifup 啟動名為 的網絡接口 import 加 入新的位置文件,擴展當前的配置。 hostname 設置主機名 class_start 啟動指定類別的所有服務 class_stop 停止指定類別的所有服務 domainname 設置域名 insmod 加載路徑為 的內核模塊 mkdir 創(chuàng)建路徑為 目錄 mount * 掛載類型為 的設備 到目錄 ,為掛載參數(shù),距離如下: mount ubifs ubi1_0 /data nosuid nodev setkey 暫時未定義 setprop 設置名為 的系統(tǒng)屬性的值為 setrlimit 設置資源限制,舉例: # set RLIMIT_NICE to allow priorities from 19 to -20 setrlimit 13 40 40 沒看懂是什么意思。 start 啟動服務 (如果服務未運行 ) stop 停止服務 (如果服務正在運行 ) symlink 創(chuàng)建一個從 指向 的符號鏈接,舉例: symlink /system/etc /etc write * 打開路徑為 的文件并將一個多這多個字符串寫入到該文件中。 (g)系統(tǒng) 屬性 (Property) android 初始化過程中會修改一些屬性,通過 getprop 命令我們可以看到屬性值,這些屬性指示了某些動作或者服務的狀態(tài),主要如下: init.action 如果當前某個動作正在執(zhí)行則 init.action屬性的值等于該動作的名稱,否則為 mand 如果當前某個命令正在執(zhí)行則 mand屬性的值等于該命令的名稱,否則為 init.svc. 此屬性指示個名為 的服務的狀態(tài) (stopped, running, 或者 restarting). android 系統(tǒng)開發(fā) (四 )-觸摸屏 tslib 移植 (內核 )和原理分析 首先了解一下 tslib的運行原理, tslib的運行分成兩部分 (1)校驗 在 LCD固定坐標位置依次顯示出 5個坐標讓用戶觸摸,把 LCD坐標和用戶觸摸時驅動屏驅動底層的坐標總共 5組值保存起來 運行 tslib庫的算法對其進行運算,得出校準用 7個值 (2)校準 每次觸摸屏驅動讀取到硬件坐標時應用校準用的 7個值對該坐標進行一次運算,然后將運算后的坐標作為正常坐標即可。 按照上面的原理, (1)我們先 修改內核部分,我的平臺用的觸摸屏幕驅動是 tsc2007,驅動文件為內核/drivers/input/touchscreen 目錄下的 tsc2007.c和 ts_linear.c 其中, ts_linear.c中定義的是校準模塊,該模塊在 proc文件系統(tǒng)中建立了 7個文件,用來存放校準用的7個點, 7的點的默認值 為 1,0,0,0,1,0,1,對應的目標平臺文件系統(tǒng)的位置為 /proc/sys/dev/ts_device 目錄下a0,a1,a2,a3,a4,a5,a6等 7個文件 此模塊中還定義了一個校準函數(shù) ts_linear_scale,此函數(shù)的主要內容是讀取 a0,a1,a2,a3,a4,a5,a6等7個文件中的值作為 7個 校準值與傳入的觸摸平坐標值進行運算,返回運算結果。 ts_linear_scale函數(shù)定義如下: int ts_linear_scale(int *x, int *y, int swap_xy) int xtemp, ytemp; xtemp = *x; ytemp = *y; if (cal.a6 = 0) return -EINVAL; *x = (cal.a2 + cal.a0 * xtemp + cal.a1 * ytemp) / cal.a6; *y = (cal.a5 + cal.a3 * xtemp + cal.a4 * ytemp) / cal.a6; if (swap_xy) int tmp = *x; *x = *y; *y = tmp; return 0; ts2007.c 為觸摸屏驅,與其 他驅動不同的地方是在取得硬件坐標值發(fā)送之前先調用了 ts_linear_scale函數(shù)對坐標值進行了校準 if (x 0 & y 0) ts_linear_scale(&x, &y, invert); input_report_abs(input, ABS_X, x); input_report_abs(input, ABS_Y, y); input_report_abs(input, ABS_PRESSURE, 255); input_report_abs(input, ABS_TOOL_WIDTH, 1); input_report_key(input, BTN_TOUCH, 1); input_sync(input); (2)在 android源代碼 /system/core/rootdir/init.rc文件中添加 tslib相關的宏定義如下: # touchscreen parameters export TSLIB_FBDEVICE /dev/graphics/fb0 export TSLIB_CALIBFILE /data/etc/pointercal export TSLIB_CONFFILE /system/etc/ts.conf export TSLIB_TRIGGERDEV /dev/input/event0 export TSLIB_TSDEVICE /dev/input/event1 (2)移植 tslib庫到 android系統(tǒng),比較麻煩,看下一節(jié)的內容。 (3)校驗程序完成后會將生成的 7 個校準值寫入到環(huán)境變量 TSLIB_CALIBFILE 對應的路徑/data/etc/pointercal文件中 (4)校驗完后將 pointercal 文件中的 7 個值分別寫入到 /proc/sys/dev/ts_device 目錄下a0,a1,a2,a3,a4,a5,a6文件即可。 (5)開機啟動的時候我們編寫一個應用程序,首先判斷環(huán)境變量 TSLIB_CALIBFILE 對應的路徑/data/etc/pointercal文件是否存在,如果 文件存在而且非空,則將該文件中的 7 個值取出來分別寫入到 /proc/sys/dev/ts_device 目錄下a0,a1,a2,a3,a4,a5,a6文件 (6)為了確保未校驗前觸摸屏可用,我們將一次校驗后得出的 7 個坐標值作為初始值,修改到內核ts_linear.c文件中。 下面是源代碼: ts_linear.c文件 /* * Touchscreen Linear Scale Adaptor * * Copyright (C) 2009 Marvell Corporation * * Author: Mark F. Brown * Based on tslib 1.0 plugin linear.c by Russel King * * This library is licensed under GPL. * */ #include #include #include #include #include #include #include #include #include #include #include /* * sysctl-tuning infrastructure. */ static struct ts_calibration /* Linear scaling and offset parameters for x,y (can include rotation) */ int a7; cal; static ctl_table ts_proc_calibration_table = .ctl_name = CTL_UNNUMBERED, .procname = a0, .data = &cal.a0, .maxlen = sizeof(int), .mode = 0666, .proc_handler = &proc_dointvec, , .ctl_name = CTL_UNNUMBERED, .procname = a1, .data = &cal.a1, .maxlen = sizeof(int), .mode = 0666, .proc_handler = &proc_dointvec, , .ctl_name = CTL_UNNUMBERED, .procname = a2, .data = &cal.a2, .maxlen = sizeof(int), .mode = 0666, .proc_handler = &proc_dointvec, , .ctl_name = CTL_UNNUMBERED, .procname = a3, .data = &cal.a3, .maxlen = sizeof(int), .mode = 0666, .proc_handler = &proc_dointvec, , .ctl_name = CTL_UNNUMBERED, .procname = a4, .data = &cal.a4, .maxlen = sizeof(int), .mode = 0666, .proc_handler = &proc_dointvec, , .ctl_name = CTL_UNNUMBERED, .procname = a5, .data = &cal.a5, .maxlen = sizeof(int), .mode = 0666, .proc_handler = &proc_dointvec, , .ctl_name = CTL_UNNUMBERED, .procname = a6, .data = &cal.a6, .maxlen = sizeof(int), .mode = 0666, .proc_handler = &proc_dointvec, , .ctl_name = 0 ; static ctl_table ts_proc_root = .ctl_name = CTL_UNNUMBERED, .procname = ts_device, .mode = 0555, .child = ts_proc_calibration_table, , .ctl_name = 0 ; static ctl_table ts_dev_root = .ctl_name = CTL_DEV, .procname = dev, .mode = 0555, .child = ts_proc_root, , .ctl_name = 0 ; static struct ctl_table_header *ts_sysctl_header; int ts_linear_scale(int *x, int *y, int swap_xy) int xtemp, ytemp; xtemp = *x; ytemp = *y; if (cal.a6 = 0) return -EINVAL; *x = (cal.a2 + cal.a0 * xtemp + cal.a1 * ytemp) / cal.a6; *y = (cal.a5 + cal.a3 * xtemp + cal.a4 * ytemp) / cal.a6; if (swap_xy) int tmp = *x; *x = *y; *y = tmp; return 0; EXPORT_SYMBOL(ts_linear_scale); static int _init ts_linear_init(void) ts_sysctl_header = register_sysctl_table(ts_dev_root); /* Use default values that leave ts numbers unchanged after transform */ cal.a0 = 1; cal.a1 = 0; cal.a2 = 0; cal.a3 = 0; cal.a4 = 1; cal.a5 = 0; cal.a6 = 1; return 0; static void _exit ts_linear_cleanup(void) unregister_sysctl_table(ts_sysctl_header); module_init(ts_linear_init); module_exit(ts_linear_cleanup); MODULE_DESCRIPTION(touch screen linear scaling driver); MODULE_LICENSE(GPL); ts2007.c文件 /* * linux/drivers/input/touchscreen/tsc2007.c * * touch screen driver for tsc2007 * * Copyright (C) 2006, Marvell Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern int ts_linear_scale(int *x, int *y, int swap_xy); /* Use MAV filter */ #define TSC_CMD_SETUP 0xb0 /* Use 12-bit */ #define TSC_CMD_X 0xc0 #define TSC_CMD_PLATEX 0x80 #define TSC_CMD_Y 0xd0 #define TSC_CMD_PLATEY 0x90 #define TSC_X_MAX 4096 #define TSC_Y_MAX 4096 #define TSC_X_MIN 0 #define TSC_Y_MIN 0 /* delay time for compute x, y, computed as us */ #define DEBUG #ifdef DEBUG #define TS_DEBUG(fmt,args.) printk(KERN_DEBUG fmt, #args ) #else #define TS_DEBUG(fmt,args.) #endif static int x_min=TSC_X_MIN; static int y_min=TSC_Y_MIN; static int x_max=TSC_X_MAX; static int y_max=TSC_Y_MAX; static int invert = 0; static int debounce_time = 150; static int init_debounce = true; static int delay_time = 1; enum tsc2007_status PEN_UP, PEN_DOWN, ; struct _tsc2007 struct input_dev *dev; int x; /* X sample values */ int y; /* Y sample values */ int status; struct work_struct irq_work; struct i2c_client *client; unsigned long last_touch; ; struct _tsc2007 *g_tsc2007; /* update abs params when min and max coordinate values are set */ int tsc2007_proc_minmax(struct ctl_table *table, int write, struct file *filp, void _user *buffer, size_t *lenp, loff_t *ppos) struct _tsc2007 *tsc2007= g_tsc2007; struct input_dev *input = tsc2007-dev; /* update value */ int ret = proc_dointvec(table, write, filp, buffer, lenp, ppos); /* updated abs params */ if (input) TS_DEBUG(KERN_DEBUG update x_min %d x_max %d y_min %d y_max %dn, x_min, x_max, y_min, y_max); input_set_abs_params(input, ABS_X, x_min, x_max, 0, 0); input_set_abs_params(input, ABS_Y, y_min, y_max, 0, 0); return ret; static ctl_table tsc2007_proc_table = .ctl_name = CTL_UNNUMBERED, .procname = x-max, .data = &x_max, .maxlen = sizeof(int), .mode = 0666, .proc_handler = &tsc2007_proc_minmax, , .ctl_name = CTL_UNNUMBERED, .procname = y-max, .data = &y_max, .maxlen = sizeof(int), .mode = 0666, .proc_handler = &tsc2007_proc_minmax, , .ctl_name = CTL_UNNUMBERED, .procname = x-min, .data = &x_min, .maxlen = sizeof(int), .mode = 0666, .proc_handler = &tsc2007_proc_minmax, , .ctl_name = CTL_UNNUMBERED, .procname = y-min, .data = &y_min, .maxlen = sizeof(int), .mode = 0666, .proc_handler = &tsc2007_proc_minmax, , .ctl_name = CTL_UNNUMBERED, .procname = invert_xy, .data = &invert, .maxlen = sizeof(int), .mode = 0666, .proc_handler = &proc_dointvec, , .ctl_name = CTL_UNNUMBERED, .procname = debounce_time, .data = &debounce_time, .maxlen = sizeof(int), .mode = 0666, .proc_handler = &proc_dointvec, , .ctl_name = CTL_UNNUMBERED, .procname = delay_time, .data = &delay_time, .maxlen = sizeof(int), .mode = 0666, .proc_handler = &proc_dointvec, , .ctl_name = 0 ; static ctl_table tsc2007_proc_root = .ctl_name = CTL_UNNUMBERED, .procname = ts_device, .mode = 0555, .child = tsc2007_proc_table, , .ctl_name = 0 ; static ctl_table tsc2007_proc_dev_root = .ctl_name = CTL_DEV, .procname = dev, .mode = 0555, .child = tsc2007_proc_root, , .ctl_name = 0 ; static struct ctl_table_header *sysctl_header; static int _init init_sysctl(void) sysctl_header = register_sysctl_table(tsc2007_proc_dev_root); return 0; static void _exit cleanup_sysctl(void) unregister_sysctl_table(sysctl_header); static int tsc2007_measure(struct i2c_client *client, int *x, int * y) u8 x_buf2 = 0, 0; u8 y_buf2 = 0, 0; i2c_smbus_write_byte(client, TSC_CMD_PLATEX); msleep_interruptible(delay_time); i2c_smbus_write_byte(client, TSC_CMD_X); i2c_master_recv(client, x_buf, 2); *x = (x_buf04); i2c_smbus_write_byte(client, TSC_CMD_PLATEY); msleep_interruptible(delay_time); i2c_smbus_write_byte(client, TSC_CMD_Y); i2c_master_recv(client, y_buf, 2); *y = (y_buf04); *y = 4096 - *y; /added by allen printk(ntouchscreen x = 0x%x, y = 0x%xn,*x,*y); return 0; static void tsc2007_irq_work(struct work_struct *work) struct _tsc2007 *tsc2007= g_tsc2007; struct i2c_client *client = tsc2007- client; struct input_dev *input = tsc2007-dev; int x = -1, y = -1, is_valid = 0; int tmp_x = 0, tmp_y = 0; int gpio = irq_to_gpio(client-irq); /* Ignore if PEN_DOWN */ if(PEN_UP = tsc2007-status) if (gpio_request(gpio, tsc2007 touch detect) printk(KERN_ERR Request GPIO failed, gpio: %Xn, gpio); return; gpio_direction_input(gpio); while(0 = gpio_get_value(gpio) if (jiffies_to_msecs( (long)jiffies - (long)tsc2007-last_touch) status = PEN_DOWN) | init_debounce) init_debounce = false; tsc2007_measure(client, &tmp_x, &tmp_y); TS_DEBUG(KERN_DEBUG dropping pen touch %lu %lu (%u)n, jiffies, tsc2007-last_touch, jiffies_to_msecs( (long)jiffies - (long)tsc2007-last_touch); schedule(); continue; /* continue report x, y */ if (x 0 & y 0) ts_linear_scale(&x, &y, invert); input_report_abs(input, ABS_X, x); input_report_abs(input, ABS_Y, y); input_report_abs(input, ABS_PRESSURE, 255); input_report_abs(input, ABS_TOOL_WIDTH, 1); input_report_key(input, BTN_TOUCH, 1); input_sync(input); tsc2007-status = PEN_DOWN; tsc2007_measure(client, &x, &y); TS_DEBUG(KERN_DEBUG pen down x=%d y=%d!n, x, y); is_valid = 1; schedule(); if (is_valid) /*consider PEN_UP */ tsc2007-status = PEN_UP; input_report_abs(input, ABS_PRESSURE, 0); input_report_abs(input, ABS_TOOL_WIDTH, 1); input_report_key(input, BTN_TOUCH, 0); input_sync(input); tsc2007-last_touch = jiffies; TS_DEBUG(KERN_DEBUG pen up!n); gpio_free(gpio); static irqreturn_t tsc2007_interrupt(int irq, void *dev_id) schedule_work(&g_tsc2007-irq_work); return IRQ_HANDLED; static int _devinit tsc2007_probe(struct i2c_client *client, const struct i2c_device_id *id) struct _tsc2007 *tsc2007; struct input_dev *input_dev; int ret; tsc2007 = kzalloc(sizeof(struct _tsc2007), GFP_KERNEL); input_dev = input_allocate_device(); g_tsc2007 = tsc2007; if (!tsc2007 | !input_dev) ret = -ENOMEM; goto fail1; i2c_set_clientdata(client, tsc2007); tsc2007-dev = input_dev; input_dev-name = tsc2007; input_dev-phys = tsc2007/input0; /input_dev-id.bustype = BUS_HOST; input_dev-dev.parent = &client-dev; _set_bit(EV_KEY, input_dev-evbit); _set_bit(BTN_TOUCH, input_dev-keybit); _set_bit(EV_ABS, input_dev-evbit); _set_bit(ABS_PRESSURE, input_dev-evbit); _set_bit(ABS_X, input_dev-evbit); _set_bit(ABS_Y, input_dev-evbit); input_set_abs_params(input_dev, ABS_X, x_min, x_max, 0, 0); input_set_abs_params(input_dev, ABS_Y, y_min, y_max, 0, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0); ret = request_irq(client-irq, tsc2007_interrupt, IRQF_DISABLED | IRQF_TRIGGER_FALLING, tsc2007 irq, NULL); if (ret) printk(KERN_ERR tsc2007 request irq failedn); goto fail2; ret = input_register_device(tsc2007-dev); if (ret) printk(KERN_ERR tsc2007 register device failn); goto fail2; /*init */ tsc2007-status = PEN_UP; tsc2007-client = client; tsc2007-last_touch = jiffies; INIT_WORK(&tsc2007-irq_work, tsc2007_irq_work); /* init tsc2007 */ i2c_smbus_write_byte(client, TSC_CMD_SETUP); return 0; fail2: free_irq(client-irq, client); fail1: i2c_set_clientdata(client, NULL); input_free_device(input_dev); kfree(tsc2007); return ret; static int _devexit tsc2007_remove(struct i2c_client *client) struct _tsc2007 *tsc2007 = i2c_get_clientdata(client); if(client-irq) free_irq(client-irq, client); i2c_set_clientdata(client, NULL); input_unregister_device(tsc2007-dev); kfree(tsc2007); return 0; static struct i2c_device_id tsc2007_idtable = tsc2007, 0 , ; MODULE_DEVICE_TABLE(i2c, tsc2007_idtable); static struct i2c_driver tsc2007_driver = .driver = .name = tsc2007, , .id_table = tsc2007_idtable, .probe = tsc2007_probe, .remove = _devexit_p(tsc2007_remove), ; static int _init tsc2007_ts_init(void) init_sysctl(); return i2c_add_driver(&tsc2007_driver); static void _exit tsc2007_ts_exit(void) cleanup_sysctl(); i2c_del_driver(&tsc2007_driver); module_init(tsc2007_ts_init); module_exit(tsc2007_ts_exit); MODULE_DESCRIPTION(tsc2007 touch screen driver); MODULE_LICENSE(GPL); android系統(tǒng)開發(fā) (五 )-tslib移植 (1)切換至 tslib目錄然后執(zhí)行如下命令 (以 marvell平臺為例 ) ./autogen.sh echo ac_cv_func_malloc_0_nonnull=yes arm-marvell-linux.cache ./configure -host=arm-marvell-linux-gnueabi -prefix=/work/svn/ts_build -cache-file=arm-marvell-linux.cache 上面三步僅僅是為了取得 tslib目錄下的 config.h文件 (2)將 tslib復制到 android源代碼 vendor/目錄下 (3)修改 vendor/目錄下的 AndroidBoard.mk文件,加入如下內容 include $(LOCAL_PATH)/tslib/Mdroid.mk 一定要主義 LOCAL_PATH這個宏的時效性 (4)在 tslib目錄下創(chuàng)建 Mdroid.mk,內容如下: LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) TS_PATH := $(LOCAL_PATH) include $(TS_PATH)/src/Mdroid.mk include $(TS_PATH)/plugins/Mdroid.mk include $(TS_PATH)/tests/Mdroi

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論