jni:java native interface java調用c語言的接口
HAL(hardware abtract layer) 硬件抽象層
binder 虛擬設備,不是硬件,用于進程間通訊(獨立的進程通訊機制)
更為安全高效、拿一段內存進行設備通訊、相比共享內存安全、可以創建多個
一般學習過程首先研究binder
總結:binder是更為安全高效的進程間通訊機制
libraries 庫 native 本地
C/C++開發的庫,一般成為本地庫,上層開發一般是java,對于內核而言是應用層
surface Manager 界面開發、圖形開發
Media Framework 音頻框架
SQLite 數據庫、本地的庫
OpenGL|ES 圖形渲染
FreeType 字體素材
WebKit 瀏覽器的內核
SGL 2d圖形渲染
SSL 加密套接層
Libc 標準C庫
Android Runtime 安卓運行時環境 runtime 一般指運行環境
Core Libreries
java 虛擬機將代碼解析到對應的平臺
Application Framework
Activity Manager 活動窗口(界面)
Window Manager 窗口管理
Content Provider 數據共享,可使2個app共享數據
View system 界面渲染
Notification Manager 通知
Package Manager apk包的管理
Telephone Manager 打電話
Resource Manager 資源管理
Location Manager 與GPS相關,定位
XMPP Service 短信接收和發送
Application
應用程序
home等(laucher)
boot.img 是一個uboot + kernal + rootfs
①source bulid/envsetup.sh
②lunch //envsetup里面的一個函數
③extract-bsp
④make -j2
⑤pack //打包
boot.img + system.img + recovery.img = 最終產物
如何進行數據的傳輸?
①adb devices
②adb push .\文件名 /system/lib
出現系統只讀則需要重新掛載 執行 adb remount
③使用adb shell 進入到對應的安卓命令行 //安卓和電腦使用數據線連接,usb可調式確認后才可使用
④使用 adb pull /system/lib/文件名 將對應的文件獲取到當前目錄
使用 exit 退出安卓平臺
⑤使用apk 安裝
adb install *.apk //有個push過程,再進行安裝
關于linux網絡這塊問題解決
使用局域網時用靜態ip連接開發板 橋接
使用wifi時用動態ip連接網絡 自定義橋接 使用wifi網卡
使用網線動態ip連接網絡 自定義橋接 使用以太網卡
5層模型
app 應用
app framework 應用框架
libs 核心庫
HAL 硬件抽象層
kernel 內核
①source build/envsetup.sh
455-460 添加默認的編譯菜單
1506-1512 查找device和vendor目錄下名稱為vendorsetup.sh腳本并執行
查看device/softwinner/fspad-733/vendorsetup.sh
添加產品編譯
8個產品編譯選項保存在 LUNCH_MENU_CHOICES數組中
②lunch
執行build/envsetup.sh 481
488-490,打印選項菜單,讀取用戶輸入值
495-507,根據用戶輸入選項,從LUNCH_MENU_CHOICES數組菜單項內容,保存到selection變量
518-536,將產品名和編譯類型提取,產品名保存到product,編譯類型保存到variant
544-546,賦值到對應的全局變量,導出
550,設置剩余的環境變量
551,打印變量列表
③extrap-bsp
將lichee編譯出來,boot.img和modules.ko拷貝到androidL下面,為下一步打包做準備
④make
執行androidL/Makefile
執行build/core/main.mk
執行對應93行,包含build/core/config.mk
跳轉到build/core/config.mk
63-99,賦值一些列編譯系統內部的子makefile路徑,為后面直接使用,可以編譯成不同類型產物
151,包含build/core/envsetup.mk
跳到該mk下
138行,包含了build/core/product_config.mk
跳轉到該文件
189,讀取源碼樹下面所有的名稱為AndroidProducts.mk產品makefile
獲取device/softwinner/fspad-733/AndroidProducts.mk
該文件獲取device/softwinner/fspad-733/fspad_733.mk
定義軟件系統配置 app屬性 copy產品信息
150-155行,查找device和vendor目錄下面產品目錄名為BoardConfig.mk獲取文件
跳轉到mk下
獲取文件為 device/softwinner/fspad-733/BoardConfig.mk
該文件進行硬件配置
配置板子上硬件,主要是wifi和bt配置
⑤pack //由于一開始source后即可使用pack命令來進行解析
打包 boot.img+system.img+recovery.img
打包為 lichee/tools/pack/sun8iw3p1_andorid_fspad_733_card0.img
添加一個產品的時候需要在哪些文件上添加?
①device/osoftwinner/fspad-733/vendorsetup.sh 下添加產品菜單
②device/softwinner/fspad-733/AndroidProducts.mk 下添加對應產品文件名
③device/softwinner/fspad-733/fspad_733.mk 軟件添加文件
④device/softwinner/fspad-733/BoardConfig.mk 硬件添加文件
A := a A賦值為a
新建一個文件夾hello
在里面
編寫 hello.c
編寫自己的Android.mk
#current module path
①LOCAL_PATH := $(call my-dir)
#clear vars old value
②include $(CLEAR_VARS)
#module name don't need to specify a path.
③LOCAL_MODULE := hello
#specify source file
④LOCAL_SRC_FILES := hello.c \
world.c\
#build this module to executable binary file
⑤include $(BUILD_EXECUTABLE)
最后
編譯
source build/envsetup.sh
lunch 9
mmm device/softwinner/fspad-733/hello/hello.c //絕對路徑
如果在當前目錄下則為 mm 使用當前路徑來進行編譯模塊
為什么會提示對應的依賴錯誤?
No private recovery resources for TARGET_DEVICE fspad-733
make: Entering directory `/home/linux/fs733/androidL'
make: *** No rule to make target `/hello.c', needed by `out/target/product/fspad-733/obj/EXECUTABLES/hello_intermediates/hello.o'. Stop.
make: Leaving directory `/home/linux/fs733/androidL'
路徑出錯
可能是自己對應的代碼敲寫錯誤導致
adb的使用說明:
adb的使用
使用過程:
1.通過usb線將主機和平板從機連接,打開PhoenixSuit工具,必須顯示和設備已經連接上。
2.使用以下命令與平板android系統交互:
a.adb shell 進入到android的linux的命令行模式
exit 進入到命令行模式之后需要的退出
b.adb push 主機需要被推送的文件目錄 平板存放推送文件的位置
將文件推送到從機指定目錄
c.adb pull 平板中需要被拉去出來的文件的位置
從從機拉取文件到主機
d.adb install xxxx.apk 將xxxx.apk android應用程序安裝到從機上
e.adb devices 列出所有連接到主機的從機信息
tips:在敲adb命令的時候,如果提示read-only file system的時候,你就使用命令adb remount 重新掛載一下
android的文件系統就可以了。如果說還是不行,任然提示該信息,那么就要修改從機目錄屬性。
編譯完成后根據
Install: out/target/product/fspad-733/system/bin/hello
來找到對應目錄將文件拷貝到windows平臺下
打開phoenixSuit程序,連接安卓后
在含有adb.exe的文件下面的空白處點擊 shift + 鼠標右鍵 訓責phoenixSuit運行
使用adb push .\hello /system/bin (由于是執行phoenixSuit后,/system/bin直接執行)
使用adb shell進入安卓shell
hello 即可打印對應的函數
init啟動流程
①解析/init.rc
action_list 、service_list
②添加action到action_queue中
③執行action相關命令(與action的序列有關),查看是否有需要重新啟動的服務,如果有則啟動這些服務
④poll監聽3路socket
屬性設置→修改屬性
組合鍵→對應服務
服務進程退出→將標志位置為重啟與restart進行結合重啟進程
init啟動zygote
①修改進程名
②android Runtime的start方法 啟動虛擬機 vm
③調用執行zygote init的main方法
C++代碼截止
init啟動后執行system/core/init/init.c
1059 判斷ueventd 還是init
1060 如果啟動設備,解析設置uevent事件,創建設備文件
1062 若是啟動watchdogd 設置看門狗以及喂狗
1072-1081 創建一些目錄并掛在文件系統
1120 從文件中加載系統屬性默認值
1123 解析init.rc 建立服務鏈表和動作鏈表
1128-1134 創建內部action
1139 創建init動作init到動作鏈表
1152 添加early-init動作到動作鏈表
action_for_each_trigger("early-init", action_add_queue_tail);
1145-1154 創建內部action并觸發
①early_init
②wait_for_coldboot_done(內部動作)
等待冷啟動設備掃描(為每個設備創建設備文件)
③keychord_init
打開組合鍵的監聽文件
④console_init
檢測console終端是否存在,顯示logo
⑤property_service_init
打開屬性修改服務的socket
⑥signal_init
設置sigchild信號處理,回收孤兒進程資源
⑦late-init
⑧queue_property_trigger
促發rc腳本中property:屬性名= 屬性值 形式的動作
1166 主循環
①execute_one_command();
執行一個命令
②restart_processes();
掃描是否有服務需要重啟
③ 監控并處理屬性修改請求、組合按鍵啟動服務請求和檢測服務進程退出
init.rc本地服務被啟動
①ueventd 接收、解析和處理uevent,新建/刪除設備文件,固件加載
②console 終端,啟動shell程序
③adbc adb程序服務端
④service manager 服務管理程序
⑤vold(volume daemon) 完成系統cdrom,usb大量存儲,mmc卡等擴展存儲的掛載任務
⑥netd 網絡服務
⑦surfaceflinger 繪制android程序的ui,完成2d和3d的無縫融合
⑧zygote 啟動虛擬機服務
⑨media 多媒體服務
⑩bootanim 負責android播放開機啟動動畫以及背景音樂
其中關鍵
①zygote
定義 在init.zygote32.rc
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
可以看到主要啟動的程序 app_process
實現在frameworks/base/cmds/app_process/app_main.cpp‘
186 main函數
解析參數后
201行之后得到
227-236 將參數 runtime
246-264 將后面參數解析出來,得到結果
301-304 進程名更改nicename = zygote
307 運行類com.android.internal.os.ZygoteInit
runtime.start();
rumtime是AndroidRuntime類
通過找到androidruntime類找到調用的start成員函數
frameworks/base/core/jni/AndroidRuntime.cpp 930行
966 啟動java虛擬機
974 注冊andorid本地函數
988 找到string類
1006 將傳進來的classname com.android.internal.os.ZygoteInit
轉換為路徑com/android/internal/os/ZygoteInit
1007 找到com/android/internal/os/ZygoteInit類
1018 com/android/internal/os/ZygoteInit類的main函數進入到java
ZygoteInit類定義在目錄
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
轉到里面 main函數 644
通過644里面函數 同時AndroidRuntime那邊將參數"start-system-server"也傳進來
668行通過注冊 zygote socket服務端
671 預加載了一些資源和庫
686 調用startSystemServer函數啟動了systemserver
查看startSystemServer 在573行定義
607行 創建一個子進程來運行forkSystemServer
624調用handleSystemServerProcess實現在494行
537行 RuntimeInit.zygoteInit();
該函數定義在rameworks/base/core/java/com/android/internal/os/RuntimeInit.java 267行
查看applicationInit函數在297行定義
關鍵321行,invokeStaticMain();
其中第一個參數就是前面傳遞過來的 com.android.server.SystemServer
該句子調用了com.android.server.SystemServer類的main函數
定義在frameworks/base/services/java/com/android/server/SystemServer.java 170
運行了run函數,定義在179
255-257 啟動了好多services
其中316行,ActivityManagerService的systemReady函數,表示ActivityManagerService的ready
ActivityManagerService的定義。frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
在11373,在systemReady調用startHomeActivityLocked啟動桌面應用
bootanimation
init.rc 中
service bootanim /system/bin/bootanimation
class main
user graphic
group graphics
disabled
oneshot
找到bootanimation源碼 frameworks/base/cmds/bootanimation/bootanimation_main.cpp 39行
55行,創建開機動畫播放線程
找到BootAnimation類,打開可以看到是利用opengl渲染的。
230行,看readyToRun函數
291行~301行,判斷在/sytem/media目錄下否有bootanimation的素材壓縮包。
313行,在線程循環函數中判斷了上面判斷結果,是否有bootanimation.zip
如果有就播放,如果沒有就調用android函數。
328行,android函數定義
330,331行,可以看到定義圖片的位置。
下面opengl播放圖片。
找到圖片放的位置, find . -depth -name android-logo-mask.png
在frameworks/base/core/res/assets/images/android-logo-mask.png
所以如何定制開機啟動動畫?
1.在/data/local或/system/media目錄下添加自己的動畫bootanimation.zip文件(同時也可以添加相應的開機音樂boot.mp3),這樣在系統啟動時就會播放自己的開機動畫和播放音樂。
2.可以替換一下frameworks/base/core/res/assets/images/ 目錄下兩張圖片。
粗略啟動流程
uboot
內核
掛載根文件系統
掛載system系統 里面含有很多文件
執行第一個進程init
解析init.rc文件
執行了一些列命令,啟動了一些服務,后退化成為一個守護進程
該守護進程 ①系統屬性修改 ②重啟子進程 ③組合鍵按下啟動對應服務
其中有一個很重要的服務zygote
創建虛擬機
運行systemserver 啟動很多java服務
其中有個很重要的服務activityManager執行一個systemReady函數運行了一個界面
VFS 統一文件系統差異,為上層提供接口
HAL
統一下層硬件差異,為上層提供接口
為了保護硬件供應商的知識產權
不是所用硬件設備都有標準的linux kernel接口
為什么open在modules中,而close在device
每個device是對應不同的關閉方式,所以在device中關閉,而打開只需統一打開
hal_*.h
#include
//stub具體某一個device id號
#define LED1 1
//led模塊stub的id
#define LED_HARDWARE_MODULE_ID "led"
①定義一個led_module_t 模塊結構體
里面第一個結構體必須為struct hw_module_t 的對象
struct led_module_t {
struct hw_module_t common;
};
②定義led_device_t 設備結構體
里面第一個為struct hw_device_t 結構體
struct led_device_t {
struct hw_device_t common;
int fd; //存放調用open返回描述符
int (*led_on)(struct hw_device_t *dev); //
int (*led_off)(struct hw_device_t *dev);
};
hal_*.c
①定義一個hw_module_t 對象HAL_MODULE_INFO_SYM必須為這個對象
在對象里面對其成員進行初始化
struct hw_module_t HAL_MODULE_INFO_SYM = {
tag: HARDWARE_MODULE_TAG,
version_major: 1,
version_minor: 0,
id: LED_HARDWARE_MODULE_ID,//頭文件中含有
name: "led module",
author: "farsight",
methods: &led_module_methods,//主要是實現一些方法
};
②定義一個 hw_module_methods_t 對象led_module_methods 里面裝著一個led_open函數地址
static struct hw_module_methods_t led_module_methods = {
open: led_open,
};
③定義 led_open函數
static int led_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device)
{
char devpath[128] = "/dev/";
struct led_device_t *dev;
//函數中新建一個結構體指針指向led_device_t開辟的空間中
//1.分配描述被打開的設備device結構體
dev = (struct led_device_t *)malloc(sizeof(struct led_device_t));
if (!dev) {
LOGE("alloc device memory failed\n");
return -EFAULT;
}
memset(dev, 0, sizeof(struct led_device_t));
//對其結構體成員進行賦值
//2.填充設備結構體的成員
dev->common.tag = HARDWARE_DEVICE_TAG;.//必須為這個
dev->common.version = 0;
dev->common.module = (struct hw_module_t *)module;
dev->common.close = led_close;
dev->led_on = led_on;
dev->led_off = led_off;
strcat(devpath, name);//devpath設備文件路徑 /dev/name
//通過結構體賦值close、led_on、led_off
//3.調用系統調用open,open再通過linux內核調用到驅動代碼中的led_open函數
dev->fd = open(devpath, O_RDWR);
if (dev->fd == -1) {
free(dev);
LOGE("open device failed\n");
return -1;
}
//4.返回打開的具體設備的描述結構體指針
*device = &(dev->common);
return 0;
}
④led_on、led_off、led_close的實現
主要是調用了系統調用,通過系統調用將設備的信息傳遞給結構體
static int led_on(struct hw_device_t* device)
{
struct led_device_t *dev = (struct led_device_t *)device;
if (dev->fd != -1)
return ioctl(dev->fd, LED_ON); //調用系統調用ioctl,ioctl回去通過linux內核調用到驅動中unlocked_ioctl
else
return -1;
}
static int led_off(struct hw_device_t* device)
{
struct led_device_t *dev = (struct led_device_t *)device;
if (dev->fd != -1)
return ioctl(dev->fd, LED_OFF);
else
return -1;
}
static int led_close(struct hw_device_t* device)
{
struct led_device_t *dev = (struct led_device_t *)device;
if (dev->fd != -1) {
close(dev->fd);//調用系統調用close,close回去通過linux內核調用到驅動中led_close
free(dev);
}
return 0;
}
lib中
使用hal提供的框架接口 hw_get_module();//獲取到對應hal里模塊的結構體地址
通過訪問這個結構體的methods里的led_open即可調用到底層的open
touch可以更新對應的代碼時間戳,使編譯的時候重新編譯
整體一個流程:
①app上 通過led_open會調用coreLib庫
②庫中使用hal接口函數hw_get_module();
來通過LED_HARDWARE_MODULE_ID進行獲取到對應的模塊module,
③通過獲取模塊中的第一個成員hw_modules_t 中的mothods方法集合里面的open方法將對應的模塊傳入進入到hal中
④在hal中通過上面傳入下來的name,將器設備路徑給獲取后,通過打開設備驅動的open函數即完成獲取,并且創建一個led_dev結構體,通過結構體進行初始化,將其傳遞給在coreLib中的device對象,便于后續的操作使用,雖然傳遞過去的不是led_dev對應的結構體,但是由于hw_device_t與對應結構體的首地址一致,所以通過強轉即可獲取到led_dev對應的方法
Android硬件抽象層框架代碼在 hardware目錄
Dalvik虛擬機作用:
①Dalvik基于虛擬機,JVM基于棧,所以效率更高
②Dalvik可運行壓縮過,針對內存優化過的dex,減少文件尺寸,提高查找類的速度
③Dalvik每一個應用程序運行與一個獨立進程
android系統中,使用 make ramdisk命令 只編譯文件系統
android系統app framework層,HAL層,core Libs 代碼編譯之后在system.img
通過GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V")找到對應的方法應該
①([Ljava/lang/String;)V") ===》 [ 數組 String =》tring 類型,參數 V ===》void 返回值
②main為函數名 即可推出 void main (String [] )
init.rc包含5個部分
①import導入 ②commond命令 ③service服務 ④action行為 ⑤option選項
簡述linux內核編譯步驟
①進入lichee ./build.sh config //編譯選擇配置
②./build.sh 編譯內核和uboot
簡述android源碼的編譯步驟(以fspad-733配套androidL源碼為例)進入androidL
①source build/envsetup.sh 添加配置調試命令到shell進程
②lunch 選擇編譯的產品好
③extract-bsp 將內核生成的bImage和模塊拷貝到androidL/device/softwinner/fspad-733/下
④make -j2 編譯
androidL ===>生成 system.img(非內核部分) + ramdisk.img(rootfs) + recovery.img(恢復出廠鏡像)
lichee ===>生成 uboot.bin + uImage === > bImage
簡單介紹一下Android系統中的HAL,并說出舊HAL架構libhardware_legacy和新HAL架構libhardware的區別
①屏蔽下層硬件差異,為上層提供統一接口
②保護硬件的知識產權
③硬件設備不全都有linux kernel接口
舊的沒有經過封裝,上層可以直接操走硬件
新的通過hal層將硬件分類,一個類一個stub,通過stub再進行訪問
請介紹Android系統架構,并簡單說明每層架構的作用
①linux內核 在內核基礎上添加了android特有的驅動,binder驅動(進程間通訊)
②HAL 屏蔽下層差異,為上層提供統一接口
③核心庫 libs 一些三方庫和c/c++庫的提供,
runtime Dalvik虛擬機和對應的運行環境
④app framework 讓應用開發更為方便
⑤app 一些與用戶進行交互的程序
android源碼樹添加新產品目錄支持,必須有哪幾個文件?
①vendorsetup.sh 添加產品編譯的選項
②BoardConfig.mk 硬件方面定制
③AndroidProduct.mk 產品文件列表
④產品名.mk 定制軟件系統的配置