Download presentation
Presentation is loading. Please wait.
Published by忒 席 Modified 8年之前
1
哈工大计算机科学与技术学院软件基础教研室 第二部分 Android 与工程和科研 授课教师:李治军 lizhijun_os@hit.edu.cn 综合楼 411 室 第 6 讲 进入 Android 内核 Lecture 6: Get Into the Android Kernels
2
- 2 - Android Development Android 的内部结构 应用程序层 应用程序框 架层 系统运行库 层 Linux 内核层
3
- 3 - Android Development Android 的应用程序层 就是我们用到的各种手机应用程序 … 如主屏、短信收发、通信录、浏览器等等 … 这些程序都是用 Java 语言编写、调用应用程序框架层 (Application Framework) 提供的 API 编写,如 getSystemService, getScanResultsdeng 等 … 前面写的程序都是应用程序,关键在于 Activity , Intent 等机制、各类 Manager 以及重要 API 的调用
4
- 4 - Android Development Android 的应用程序框架层 用来给上层程序提供 API 框架,就是常说的 Manager… 有 ActivityManager , WifiManager ,等等 这一层之上代码是用 Java 写的,之下使用 C 写的,所 以这是一个从 Java 到 C 的一个过度,就是 JNI Java Native Interface (JNI) 允许 Java 代码和其他语 言写的代码进行交互
5
- 5 - Android Development Android 的运行库层 包括核心库和 Dalvik 虚拟机两个部分 核心库是用 C 语言写的一些库功能,比如 Media Framework 采用 OpenCORE 提供视频编、解码功能 每一个 Android 应用程序都在自己的进程中运行,拥 有一个独立的 Dalvik 虚拟机 整个系统采用虚拟 机结构
6
- 6 - Android Development Android 的 Linux 内核层 基于 Linux 操作系统的核心:进程管理、内存管理、网 络栈、各种设备的驱动等 Android 对内核有了一定的增强,如日志设备,电源管 理, Android IPC(Binder) 机制等 在 Android 中,这个层是硬件层和其他层之间的抽象层, 该系统并非 GNU/Linux 的,其初始化、接口都和标准 的 Linux 有所不同
7
- 7 - Android Development 一个例子来这些模块之间的关系 Application Location Manager Service libgps.so Gps 设备驱动 应用层 框架层 库层 内核层 Binder IPC JNI 系统调用
8
- 8 - Android Development 学习 JNI 就是看一看如何使用 JNI 来调用 C 库中的函数 public class TrackActivity extends Activity { static { System.loadLibrary("track"); } 首先需要有一个 C 库, libtrack.so ,并导入 … 需要告诉 Java ,要调用 C 库中的哪些函数 public native String GetTrack(); public void onCreate() { String str = GetTrack(); // 进行地图展示 这样声明以后就可 以 Java 编译了 现在可以开始写 C 函数了 javah -classpath bin -d jni 包名.TrackActivity
9
- 9 - Android Development 有了.h 文件才可以编写.c 文件 javah 可以自动生成 JNI 对应的 C 头文件 #include JNIEXPORT jstring JNICALL Java_com_hit_os_Trac kActivity_GetTrack(JNIEnv *, jobject); 现在可以写 C 库中的函数了 #include "com_hit_os_track.h" JNIEXPORT jstring JNICALL Java_com_hit_os_TrackA ctivity_GetTrack(JNIEnv * env, jobject obj){ return (*env)->NewStringUTF(env,(char *) “ 轨迹数据 ”);} 现在可以编译了,要使用 NDK(Native Development Kit) 编译,不是 gcc ,因为是 arm 结构,并且有 jint…
10
- 10 - Android Development 现在开始编译 C 库、使用 C 库 编译使用命令 ndk-build ,类似 make 命令 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := libtrack LOCAL_SRC_FILES:= com_hit_os_track.c include $(BUILD_SHARED_LIBRARY) 将这个.so 文件拷贝到工程的根目录下 需要写 Makefile 文件: Android.mk 会编译成 libtrack.so 文件 会放在.apk 中,然 后拷到 /data/data/ 你的包 也可以 adb push 到 /system/lib 下
11
- 11 - Android Development 开始修改 Linux 内核,给内核加系统调用 思路和 Linux 0.11 基本上一样 CALL(sys_gettrack) 在函数表中增加一个函数,就是系统调用处理函数 建立一个号 ( 整数 ) 来标识新的系统调用 #define __NR_gettrack (__NR_SYSCALL_BASE+322) 实现 sys_gettrack ,新建 track 目录和其下的 track.c SYSCALL_DEFINE1(gettrack, char *, retstr) { return do_sys_gettrack(retstr); } 这个宏在 #include 中 在 arch/arm/kernel/calls.S 中 在 include/asm-arm/unistd.h 中
12
- 12 - Android Development 实现函数 do_sys_gettrack 并编译 gettrack 的功能是从内核中返回一个包含 gps 坐 标序列的字符串 #include int do_sys_gettrack(char * retstr){ char kernelstr[20] = "kernel track"; copy_to_user(retstr, kernelstr, 12); return 12; } 开始编译内核,首先写 Makefile core-y += kernel/ mm/ fs/... track/ objs-y += track.o
13
- 13 - Android Development 开始编译 Linux 内核 定义两个宏,在 Makefile 中使用 export ARCH=arm export CROSS_COMPILE=/home/lizhijun/android- ndk-r6b/toolchains/arm-linux-androideabi- 4.4.3/prebuilt/linux-x86/bin/arm-linux- androideabi- arm 体系结构 配置内核,需要哪些模块等 交叉编译环境 make herring_defconfig 开始编译 make 或者是 make –j4 // 表示用几核编译 grep -c processor /proc/cpuinfo 编译后的结果是 /arch/arm/boot/zImage
14
- 14 - Android Development 有了内核就可以刷机了 首先需要知道你的手机的 boot 在哪个分区 adb shell cat /proc/mtd | awk -F’[:"]‘ ‘$3 == "boot" {print $1}’ 结果是 mtd2 ,根据手 机型号而不同 取出你的手机的 boot 分区内容 adb shell # su # dd if=/dev/mtd/mtd2 of=/sdcard/boot.img bs=4096 2048+0 records in 2048+0 records out 8388608 bytes transferred in 1.232 secs (6808935 bytes/sec) 需要有 root 权限, 需要破解
15
- 15 - Android Development 需要产生你的 boot.img 先把那个 sdcard 上的 boot.img 弄过来 adb pull /sdcard/boot.img 会放到当前目录下 拆开这个 img 文件 unbootimg boot.img 这些工具都能下到 拆开以后有三个文件 boot.img-mk : containing the mkbootimg options required to produce a working boot image boot.img-kernel : containing the kernel image boot.img-ramdisk.cpio.gz : containing the gzipped ramdisk, which we will reuse as-is
16
- 16 - Android Development 用 zImage 替换 boot.img-kernel 用我们编译形成的 zImage 替换其中 boot.img- kernel 就产生可以刷机的 boot.img 了 eval./mkbootimg $(sed s,boot.img- kernel,./zImage, boot.img-mk) 产生完 boot.img 就可以刷机了 adb reboot bootloader // 让手机会进入 fastboot 模式./fastboot boot boot.img // 载入新的 boot.img 并启动./fastboot flash boot boot.img // 将新的 boot.img 写入 mtd2 ,并启动
17
- 17 - Android Development 启动了新内核以后 … 新内核的 “ 某个函数表 ” 中有了函数 sys_gettrack JNIEXPORT jstring JNICALL Java_xxx (JNIEnv *env, jobject obj){ char str[20]; int size = gettrack(str); str[size] = 0; return (*env)->NewStringUTF(env, str); } 在上层调用这个函数 ( 在 JNI 的那个 C 函数中 ) 用宏展开实现 gettrack /*#define _syscall1(name, type, arg1) \ int name(type arg1) { \ return syscall(__NR_##name, arg1); } \ syscall1(gettrack, char*, str)
18
- 18 - Android Development syscall 在 ndk 的头文件 中定义了原型 实质是使用 swi 软中断指令进管理模式 syscall(int number, …) , number 是一个编号, … 是 可以扩展的参数列表 … 在 ndk 的库中有实现:根据 number 编号跳到内核函数 表中的某个位置,然后将参数一个一个拷贝过去 #include #define __NR_gettrack (__NR_SYSCALL_BASE+376) 在 eabi(Embedded application binary interface) 中 是连接规范 mov r0, #num swi 0x00 // 调用软件中断
Similar presentations