1 第一步:安装软件。
安装客户端
sudo apt-get install subversion
安装服务器端
sudo apt-get install libapache2-svn
2 svn的基本操作
(1)从服务器上下载代码:svn checkout
举例:
svn checkout svn://192.168.6.10/project/Source_code/trunk/src
svn checkout可以所写成svn co
(2)添加新的文件或者文件夹到本地版本控制中
svn add 文件(夹)
如果指定的是一个文件夹,则会将文件夹的所有内容都添加进来,如果你只想要添加文件夹而不是文件夹里面的内容,则用如下参数
svn add --non-recursive 目录名
(3)提交本地更改到服务器
svn commit -m "说明信息" [-N] [--no-unlock] [文件(夹)]
文件(夹)不填写则代码提交当前目录下(包含子目录)的所有更改
举例:
svn commit -m "modify some code"
(4)显示本地修改状态
svn status [path]缩写成svn st [path]
path为空则代码显示当前目录下的所有修改文件(递归到子目录)的状态,状态显示如下:
? 不在svn控制中
M 内容被修改
C 发生冲突
A 预定加入到版本库中
K 被锁定
举例:svn st
(5)显示指定目录下所有文件(递归到子目录)的状态
svn status -v [path] 缩写成svn st -v [path]
(6)同步服务器代码到本地仓库
svn up
(7)显示指定目录下的文件和目录
svn list [path]缩写成svn ls [path]
(8)恢复本地修改(撤销指定目录下的未提交的所有修改)
svn revert path [--depth infinity]
(9)删除文件(夹)
svn delete 文件(夹)
3 svn的配置文件
修改/root/.subversion目录下的config文件。
比如说修改svn所控制的文件类型,则可以修改config文件中的global-ignores参数,这个参数是指定了svn版本控制忽略的
文件类型,举例如下:
global-ignores = *.o *.lo *.la *.al .[0-9]* *.a *.pyc *.pyo
android系统开发(六)-HAL层开发基础
Android HAL层,即硬件抽象层,是Google响应厂家“希望不公开源码”的要求推出的新概念
1,源代码和目标位置
源代码: /hardware/libhardware目录,该目录的目录结构如下:
/hardware/libhardware/hardware.c编译成libhardware.so,目标位置为/system/lib目录
/hardware/libhardware/include/hardware目录下包含如下头文件:
hardware.h 通用硬件模块头文件
copybit.h copybit模块头文件
gralloc.h gralloc模块头文件
lights.h 背光模块头文件
overlay.h overlay模块头文件
qemud.h qemud模块头文件
sensors.h 传感器模块头文件
/hardware/libhardware/modules目录下定义了很多硬件模块
这些硬件模块都编译成xxx.xxx.so,目标位置为/system/lib/hw目录
2,HAL层的实现方式
JNI->通用硬件模块->硬件模块->内核驱动接口
具体一点:JNI->libhardware.so->xxx.xxx.so->kernel
具体来说:android frameworks中JNI调用/hardware/libhardware/hardware.c中定义的hw_get_module函数来获取硬件模块,
然后调用硬件模块中的方法,硬件模块中的方法直接调用内核接口完成相关功能
3,通用硬件模块(libhardware.so)
(1)头文件为:/hardware/libhardware/include/hardware/hardware.h
头文件中主要定义了通用硬件模块结构体hw_module_t,声明了JNI调用的接口函数hw_get_module
hw_module_t定义如下:
typedef struct hw_module_t {
/** tag must be initialized to HARDWARE_MODULE_TAG */
uint32_t tag;
/** major version number for the module */
uint16_t version_major;
/** minor version number of the module */
uint16_t version_minor;
/** 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;
/** padding to 128 bytes, reserved for future use */
uint32_t reserved[32-7];
} hw_module_t;
硬件模块方法结构体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;
只定义了一个open方法,其中调用的设备结构体参数hw_device_t定义如下:
typedef struct hw_device_t {
/** tag must be initialized to HARDWARE_DEVICE_TAG */
uint32_t tag;
/** version number for hw_device_t */
uint32_t version;
/** reference to the module this device belongs to */
struct hw_module_t* module;
/** padding reserved for future use */
uint32_t reserved[12];
/** Close this device */
int (*close)(struct hw_device_t* device);
} hw_device_t;
hw_get_module函数声明如下:
int hw_get_module(const char *id, const struct hw_module_t **module);
参数id为模块标识,定义在/hardware/libhardware/include/hardware目录下的硬件模块头文件中,
参数module是硬件模块地址,定义了/hardware/libhardware/include/hardware/hardware.h中
(2)hardware.c中主要是定义了hw_get_module函数如下:
#define HAL_LIBRARY_PATH "/system/lib/hw"
static const char *variant_keys[] = {
"ro.hardware",
"ro.product.board",
"ro.board.platform",
"ro.arch"
};
static const int HAL_VARIANT_KEYS_COUNT =
(sizeof(variant_keys)/sizeof(variant_keys[0]));
int hw_get_module(const char *id, const struct hw_module_t **module)
{
int status;
int i;
const struct hw_module_t *hmi = NULL;
char prop[PATH_MAX];
char path[PATH_MAX];
for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++)
{
if (i < HAL_VARIANT_KEYS_COUNT)
{
if (property_get(variant_keys[i], prop, NULL) == 0)
{
continue;
}
snprintf(path, sizeof(path), "%s/%s.%s.so",
HAL_LIBRARY_PATH, id, prop);
}
else
{
snprintf(path, sizeof(path), "%s/%s.default.so",
HAL_LIBRARY_PATH, id);
}
if (access(path, R_OK))
{
continue;
}
/* we found a library matching this id/variant */
break;
}
status = -ENOENT;
if (i < HAL_VARIANT_KEYS_COUNT+1) {
/* load the module, if this fails, we're doomed, and we should not try
* to load a different variant. */
status = load(id, path, module);
}
return status;
}
从源代码我们可以看出,hw_get_module完成的主要工作是根据模块id寻找硬件模块动态连接库地址,然后调用load函数去打开动态连接库
并从动态链接库中获取硬件模块结构体地址。硬件模块路径格式如下:
HAL_LIBRARY_PATH/id.prop.so
HAL_LIBRARY_PATH定义为/system/lib/hw
id是hw_get_module函数的第一个参数所传入,prop部分首先按照variant_keys数组中的名称逐一调用property_get获取对应的系统属性,
然后访问HAL_LIBRARY_PATH/id.prop.so,如果找到能访问的就结束,否则就访问HAL_LIBRARY_PATH/id.default.so
举例如下:
假定访问的是背光模块,id定义为"lights"则系统会按照如下的顺序去访问文件:
/system/lib/hw/lights.[ro.hardware属性值].so
/system/lib/hw/lights.[ro.product.board属性值].so
/system/lib/hw/lights.[ro.board.platform属性值].so
/system/lib/hw/lights.[ro.arch属性值].so
/system/lib/hw/lights.default.so
所以开发硬件模块的时候Makefile文件(Android.mk)中模块的命名LOCAL_MODULE要参考上面的内容,否则就会访问不到没作用了。
load函数的关键部分代码如下:
handle = dlopen(path, RTLD_NOW); //打开动态链接库
if (handle == NULL) {
char const *err_str = dlerror();
LOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");
status = -EINVAL;
goto done;
}
const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
hmi = (struct hw_module_t *)dlsym(handle, sym); //从动态链接库中获取硬件模块结构体的指针
if (hmi == NULL) {
LOGE("load: couldn't find symbol %s", sym);
status = -EINVAL;
goto done;
}
HAL_MODULE_INFO_SYM_AS_STR是硬件模块在动态链接库中的标志,定义在hardware.h中如下:
#define HAL_MODULE_INFO_SYM HMI
#define HAL_MODULE_INFO_SYM_AS_STR "HMI"
4,硬件模块
硬件模块的开发主要是完成/hardware/libhardware/include/hardware目录下对应的头文件中的内容,主要是硬件模块头文件和hardware.h中
的结构体中定义了一些函数指针,调用内核提供的接口将具体的函数实现,然后编译成指定名称的动态链接库放到/system/lib/hw目录下即可。
用一句话来概括:硬件模块的开发就是定义一个hardware.h中定义的hw_module_t结构体,结构体名称为宏HAL_MODULE_INFO_SYM,然后实现结构体
的相关内容即可。
5,内核驱动
主要是要向用户层开放接口,让硬件模块和内核可以交互。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/jiajie961/archive/2010/11/22/6026585.aspx
1,总论
背光模块属于HAL层开发,HAL层开发,用一句话来概括就是定义一个hardware.h中定义的名称为宏HAL_MODULE_INFO_SYM的hw_module_t结构体,
然后实现结构体的相关内容
2,驱动方面的准备
简单的嵌入式linux驱动,编写LCD背光驱动,并提供接口给上层修改,我所用的是直接修改接口文件,接口如下:
/sys/class/backlight/pwm-backlight/brightness 这个是亮度调节
/sys/class/backlight/pwm-backlight/max_brightness 这个是最大亮度,按照android系统的要求应该设置成255
控制亮度直接写brightness文件即可
背光驱动主要是通过PWM来完成,这里不详细说明。
3,需要包含的头文件
/hardware/libhardware/include/hardware目录下的hardware.h和lights.h
其中hardware.h中定义了通用硬件模块,lights.h中定义了背光设备相关的内容
4,android已有的硬件模块在/hardware/libhardware/modules目录下,为了区分,我们开发的背光模块放置在如下的目录:
vendor/ardent/merlin/lights目录下,编译成lights.default.so放置到/system/lib/hw目录下,模块命名规则可以
参考上一节的内容。
5,修改vendor/ardent/merlin目录下AndroidBoard.mk文件,添加如下内容:
include $(LOCAL_PATH)/lights/Mdroid.mk
6,lights目录新建Mdroid.mk文件,内容如下:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SRC_FILES:= lights.c
LOCAL_SHARED_LIBRARIES := \
libutils \
libcutils \
libhardware
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := lights.default
include $(BUILD_SHARED_LIBRARY)
7,lights目录下新建一个lights.c文件,如下:
const struct hw_module_t HAL_MODULE_INFO_SYM = {
.tag = HARDWARE_MODULE_TAG,
.version_major = 1,
.version_minor = 0,
.id = LIGHTS_HARDWARE_MODULE_ID,
.name = "lights module",
.author = "allen",
.methods = NULL,
};
8,上面的内容可以直接编译通过,但是因为我将其methods部分指向了空指针,因此没有任何功能,下面来实现此部分
hw_module_t机构体的methods成员是一个指向hw_module_methods_t结构体的一个指针,hw_module_methods_t结构体定义如下:
typedef struct hw_module_methods_t {
int (*open)(const struct hw_module_t* module, const char* id,struct hw_device_t** device);
} hw_module_methods_t;
据此我们定义一个hw_module_methods_t类型的参数lights_module_methods如下:
struct hw_module_methods_t lights_module_methods = {
.open = lights_device_open
};
然后将上面的methods由NULL改成lights_module_methods
9,接下来就是定义lights_device_open函数了,此函数的参数和返回值由hw_module_methods_t结构体的open成员决定,此函数定义如下:
static int lights_device_open(const struct hw_module_t *module,const char *id, struct hw_device_t **device)
从lights_device_open函数的参数来看,第一个参数和第二个参数是常量,第三个参数是 一个指向hw_device_t结构体的指针,因此可以断定
实现此函数也就是要完成第三个参数的内容,详细的内容我们可以参考直接调用该函数的内容,在frameworks/base/services/jni目录下的
com_android_server_LightsService.cpp文件中,内容如下:
static light_device_t* get_device(hw_module_t* module, char const* name)
{
int err;
hw_device_t* device;
err = module->methods->open(module, name, &device);
if (err == 0) {
return (light_device_t*)device;//device由hw_device_t指针强制转换成light_device_t指针
} else {
return NULL;
}
}
static jint init_native(JNIEnv *env, jobject clazz)
{
int err;
hw_module_t* module;
Devices* devices;
devices = (Devices*)malloc(sizeof(Devices));
err = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
if (err == 0) {
devices->lights[LIGHT_INDEX_BACKLIGHT]
= get_device(module, LIGHT_ID_BACKLIGHT);
devices->lights[LIGHT_INDEX_KEYBOARD]
= get_device(module, LIGHT_ID_KEYBOARD);
devices->lights[LIGHT_INDEX_BUTTONS]
= get_device(module, LIGHT_ID_BUTTONS);
devices->lights[LIGHT_INDEX_BATTERY]
= get_device(module, LIGHT_ID_BATTERY);
devices->lights[LIGHT_INDEX_NOTIFICATIONS]
= get_device(module, LIGHT_ID_NOTIFICATIONS);
devices->lights[LIGHT_INDEX_ATTENTION]
= get_device(module, LIGHT_ID_ATTENTION);
devices->lights[LIGHT_INDEX_BLUETOOTH]
= get_device(module, LIGHT_ID_BLUETOOTH);
devices->lights[LIGHT_INDEX_WIFI]
= get_device(module, LIGHT_ID_WIFI);
} else {
memset(devices, 0, sizeof(Devices));
}
return (jint)devices;
}
从上面的内容我们可以看出lights_device_open的第一个参数是JNI层用hw_get_module所获得,第二个参数根据设备的不同有很多种情况
该参数的内容定义在lights.h中,全部情况如下:
#define LIGHT_ID_BACKLIGHT "backlight"
#define LIGHT_ID_KEYBOARD "keyboard"
#define LIGHT_ID_BUTTONS "buttons"
#define LIGHT_ID_BATTERY "battery"
#define LIGHT_ID_NOTIFICATIONS "notifications"
#define LIGHT_ID_ATTENTION "attention"
#define LIGHT_ID_BLUETOOTH "bluetooth"
#define LIGHT_ID_WIFI "wifi"
lights调节有背光,键盘,按键,电池,通知,提醒,蓝牙和WIF
第三个参数是一个指向一个hw_device_t的指针,但是com_android_server_LightsService.cpp文件中的背光调节函数定义如下:
static void setLight_native(JNIEnv *env, jobject clazz, int ptr,
int light, int colorARGB, int flashMode, int onMS, int offMS, int brightnessMode)
{
Devices* devices = (Devices*)ptr;
light_state_t state;
if (light < 0 || light >= LIGHT_COUNT || devices->lights[light] == NULL) {
return ;
}
memset(&state, 0, sizeof(light_state_t));
state.color = colorARGB;
state.flashMode = flashMode;
state.flashOnMS = onMS;
state.flashOffMS = offMS;
state.brightnessMode = brightnessMode;
devices->lights[light]->set_light(devices->lights[light], &state);
}
get_device函数中将hw_device_t指针强制转换成light_device_t指针给调节背光用,而light_device_t定义如下:
struct light_device_t {
struct hw_device_t common;
int (*set_light)(struct light_device_t* dev,
struct light_state_t const* state);
};
因此在实现lights_device_open的第三个参数的时候,我们应该定义一个light_device_t类型结构体,然后
将起common域的指针地址传递过去。这样虽然传递的是一个hw_device_t指针地址,但是JNI层可以将其强制转换
成light_device_t指针地址用,否则devices->lights[light]->set_light就会起不到作用了。实现如下:
static int lights_device_open(const struct hw_module_t *module,const char *id, struct hw_device_t **device)
{
struct light_device_t *dev = NULL;
int resvalue = -1;
dev = calloc(sizeof(struct light_device_t),1);
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = 0;
dev->common.module = (struct hw_module_t *)module;
dev->common.close = lights_device_close;
if(!strcmp(id, LIGHT_ID_BACKLIGHT))
{
dev->set_light = lcd_set_light;
resvalue = 0;
}
else
{
dev->set_light = other_set_light;
resvalue = 0;
}
*device = &dev->common;
return resvalue;
}
10,实现lights_device_close,lcd_set_light和other_set_light,这个主要是调用驱动提供的接口直接控制硬件,举例如下:
static int lights_device_close(struct hw_device_t* device)
{
struct light_device_t *m_device = (struct light_device_t *)device;
if(m_device)
free(m_device);
return 0;
}
static int lcd_set_light(struct light_device_t* dev,struct light_state_t const* state)
{
int fd = -1;
int bytes = 0;
int rlt = -1;
unsigned char brightness = ((77*((state->color>>16)&0x00ff))
+ (150*((state->color>>8)&0x00ff))
+ (29*(state->color&0x00ff))) >> 8;
fd = open("/sys/class/backlight/pwm-backlight/brightness", O_RDWR);
if(fd>0)
{
char buffer[20];
memset(buffer, 0, 20);
bytes = sprintf(buffer, "%d", brightness);
rlt = write(fd, buffer, bytes);
if(rlt>0)
{
close(fd);
return 0;
}
}
close(fd);
return -1;
}
static int other_set_light(struct light_device_t* dev,struct light_state_t const* state)
{
return 0;
}
11,因为上面调节背光是通过写/sys/class/backlight/pwm-backlight/brightness文件来完成,因此一定要设置该文件的权限,
在init.xxx.rc文件中添加如下的内容:
# for control LCD backlight
chown system system /sys/class/backlight/pwm-backlight/brightness
chmod 0666 /sys/class/backlight/pwm-backlight/brightness
12,修改完成后经验证亮度调节可用,上面的例子只是实现了lights部分功能,如果需要完成所有的功能,请参考hardware.h, lights.h和com_android_server_LightsService.cpp文件中的内容。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/jiajie961/archive/2010/11/23/6030405.aspx
关于android系统开发sdcard移植,主要有如下工作:
1,内核驱动开发,完成后每次插入和拔出sdcard系统都会有相关的信息显示,而且sdcard可以手动挂载。
2,android的sdcard挂载主要是vold来完成,vold的源代码在/system/vold目录下,编译成/system/bin/vold
init.rc文件中有vold系统服务,确保android系统开机后vold有正常运行。
3,添加vold的配置文件,先查看/system/bin/vold/main.cpp文件中的process_config函数,发现配置文件路径如下:
/etc/vold.fstab
android2.2下/etc目录指向了/system/etc目录,因此我们要新建一个vold.fstab文件,目标路径为/system/etc/vold.fstab
4,vold.fstab文件的写法,参考/system/core/rootdir/etc目录下的vold.fstab,里面有详细的说明和例子,写法如下:
dev_mount <label> <mount_point> <part> <sysfs_path1...>
dev_mount命令 标签 挂载点 子分区 设备在sysfs文件系统下的路径(可多个)
按照上面的要求和我的平台的实际情况,在vold.fstab中添加如下内容:
dev_mount sdcard /mnt/sdcard auto /block/mmcblk0
上面的/block/mmcblk0表示sysfs下的路径,由于linux的sysfs文件系统是在sys目录下,所以对应到/sys/block/mmcblk0目录
5,完成后发现android系统中sdcard可用了,总结下载,sdcard部分很简单,主要是找到sdcard设备对应的sysfs文件系统路径
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/jiajie961/archive/2010/11/25/6035369.aspx
1,audio内核部分的开发,包含codec驱动,cpu的声音驱动和内核alsa驱动等,
这个是完全的嵌入式linux的开发内容,这里跳过,请确保这几部分正确。
2,从alsa的官方网站下载最新的alsa-lib-1.0.23和alsa-utils-1.0.23
官方网站:http://www.alsa-project.org
alsa-lib基于内核alsa驱动,它将对内核alsa接口的操作封装成libasound库
alsa-utils是一个工具包,基于alsa-lib来控制底层alsa驱动,包含aplay/amixer/control等工具
alsa的系统架构如下:
alsa应用
|
alsa-utils
|
alsa-lib
|
alsa-driver
alsa-driver已经集成在linux内核中,alsa应用直接调用alsa-utils工具包的工具来控制底层驱动以操作声卡
3,在vendor/ardent/merlin目录下新建一个alsa目录,然后将下载的alsa-lib-1.0.23和alsa-utils-1.0.23
解压缩到alsa目录下,将解压缩后的文件夹去掉版本号改成alsa-lib和alsa-utils
4,在vendor/ardent/merlin/AndroidBoard.mk文件中加入如下内容:
L_PATH := $(LOCAL_PATH)
include $(L_PATH)/alsa/Mdroid.mk
5,在vendor/ardent/merlin/alsa目录下新建Mdroid.mk文件,内容如下:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
ALSA_PATH := $(LOCAL_PATH)
include $(ALSA_PATH)/alsa-lib/Mdroid.mk
include $(ALSA_PATH)/alsa-utils/Mdroid.mk
6,在vendor/ardent/merlin/alsa/alsa-lib目录下新建Mdroid.mk文件,内容如下:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
include $(LOCAL_PATH)/src/Mdroid.mk
7,在vendor/ardent/merlin/alsa/alsa-lib/src目录下新建Mdroid.mk文件,内容在文章后面。
注:alsa-lib中编译的内容很多,我们可以先将alsa-lib当成普通的linux库来编译,编译完成后通过查找lo文件的方法
看那些文件被编译到了,同而找到需要编译的c文件,通过make install到指定目录找到需要复制的库和其它文件。代码中
的很多部分是不需要用到了,目前暂时未作详细处理,alsa-lib/modules/mixer/simple目录下的内容编译成了另外的几个
动态库(smixer-ac97,smixer-hda.so,smixer-sbase.so),alsa-lib/aserver目录下的内容编译成aserver,
这两部分因为不会用到,所以未加入到android编译系统中。
8,找个目录将alsa-lib当成普通的linux库编译一次,在include目录下会生成config.h文件,将该文件复制到
vendor/ardent/merlin/alsa/alsa-lib/include目录下并修改config.h的部分内容如下:
#define ALOAD_DEVICE_DIRECTORY "/dev/snd"
#define ALSA_CONFIG_DIR "/etc"
#define ALSA_DEVICE_DIRECTORY "/dev/snd/"
//#define HAVE_WORDEXP_H 1
//#define VERSIONED_SYMBOLS
9,修改alsa-lib/include/global.h文件,删除如下内容:
#if !defined(_POSIX_C_SOURCE) && !defined(_POSIX_SOURCE)
struct timeval {
time_t tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
struct timespec {
time_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
#endif
10,将源代码中所有的
#include <sys/shm.h>
改成
#include <linux/shm.h>
类似
#include <sys/sem.h>
改成
#include <linux/sem.h>
11,修改alsa-lib/src/alisp/alisp.c,在obj_type_str函数最后面位置加上如下内容:
return NULL;
12,将alsa-lib当普通linux库编译时alsa-lib/src/control目录下生成的ctl_symbols_list.c文件和
alsa-lib/src/pcm目录下生成的pcm_symbols_list.c文件复制到android中alsa-lib对应位置。
13,修改alsa-lib/src/pcm/pcm_direct.c文件,删除如下内容:
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO (Linux specific) */
};
14,查找alsa-lib源代码所有文件,确保
#include <linux/shm.h>的前面有
#include <stdlib.h>
没有的自己加上,否则会报告错误说size_t未定义
15,修改alsa-lib/src/pcm/pcm_ladspa.c文件,将
*strrchr (labellocale, '.') = *lc->decimal_point;
改成
*strrchr (labellocale, '.') = ".";
屏蔽掉如下内容:
//lc = localeconv ();
这个是因为android用的C库是bionic,和标准C库不同,对应的locale.h文件中的lconv结构体定义不同所导致。
16,修改alsa-lib/src/pcm/pcm_mmap.c文件中的snd_pcm_mmap函数,将switch (i->type)语句下SND_PCM_AREA_SHM分支的内容
屏蔽掉,同时修改该文件中snd_pcm_munmap函数,将switch (i->type)语句下的SND_PCM_AREA_SHM分支内容屏蔽掉。
17,搜索alsa-lib/src目录下的所有文件,搜索shmctl,shmget,shmat,shmdt等4个函数的调用处,将调用到的地方删除。
这个主要是因为android的bionic libc库不支持System V IPC所导致,具体的可以从头文件中看出来。System V IPC通过共享
内存的方式来实现,GNU C库对应共享内存头文件为linux pc的/usr/include/sys/shm.h文件,在此文件中,你可以看到
shmctl,shmget,shmat,shmdt等4个函数的声明,bionic libc库也有一个同样的头文件,在android源代码目录的
bionic/libc/kernel/common/linux目录下,但是文件中的内容却没有上面4个函数的声明。上面16所作的修改也是基于这个原因。
18,按照16和17的结论,由于bionic libc所引发的System V IPC功能的缺失,导致alsa库中的相关功能不能正常实现,所以最好的
方法是将相关的部分不编译进来,以免找成不必要的错误。据此将一些文件从编译中删除,修改alsa-lib/src/Mdroid.mk文件即可
alsa-lib/src/control/control_shm.c
alsa-lib/src/pcm/pcm_direct.c
alsa-lib/src/pcm/pcm_dmix.c
alsa-lib/src/pcm/pcm_dshare.c
alsa-lib/src/pcm/pcm_dsnoop.c
alsa-lib/src/pcm/pcm_ladspa.c
alsa-lib/src/pcm/pcm_shm.c
alsa-lib/src/shmarea.c
删除了这几个模块后要将alsa-lib/src/control目录下的ctl_symbols_list.c文件和
alsa-lib/src/pcm目录下的pcm_symbols_list.c文件中的相关内容删除,否则会编译不过。
19,最后要实现的功能当然是复制alsa-lib的配置文件了,在alsa-lib/src/conf目录下,复制操作在alsa-lib/src/Mdroid.mk中实现,
最终的Mdroid.mk文件内容如下:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
async.c conf.c confmisc.c dlmisc.c error.c input.c \
names.c output.c socket.c userfile.c \
alisp/alisp.c \
control/cards.c control/control.c control/control_ext.c \
control/control_hw.c control/control_symbols.c \
control/hcontrol.c control/namehint.c control/setup.c control/tlv.c \
hwdep/hwdep.c hwdep/hwdep_hw.c hwdep/hwdep_symbols.c \
mixer/bag.c mixer/mixer.c mixer/simple.c mixer/simple_abst.c mixer/simple_none.c \
pcm/atomic.c pcm/interval.c pcm/mask.c pcm/pcm.c pcm/pcm_adpcm.c \
pcm/pcm_alaw.c pcm/pcm_asym.c pcm/pcm_copy.c pcm/pcm_empty.c \
pcm/pcm_extplug.c pcm/pcm_file.c pcm/pcm_generic.c pcm/pcm_hooks.c \
pcm/pcm_hw.c pcm/pcm_iec958.c pcm/pcm_ioplug.c \
pcm/pcm_lfloat.c pcm/pcm_linear.c pcm/pcm_meter.c pcm/pcm_misc.c \
pcm/pcm_mmap.c pcm/pcm_mmap_emul.c pcm/pcm_mulaw.c pcm/pcm_multi.c \
pcm/pcm_null.c pcm/pcm_params.c pcm/pcm_plug.c pcm/pcm_plugin.c \
pcm/pcm_rate.c pcm/pcm_rate_linear.c pcm/pcm_route.c pcm/pcm_share.c \
pcm/pcm_simple.c pcm/pcm_softvol.c pcm/pcm_symbols.c \
rawmidi/rawmidi.c rawmidi/rawmidi_hw.c rawmidi/rawmidi_symbols.c \
rawmidi/rawmidi_virt.c \
seq/seq.c seq/seq_event.c seq/seq_hw.c seq/seqmid.c \
seq/seq_midi_event.c seq/seq_old.c seq/seq_symbols.c \
timer/timer.c timer/timer_hw.c timer/timer_query.c \
timer/timer_query_hw.c timer/timer_symbols.c
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/../include
LOCAL_SHARED_LIBRARIES := libdl
LOCAL_ARM_MODE := arm
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := libasound
include $(BUILD_SHARED_LIBRARY)
TARGET_ALSA_CONF_DIR := $(TARGET_OUT)/usr/share/alsa
LOCAL_ALSA_CONF_DIR := $(LOCAL_PATH)/conf
copy_from := \
alsa.conf \
pcm/dsnoop.conf \
pcm/modem.conf \
pcm/dpl.conf \
pcm/default.conf \
pcm/surround51.conf \
pcm/surround41.conf \
pcm/surround50.conf \
pcm/dmix.conf \
pcm/center_lfe.conf \
pcm/surround40.conf \
pcm/side.conf \
pcm/iec958.conf \
pcm/rear.conf \
pcm/surround71.conf \
pcm/front.conf \
cards/aliases.conf
copy_to := $(addprefix $(TARGET_ALSA_CONF_DIR)/,$(copy_from))
copy_from := $(addprefix $(LOCAL_ALSA_CONF_DIR)/,$(copy_from))
$(copy_to) : $(TARGET_ALSA_CONF_DIR)/% : $(LOCAL_ALSA_CONF_DIR)/% | $(ACP)
$(transform-prebuilt-to-target)
ALL_PREBUILT += $(copy_to)
20,alsa-utils的移植方法也类似,这里就不再介绍,上面的过程只是体验了一下android下开源库的移植方法,
实际上google服务器上已经有alsa的代码,直接下载下载便可用,下载方法如下:
git clone git://android.git.kernel.org/platform/external/alsa-lib.git
git clone git://android.git.kernel.org/platform/external/alsa-utils.git
将下载的alsa-lib和alsa-utils部分复制到vendor/ardent/merlin/alsa目录下参考上面的方法只需对以上
的4和5部分稍作修改即可。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/jiajie961/archive/2010/11/30/6045507.aspx
android系统开发移植alsa-lib库的过程中编译的时候出现了如下的错误:
错误1
/tmp/cckyaR40.s: Assembler messages:
/tmp/cckyaR40.s:2763: Error: selected processor does not support `mrs ip,cpsr'
/tmp/cckyaR40.s:2764: Error: unshifted register required -- `orr r2,ip,#128'
/tmp/cckyaR40.s:2765: Error: selected processor does not support `msr cpsr_c,r2'
/tmp/cckyaR40.s:2777: Error: selected processor does not support `msr cpsr_c,ip'
/tmp/cckyaR40.s:2945: Error: selected processor does not support `mrs r3,cpsr'
/tmp/cckyaR40.s:2946: Error: unshifted register required -- `orr r2,r3,#128'
/tmp/cckyaR40.s:2947: Error: selected processor does not support `msr cpsr_c,r2'
/tmp/cckyaR40.s:2959: Error: selected processor does not support `msr cpsr_c,r3'
/tmp/cckyaR40.s:3551: Error: selected processor does not support `mrs ip,cpsr'
/tmp/cckyaR40.s:3552: Error: unshifted register required -- `orr r1,ip,#128'
/tmp/cckyaR40.s:3553: Error: selected processor does not support `msr cpsr_c,r1'
/tmp/cckyaR40.s:3564: Error: selected processor does not support `msr cpsr_c,ip'
字面的意思报的是汇编错误,选择的处理器不支持mrs和msr指令。
原来的ARM指令有32位和16位两种指令模式,16位为thumb指令集,thumb指令集编译出的代码占用空间小,
而且效率也高,所以android的arm编译器默认用的是thumb模式编译,问题在于alsa的代码中有部分的内容
用到了32位的指令,所以才会报如下的错误,修改的方法也很简单,在Android.mk中加入如下内容即可:
LOCAL_ARM_MODE := arm
android的编译系统中LOCAL_ARM_MODE变量的取值为arm或者thumb,代表32位和16位两种arm指令集,
默认为thumb
错误2
target SharedLib: libasound (out/target/product/merlin/obj/SHARED_LIBRARIES/libasound_intermediates/LINKED/libasound.so)
/work/android-froyo-r3/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/../lib/gcc/arm-eabi/4.4.0/../../../../arm-eabi/bin/ld: out/target/product/merlin/obj/SHARED_LIBRARIES/libasound_intermediates/LINKED/libasound.so: version node not found for symbol snd_pcm_sw_params_get_start_threshold@ALSA_0.9
/work/android-froyo-r3/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/../lib/gcc/arm-eabi/4.4.0/../../../../arm-eabi/bin/ld: failed to set dynamic section sizes: Bad value
collect2: ld returned 1 exit status
make: *** [out/target/product/merlin/obj/SHARED_LIBRARIES/libasound_intermediates/LINKED/libasound.so] 错误 1
解决此问题将alsa-lib/include/config.h文件中的如下宏定义去掉即可:
#define VERSIONED_SYMBOLS
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/jiajie961/archive/2010/11/30/6045513.aspx
1,移植基础:
(1)内核声音驱动和alsa驱动
(2)alsa-lib和alsa-utils库移植
这两部分上一节已经介绍过了。
2,android的audio最核心的部分是audioflinger,audioflinger向上处理来自于应用程序的声音相关的所有请求
向下通过AudioHardwareInterface访问硬件,android的audio架构如下所示:
Applications
|
Frameworks
|
JNI
|
AudioFlinger
|
AudioHardwareInterface
| | |
专有audio库 | alsa用户库
| |
/dev/eac /dev/snd/*
| |
内核eac驱动 内核alsa驱动
AudioHardwareInterface是audioflinger和硬件驱动之间的桥梁,android默认编译的是generic audio,此时
AudioHardwareInterface直接指向了/dev/eac驱动,它通过eac驱动来操作声卡,android audio移植就是要让
AudioHardwareInterface直接或者间接指向我们自己定义的声音驱动,一般都采用alsa声音体系,所以我们的目的就是
要让AudioHardwareInterface指向alsa用户库。下面的内容开始移植alsa-audio
3,修改vendor/ardent/merlin/BoardConfig.mk文件内容如下:
BOARD_USES_GENERIC_AUDIO := false
BOARD_USES_ALSA_AUDIO := true
BUILD_WITH_ALSA_UTILS := true
上面配置的目的就是为了让要让AudioHardwareInterface指向alsa用户库
4,下面来添加audio库的编译
在vendor/ardent/merlin目录下新建一个libaudio目录,修改AndroidBoard.mk文件,添加编译路径如下:
LOCAL_PATH := $(call my-dir)
L_PATH := $(LOCAL_PATH)
include $(L_PATH)/libaudio/Mdroid.mk
5,vendor/ardent/merlin/libaudio目录下新建一个Mdroid.mk文件,内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libaudio
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libmedia \
libhardware
LOCAL_SRC_FILES += AudioHardwareMerlin.cpp
LOCAL_CFLAGS +=
LOCAL_C_INCLUDES +=
LOCAL_STATIC_LIBRARIES += libaudiointerface
include $(BUILD_SHARED_LIBRARY)
6,android audio的实现方法,我们现看看接口部分,上面有说道audioflinger是通过AudioHardwareInterface指向驱动的
AudioHardwareInterface类的代码在frameworks/base/libs/audioflinger/AudioHardwareInterface.cpp文件中
该文件中的create函数中定义了AudioHardwareInterface指向驱动的代码如下:
AudioHardwareInterface* hw = 0;
char value[PROPERTY_VALUE_MAX];
#ifdef GENERIC_AUDIO
hw = new AudioHardwareGeneric();
#else
// if running in emulation - use the emulator driver
if (property_get("ro.kernel.qemu", value, 0)) {
LOGD("Running in emulation - using generic audio driver");
hw = new AudioHardwareGeneric();
}
else {
LOGV("Creating Vendor Specific AudioHardware");
hw = createAudioHardware();
}
#endif
return hw;
当系统为generic audio的时候此函数返回的是一个指向AudioHardwareGeneric对象的指针,其实是返回一个指向AudioHardwareInterface对象
的指针,因为AudioHardwareGeneric是AudioHardwareInterface的子类,继承关系如下:
AudioHardwareInterface->AudioHardwareBase->AudioHardwareGeneric
如果系统不是generic audio,则通过调用createAudioHardware函数来返回一个指向一个指向AudioHardwareInterface对象的指针,
所以,简单的将,我们要做的事情就是实现这个函数以及它相关的内容即可。createAudioHardware函数我们可以在
hardware/libhardware_legacy/include/hardware_legacy/AudioHardwareInterface.h中也就是AudioHardwareInterface
的声明中找到原型如下:
extern "C" AudioHardwareInterface* createAudioHardware(void);
7,通过6我们不难知道,我们实现自己的audio接口完全可以模仿generic audio的做法,只是要多实现一个createAudioHardware函数而已,
因此我们将frameworks/base/libs/audioflinger/AudioHardwareInterface.h文件复制到
vendor/ardent/merlin/libaudio目录下,改名为AudioHardwareMerlin.h,然后将此文件中所有的Generic字段通通替换成Merlin
然后将frameworks/base/libs/audioflinger/AudioHardwareInterface.cpp复制到
vendor/ardent/merlin/libaudio目录下,改名为AudioHardwareMerlin.cpp,然后将此文件中所有的Generic字段通通替换成Merlin
最后在AudioHardwareMerlin.cpp中定义createAudioHardware函数如下:
extern "C" AudioHardwareInterface* createAudioHardware(void)
{
return new AudioHardwareMerlin();
}
8,进行到7后直接编译,发现编译不过,错误如下
target thumb C++: libaudioflinger <= frameworks/base/libs/audioflinger/AudioFlinger.cpp
make: *** 没有规则可以创建“out/target/product/merlin/obj/SHARED_LIBRARIES/libaudioflinger_intermediates/LINKED/libaudioflinger.so”需要的目标“out/target/product/merlin/obj/lib/libaudiopolicy.so”。 停止。
原来是编译audioflinger的时候需要libaudiopolicy.so的支持
查看frameworks/base/libs/audioflinger/Android.mk文件,发现有如下内容:
ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
LOCAL_STATIC_LIBRARIES += libaudiointerface libaudiopolicybase
LOCAL_CFLAGS += -DGENERIC_AUDIO
else
LOCAL_SHARED_LIBRARIES += libaudio libaudiopolicy
endif
看来generic audio的时候需要的是libaudiointerface和libaudiopolicybase静态库,否则需要libaudio和libaudiopolicy动态库
libaudio库上面我们已经实现,看来下面的内容就是要实现libaudiopolicy库了
9,audio policy接口的调用在frameworks/base/libs/audioflinger/AudioPolicyService.cpp文件中的AudioPolicyService类
的构造函数中,如下:
#if (defined GENERIC_AUDIO) || (defined AUDIO_POLICY_TEST)
mpPolicyManager = new AudioPolicyManagerBase(this);
LOGV("build for GENERIC_AUDIO - using generic audio policy");
#else
// if running in emulation - use the emulator driver
if (property_get("ro.kernel.qemu", value, 0)) {
LOGV("Running in emulation - using generic audio policy");
mpPolicyManager = new AudioPolicyManagerBase(this);
}
else {
LOGV("Using hardware specific audio policy");
mpPolicyManager = createAudioPolicyManager(this);
}
#endif
该目录下的AudioPolicyService.h文件中定义了mpPolicyManager如下:
AudioPolicyInterface* mpPolicyManager; // the platform specific policy manager
可见,当系统为generic audio或者运行在模拟器上时,mpPolicyManager是一个指向AudioPolicyManagerBase对象的指针
否则就要通过createAudioPolicyManager函数来返回。
AudioPolicyInterface类和AudioPolicyManagerBase类声明在hardware/libhardware_legacy/include/hardware_legacy
目录下的AudioPolicyInterface.h和AudioPolicyManagerBase.h文件中,而且AudioPolicyManagerBase类是AudioPolicyInterface
的子类。
10,实现libaudiopolicy库
libaudiopolicy库的实现我们也可以模仿generic audio的实现方式,从8我们可以看出,generic audio的时候audiopolicy用的是
静态的libaudiopolicybase库,从frameworks/base/libs/audioflinger/Android.mk文件可以找到该静态库的编译内容如下:
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
AudioPolicyManagerBase.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libmedia
ifeq ($(TARGET_SIMULATOR),true)
LOCAL_LDLIBS += -ldl
else
LOCAL_SHARED_LIBRARIES += libdl
endif
LOCAL_MODULE:= libaudiopolicybase
ifeq ($(BOARD_HAVE_BLUETOOTH),true)
LOCAL_CFLAGS += -DWITH_A2DP
endif
ifeq ($(AUDIO_POLICY_TEST),true)
LOCAL_CFLAGS += -DAUDIO_POLICY_TEST
endif
include $(BUILD_STATIC_LIBRARY)
由此可见,libaudiopolicybase静态库编译的就是frameworks/base/libs/audioflinger/AudioPolicyManagerBase.cpp文件
11,通过9和10的分析,结合libaudio库的写法,要完成libaudiopolicy库,我们可以将AudioPolicyManagerBase.cpp
和AudioPolicyManagerBase.h复制到vendor/ardent/merlin/libaudio目录下,然后将这两个文件名改成和其中的内容作
一定修改,让它变成两外一个类如AudioPolicyManagerMerlin类的定义,然后在cpp文件中定义接口函数createAudioPolicyManager如下:
extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
{
return new AudioPolicyManagerMerlin(clientInterface);
}
然后再修改相关Mdroid.mk文件编译成libaudiopolicy.so即可
采用这种方法可以实现,但是却不必要,因为generic audio所用的AudioPolicyManagerBase已经非常完善,所以我们只需要直接继承这个类即可
下面来实现它。
12,在vendor/ardent/merlin/libaudio目录下创建一个AudioPolicyManagerMerlin.h文件,内容如下:
#include <stdint.h>
#include <sys/types.h>
#include <utils/Timers.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <hardware_legacy/AudioPolicyManagerBase.h>
namespace android {
class AudioPolicyManagerMerlin: public AudioPolicyManagerBase
{
public:
AudioPolicyManagerMerlin(AudioPolicyClientInterface *clientInterface)
: AudioPolicyManagerBase(clientInterface) {}
virtual ~AudioPolicyManagerMerlin() {}
};
};
主要是声明我们所用的AudioPolicyManagerMerlin,通过直接继承generic audio所用AudioPolicyManagerBase类来实现
13,在vendor/ardent/merlin/libaudio目录下创建一个AudioPolicyManagerMerlin.cpp文件,内容如下:
#include "AudioPolicyManagerMerlin.h"
#include <media/mediarecorder.h>
namespace android {
extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
{
return new AudioPolicyManagerMerlin(clientInterface);
}
}; // namespace android
主要就是定义了接口函数createAudioPolicyManager
14,修改vendor/ardent/merlin/libaudio/Mdroid.mk函数,添加libaudiopolicy的编译如下:
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
AudioPolicyManagerMerlin.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libmedia
LOCAL_STATIC_LIBRARIES += libaudiopolicybase
LOCAL_MODULE:= libaudiopolicy
include $(BUILD_SHARED_LIBRARY)
经过以上过程再修改一些小错误,基本上就能编译通过,声音的框架也已经起来了,但是系统还是没哟声音,因为还需要进一步的工作,
下一节继续。
android系统开发小知识-启动脚本文件内部的执行顺序
我们知道android在启动的时候通过init进程来解析init.rc和init.xxx.rc文件,
然后执行这两个文件解析出来的内容,init.rc和init.xxx.rc文件中的内容却并不是
按照顺序来执行的,而是有固定的执行顺序,首先,init.rc和init.xxx.rc文件中的内容
全部会放在4个关键字下:
early-init, init, early-boot, boot
所以一个典型的rc文件的写法如下:
on early-init
--------------
on init
--------------
on early-boot
--------------
on boot
--------------
rc文件中这4个部分是可以打乱顺序随便写的,甚至可以有多个部分出现,但是解析完了以后的执行
顺序确实固定的,执行顺序如下:
early-init -> init -> early-boot -> boot
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/jiajie961/archive/2010/12/01/6047219.aspx