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