Android基本框架笔记

最近学习下Android 的Camera开发,做一下相关笔记,首先对Android的基本框架有一定了解,

Android 基本框架

可以参考《Android 系统源代码情景分析》、《Android驱动开发权威指南》相关书籍。
这个是很经典的两个Android基本架构图:
在这里插入图片描述
在这里插入图片描述
从图中可以很清楚得看出,整个架构可以分为五大层次:

1、System Apps:即系统应用层,这一层中都是我们使用手机时都会直接接触到的各种应用。
2、Java API Framework:即 Java 接口框架层,这一层是为了上层应用提供各种接口。
3、Native C/C++ Libraries && Android Runtime:分别是原生 C/C++ 库,安卓运行时环境。这一层中,C/C++ 库集成了许多诸如 OpenGL ES 这样的开源库,提供了很多封装好的方法。而运行时环境则是与一些核心库、Dalvik Virtual Machine 相关的东西。
4、HAL(Hardware Abstract Layer):这是一个硬件抽象层,它主要是在 Framework 层和 Linux Kernel 层之间起到一个链接作用。
5、Linux Kernel:即 Linux 内核层,整个 Android 系统实际上是基于 Linux 的内核搭建起来的。


系统应用层
1)它包含了一系列使用 Java 编写的核心程序包(Home,Phone,Browser…)。
2)应用程序通过调用框架层的接口,或者 JNI (Java 原生接口)来完成自己的业务逻辑。
3)值得注意的是,要使用 JNI 开发原生应用程序,需要与 Android NDK 配合,NDK 使得 Java 可以与 C/C++ 进行交互。


Java 接口框架层
1)也有人称为应用程序框架层,实际上这一层主要是提供给上层应用一些访问核心功能的 API 框架。
2)框架是应用程序的核心,也是开发者需要共同遵守的一个约定,大家可以在这个约定的基础之上进行一些必要的扩展,但是主体结构需要保持一致。
3)框架层提供了大量的接口,当需要使用到某些接口的时候,可以去看看它对应的官方文档。


C/C++ 库 && Android 运行时环境
1)官方 API 不是万能的,开发者常常需要自己一些 API 以实现自己的业务逻辑,这时候我们就可以通过调用 C/C++ 本地库的接口来进行个性化设计。
2)需要注意的是,这些 C/C++ 库(第三方库)是独立于 Android 系统架构实现的,但是它与系统架构处于相同的地位:
他们都使用 Linux 内核层提供服务,实现、封装模块,以供应用层调用。
3)运行时环境提供了一些核心链接库。
以及 Dalvik 虚拟机:
DVM 代替了 JVM,“.java”文件编译为“.class”文件后,再编译得到“.dex”程序,最后又打包成为 Android 可执行文件“.apk”。
每个应用都运行在自己的进程上(一个应用程序对应一个虚拟机,一一对应关系),而 DVM 为它分配自有实例。
Dalvik 的好处是,使得一台设备可以运行多个虚拟机程序,并且消耗比较少的资源。


硬件抽象层
1)向下屏蔽了硬件驱动模块的实现细节,并向上提供硬件访问服务。
2)这一层的存在,实际上主要是为了保护移动设备厂商的商业利益:
Linux 内核源码遵循 GPL 协议,基于它所修改的源码需要完全公开,如果设备厂商通过修改内核源码来提供服务,就需要公开对应的代码,这就暴露了很多硬件相关的参数和实现的细节。
3)为了保证商业利益,在 Android 架构中提供一个硬件抽象层给设备厂商对硬件做出具体实现,而 Linux 内核仅提供简单的硬件访问通道。由于 Android 源码遵循商业友好的Apache License 协议,这样设备厂商的利益就得到了保障。

HAL屏蔽了不同硬件设备的差异,为Android提供了统一的访问硬件设备的接口。不同的硬件厂商遵循HAL标准来实现自己的硬件控制逻辑,但开发者不必关心不同硬件设备的差异,只需要按照HAL提供的标准接口访问硬件就可以了。
有了HAL层之后,他们可以把一些核心的算法之类的东西的实现放在HAL层,而HAL层位于用户空间,不属于linux内核,和android源码一样遵循的是Apache license协议,这个是可以开源或者不开的。


