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 定制软件系统的配置