Linux 内核层
1)Android 是基于 Linux 内核开发的(官方给出的例子是,Android Runtime (ART) 依靠 Linux 内核来执行底层功能,例如线程和底层内存管理)。
2)一个很重要的部分是 Linux 内核驱动部分,在 Camera 流程中,我们的控制指令最终要通过内核驱动发送给 Camera 设备,同时也要通过它对设备返回的数据向上传输。
3)在 Android 中,增加了 YAFFS2(Yet Another Flash File System, 2nd edition)文件系统。(这个系统没有去深入了解)
增加了一个进程间通信的机制 IPC Binder,通过 Binder ,可以使不同进程可以访问同一块共享内存。Binder 机制在整个 Camera 流程中起到了十分重要的作用,它主要使用在 CameraClient 与 CameraServer 的交互中(Camera 架构中,采用了一个 C/S 交互的流程,在之后的学习中会有比较深入的了解)。

Android 硬件抽象层

1.1 HAL 层模块编写规范

Android 系统的硬件抽象层以模块的形式来管理各个硬件访问接口。每一个硬件模块都对应有一个动态链接库文件。

在系统内部,每一个硬件抽象层模块都使用结构体 hw_moudle_t 描述,而硬件设备则使用结构体 hw_device_t 来描述。下面分别描述硬件抽象层模块文件的命令规范以及结构体 hw_moudle_t 和 hw_device_t 的含义。

1.1.1 硬件抽象层模块编写规范

硬件抽象层的模块文件的命令规范定义在 hardware/libhardware/hardware.c 文件中

/**
 * There are a set of variant filename for modules. The form of the filename
 * is "<MODULE_ID>.variant.so" so for the led module the Dream variants 
 * of base "ro.product.board", "ro.board.platform" and "ro.arch" would be:
 *
 * led.trout.so
 * led.msm7k.so
 * led.ARMV6.so
 * led.default.so
 */

static const char *variant_keys[] = {
    "ro.hardware",  /* This goes first so that it can pick up a different
                       file on the emulator. */
    "ro.product.board",
    "ro.board.platform",
    "ro.arch"
};
  • 硬件抽象层模块文件的命令规范:<MOUDLE_ID>.variant.so
  • MOUDLE_ID 表示模块的ID variant 表示variant_keys四个系统属性值的其中一个,顺序依次
  • variant 如果四个属性值都不存在,则将 variant 的值设为 default

variant变量取值过程: ro.hardware: /prop/cpuinfo 的 Hardware
字段其他三个在:/system/build.prop 中查找

1.1.2 硬件抽象层模块结构体定义规范

结构体 hw_device_t 和 hw_moudle_t 及其它相关结构体定义在文件 hardware/hardware.h 中

/**
 * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM
 * and the fields of this data structure must begin with hw_module_t
 * followed by module specific information.
 */
typedef struct hw_module_t {
    /** tag must be initialized to HARDWARE_MODULE_TAG */
    uint32_t tag;

    uint16_t module_api_version;
    
    uint16_t hal_api_version;
#define version_minor hal_api_version

    /** Identifier of module */
    const char *id;

    /** Name of this module */
    const char *name;

    /** Author/owner/implementor of the module */
    const char *author;

    /** Modules methods */
    struct hw_module_methods_t* methods;

    /** module's dso */
    void* dso;

#ifdef __LP64__
    uint64_t reserved[32-7];
#else
    /** padding to 128 bytes, reserved for future use */
    uint32_t reserved[32-7];
#endif
}
  1. 硬件抽象层中的每一个模块都必须自定义一个硬件抽象层模块结构体,而且它的第一个成员变量的类型必须是 hw_moudle_t。
  2. 硬件抽象层的每一个模块都必须存在一个导出符号 HAL_MODULE_INFO_SYM,它指向一个自定义的硬件抽象层模块结构体。
  3. 结构体 hw_moudle_t 的成员变量 tag 值必须设置为
    HARDWARE_MODULE_TAG,用来标识这是一个硬件抽象层模块结构体。
  4. 结构体 hw_moudle_t 的成员变量 dso
    用来保存加载硬件设备层模块后得到的句柄值。我们知道每一个硬件抽象层模块都对应有一个动态链接库文件。加载硬件抽象层模块的过程实际上就是调用dlopen 函数来加载与其对应的动态链接库文件的过程。在调用 dlclose 函数来卸载这个硬件抽象层模块时,需要用到这个句柄值。
  5. hw_module_methods_t 变量定义了硬件抽象层模块的操作方法列表。
typedef struct hw_module_methods_t {
    /** Open a specific device */
    int (*open)(const struct hw_module_t* module, const char* id,
            struct hw_device_t** device);

} hw_module_methods_t;
  1. 结构体 hw_device_t 用来描述一个已经打开的硬件设备。
    typedef struct hw_device_t {
    /** tag must be initialized to HARDWARE_DEVICE_TAG */
    uint32_t tag;

    uint32_t version;

    /** reference to the module this device belongs to */
    struct hw_module_t* module;

    /** padding reserved for future use */
#ifdef __LP64__
    uint64_t reserved[12];
#else
    uint32_t reserved[12];
#endif

    /** Close this device */
    int (*close)(struct hw_device_t* device);

} hw_device_t;


###################################
(1) 硬件抽象层模块中的每一个硬件设备必须自定义一个硬件设备结构体
    而且它的第一个成员变量的类型必须为 hw_device_t
(2) 结构体 hw_device_t 的成员变量 tag 的值必须设置为 HARDWARE_DEVICE_TAG
    用来标识这是一个硬件抽象层中的硬件设备结构体
(3) close 是一个函数指针,用来关闭一个硬件设备

1.2 编写硬件抽象层模块接口

每一个硬件抽象层模块在内核中都对应一个驱动程序,硬件抽象层模块就是通过这些驱动程序来访问硬件设备的,他们通过读写设备文件来进行通信。

硬件抽象层的模块接口源文件一般保存在 harware/libhardware 中,以 freg模块 寄存器操作为例,进行说明,它的目录结构如下:

~ Android/hardware/libhardware
---- include
    ----- hardware
        ---- freg.h
        
---- moudles
    ---- power
        ---- freg.c
        ---- Android.mk

其中 freg.h 和 freg.c 是源文件,Android.mk 是模块的编译脚本文件

—> frag.h

#ifndef ANDROID_INCLUDE_HARDWARE_FRAG_H
#define ANDROID_INCLUDE_HARDWARE_FRAG_H

#include <hardware/hardware.h>

__BEGIN_DECLS

// 硬件模块ID
#define FRAG_HARDWARE_MODULE_ID "freg"

// 硬件设备ID
#define FRAG_HARDWARE_DEVICE_ID "freg"

// 自定义硬件模块结构体
typedef struct freg_moudle_t {
    struct hw_module_t common;
}

// 自定义设备结构体
typedef struct freg_device_t {
    struct hw_device_t common;
    int fd;
    int (*set_val)(struct freg_device_t* dev, int val);
    int (*get_val)(struct freg_device_t* dev, int* val);
}

__END_DECLS

#endif  // ANDROID_INCLUDE_HARDWARE_FRAG_H

这个文件中的常量结构体都是按照硬件抽象层模块编写规范来定义的。

宏 FRAG_HARDWARE_MODULE_ID 描述模块ID
宏 FRAG_HARDWARE_DEVICE_ID 描述设备ID
结构体 freg_moudle_t 描述自定义的模块结构体
结构体 freg_device_t 描述虚拟硬件设备,其中 fd 用来描述打开的文件设备 /dev/frag,成员变量 set_val 和 get_val 是函数指针,用来写和读虚拟硬件设备freg的寄存器地址。
—> frag.c

#define DEVICE_NAME "/dev/frag"
#define DMOUDLE_NAME "frag"
#define MOUDLE_AUTHOR "kevin"

/* 设备打开与关闭接口 */
static int freg_device_open(const struct hw_moudle_t* moudle, const char* id, struct hw_device_t** device);
static int freg_device_open( struct hw_device_t** device);

/* 设备寄存器读写接口 */
static int freg_get_val(struct freg_device_t* dev, int* val);
static int freg_set_val(struct freg_device_t* dev, int val);

/* 定义模块操作方法结构体变量  */
static struct hw_moudle_methonds_t freg_moudle_methods = {
    open: freg_device_open
}

/* 定义模块结构体变量 */
struct freg_module_t HAL_MODULE_INFO_SYM = {
    .common = {
        .tag = HARDWARE_MODULE_TAG,
        .module_api_version = 1,
        .hal_api_version = 1,
        .id = POWER_HARDWARE_MODULE_ID,
        .name = MOUDLE_NAME,
        .author = MOUDLE_AUTHOR,
        .methods = &freg_moudle_methods,
    },

    .init = power_init,
    .setInteractive = power_set_interactive,
    .powerHint = power_hint,
};

在这段代码中,最值得关注的是模块变量 HAL_MODULE_INFO_SYM 的定义,按照硬件抽象层模块编写规范,每一个硬件抽象层模块必须导出一个名称为 HAL_MODULE_INFO_SYM 的符号,它指向一个自定义的硬件抽象层模块结构体。

—> Android.mk

 1. LOCAL_PATH := $(call my-dir)
 2. include $(CLEAR_VARS)
 3. LOCAL_MODULE_TAGS := optional
 4. LOCAL_PROPRIETARY_MODULE := true
 5. LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
 6. LOCAL_SHARED_LIBRARIES := liblog
 7. LOCAL_SRC_FILES := freg.cpp
 8. LOCAL_MODULE := freg.default
 9. include $(BUILD_SHARED_LIBRARY)
  1. 这是硬件抽象层的编译脚本文件,第九行指定将模块编译成一个动态链接库文件。
  2. LOCAL_MODULE_PATH 指定了库保存的路径(8.1: /vendor/lib/hw)。
  3. 将硬件抽象层模块 freg 对应的文件命令为 freg.default,编译成功后在指定的位置成功
    freg.default.so,当我们要加载 freg 抽象层模块 freg 时,只需要指定它的ID值,就能找到对应的 so 文件。

1.3 硬件抽象层模块的加载过程

在 Android 硬件抽象层,负责加载硬件抽象模块的函数时 hw_get_moudle,它的原型如下:

#Android/hardware/libhardware/include/hardware/hardware.h

/**
 * Get the module info associated with a module by id.
 *
 * @return: 0 == success, <0 == error and *module == NULL
 */
int hw_get_module(const char *id, const struct hw_module_t **module);

===================================================
id:输入参数,表示要加载的硬件抽象层模块ID
moudle:输出参数,如果加载成功,它指向一个自定义的硬件抽象层模块结构体

函数返回值等于0代表加载成功,小于0则表示加载失败

简单阐述一下 hw_get_module 的实现过程,代码在 hardware.c 中

  1. 从 variant_keys 中查找对应注册的模块,获取动态链接库路径。
  2. 调用 dlopen 函数将动态连接库加载到内存中,成功则返回
    handler 句柄。
  3. 使用 dlsym 函数获取名称为 HAL_MODULE_INFO_SYM_AS_STR 的符号,这个
    HAL_MODULE_INFO_SYM_AS_STR 符号指向一个自定义的抽象层模块结构体,它包含了模块的所有信息。
  4. HAL_MODULE_INFO_SYM_AS_STR 自定义抽象层模块结构体的第一个成员变量为 hw_moudle_t,将
    hw_moudle_t.id 与所要加载的模块ID做比较,返回结果。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、volley 项目地址 https://github.com/smanikandan14/Volley-demo (1) JSON,图像等的异步下载; (2) 网络请求的排序(scheduling) (3) 网络请求的优先级处理 (4) 缓存 (5) 多级别取消请求 (6) 和Activity和生命周期的联动(Activity结束时同时取消所有网络请求) 2、android-async-http 项目地址:https://github.com/loopj/android-async-http 文档介绍:http://loopj.com/android-async-http/ (1) 在匿名回调中处理请求结果 (2) 在UI线程外进行http请求 (3) 文件断点上传 (4) 智能重试 (5) 默认gzip压缩 (6) 支持解析成Json格式 (7) 可将Cookies持久化到SharedPreferences 3、Afinal框架 项目地址:https://github.com/yangfuhai/afinal 主要有四大模块: (1) 数据库模块:android中的orm框架,使用了线程池对sqlite进行操作。 (2) 注解模块:android中的ioc框架,完全注解方式就可以进行UI绑定和事件绑定。无需findViewById和setClickListener等。 (3) 网络模块:通过httpclient进行封装http数据请求,支持ajax方式加载,支持下载、上传文件功能。 (4) 图片缓存模块:通过FinalBitmap,imageview加载bitmap的时候无需考虑bitmap加载过程中出现的oom和android容器快速滑动时候出现的图片错位等现象。 FinalBitmap可以配置线程加载线程数量,缓存大小,缓存路径,加载显示动画等。FinalBitmap的内存管理使用lru算法, 没有使用弱引用(android2.3以后google已经不建议使用弱引用,android2.3后强行回收软引用和弱引用,详情查看android官方文档), 更好的管理bitmap内存。FinalBitmap可以自定义下载器,用来扩展其他协议显示网络图片,比如ftp等。同时可以自定义bitmap显示器, 在imageview显示图片的时候播放动画等(默认是渐变动画显示)。 4、xUtils框架 项目地址:https://github.com/wyouflf/xUtils 主要有四大模块: (1) 数据库模块:android中的orm框架,一行代码就可以进行增删改查; 支持事务,默认关闭; 可通过注解自定义表名,列名,外键,唯一性约束,NOT NULL约束,CHECK约束等(需要混淆的时候请注解表名和列名); 支持绑定外键,保存实体时外键关联实体自动保存或更新; 自动加载外键关联实体,支持延时加载; 支持链式表达查询,更直观的查询语义,参考下面的介绍或sample中的例子。 (2) 注解模块:android中的ioc框架,完全注解方式就可以进行UI,资源和事件绑定; 新的事件绑定方式,使用混淆工具混淆后仍可正常工作; 目前支持常用的20种事件绑定,参见ViewCommonEventListener类和包com.lidroid.xutils.view.annotation.event。 (3) 网络模块:支持同步,异步方式的请求; 支持大文件上传,上传大文件不会oom; 支持GET,POST,PUT,MOVE,COPY,DELETE,HEAD,OPTIONS,TRACE,CONNECT请求; 下载支持301/302重定向,支持设置是否根据Content-Disposition重命名下载的文件; 返回文本内容的请求(默认只启用了GET请求)支持缓存,可设置默认过期时间和针对当前请求的过期时间。 (4) 图片缓存模块:加载bitmap的时候无需考虑bitmap加载过程中出现的oom和android容器快速滑动时候出现的图片错位等现象; 支持加载网络图片和本地图片; 内存管理使用lru算法,更好的管理bitmap内存; 可配置线程加载线程数量,缓存大小,缓存路径,加载显示动画等... 5、ThinkAndroid 项目地址:https://github.com/white-cat/ThinkAndroid 主要有以下模块: (1) MVC模块:实现视图与模型的分离。 (2) ioc模块:android中的ioc模块,完全注解方式就可以进行UI绑定、res中的资源的读取、以及对象的初始化。 (3) 数据库模块:android中的orm框架,使用了线程池对sqlite进行操作。 (4) http模块:通过httpclient进行封装http数据请求,支持异步及同步方式加载。 (5) 缓存模块:通过简单的配置及设计可以很好的实现缓存,对缓存可以随意的配置 (6) 图片缓存模块:imageview加载图片的时候无需考虑图片加载过程中出现的oom和android容器快速滑动时候出现的图片错位等现象。 (7) 配置器模块:可以对简易的实现配对配置的操作,目前配置文件可以支持Preference、Properties对配置进行存取。 (8) 日志打印模块:可以较快的轻易的是实现日志打印,支持日志打印的扩展,目前支持对sdcard写入本地打印、以及控制台打印 (9) 下载器模块:可以简单的实现多线程下载、后台下载、断点续传、对下载进行控制、如开始、暂停、删除等等。 (10) 网络状态检测模块:当网络状态改变时,对其进行检 6、LoonAndroid 项目地址:https://github.com/gdpancheng/LoonAndroid 主要有以下模块: (1) 自动注入框架(只需要继承框架内的application既可) (2) 图片加载框架(多重缓存,自动回收,最大限度保证内存的安全性) (3) 网络请求模块(继承了基本上现在所有的http请求) (4) eventbus(集成一个开源的框架) (5) 验证框架(集成开源框架) (6) json解析(支持解析成集合或者对象) (7) 数据库(不知道是哪位写的 忘记了) (8) 多线程断点下载(自动判断是否支持多线程,判断是否是重定向) (9) 自动更新模块 (10) 一系列工具类

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值