The Android Java SDK is nice and all, but what if you want to run some C service or code? Well, it turns out that this isn't exactly difficult. You can compile an application using a standard Linux cross-compiler, install it and run your programs from the shell.
You will need a cross-compiler (make sure you get the ARM GNU/Linux target). Then you can just create your program, compile, and upload to the device:
$ arm-none-linux-gnueabi-gcc -static hello.c -o hello
$ adb push hello/hello data/hello
You can then simply run you application:
$ adb shell data/hello
Hello, Android!
Now of course, this doesn't at all explain how to tie into the graphics or the rest of the system, but that is left as an exercise for the reader ;)
Update: My instructions were missing the essential -static part!
2010年3月8日 星期一
2010年2月4日 星期四
git get the patches
0. git tag
1. git tag R6-v0.0.1 xxxxxxxxx1
2 git config core.filemode false
4. git add .
3. git commit -a(for new files)
5 git tag R6-v0.0.2 xxxxxxxxx2
view the logs
6. git log R6-v0.0.2 --stat --summary |sed '/mode\ change\ 100644/d' > pd_r6.patch
get the patches
7. git diff --binary R6FSL.0.0.1.. |sed '/mode\change\ 100644/d' >pd_kernel_patch.diff
(include binary files like *.a *.jar)
===================create new git repository=========
1. git init
make modfication
2. git add .
3. git commit
4. "git log" to check back
5
2010年1月27日 星期三
Android init 启动过程分析
分析android的启动过程,从内核之上,我们首先应该从文件系统的init开始,因为 init 是内核进入文件系统后第一个运行的程序,通常我们可以在linux的命令行中指定内核第一个调用谁,如果没指定那么内核将会到/sbin/, /bin/ 等目录下查找默认的init,如果没有找到那么就报告出错。
下面是曾经用过的几种开发板的命令行参数:
S3C2410 启动参数:
noinitrd root=/dev/nfs nfsroot=192.168.2.56:/nfsroot/rootfs ip=192.168.2.188:192.168.2.56:192.168.2.56:255.255.255.0::eth0:on console=ttySAC0
S3C2440 启动参数:
setenv bootargs console=ttySAC0 root=/dev/nfs nfsroot=192.168.2.56:/nfsroot/rootfs ip=192.168.2.175:192.168.2.56:192.168.2.201:255.255.255.0::eth0:on mem=64M init=/init
marvell 310 启动参数:
boot root=/dev/nfs nfsroot=192.168.2.56:/nfsroot/rootfs,rsize=1024,wsize=1024 ip=192.168.2.176:192.168.2.201:192.168.2.201:255.255.255.0::eth0:-On console=ttyS2,115200 mem=64M init=/init
init的源代码在文件:./system/core/init/init.c 中,init会一步步完成下面的任务:
1.初始化log系统
2.解析/init.rc和/init.%hardware%.rc文件
3. 执行 early-init action in the two files parsed in step 2.
4. 设备初始化,例如:在 /dev 下面创建所有设备节点,下载 firmwares.
5. 初始化属性服务器,Actually the property system is working as a share memory. Logically it looks like a registry under Windows system.
6. 执行 init action in the two files parsed in step 2.
7. 开启 属性服务。
8. 执行 early-boot and boot actions in the two files parsed in step 2.
9. 执行 Execute property action in the two files parsed in step 2.
10. 进入一个无限循环 to wait for device/property set/child process exit events.例如, 如果SD卡被插入,init会收到一个设备插入事件,它会为这个设备创建节点。系统中比较重要的进程都是由init来fork的,所以如果他们他谁崩溃了,那么init 将会收到一个 SIGCHLD 信号,把这个信号转化为子进程退出事件, 所以在loop中,init 会操作进程退出事件并且执行 *.rc 文件中定义的命令。
例如,在init.rc中,因为有:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
socket zygote stream 666
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
所以,如果zygote因为启动某些服务导致异常退出后,init将会重新去启动它。
int main(int argc, char **argv)
{
...
//需要在后面的程序中看打印信息的话,需要屏蔽open_devnull_stdio()函数
open_devnull_stdio();
...
//初始化log系统
log_init();
//解析/init.rc和/init.%hardware%.rc文件
parse_config_file("/init.rc");
...
snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);
parse_config_file(tmp);
...
//执行 early-init action in the two files parsed in step 2.
action_for_each_trigger("early-init", action_add_queue_tail);
drain_action_queue();
...
/* execute all the boot actions to get us started */
/* 执行 init action in the two files parsed in step 2 */
action_for_each_trigger("init", action_add_queue_tail);
drain_action_queue();
...
/* 执行 early-boot and boot actions in the two files parsed in step 2 */
action_for_each_trigger("early-boot", action_add_queue_tail);
action_for_each_trigger("boot", action_add_queue_tail);
drain_action_queue();
/* run all property triggers based on current state of the properties */
queue_all_property_triggers();
drain_action_queue();
/* enable property triggers */
property_triggers_enabled = 1;
...
for(;;) {
int nr, timeout = -1;
...
drain_action_queue();
restart_processes();
if (process_needs_restart) {
timeout = (process_needs_restart - gettime()) * 1000;
if (timeout < 0)
timeout = 0;
}
...
nr = poll(ufds, 3, timeout);
if (nr <= 0)
continue;
if (ufds[2].revents == POLLIN) {
/* we got a SIGCHLD - reap and restart as needed */
read(signal_recv_fd, tmp, sizeof(tmp));
while (!wait_for_one_process(0))
;
continue;
}
if (ufds[0].revents == POLLIN)
handle_device_fd(device_fd);
if (ufds[1].revents == POLLIN)
{
handle_property_set_fd(property_set_fd);
}
}
return 0;
}
2.解析init.rc脚本
init.rc 脚本的具体语法可以参考下面文档
http://www.kandroid.org/android_pdk/bring_up.html
名词解释:
Android初始化語言由四大类声明组成:行为类(Actions),命令类(Commands),服务类(Services),选项类(Options).
初始化语言以行为单位,由以空格间隔的语言符号組成。C风格的反斜杠转义符可以用来插入空白到语言符号。双引号也可以用来防止文本被空格分成多个语言符号。当反斜杠在行末时,作为换行符。
* 以#开始(前面允许空格)的行为注释。
* Actions和Services隐含声明一个新的段落。所有该段落下Commands或Options的声明属于该段落。第一段落前的Commands或Options被忽略。
* Actions和Services拥有唯一的命名。在他们之后声明相同命名的类将被当作错误并忽略。
Actions是一系列命令的命名。Actions拥有一个触发器(trigger)用来決定action何時执行。当一个action在符合触发条件被执行时,如果它还没被加入到待执行队列中的话,則加入到队列最后。
队列中的action依次执行,action中的命令也依次执行。Init在执行命令的中间处理其他活动(设备创建/销毁,property 设置,进程重启)。
Actions的表现形式:
on
重要的数据结构
两个列表,一个队列。
static list_declare(service_list);
static list_declare(action_list);
static list_declare(action_queue);
*.rc 脚本中所有 service关键字定义的服务将会添加到 service_list 列表中。
*.rc 脚本中所有 on 关键开头的项将会被会添加到 action_list 列表中。
每个action列表项都有一个列表,此列表用来保存该段落下的 Commands
脚本解析过程:
parse_config_file("/init.rc")
int parse_config_file(const char *fn)
{
char *data;
data = read_file(fn, 0);
if (!data) return -1;
parse_config(fn, data);
DUMP();
return 0;
}
static void parse_config(const char *fn, char *s)
{
...
case T_NEWLINE:
if (nargs) {
int kw = lookup_keyword(args[0]);
if (kw_is(kw, SECTION)) {
state.parse_line(&state, 0, 0);
parse_new_section(&state, kw, nargs, args);
} else {
state.parse_line(&state, nargs, args);
}
nargs = 0;
}
...
}
parse_config会逐行对脚本进行解析,如果关键字类型为 SECTION ,那么将会执行 parse_new_section()
类型为 SECTION 的关键字有: on 和 sevice
关键字类型定义在 Parser.c (system\core\init) 文件中
Parser.c (system\core\init)
#define SECTION 0x01
#define COMMAND 0x02
#define OPTION 0x04
关键字 属性
capability, OPTION, 0, 0)
class, OPTION, 0, 0)
class_start, COMMAND, 1, do_class_start)
class_stop, COMMAND, 1, do_class_stop)
console, OPTION, 0, 0)
critical, OPTION, 0, 0)
disabled, OPTION, 0, 0)
domainname, COMMAND, 1, do_domainname)
exec, COMMAND, 1, do_exec)
export, COMMAND, 2, do_export)
group, OPTION, 0, 0)
hostname, COMMAND, 1, do_hostname)
ifup, COMMAND, 1, do_ifup)
insmod, COMMAND, 1, do_insmod)
import, COMMAND, 1, do_import)
keycodes, OPTION, 0, 0)
mkdir, COMMAND, 1, do_mkdir)
mount, COMMAND, 3, do_mount)
on, SECTION, 0, 0)
oneshot, OPTION, 0, 0)
onrestart, OPTION, 0, 0)
restart, COMMAND, 1, do_restart)
service, SECTION, 0, 0)
setenv, OPTION, 2, 0)
setkey, COMMAND, 0, do_setkey)
setprop, COMMAND, 2, do_setprop)
setrlimit, COMMAND, 3, do_setrlimit)
socket, OPTION, 0, 0)
start, COMMAND, 1, do_start)
stop, COMMAND, 1, do_stop)
trigger, COMMAND, 1, do_trigger)
symlink, COMMAND, 1, do_symlink)
sysclktz, COMMAND, 1, do_sysclktz)
user, OPTION, 0, 0)
write, COMMAND, 2, do_write)
chown, COMMAND, 2, do_chown)
chmod, COMMAND, 2, do_chmod)
loglevel, COMMAND, 1, do_loglevel)
device, COMMAND, 4, do_device)
parse_new_section()中再分别对 service 或者 on 关键字开头的内容进行解析。
...
case K_service:
state->context = parse_service(state, nargs, args);
if (state->context) {
state->parse_line = parse_line_service;
return;
}
break;
case K_on:
state->context = parse_action(state, nargs, args);
if (state->context) {
state->parse_line = parse_line_action;
return;
}
break;
}
...
对 on 关键字开头的内容进行解析
static void *parse_action(struct parse_state *state, int nargs, char **args)
{
...
act = calloc(1, sizeof(*act));
act->name = args[1];
list_init(&act->commands);
list_add_tail(&action_list, &act->alist);
...
}
对 service 关键字开头的内容进行解析
static void *parse_service(struct parse_state *state, int nargs, char **args)
{
struct service *svc;
if (nargs < 3) {
parse_error(state, "services must have a name and a program\n");
return 0;
}
if (!valid_name(args[1])) {
parse_error(state, "invalid service name '%s'\n", args[1]);
return 0;
}
//如果服务已经存在service_list列表中将会被忽略
svc = service_find_by_name(args[1]);
if (svc) {
parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]);
return 0;
}
nargs -= 2;
svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs);
if (!svc) {
parse_error(state, "out of memory\n");
return 0;
}
svc->name = args[1];
svc->classname = "default";
memcpy(svc->args, args + 2, sizeof(char*) * nargs);
svc->args[nargs] = 0;
svc->nargs = nargs;
svc->onrestart.name = "onrestart";
list_init(&svc->onrestart.commands);
//添加该服务到 service_list 列表
list_add_tail(&service_list, &svc->slist);
return svc;
}
服务的表现形式:
service [ ]*
下面是曾经用过的几种开发板的命令行参数:
S3C2410 启动参数:
noinitrd root=/dev/nfs nfsroot=192.168.2.56:/nfsroot/rootfs ip=192.168.2.188:192.168.2.56:192.168.2.56:255.255.255.0::eth0:on console=ttySAC0
S3C2440 启动参数:
setenv bootargs console=ttySAC0 root=/dev/nfs nfsroot=192.168.2.56:/nfsroot/rootfs ip=192.168.2.175:192.168.2.56:192.168.2.201:255.255.255.0::eth0:on mem=64M init=/init
marvell 310 启动参数:
boot root=/dev/nfs nfsroot=192.168.2.56:/nfsroot/rootfs,rsize=1024,wsize=1024 ip=192.168.2.176:192.168.2.201:192.168.2.201:255.255.255.0::eth0:-On console=ttyS2,115200 mem=64M init=/init
init的源代码在文件:./system/core/init/init.c 中,init会一步步完成下面的任务:
1.初始化log系统
2.解析/init.rc和/init.%hardware%.rc文件
3. 执行 early-init action in the two files parsed in step 2.
4. 设备初始化,例如:在 /dev 下面创建所有设备节点,下载 firmwares.
5. 初始化属性服务器,Actually the property system is working as a share memory. Logically it looks like a registry under Windows system.
6. 执行 init action in the two files parsed in step 2.
7. 开启 属性服务。
8. 执行 early-boot and boot actions in the two files parsed in step 2.
9. 执行 Execute property action in the two files parsed in step 2.
10. 进入一个无限循环 to wait for device/property set/child process exit events.例如, 如果SD卡被插入,init会收到一个设备插入事件,它会为这个设备创建节点。系统中比较重要的进程都是由init来fork的,所以如果他们他谁崩溃了,那么init 将会收到一个 SIGCHLD 信号,把这个信号转化为子进程退出事件, 所以在loop中,init 会操作进程退出事件并且执行 *.rc 文件中定义的命令。
例如,在init.rc中,因为有:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
socket zygote stream 666
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
所以,如果zygote因为启动某些服务导致异常退出后,init将会重新去启动它。
int main(int argc, char **argv)
{
...
//需要在后面的程序中看打印信息的话,需要屏蔽open_devnull_stdio()函数
open_devnull_stdio();
...
//初始化log系统
log_init();
//解析/init.rc和/init.%hardware%.rc文件
parse_config_file("/init.rc");
...
snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);
parse_config_file(tmp);
...
//执行 early-init action in the two files parsed in step 2.
action_for_each_trigger("early-init", action_add_queue_tail);
drain_action_queue();
...
/* execute all the boot actions to get us started */
/* 执行 init action in the two files parsed in step 2 */
action_for_each_trigger("init", action_add_queue_tail);
drain_action_queue();
...
/* 执行 early-boot and boot actions in the two files parsed in step 2 */
action_for_each_trigger("early-boot", action_add_queue_tail);
action_for_each_trigger("boot", action_add_queue_tail);
drain_action_queue();
/* run all property triggers based on current state of the properties */
queue_all_property_triggers();
drain_action_queue();
/* enable property triggers */
property_triggers_enabled = 1;
...
for(;;) {
int nr, timeout = -1;
...
drain_action_queue();
restart_processes();
if (process_needs_restart) {
timeout = (process_needs_restart - gettime()) * 1000;
if (timeout < 0)
timeout = 0;
}
...
nr = poll(ufds, 3, timeout);
if (nr <= 0)
continue;
if (ufds[2].revents == POLLIN) {
/* we got a SIGCHLD - reap and restart as needed */
read(signal_recv_fd, tmp, sizeof(tmp));
while (!wait_for_one_process(0))
;
continue;
}
if (ufds[0].revents == POLLIN)
handle_device_fd(device_fd);
if (ufds[1].revents == POLLIN)
{
handle_property_set_fd(property_set_fd);
}
}
return 0;
}
2.解析init.rc脚本
init.rc 脚本的具体语法可以参考下面文档
http://www.kandroid.org/android_pdk/bring_up.html
名词解释:
Android初始化語言由四大类声明组成:行为类(Actions),命令类(Commands),服务类(Services),选项类(Options).
初始化语言以行为单位,由以空格间隔的语言符号組成。C风格的反斜杠转义符可以用来插入空白到语言符号。双引号也可以用来防止文本被空格分成多个语言符号。当反斜杠在行末时,作为换行符。
* 以#开始(前面允许空格)的行为注释。
* Actions和Services隐含声明一个新的段落。所有该段落下Commands或Options的声明属于该段落。第一段落前的Commands或Options被忽略。
* Actions和Services拥有唯一的命名。在他们之后声明相同命名的类将被当作错误并忽略。
Actions是一系列命令的命名。Actions拥有一个触发器(trigger)用来決定action何時执行。当一个action在符合触发条件被执行时,如果它还没被加入到待执行队列中的话,則加入到队列最后。
队列中的action依次执行,action中的命令也依次执行。Init在执行命令的中间处理其他活动(设备创建/销毁,property 设置,进程重启)。
Actions的表现形式:
on
重要的数据结构
两个列表,一个队列。
static list_declare(service_list);
static list_declare(action_list);
static list_declare(action_queue);
*.rc 脚本中所有 service关键字定义的服务将会添加到 service_list 列表中。
*.rc 脚本中所有 on 关键开头的项将会被会添加到 action_list 列表中。
每个action列表项都有一个列表,此列表用来保存该段落下的 Commands
脚本解析过程:
parse_config_file("/init.rc")
int parse_config_file(const char *fn)
{
char *data;
data = read_file(fn, 0);
if (!data) return -1;
parse_config(fn, data);
DUMP();
return 0;
}
static void parse_config(const char *fn, char *s)
{
...
case T_NEWLINE:
if (nargs) {
int kw = lookup_keyword(args[0]);
if (kw_is(kw, SECTION)) {
state.parse_line(&state, 0, 0);
parse_new_section(&state, kw, nargs, args);
} else {
state.parse_line(&state, nargs, args);
}
nargs = 0;
}
...
}
parse_config会逐行对脚本进行解析,如果关键字类型为 SECTION ,那么将会执行 parse_new_section()
类型为 SECTION 的关键字有: on 和 sevice
关键字类型定义在 Parser.c (system\core\init) 文件中
Parser.c (system\core\init)
#define SECTION 0x01
#define COMMAND 0x02
#define OPTION 0x04
关键字 属性
capability, OPTION, 0, 0)
class, OPTION, 0, 0)
class_start, COMMAND, 1, do_class_start)
class_stop, COMMAND, 1, do_class_stop)
console, OPTION, 0, 0)
critical, OPTION, 0, 0)
disabled, OPTION, 0, 0)
domainname, COMMAND, 1, do_domainname)
exec, COMMAND, 1, do_exec)
export, COMMAND, 2, do_export)
group, OPTION, 0, 0)
hostname, COMMAND, 1, do_hostname)
ifup, COMMAND, 1, do_ifup)
insmod, COMMAND, 1, do_insmod)
import, COMMAND, 1, do_import)
keycodes, OPTION, 0, 0)
mkdir, COMMAND, 1, do_mkdir)
mount, COMMAND, 3, do_mount)
on, SECTION, 0, 0)
oneshot, OPTION, 0, 0)
onrestart, OPTION, 0, 0)
restart, COMMAND, 1, do_restart)
service, SECTION, 0, 0)
setenv, OPTION, 2, 0)
setkey, COMMAND, 0, do_setkey)
setprop, COMMAND, 2, do_setprop)
setrlimit, COMMAND, 3, do_setrlimit)
socket, OPTION, 0, 0)
start, COMMAND, 1, do_start)
stop, COMMAND, 1, do_stop)
trigger, COMMAND, 1, do_trigger)
symlink, COMMAND, 1, do_symlink)
sysclktz, COMMAND, 1, do_sysclktz)
user, OPTION, 0, 0)
write, COMMAND, 2, do_write)
chown, COMMAND, 2, do_chown)
chmod, COMMAND, 2, do_chmod)
loglevel, COMMAND, 1, do_loglevel)
device, COMMAND, 4, do_device)
parse_new_section()中再分别对 service 或者 on 关键字开头的内容进行解析。
...
case K_service:
state->context = parse_service(state, nargs, args);
if (state->context) {
state->parse_line = parse_line_service;
return;
}
break;
case K_on:
state->context = parse_action(state, nargs, args);
if (state->context) {
state->parse_line = parse_line_action;
return;
}
break;
}
...
对 on 关键字开头的内容进行解析
static void *parse_action(struct parse_state *state, int nargs, char **args)
{
...
act = calloc(1, sizeof(*act));
act->name = args[1];
list_init(&act->commands);
list_add_tail(&action_list, &act->alist);
...
}
对 service 关键字开头的内容进行解析
static void *parse_service(struct parse_state *state, int nargs, char **args)
{
struct service *svc;
if (nargs < 3) {
parse_error(state, "services must have a name and a program\n");
return 0;
}
if (!valid_name(args[1])) {
parse_error(state, "invalid service name '%s'\n", args[1]);
return 0;
}
//如果服务已经存在service_list列表中将会被忽略
svc = service_find_by_name(args[1]);
if (svc) {
parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]);
return 0;
}
nargs -= 2;
svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs);
if (!svc) {
parse_error(state, "out of memory\n");
return 0;
}
svc->name = args[1];
svc->classname = "default";
memcpy(svc->args, args + 2, sizeof(char*) * nargs);
svc->args[nargs] = 0;
svc->nargs = nargs;
svc->onrestart.name = "onrestart";
list_init(&svc->onrestart.commands);
//添加该服务到 service_list 列表
list_add_tail(&service_list, &svc->slist);
return svc;
}
服务的表现形式:
service
2010年1月23日 星期六
ramdisk android
1、解压、修改Android的ramdisk.img的方法
将ramdisk.img复制一份到任何其他目录下,将其名称改为ramdisk.img.gz,并使用命令
gunzip ramdisk.img.gz
然后新建一个文件夹,叫ramdisk吧,进入,输入命令
cpio -i -F ../ramdisk.img
这下,你就能看见并操作ramdisk里面的内容了。
根据自己的需要对里面的内容修改之后,可以使用下列命令重新打包成镜像
cpio -i -t -F ../ramdisk.img > list
cpio -o -H newc -O lk.img < list
当前目录下生成的lk.img就是我们的新镜像了。
将ramdisk.img复制一份到任何其他目录下,将其名称改为ramdisk.img.gz,并使用命令
gunzip ramdisk.img.gz
然后新建一个文件夹,叫ramdisk吧,进入,输入命令
cpio -i -F ../ramdisk.img
这下,你就能看见并操作ramdisk里面的内容了。
根据自己的需要对里面的内容修改之后,可以使用下列命令重新打包成镜像
cpio -i -t -F ../ramdisk.img > list
cpio -o -H newc -O lk.img < list
当前目录下生成的lk.img就是我们的新镜像了。
2010年1月11日 星期一
clocks node in file system
# cat /proc/cpu/clocksvalue in CDCR=0
value in u32_CDCR=0
value in CBCDR=1680044416
value in u32_CBCDR=1680044416
scc_clk-0 ahb_clk-0 ______ 0 133000000 (133MHz)
gpu2d_clk-0 axi_b_clk-0 ___TH_ 0 133000000 (133MHz)
ddr_hf_clk-0 pll1_sw_clk-0 P_____ 1 160000000 (160MHz)
emi_garb_clk-0 axi_a_clk-0 ______ 0 166250000 (166MHz)
garb_clk-0 axi_a_clk-0 ______ 0 166250000 (166MHz)
gpu3d_clk-0 axi_b_clk-0 ___TH_ 0 133000000 (133MHz)
sahara_sec_clk-0 tmax1_clk-0 ______ 0 133000000 (133MHz)
sahara_clk-0 ahb_clk-0 ______ 0 133000000 (133MHz)
mipi_hsp_clk-0 ipu_clk-0 ______ 0 133000000 (133MHz)
mipi_esc_clk-0 pll2-0 ______ 0 665000000 (665MHz)
mipi_hsc2_clk-0 pll2-0 ______ 0 665000000 (665MHz)
mipi_hsc1_clk-0 pll2-0 ______ 0 665000000 (665MHz)
fec_sec2_clk-0 aips_tz2_clk-0 ______ 0 133000000 (133MHz)
fec_sec1_clk-0 tmax2_clk-0 ______ 0 133000000 (133MHz)
fec_clk-0 ipg_clk-0 ___TH_ 0 66500000 (66MHz)
owire_clk-0 ipg_perclk-0 ______ 0 8000000 (8MHz)
ata_clk-0 ipg_clk-0 ___TH_ 0 66500000 (66MHz)
rtc_clk-0 ckil-0 ______ 0 32768 (32KHz)
pgc_clk-0 ipg_clk-0 ______ 0 66500000 (66MHz)
lpsr_clk-0 ckil-0 ______ 0 32768 (32KHz)
vpu_emi_clk-0 emi_fast_clk-0 ______ 0 160000000 (160MHz)
vpu_core_clk-0 axi_b_clk-0 ______ 0 133000000 (133MHz)
vpu_clk-0 axi_b_clk-0 ___TH_ 0 133000000 (133MHz)
arm_axi_clk-0 axi_a_clk-0 ______ 0 166250000 (166MHz)
spdif_ipg_clk-0 ipg_clk-0 ______ 0 66500000 (66MHz)
spdif_clk-1 spdif_xtal_clk-0 ___TH_ 0 24000000 (24MHz)
spdif_ipg_clk-0 ipg_clk-0 ______ 0 66500000 (66MHz)
spdif_clk-0 spdif_xtal_clk-0 ___TH_ 0 24000000 (24MHz)
spdif_xtal_clk-0 osc-0 ______ 0 24000000 (24MHz)
emi_intr_clk-0 ahb_clk-0 ______ 2 133000000 (133MHz)
emi_fast_clk-0 ddr_clk-0 ______ 2 160000000 (160MHz)
nfc_clk-0 emi_slow_clk-0 ______ 2 33250000 (33MHz)
ddr_clk-0 ddr_hf_clk-0 P_____ 1 160000000 (160MHz)
emi_slow_clk-0 ahb_clk-0 P_____ 1 133000000 (133MHz)
sim_ipg_clk-0 ipg_clk-0 ______ 0 66500000 (66MHz)
sim_clk-0 pll3-0 ___TH_ 0 54000000 (54MHz)
sd_dep_clk-0 spba_clk-0 ______ 0 66500000 (66MHz)
esdhc_ipg_clk-3 ipg_clk-0 ______ 0 66500000 (66MHz)
esdhc_clk-3 esdhc_clk-0 ___TH_ 0 54000000 (54MHz)
esdhc_ipg_clk-2 ipg_clk-0 ______ 0 66500000 (66MHz)
esdhc_clk-2 esdhc_clk-0 ___TH_ 0 54000000 (54MHz)
esdhc_ipg_clk-1 ipg_clk-0 ______ 0 66500000 (66MHz)
esdhc_clk-1 pll3-0 ___TH_ 0 54000000 (54MHz)
esdhc_ipg_clk-0 ipg_clk-0 ______ 0 66500000 (66MHz)
esdhc_clk-0 pll3-0 ___TH_ 0 54000000 (54MHz)
usb_clk-0 ______ 1 60000000 (60MHz)
usb_utmi_clk-0 ______ 0 0 (0Hz)
usb_phy_clk-0 osc-0 ______ 1 24000000 (24MHz)
usb_ahb_clk-0 ipg_clk-0 ______ 1 66500000 (66MHz)
usb_sec_clk-0 tmax2_clk-0 ______ 1 133000000 (133MHz)
usboh3_clk-0 pll2-0 ___T_M 1 66500000 (66MHz)
tmax3_clk-0 ahb_clk-0 ______ 1 133000000 (133MHz)
tmax2_clk-0 ahb_clk-0 ______ 1 133000000 (133MHz)
tmax1_clk-0 ahb_clk-0 ______ 0 133000000 (133MHz)
iim_clk-0 ipg_clk-0 ______ 0 66500000 (66MHz)
ssi_ext2_clk-0 ssi_clk-1 ______ 0 12000000 (12MHz)
ssi_ext1_clk-0 ssi_clk-0 ______ 0 12000000 (12MHz)
ssi_dep_clk-1 spba_clk-0 ______ 1 66500000 (66MHz)
ssi_ipg_clk-1 ipg_clk-0 ______ 1 66500000 (66MHz)
ssi_clk-1 ssi_lp_apm_clk-0 ______ 1 12000000 (12MHz)
ssi_dep_clk-0 aips_tz2_clk-0 ______ 0 133000000 (133MHz)
ssi_ipg_clk-0 ipg_clk-0 ______ 0 66500000 (66MHz)
ssi_clk-0 ssi_lp_apm_clk-0 ______ 0 12000000 (12MHz)
ssi_lp_apm_clk-0 lp_apm-0 ______ 1 24000000 (24MHz)
cspi_ipg_clk-2 ipg_clk-0 ______ 0 66500000 (66MHz)
cspi_clk-2 cspi_main_clk-0 ______ 0 6000000 (6MHz)
cspi_ipg_clk-1 ipg_clk-0 ______ 0 66500000 (66MHz)
cspi_clk-1 cspi_main_clk-0 ______ 0 6000000 (6MHz)
cspi_ipg_clk-0 ipg_clk-0 ______ 0 66500000 (66MHz)
cspi_clk-0 cspi_main_clk-0 ______ 0 6000000 (6MHz)
cspi_main_clk-0 lp_apm-0 P_____ 0 6000000 (6MHz)
pwm_32k_clk-1 ckil-0 ______ 0 32768 (32KHz)
pwm_ipg_clk-1 ipg_clk-0 ______ 0 66500000 (66MHz)
pwm-1 ipg_perclk-0 ______ 0 8000000 (8MHz)
pwm_32k_clk-0 ckil-0 ______ 0 32768 (32KHz)
pwm_ipg_clk-0 ipg_clk-0 ______ 1 66500000 (66MHz)
pwm-0 ipg_perclk-0 ______ 1 8000000 (8MHz)
gpt_32k_clk-0 ckil-0 ______ 0 32768 (32KHz)
gpt_ipg_clk-0 ipg_clk-0 ______ 1 66500000 (66MHz)
gpt_clk-0 ipg_perclk-0 ______ 1 8000000 (8MHz)
hsi2c_serial_clk-0 pll3-0 ______ 0 54000000 (54MHz)
hsi2c_clk-0 ipg_clk-0 ___TH_ 0 66500000 (66MHz)
i2c_clk-1 ipg_perclk-0 ______ 0 8000000 (8MHz)
i2c_clk-0 ipg_perclk-0 ______ 0 8000000 (8MHz)
spba_clk-0 ipg_clk-0 ______ 1 66500000 (66MHz)
uart_ipg_clk-2 ipg_clk-0 ______ 0 66500000 (66MHz)
uart_clk-2 uart_main_clk-0 ______ 0 66500000 (66MHz)
uart_ipg_clk-1 ipg_clk-0 ______ 0 66500000 (66MHz)
uart_clk-1 uart_main_clk-0 ______ 0 66500000 (66MHz)
uart_ipg_clk-0 ipg_clk-0 ______ 1 66500000 (66MHz)
uart_clk-0 uart_main_clk-0 ______ 2 66500000 (66MHz)
uart_main_clk-0 pll2-0 P_____ 1 66500000 (66MHz)
csi_mclk2-0 pll3-0 ______ 0 54000000 (54MHz)
csi_mclk1-0 pll3-0 ______ 0 24000000 (24MHz)
tve_clk-0 pll3-0 ___TH_ 0 216000000 (216MHz)
ipu_di1_clk-1 tve_clk-0 ______ 0 27000000 (27MHz)
ipu_di0_clk-0 pll3-0 ______ 0 27000000 (27MHz)
ipu_sec_clk-0 emi_fast_clk-0 ______ 1 160000000 (160MHz)
ipu_clk-0 axi_b_clk-0 ___T_M 1 133000000 (133MHz)
sdma_ipg_clk-0 ipg_clk-0 ______ 1 66500000 (66MHz)
sdma_ahb_clk-0 ahb_clk-0 ______ 1 133000000 (133MHz)
aips_tz2_clk-0 ahb_clk-0 ______ 0 133000000 (133MHz)
aips_tz1_clk-0 ahb_clk-0 ______ 0 133000000 (133MHz)
ahbmux2_clk-0 ahb_clk-0 ______ 1 133000000 (133MHz)
ahbmux1_clk-0 ahb_clk-0 ______ 1 133000000 (133MHz)
ipg_perclk-0 lp_apm-0 P_____ 2 8000000 (8MHz)
ipg_clk-0 ahb_clk-0 P_____ 7 66500000 (66MHz)
max_clk-0 ahb_clk-0 ______ 3 133000000 (133MHz)
ahb_clk-0 main_bus_clk-0 P_____ 9 133000000 (133MHz)
axi_b_clk-0 main_bus_clk-0 P_____ 1 133000000 (133MHz)
axi_a_clk-0 main_bus_clk-0 P_____ 0 166250000 (166MHz)
main_bus_clk-0 pll2-0 P_____ 3 665000000 (665MHz)
periph_apm_clk-0 pll1_sw_clk-0 P_____ 0 800000000 (800MHz)
cpu_clk-0 pll1_sw_clk-0 ______ 1 800000000 (800MHz)
lp_apm-0 osc-0 P_____ 2 24000000 (24MHz)
gpc_dvfs_clk-0 ______ 0 0 (0Hz)
pll3-0 osc-0 P_____ 0 216000000 (216MHz)
pll2-0 osc-0 P_____ 3 665000000 (665MHz)
pll1_sw_clk-0 pll1_main_clk-0 P_____ 2 800000000 (800MHz)
pll1_main_clk-0 osc-0 P_____ 1 800000000 (800MHz)
fpm_div2_clk-0 fpm_clk-0 P_____ 0 16777216 (16MHz)
fpm_clk-0 ckil-0 P_____ 0 33554432 (33MHz)
ckil-0 P_____ 0 32768 (32KHz)
ckih2-0 P_____ 0 24576000 (24MHz)
ckih-0 P_____ 0 22579200 (22MHz)
osc-0 P_____ 4 24000000 (24MHz)
#
value in u32_CDCR=0
value in CBCDR=1680044416
value in u32_CBCDR=1680044416
scc_clk-0 ahb_clk-0 ______ 0 133000000 (133MHz)
gpu2d_clk-0 axi_b_clk-0 ___TH_ 0 133000000 (133MHz)
ddr_hf_clk-0 pll1_sw_clk-0 P_____ 1 160000000 (160MHz)
emi_garb_clk-0 axi_a_clk-0 ______ 0 166250000 (166MHz)
garb_clk-0 axi_a_clk-0 ______ 0 166250000 (166MHz)
gpu3d_clk-0 axi_b_clk-0 ___TH_ 0 133000000 (133MHz)
sahara_sec_clk-0 tmax1_clk-0 ______ 0 133000000 (133MHz)
sahara_clk-0 ahb_clk-0 ______ 0 133000000 (133MHz)
mipi_hsp_clk-0 ipu_clk-0 ______ 0 133000000 (133MHz)
mipi_esc_clk-0 pll2-0 ______ 0 665000000 (665MHz)
mipi_hsc2_clk-0 pll2-0 ______ 0 665000000 (665MHz)
mipi_hsc1_clk-0 pll2-0 ______ 0 665000000 (665MHz)
fec_sec2_clk-0 aips_tz2_clk-0 ______ 0 133000000 (133MHz)
fec_sec1_clk-0 tmax2_clk-0 ______ 0 133000000 (133MHz)
fec_clk-0 ipg_clk-0 ___TH_ 0 66500000 (66MHz)
owire_clk-0 ipg_perclk-0 ______ 0 8000000 (8MHz)
ata_clk-0 ipg_clk-0 ___TH_ 0 66500000 (66MHz)
rtc_clk-0 ckil-0 ______ 0 32768 (32KHz)
pgc_clk-0 ipg_clk-0 ______ 0 66500000 (66MHz)
lpsr_clk-0 ckil-0 ______ 0 32768 (32KHz)
vpu_emi_clk-0 emi_fast_clk-0 ______ 0 160000000 (160MHz)
vpu_core_clk-0 axi_b_clk-0 ______ 0 133000000 (133MHz)
vpu_clk-0 axi_b_clk-0 ___TH_ 0 133000000 (133MHz)
arm_axi_clk-0 axi_a_clk-0 ______ 0 166250000 (166MHz)
spdif_ipg_clk-0 ipg_clk-0 ______ 0 66500000 (66MHz)
spdif_clk-1 spdif_xtal_clk-0 ___TH_ 0 24000000 (24MHz)
spdif_ipg_clk-0 ipg_clk-0 ______ 0 66500000 (66MHz)
spdif_clk-0 spdif_xtal_clk-0 ___TH_ 0 24000000 (24MHz)
spdif_xtal_clk-0 osc-0 ______ 0 24000000 (24MHz)
emi_intr_clk-0 ahb_clk-0 ______ 2 133000000 (133MHz)
emi_fast_clk-0 ddr_clk-0 ______ 2 160000000 (160MHz)
nfc_clk-0 emi_slow_clk-0 ______ 2 33250000 (33MHz)
ddr_clk-0 ddr_hf_clk-0 P_____ 1 160000000 (160MHz)
emi_slow_clk-0 ahb_clk-0 P_____ 1 133000000 (133MHz)
sim_ipg_clk-0 ipg_clk-0 ______ 0 66500000 (66MHz)
sim_clk-0 pll3-0 ___TH_ 0 54000000 (54MHz)
sd_dep_clk-0 spba_clk-0 ______ 0 66500000 (66MHz)
esdhc_ipg_clk-3 ipg_clk-0 ______ 0 66500000 (66MHz)
esdhc_clk-3 esdhc_clk-0 ___TH_ 0 54000000 (54MHz)
esdhc_ipg_clk-2 ipg_clk-0 ______ 0 66500000 (66MHz)
esdhc_clk-2 esdhc_clk-0 ___TH_ 0 54000000 (54MHz)
esdhc_ipg_clk-1 ipg_clk-0 ______ 0 66500000 (66MHz)
esdhc_clk-1 pll3-0 ___TH_ 0 54000000 (54MHz)
esdhc_ipg_clk-0 ipg_clk-0 ______ 0 66500000 (66MHz)
esdhc_clk-0 pll3-0 ___TH_ 0 54000000 (54MHz)
usb_clk-0 ______ 1 60000000 (60MHz)
usb_utmi_clk-0 ______ 0 0 (0Hz)
usb_phy_clk-0 osc-0 ______ 1 24000000 (24MHz)
usb_ahb_clk-0 ipg_clk-0 ______ 1 66500000 (66MHz)
usb_sec_clk-0 tmax2_clk-0 ______ 1 133000000 (133MHz)
usboh3_clk-0 pll2-0 ___T_M 1 66500000 (66MHz)
tmax3_clk-0 ahb_clk-0 ______ 1 133000000 (133MHz)
tmax2_clk-0 ahb_clk-0 ______ 1 133000000 (133MHz)
tmax1_clk-0 ahb_clk-0 ______ 0 133000000 (133MHz)
iim_clk-0 ipg_clk-0 ______ 0 66500000 (66MHz)
ssi_ext2_clk-0 ssi_clk-1 ______ 0 12000000 (12MHz)
ssi_ext1_clk-0 ssi_clk-0 ______ 0 12000000 (12MHz)
ssi_dep_clk-1 spba_clk-0 ______ 1 66500000 (66MHz)
ssi_ipg_clk-1 ipg_clk-0 ______ 1 66500000 (66MHz)
ssi_clk-1 ssi_lp_apm_clk-0 ______ 1 12000000 (12MHz)
ssi_dep_clk-0 aips_tz2_clk-0 ______ 0 133000000 (133MHz)
ssi_ipg_clk-0 ipg_clk-0 ______ 0 66500000 (66MHz)
ssi_clk-0 ssi_lp_apm_clk-0 ______ 0 12000000 (12MHz)
ssi_lp_apm_clk-0 lp_apm-0 ______ 1 24000000 (24MHz)
cspi_ipg_clk-2 ipg_clk-0 ______ 0 66500000 (66MHz)
cspi_clk-2 cspi_main_clk-0 ______ 0 6000000 (6MHz)
cspi_ipg_clk-1 ipg_clk-0 ______ 0 66500000 (66MHz)
cspi_clk-1 cspi_main_clk-0 ______ 0 6000000 (6MHz)
cspi_ipg_clk-0 ipg_clk-0 ______ 0 66500000 (66MHz)
cspi_clk-0 cspi_main_clk-0 ______ 0 6000000 (6MHz)
cspi_main_clk-0 lp_apm-0 P_____ 0 6000000 (6MHz)
pwm_32k_clk-1 ckil-0 ______ 0 32768 (32KHz)
pwm_ipg_clk-1 ipg_clk-0 ______ 0 66500000 (66MHz)
pwm-1 ipg_perclk-0 ______ 0 8000000 (8MHz)
pwm_32k_clk-0 ckil-0 ______ 0 32768 (32KHz)
pwm_ipg_clk-0 ipg_clk-0 ______ 1 66500000 (66MHz)
pwm-0 ipg_perclk-0 ______ 1 8000000 (8MHz)
gpt_32k_clk-0 ckil-0 ______ 0 32768 (32KHz)
gpt_ipg_clk-0 ipg_clk-0 ______ 1 66500000 (66MHz)
gpt_clk-0 ipg_perclk-0 ______ 1 8000000 (8MHz)
hsi2c_serial_clk-0 pll3-0 ______ 0 54000000 (54MHz)
hsi2c_clk-0 ipg_clk-0 ___TH_ 0 66500000 (66MHz)
i2c_clk-1 ipg_perclk-0 ______ 0 8000000 (8MHz)
i2c_clk-0 ipg_perclk-0 ______ 0 8000000 (8MHz)
spba_clk-0 ipg_clk-0 ______ 1 66500000 (66MHz)
uart_ipg_clk-2 ipg_clk-0 ______ 0 66500000 (66MHz)
uart_clk-2 uart_main_clk-0 ______ 0 66500000 (66MHz)
uart_ipg_clk-1 ipg_clk-0 ______ 0 66500000 (66MHz)
uart_clk-1 uart_main_clk-0 ______ 0 66500000 (66MHz)
uart_ipg_clk-0 ipg_clk-0 ______ 1 66500000 (66MHz)
uart_clk-0 uart_main_clk-0 ______ 2 66500000 (66MHz)
uart_main_clk-0 pll2-0 P_____ 1 66500000 (66MHz)
csi_mclk2-0 pll3-0 ______ 0 54000000 (54MHz)
csi_mclk1-0 pll3-0 ______ 0 24000000 (24MHz)
tve_clk-0 pll3-0 ___TH_ 0 216000000 (216MHz)
ipu_di1_clk-1 tve_clk-0 ______ 0 27000000 (27MHz)
ipu_di0_clk-0 pll3-0 ______ 0 27000000 (27MHz)
ipu_sec_clk-0 emi_fast_clk-0 ______ 1 160000000 (160MHz)
ipu_clk-0 axi_b_clk-0 ___T_M 1 133000000 (133MHz)
sdma_ipg_clk-0 ipg_clk-0 ______ 1 66500000 (66MHz)
sdma_ahb_clk-0 ahb_clk-0 ______ 1 133000000 (133MHz)
aips_tz2_clk-0 ahb_clk-0 ______ 0 133000000 (133MHz)
aips_tz1_clk-0 ahb_clk-0 ______ 0 133000000 (133MHz)
ahbmux2_clk-0 ahb_clk-0 ______ 1 133000000 (133MHz)
ahbmux1_clk-0 ahb_clk-0 ______ 1 133000000 (133MHz)
ipg_perclk-0 lp_apm-0 P_____ 2 8000000 (8MHz)
ipg_clk-0 ahb_clk-0 P_____ 7 66500000 (66MHz)
max_clk-0 ahb_clk-0 ______ 3 133000000 (133MHz)
ahb_clk-0 main_bus_clk-0 P_____ 9 133000000 (133MHz)
axi_b_clk-0 main_bus_clk-0 P_____ 1 133000000 (133MHz)
axi_a_clk-0 main_bus_clk-0 P_____ 0 166250000 (166MHz)
main_bus_clk-0 pll2-0 P_____ 3 665000000 (665MHz)
periph_apm_clk-0 pll1_sw_clk-0 P_____ 0 800000000 (800MHz)
cpu_clk-0 pll1_sw_clk-0 ______ 1 800000000 (800MHz)
lp_apm-0 osc-0 P_____ 2 24000000 (24MHz)
gpc_dvfs_clk-0 ______ 0 0 (0Hz)
pll3-0 osc-0 P_____ 0 216000000 (216MHz)
pll2-0 osc-0 P_____ 3 665000000 (665MHz)
pll1_sw_clk-0 pll1_main_clk-0 P_____ 2 800000000 (800MHz)
pll1_main_clk-0 osc-0 P_____ 1 800000000 (800MHz)
fpm_div2_clk-0 fpm_clk-0 P_____ 0 16777216 (16MHz)
fpm_clk-0 ckil-0 P_____ 0 33554432 (33MHz)
ckil-0 P_____ 0 32768 (32KHz)
ckih2-0 P_____ 0 24576000 (24MHz)
ckih-0 P_____ 0 22579200 (22MHz)
osc-0 P_____ 4 24000000 (24MHz)
#
2010年1月5日 星期二
android power management
PM_SUSPEND_MEM -> mxc_cpu_lp_set(STOP_POWER_OFF)
PM_SUSPEND_STANDBY-> mxc_cpu_lp_set(WAIT_UNLOCKED_POWER_OFF)
~/myandroid/frameworks/base/services/java/com/android/server/PowerManagerService.java]
It offers the core service and is encapsulated as the package com.android.server. It calls Power.java to do the real job.
[~/myandroid/frameworks/base/core/java/android/os/Power.java]
It will communicate with the low level through JNI.
[~/myandroid/frameworks/base/core/jni/android_os_Power.cpp]
It is the JNI implementation for Power.java. It will call lower level power.c
[~/myandroid/hardware/libhardware_legacy/power/power.c]
In this file, it offers some functions, like initialize_fds(), though writing or reading some files, to control the power divice driver.
On the kernel side,
[~/myandroid/kernel_imx/include/linux/sysfs.h]
A macro __ATTR is defined in this file.
[~/myandroid/kernel_imx/kernel/power/main.c]
state_show() and state_store() are defined in this file. In state_store(), request_suspend_state function is called.
这个东东又不是驱动——我不清楚它是如何将最简单的用户态系统调用write最终映射到这个
> state_store上来的(或者说我没有找到的某个更上层的函数)~
这个涉及到sysfs文件系统和kobject.
在state_store下面有个宏power_attr(state),它定义了一个kobj_attribute (state_attr), 在pm_init()的时候会创建一个名为power的kobject.最后通过sysfs_create_group会在/sys/下面创建一个 power的目录,这个目录下面会后所有在kernel/power/main.c里定义的attribute(在g[]中), 包括state_attr.读写这些attribute的话就会调用相应attribute的show和store函数。这些都是在sysfs里面做的,使用者只需准备好这些函数就行了。
call trace is like following:
sys_write -> sysfs_write_file -> flush_write_buffer -> sysfs_ops.store
(sysfs_ops在open一个sysfs文件的时候会设置,这里是kobj_sysfs_ops)
-> kobj_sysfs_ops.store (kobj_attr_store) -> state_store
[~/myandroid/kernel_imx/kernel/power/earlysuspend.c]
The request_suspend_state() is defined here and it will generate the debug info about suspend status changing in console.
PM_SUSPEND_STANDBY-> mxc_cpu_lp_set(WAIT_UNLOCKED_POWER_OFF)
~/myandroid/frameworks/base/services/java/com/android/server/PowerManagerService.java]
It offers the core service and is encapsulated as the package com.android.server. It calls Power.java to do the real job.
[~/myandroid/frameworks/base/core/java/android/os/Power.java]
It will communicate with the low level through JNI.
[~/myandroid/frameworks/base/core/jni/android_os_Power.cpp]
It is the JNI implementation for Power.java. It will call lower level power.c
[~/myandroid/hardware/libhardware_legacy/power/power.c]
In this file, it offers some functions, like initialize_fds(), though writing or reading some files, to control the power divice driver.
On the kernel side,
[~/myandroid/kernel_imx/include/linux/sysfs.h]
A macro __ATTR is defined in this file.
[~/myandroid/kernel_imx/kernel/power/main.c]
state_show() and state_store() are defined in this file. In state_store(), request_suspend_state function is called.
这个东东又不是驱动——我不清楚它是如何将最简单的用户态系统调用write最终映射到这个
> state_store上来的(或者说我没有找到的某个更上层的函数)~
这个涉及到sysfs文件系统和kobject.
在state_store下面有个宏power_attr(state),它定义了一个kobj_attribute (state_attr), 在pm_init()的时候会创建一个名为power的kobject.最后通过sysfs_create_group会在/sys/下面创建一个 power的目录,这个目录下面会后所有在kernel/power/main.c里定义的attribute(在g[]中), 包括state_attr.读写这些attribute的话就会调用相应attribute的show和store函数。这些都是在sysfs里面做的,使用者只需准备好这些函数就行了。
call trace is like following:
sys_write -> sysfs_write_file -> flush_write_buffer -> sysfs_ops.store
(sysfs_ops在open一个sysfs文件的时候会设置,这里是kobj_sysfs_ops)
-> kobj_sysfs_ops.store (kobj_attr_store) -> state_store
[~/myandroid/kernel_imx/kernel/power/earlysuspend.c]
The request_suspend_state() is defined here and it will generate the debug info about suspend status changing in console.
2009年12月24日 星期四
2009年12月10日 星期四
android: pass value from system
1) method 1
import android.os.SystemProperties;
String strResult = SystemProperties.get("hw.VIDEO_TVOUT_DISPLAY");
SystemProperties.set("hw.VIDEO_TVOUT_DISPLAY", "1");
2) method 2
Settings.System.getInt(getContentResolver(), "PlayVieo", 0);
Settings.System.putInt(getContentResolver(), "PlayVieo", 1);
import android.provider.Settings;
import android.os.SystemProperties;
String strResult = SystemProperties.get("hw.VIDEO_TVOUT_DISPLAY");
SystemProperties.set("hw.VIDEO_TVOUT_DISPLAY", "1");
2) method 2
Settings.System.getInt(getContentResolver(), "PlayVieo", 0);
Settings.System.putInt(getContentResolver(), "PlayVieo", 1);
import android.provider.Settings;
2009年12月8日 星期二
Android wifi on off tutorial
Turn off, Turn on wifi in android using code tutorial
For list of android tutorial click here
Here is how to turn on and turn off wifi in android.
First you need to declare the following in your manifest file
XML | copy code | ?
1
2
3
4
After doing it that on your Activity class
Java | copy code | ?
01
private WifiManager wifiManager;
02
@Override
03
public void onCreate(Bundle icicle) {
04
....................
05
wifiManager = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
06
if(wifiManager.isWifiEnabled()){
07
wifiManager.setWifiEnabled(false);
08
}else{
09
wifiManager.setWifiEnabled(true);
10
}
11
}
Explanation
Get the Wifi service from our system
wifiManager = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
Check the our wifi is currently turned on or turned off
if(wifiManager.isWifiEnabled()){
Turn on/off our wifi
wifiManager.setWifiEnabled();
Reference
WifiEnabler
Permissions Journey: ACCESS_WIFI_STATE
Share and Enjoy:
* Digg
* Sphinn
* del.icio.us
* Facebook
* Mixx
* Google Bookmarks
* Reddit
* Yahoo! Buzz
* email
* Fark
* HackerNews
* PDF
* Slashdot
* StumbleUpon
* Technorati
October 17th, 2009 | Tags: Wifi | Category: Android | One comment
1 comment to Turn off, Turn on wifi in android using code tutorial
For list of android tutorial click here
Here is how to turn on and turn off wifi in android.
First you need to declare the following in your manifest file
XML | copy code | ?
1
2
3
4
After doing it that on your Activity class
Java | copy code | ?
01
private WifiManager wifiManager;
02
@Override
03
public void onCreate(Bundle icicle) {
04
....................
05
wifiManager = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
06
if(wifiManager.isWifiEnabled()){
07
wifiManager.setWifiEnabled(false);
08
}else{
09
wifiManager.setWifiEnabled(true);
10
}
11
}
Explanation
Get the Wifi service from our system
wifiManager = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
Check the our wifi is currently turned on or turned off
if(wifiManager.isWifiEnabled()){
Turn on/off our wifi
wifiManager.setWifiEnabled(
Reference
WifiEnabler
Permissions Journey: ACCESS_WIFI_STATE
Share and Enjoy:
* Digg
* Sphinn
* del.icio.us
* Mixx
* Google Bookmarks
* Yahoo! Buzz
* Fark
* HackerNews
* Slashdot
* StumbleUpon
* Technorati
October 17th, 2009 | Tags: Wifi | Category: Android | One comment
1 comment to Turn off, Turn on wifi in android using code tutorial
install android sDK and eclipse
http://hi.baidu.com/samson2008/blog/item/276b2d505149e2561138c23e.html
2009年12月7日 星期一
2009年12月3日 星期四
Android的电源管理
Android的电源管理
接下来我们从Java应用层面, Android framework层面, Linux内核层面分别进行详细的讨论:
应用层的使用:
Android提供了现成android.os.PowerManager类,该类用于控制设备的电源状态的切换.
该类对外有三个接口函数:
void goToSleep(long time); //强制设备进入Sleep状态
Note:
尝试在应用层调用该函数,却不能成功,出现的错误好象是权限不够, 但在Framework下面的Service里调用是可以的.
newWakeLock(int flags, String tag);//取得相应层次的锁
flags参数说明:
PARTIAL_WAKE_LOCK: Screen off, keyboard light off
SCREEN_DIM_WAKE_LOCK: screen dim, keyboard light off
SCREEN_BRIGHT_WAKE_LOCK: screen bright, keyboard light off
FULL_WAKE_LOCK: screen bright, keyboard bright
ACQUIRE_CAUSES_WAKEUP: 一旦有请求锁时强制打开Screen和keyboard light
ON_AFTER_RELEASE: 在释放锁时reset activity timer
Note:
如果申请了partial wakelock,那么即使按Power键,系统也不会进Sleep,如Music播放时
如果申请了其它的wakelocks,按Power键,系统还是会进Sleep
void userActivity(long when, boolean noChangeLights);//User activity事件发生,设备会被切换到Full on的状态,同时Reset Screen off timer.
Sample code:
PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock (PowerManager.SCREEN_DIM_WAKE_LOCK, “My Tag”);
wl.acquire();
…….
wl.release();
Note:
1. 在使用以上函数的应用程序中,必须在其Manifest.xml文件中加入下面的权限:
2. 所有的锁必须成对的使用,如果申请了而没有及时释放会造成系统故障.如申请了partial wakelock,而没有及时释放,那系统就永远进不了Sleep模式.
Android Framework层面:
其主要代码文件如下:
frameworks\base\core\java\android\os\PowerManager.java
frameworks\base\services\java\com\android\server\PowerManagerService.java
frameworks\base\core\java\android\os\Power.java
frameworks\base\core\jni\android_os_power.cpp
hardware\libhardware\power\power.c
其中PowerManagerService.java是核心, Power.java提供底层的函数接口,与JNI层进行交互, JNI层的代码主要在文件android_os_Power.cpp中,与Linux kernel交互是通过Power.c来实现的, Andriod跟Kernel的交互主要是通过sys文件的方式来实现的,具体请参考Kernel层的介绍.
这一层的功能相对比较复杂,比如系统状态的切换,背光的调节及开关,Wake Lock的申请和释放等等,但这一层跟硬件平台无关,而且由Google负责维护,问题相对会少一些,有兴趣的朋友可以自己查看相关的代码.
Kernel层:
其主要代码在下列位置:
drivers/android/power.c
其对Kernel提供的接口函数有
EXPORT_SYMBOL(android_init_suspend_lock); //初始化Suspend lock,在使用前必须做初始化
EXPORT_SYMBOL(android_uninit_suspend_lock); //释放suspend lock相关的资源
EXPORT_SYMBOL(android_lock_suspend); //申请lock,必须调用相应的unlock来释放它
EXPORT_SYMBOL(android_lock_suspend_auto_expire);//申请partial wakelock, 定时时间到后会自动释放
EXPORT_SYMBOL(android_unlock_suspend); //释放lock
EXPORT_SYMBOL(android_power_wakeup); //唤醒系统到on
EXPORT_SYMBOL(android_register_early_suspend); //注册early suspend的驱动
EXPORT_SYMBOL(android_unregister_early_suspend); //取消已经注册的early suspend的驱动
提供给Android Framework层的proc文件如下:
"/sys/android_power/acquire_partial_wake_lock" //申请partial wake lock
"/sys/android_power/acquire_full_wake_lock" //申请full wake lock
"/sys/android_power/release_wake_lock" //释放相应的wake lock
"/sys/android_power/request_state" //请求改变系统状态,进standby和回到wakeup两种状态
"/sys/android_power/state" //指示当前系统的状态
Android的电源管理主要是通过Wake lock来实现的,在最底层主要是通过如下三个队列来实现其管理:
static LIST_HEAD(g_inactive_locks);
static LIST_HEAD(g_active_partial_wake_locks);
static LIST_HEAD(g_active_full_wake_locks);
所有初始化后的lock都会被插入到g_inactive_locks的队列中,而当前活动的partial wake lock都会被插入到g_active_partial_wake_locks队列中, 活动的full wake lock被插入到g_active_full_wake_locks队列中, 所有的partial wake lock 和full wake lock在过期后或unlock后都会被移到inactive的队列,等待下次的调用.
在Kernel层使用wake lock步骤如下:
1. 调用函数android_init_suspend_lock初始化一个wake lock
2. 调用相关申请lock的函数android_lock_suspend 或 android_lock_suspend_auto_expire请求lock,这里只能申请partial wake lock, 如果要申请Full wake lock,则需要调用函数android_lock_partial_suspend_auto_expire(该函数没有EXPORT出来),这个命名有点奇怪,不要跟前面的android_lock_suspend_auto_expire搞混了.
3. 如果是auto expire的wake lock则可以忽略,不然则必须及时的把相关的wake lock释放掉,否则会造成系统长期运行在高功耗的状态.
4. 在驱动卸载或不再使用Wake lock时请记住及时的调用android_uninit_suspend_lock释放资源.
系统的状态:
USER_AWAKE, //Full on status
USER_NOTIFICATION, //Early suspended driver but CPU keep on
USER_SLEEP // CPU enter sleep mode
其状态切换示意图如下:
系统正常开机后进入到AWAKE状态, Backlight会从最亮慢慢调节到用户设定的亮度,系统screen off timer(settings->sound & display-> Display settings -> Screen timeout)开始计时,在计时时间到之前,如果有任何的activity事件发生,如Touch click, keyboard pressed等事件, 则将Reset screen off timer, 系统保持在AWAKE状态. 如果有应用程序在这段时间内申请了Full wake lock,那么系统也将保持在AWAKE状态, 除非用户按下power key. 在AWAKE状态下如果电池电量低或者是用AC供电screen off timer时间到并且选中Keep screen on while pluged in选项,backlight会被强制调节到DIM的状态.
如果Screen off timer时间到并且没有Full wake lock或者用户按了power key,那么系统状态将被切换到NOTIFICATION,并且调用所有已经注册的g_early_suspend_handlers函数, 通常会把LCD和Backlight驱动注册成early suspend类型,如有需要也可以把别的驱动注册成early suspend, 这样就会在第一阶段被关闭. 接下来系统会判断是否有partial wake lock acquired, 如果有则等待其释放, 在等待的过程中如果有user activity事件发生,系统则马上回到AWAKE状态;如果没有partial wake lock acquired, 则系统会马上调用函数pm_suspend关闭其它相关的驱动, 让CPU进入休眠状态.
系统在Sleep状态时如果检测到任何一个Wakeup source, 则CPU会从Sleep状态被唤醒,并且调用相关的驱动的resume函数,接下来马上调用前期注册的early suspend驱动的resume函数,最后系统状态回到AWAKE状态.这里有个问题就是所有注册过early suspend的函数在进Suspend的第一阶段被调用可以理解,但是在resume的时候, Linux会先调用所有驱动的resume函数,而此时再调用前期注册的early suspend驱动的resume函数有什么意义呢?个人觉得android的这个early suspend和late resume函数应该结合Linux下面的suspend和resume一起使用,而不是单独的使用一个队列来进行管理.
接下来我们从Java应用层面, Android framework层面, Linux内核层面分别进行详细的讨论:
应用层的使用:
Android提供了现成android.os.PowerManager类,该类用于控制设备的电源状态的切换.
该类对外有三个接口函数:
void goToSleep(long time); //强制设备进入Sleep状态
Note:
尝试在应用层调用该函数,却不能成功,出现的错误好象是权限不够, 但在Framework下面的Service里调用是可以的.
newWakeLock(int flags, String tag);//取得相应层次的锁
flags参数说明:
PARTIAL_WAKE_LOCK: Screen off, keyboard light off
SCREEN_DIM_WAKE_LOCK: screen dim, keyboard light off
SCREEN_BRIGHT_WAKE_LOCK: screen bright, keyboard light off
FULL_WAKE_LOCK: screen bright, keyboard bright
ACQUIRE_CAUSES_WAKEUP: 一旦有请求锁时强制打开Screen和keyboard light
ON_AFTER_RELEASE: 在释放锁时reset activity timer
Note:
如果申请了partial wakelock,那么即使按Power键,系统也不会进Sleep,如Music播放时
如果申请了其它的wakelocks,按Power键,系统还是会进Sleep
void userActivity(long when, boolean noChangeLights);//User activity事件发生,设备会被切换到Full on的状态,同时Reset Screen off timer.
Sample code:
PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock (PowerManager.SCREEN_DIM_WAKE_LOCK, “My Tag”);
wl.acquire();
…….
wl.release();
Note:
1. 在使用以上函数的应用程序中,必须在其Manifest.xml文件中加入下面的权限:
2. 所有的锁必须成对的使用,如果申请了而没有及时释放会造成系统故障.如申请了partial wakelock,而没有及时释放,那系统就永远进不了Sleep模式.
Android Framework层面:
其主要代码文件如下:
frameworks\base\core\java\android\os\PowerManager.java
frameworks\base\services\java\com\android\server\PowerManagerService.java
frameworks\base\core\java\android\os\Power.java
frameworks\base\core\jni\android_os_power.cpp
hardware\libhardware\power\power.c
其中PowerManagerService.java是核心, Power.java提供底层的函数接口,与JNI层进行交互, JNI层的代码主要在文件android_os_Power.cpp中,与Linux kernel交互是通过Power.c来实现的, Andriod跟Kernel的交互主要是通过sys文件的方式来实现的,具体请参考Kernel层的介绍.
这一层的功能相对比较复杂,比如系统状态的切换,背光的调节及开关,Wake Lock的申请和释放等等,但这一层跟硬件平台无关,而且由Google负责维护,问题相对会少一些,有兴趣的朋友可以自己查看相关的代码.
Kernel层:
其主要代码在下列位置:
drivers/android/power.c
其对Kernel提供的接口函数有
EXPORT_SYMBOL(android_init_suspend_lock); //初始化Suspend lock,在使用前必须做初始化
EXPORT_SYMBOL(android_uninit_suspend_lock); //释放suspend lock相关的资源
EXPORT_SYMBOL(android_lock_suspend); //申请lock,必须调用相应的unlock来释放它
EXPORT_SYMBOL(android_lock_suspend_auto_expire);//申请partial wakelock, 定时时间到后会自动释放
EXPORT_SYMBOL(android_unlock_suspend); //释放lock
EXPORT_SYMBOL(android_power_wakeup); //唤醒系统到on
EXPORT_SYMBOL(android_register_early_suspend); //注册early suspend的驱动
EXPORT_SYMBOL(android_unregister_early_suspend); //取消已经注册的early suspend的驱动
提供给Android Framework层的proc文件如下:
"/sys/android_power/acquire_partial_wake_lock" //申请partial wake lock
"/sys/android_power/acquire_full_wake_lock" //申请full wake lock
"/sys/android_power/release_wake_lock" //释放相应的wake lock
"/sys/android_power/request_state" //请求改变系统状态,进standby和回到wakeup两种状态
"/sys/android_power/state" //指示当前系统的状态
Android的电源管理主要是通过Wake lock来实现的,在最底层主要是通过如下三个队列来实现其管理:
static LIST_HEAD(g_inactive_locks);
static LIST_HEAD(g_active_partial_wake_locks);
static LIST_HEAD(g_active_full_wake_locks);
所有初始化后的lock都会被插入到g_inactive_locks的队列中,而当前活动的partial wake lock都会被插入到g_active_partial_wake_locks队列中, 活动的full wake lock被插入到g_active_full_wake_locks队列中, 所有的partial wake lock 和full wake lock在过期后或unlock后都会被移到inactive的队列,等待下次的调用.
在Kernel层使用wake lock步骤如下:
1. 调用函数android_init_suspend_lock初始化一个wake lock
2. 调用相关申请lock的函数android_lock_suspend 或 android_lock_suspend_auto_expire请求lock,这里只能申请partial wake lock, 如果要申请Full wake lock,则需要调用函数android_lock_partial_suspend_auto_expire(该函数没有EXPORT出来),这个命名有点奇怪,不要跟前面的android_lock_suspend_auto_expire搞混了.
3. 如果是auto expire的wake lock则可以忽略,不然则必须及时的把相关的wake lock释放掉,否则会造成系统长期运行在高功耗的状态.
4. 在驱动卸载或不再使用Wake lock时请记住及时的调用android_uninit_suspend_lock释放资源.
系统的状态:
USER_AWAKE, //Full on status
USER_NOTIFICATION, //Early suspended driver but CPU keep on
USER_SLEEP // CPU enter sleep mode
其状态切换示意图如下:
系统正常开机后进入到AWAKE状态, Backlight会从最亮慢慢调节到用户设定的亮度,系统screen off timer(settings->sound & display-> Display settings -> Screen timeout)开始计时,在计时时间到之前,如果有任何的activity事件发生,如Touch click, keyboard pressed等事件, 则将Reset screen off timer, 系统保持在AWAKE状态. 如果有应用程序在这段时间内申请了Full wake lock,那么系统也将保持在AWAKE状态, 除非用户按下power key. 在AWAKE状态下如果电池电量低或者是用AC供电screen off timer时间到并且选中Keep screen on while pluged in选项,backlight会被强制调节到DIM的状态.
如果Screen off timer时间到并且没有Full wake lock或者用户按了power key,那么系统状态将被切换到NOTIFICATION,并且调用所有已经注册的g_early_suspend_handlers函数, 通常会把LCD和Backlight驱动注册成early suspend类型,如有需要也可以把别的驱动注册成early suspend, 这样就会在第一阶段被关闭. 接下来系统会判断是否有partial wake lock acquired, 如果有则等待其释放, 在等待的过程中如果有user activity事件发生,系统则马上回到AWAKE状态;如果没有partial wake lock acquired, 则系统会马上调用函数pm_suspend关闭其它相关的驱动, 让CPU进入休眠状态.
系统在Sleep状态时如果检测到任何一个Wakeup source, 则CPU会从Sleep状态被唤醒,并且调用相关的驱动的resume函数,接下来马上调用前期注册的early suspend驱动的resume函数,最后系统状态回到AWAKE状态.这里有个问题就是所有注册过early suspend的函数在进Suspend的第一阶段被调用可以理解,但是在resume的时候, Linux会先调用所有驱动的resume函数,而此时再调用前期注册的early suspend驱动的resume函数有什么意义呢?个人觉得android的这个early suspend和late resume函数应该结合Linux下面的suspend和resume一起使用,而不是单独的使用一个队列来进行管理.
2009年12月2日 星期三
add domain_name_servers to default reqeust options
add domain_name_servers to default reqeust options donut-x86 master android-x86-1.6
author Chih-Wei Huang
Wed, 2 Sep 2009 06:57:13 +0000 (14:57 +0800)
committer Chih-Wei Huang
Wed, 2 Sep 2009 06:57:13 +0000 (14:57 +0800)
dhcpcd.c
patch | blob | history
diff --git a/dhcpcd.c b/dhcpcd.c
index e674bd2..f4f21c3 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -659,8 +659,8 @@ main(int argc, char **argv)
VENDORCLASSID_MAX_LEN,
"%s %s", PACKAGE, VERSION);
-#ifdef CMDLINE_COMPAT
add_option_mask(options->requestmask, DHO_DNSSERVER);
+#ifdef CMDLINE_COMPAT
add_option_mask(options->requestmask, DHO_DNSDOMAIN);
add_option_mask(options->requestmask, DHO_DNSSEARCH);
add_option_mask(options->requestmask, DHO_NISSERVER);
/system/core/libnetutil
/external/dhcpcd
frameworks/base/core/java/android/net/MobileDataState.java
author Chih-Wei Huang
Wed, 2 Sep 2009 06:57:13 +0000 (14:57 +0800)
committer Chih-Wei Huang
Wed, 2 Sep 2009 06:57:13 +0000 (14:57 +0800)
dhcpcd.c
patch | blob | history
diff --git a/dhcpcd.c b/dhcpcd.c
index e674bd2..f4f21c3 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -659,8 +659,8 @@ main(int argc, char **argv)
VENDORCLASSID_MAX_LEN,
"%s %s", PACKAGE, VERSION);
-#ifdef CMDLINE_COMPAT
add_option_mask(options->requestmask, DHO_DNSSERVER);
+#ifdef CMDLINE_COMPAT
add_option_mask(options->requestmask, DHO_DNSDOMAIN);
add_option_mask(options->requestmask, DHO_DNSSEARCH);
add_option_mask(options->requestmask, DHO_NISSERVER);
/system/core/libnetutil
/external/dhcpcd
frameworks/base/core/java/android/net/MobileDataState.java
2009年11月28日 星期六
WIFI DNS ANDROID
android-porting
Thread Date
[android-porting] Re: android DNS fail to resolve website IP adddres
vinay
Tue, 03 Feb 2009 19:36:50 -0800
On Thu, Jan 29, 2009 at 11:47 AM, vinay wrote:
> hi,
>
> DNS started working after setting net dns proprty.. ,
> setprop net.dns1
>
> thanks,
> -vinay
>
> On Wed, Jan 21, 2009 at 12:10 PM, Sean McNeilwrote:
>
>>
>> eth1 isn't a valid device for tracking. Take a look at
>> frameworks/base/core/java/android/net/MobileDataStateTracker.java.
>> You'll see that it really only looks at rmnet0, eth0, and gprs. For DNS
>> to work, the net.dns# properties need to get set. You'll either have to
>> add eth1 into the MobileDataStateTracker, get the wifi to set net.dns#,
>> or change your kernel so the wifi is eth0.
>>
>> vinay wrote:
>> > hi,
>> > I have configured wifi with custom driver and able to connect to
>> > secured Access point. But IP resolv for website link is not
>> > happening. If I type IP address in the url then browser opens the
>> > site.
>> >
>> > Are there any known problems/limitations with DNS deployment in
>> > android on real target ?
>> >
>> > below getprop detaiils:--------------
>> > [dhcp.eth1.dns1]: [192.168.200.100]
>> > [dhcp.eth1.dns2]: []
>> > [dhcp.eth1.dns3]: []
>> > [dhcp.eth1.dns4]: []
>> > [dhcp.eth1.reason]: [BOUND]
>> > [dhcp.eth1.ipaddress]: [192.168.200.104]
>> > [dhcp.eth1.gateway]: [192.168.200.100]
>> > [dhcp.eth1.mask]: [255.255.255.0]
>> > [dhcp.eth1.leasetime]: [86400]
>> > [dhcp.eth1.server]: [192.168.200.100]
>> > [dhcp.eth1.result]: [ok]
>> >
>> > In browser AndroidManifest.xml ---------
>> > is
>> > also present.
>> >
>> > logcat detail below---------------
>> > I/ActivityManager( 1553): Starting activity: Intent
>> > { action=android.intent.ac
>> > tion.VIEW categories={android.intent.category.BROWSABLE} data=http://
>> > 164.129.225
>> > .192/ comp={com.android.browser/com.android.browser.BrowserActivity} }
>> > D/dalvikvm( 1672): GC freed 2989 objects / 215368 bytes in 144ms
>> > D/browser ( 1672): updating cursor
>> > D/dalvikvm( 1672): GC freed 4780 objects / 439912 bytes in 112ms
>> > W/KeyCharacterMap( 1672): No keyboard for id 0
>> > W/KeyCharacterMap( 1672): Using default keymap: /system/usr/keychars/
>> > qwerty.kcm.
>> > bin
>> > D/browser ( 1672): updating cursor
>> > I/ActivityManager( 1553): Starting activity: Intent
>> > { action=android.intent.acti
>> > on.VIEW categories={android.intent.category.BROWSABLE} data=http://
>> > stway.st.com/
>> > comp={com.android.browser/com.android.browser.BrowserActivity} }
>> > E/browser ( 1672): onReceivedError code:-2 The URL could not be found.
>> > D/browser ( 1672): updating cursor
>> >
>> > # cat /proc/net/route ------------
>> > Iface Destination Gateway Flags RefCnt Use
>> > Metric Mask M
>> > TU Window IRTT
>> > eth1 00C8A8C0 00000000 0001 0 0
>> > 0 00FFFFF0
>> >
>> > eth1 00000000 64C8A8C0 0003 0 0
>> > 0 00000000
>> >
>> > >
>> >
>>
>>
>> >>
>>
>
--~--~---------~--~----~------------~-------~--~----~
unsubscribe: android-porting+unsubscr...@googlegroups.com
website: http://groups.google.com/group/android-porting
-~----------~----~----~----~------~----~------~--~---
[android-porting] android DNS fail to resolve website IP adddres vinay
[android-porting] Re: android DNS fail to resolve website IP adddres Sean McNeil
[android-porting] Re: android DNS fail to resolve website IP adddres vinay
[android-porting] Re: android DNS fail to resolve website IP adddres vinay
Reply via email to
Thread Date
[android-porting] Re: android DNS fail to resolve website IP adddres
vinay
Tue, 03 Feb 2009 19:36:50 -0800
On Thu, Jan 29, 2009 at 11:47 AM, vinay
> hi,
>
> DNS started working after setting net dns proprty.. ,
> setprop net.dns1
>
> thanks,
> -vinay
>
> On Wed, Jan 21, 2009 at 12:10 PM, Sean McNeil
>
>>
>> eth1 isn't a valid device for tracking. Take a look at
>> frameworks/base/core/java/android/net/MobileDataStateTracker.java.
>> You'll see that it really only looks at rmnet0, eth0, and gprs. For DNS
>> to work, the net.dns# properties need to get set. You'll either have to
>> add eth1 into the MobileDataStateTracker, get the wifi to set net.dns#,
>> or change your kernel so the wifi is eth0.
>>
>> vinay wrote:
>> > hi,
>> > I have configured wifi with custom driver and able to connect to
>> > secured Access point. But IP resolv for website link is not
>> > happening. If I type IP address in the url then browser opens the
>> > site.
>> >
>> > Are there any known problems/limitations with DNS deployment in
>> > android on real target ?
>> >
>> > below getprop detaiils:--------------
>> > [dhcp.eth1.dns1]: [192.168.200.100]
>> > [dhcp.eth1.dns2]: []
>> > [dhcp.eth1.dns3]: []
>> > [dhcp.eth1.dns4]: []
>> > [dhcp.eth1.reason]: [BOUND]
>> > [dhcp.eth1.ipaddress]: [192.168.200.104]
>> > [dhcp.eth1.gateway]: [192.168.200.100]
>> > [dhcp.eth1.mask]: [255.255.255.0]
>> > [dhcp.eth1.leasetime]: [86400]
>> > [dhcp.eth1.server]: [192.168.200.100]
>> > [dhcp.eth1.result]: [ok]
>> >
>> > In browser AndroidManifest.xml ---------
>> >
>> > also present.
>> >
>> > logcat detail below---------------
>> > I/ActivityManager( 1553): Starting activity: Intent
>> > { action=android.intent.ac
>> > tion.VIEW categories={android.intent.category.BROWSABLE} data=http://
>> > 164.129.225
>> > .192/ comp={com.android.browser/com.android.browser.BrowserActivity} }
>> > D/dalvikvm( 1672): GC freed 2989 objects / 215368 bytes in 144ms
>> > D/browser ( 1672): updating cursor
>> > D/dalvikvm( 1672): GC freed 4780 objects / 439912 bytes in 112ms
>> > W/KeyCharacterMap( 1672): No keyboard for id 0
>> > W/KeyCharacterMap( 1672): Using default keymap: /system/usr/keychars/
>> > qwerty.kcm.
>> > bin
>> > D/browser ( 1672): updating cursor
>> > I/ActivityManager( 1553): Starting activity: Intent
>> > { action=android.intent.acti
>> > on.VIEW categories={android.intent.category.BROWSABLE} data=http://
>> > stway.st.com/
>> > comp={com.android.browser/com.android.browser.BrowserActivity} }
>> > E/browser ( 1672): onReceivedError code:-2 The URL could not be found.
>> > D/browser ( 1672): updating cursor
>> >
>> > # cat /proc/net/route ------------
>> > Iface Destination Gateway Flags RefCnt Use
>> > Metric Mask M
>> > TU Window IRTT
>> > eth1 00C8A8C0 00000000 0001 0 0
>> > 0 00FFFFF0
>> >
>> > eth1 00000000 64C8A8C0 0003 0 0
>> > 0 00000000
>> >
>> > >
>> >
>>
>>
>> >>
>>
>
--~--~---------~--~----~------------~-------~--~----~
unsubscribe: android-porting+unsubscr...@googlegroups.com
website: http://groups.google.com/group/android-porting
-~----------~----~----~----~------~----~------~--~---
[android-porting] android DNS fail to resolve website IP adddres vinay
[android-porting] Re: android DNS fail to resolve website IP adddres Sean McNeil
[android-porting] Re: android DNS fail to resolve website IP adddres vinay
[android-porting] Re: android DNS fail to resolve website IP adddres vinay
Reply via email to
2009年11月27日 星期五
浅析android下如何通过jni监控wifi
December 18
浅析android下如何通过jni监控wifi(三)
jni
=>runDhcp
=>android_net_utils_runDhcp
libs/netutils/dhcp_utils.c
=>dhcp_do_request
=>
static const char DAEMON_NAME[] = "dhcpcd";
static const char DAEMON_PROP_NAME[] = "init.svc.dhcpcd";
static const char DHCP_PROP_NAME_PREFIX[] = "dhcp";
const char *ctrl_prop = "ctl.start";
const char *desired_status = "running";
snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
DHCP_PROP_NAME_PREFIX,
interface);
property_set(result_prop_name, "");//设置dhcp.eth0.result="";等到成功完成dhcp之后,
property_set(ctrl_prop, DAEMON_NAME);//向名字为dhcpcd的service,发送"ctrl.start"启动命令字,该service在init.rc中
//init.rc中dhcpcd服务进程命令字
//service dhcpcd /system/bin/dhcpcd eth0
// disabled
// oneshot
wait_for_property(DAEMON_PROP_NAME, desired_status, 10);
//init.c=>init进程
//=>handle_property_set_fd因为是"ctrl.start"命令字,所以调用handle_control_message处理控制信息
//=>handle_control_message
//=>msg_start
//=>
// struct service *svc = service_find_by_name(name);
// service_start(svc);//启动svc,即执行:/system/bin/dhcpcd eth0
//=>service_start
//=>pid = fork();
// if(pid == 0)execve(svc->args[0], (char**) svc->args, (char**) ENV);子进程执行execve运行/system/bin/dhcpcd,参数为eth0
//=>否则父进程,即init进程将
//=>notify_service_state(svc->name, "running");设置该svc的状态prop
// snprintf(pname, sizeof(pname), "init.svc.%s", name);
// property_set(pname, state);//所以这样上面wait_for_property(DAEMON_PROP_NAME, desired_status, 10);也才能够正常pass[luther.gliethttp].
wait_for_property(result_prop_name, NULL, 15);//等待dhcp.eth0.result=非空
=============================================================================================================
system/extra/dhcpcd-4.0.0-beta9/dhcpcd.c
dhcpcd
=>main
# define SYSCONFDIR "/system/etc/dhcpcd"
#define PACKAGE "dhcpcd"
# define CONFIG SYSCONFDIR "/" PACKAGE ".conf"
# define LIBEXECDIR "/system/etc/dhcpcd"
# define SCRIPT LIBEXECDIR "/" PACKAGE "-run-hooks"
=>strlcpy(options->script, SCRIPT, sizeof(options->script));//默认的options->script="/system/etc/dhcpcd/dhcpcd-run-hooks"
=>f = fopen(cf ? cf : CONFIG, "r");//如果没有指定.conf文件,那么使用默认.conf文件
=>parse_config_line//解析"/system/etc/dhcpcd/dhcpcd.conf"默认配置文件
=>parse_option
=>如果在"/system/etc/dhcpcd/dhcpcd.conf"有"script"这个节
=>那么执行strlcpy(options->script, oarg, sizeof(options->script));直接拷贝
/*
{"script", required_argument, NULL, 'c'},
{"option", required_argument, NULL, 'o'},
"/system/etc/dhcpcd/dhcpcd.conf"中的部分内容如下:
...
option domain_name_servers, domain_name, domain_search, host_name
...
*/
=>dhcp_run
=>handle_dhcp_packet
=>handle_dhcp
=>bind_dhcp
reason = "TIMEOUT";reason = "BOUND";reason = "REBIND";reason = "RENEW";
system/extra/dhcpcd-4.0.0-beta9/configure.c
=> configure(iface, reason, state->new, state->old, &state->lease, options, 1);
//如果dhcp超时或者dhcp成功,都会调用exec_script来执行脚本,
//执行setprop dhcp.${interface}.result "failed"或者
//执行setprop dhcp.${interface}.result "ok"
=>exec_script(options, iface->name, reason, NULL, old);
=>然后configure_env通过环境变量将reason传递到脚本中
int exec_script(const struct options *options, const char *iface, const char *reason,
const struct dhcp_message *dhcpn, const struct dhcp_message *dhcpo)
=>pid = fork();
=>if(pid == 0)execve(options->script, argv, env);//子进程执行脚本,默认"/system/etc/dhcpcd/dhcpcd-run-hooks"
//dhcpcd-run-hooks脚本会根据level值,决定是否执行system/etc/dhcpcd/dhcpcd-hook/*目录下的相应文件
//我们的系统在该system/etc/dhcpcd/dhcpcd-hook/*目录下有如下3个文件
//95-configured
//20-dns.conf
//01-test
=>父进程返回while (waitpid(pid, &status, 0) == -1)等待子进程脚本执行完成
system/extra/dhcpcd-4.0.0-beta9/dhcpcd-hooks/20-dns.conf
system/extra/dhcpcd-4.0.0-beta9/dhcpcd-hooks/95-configured
...
setprop dhcp.${interface}.ipaddress "${new_ip_address}"
setprop dhcp.${interface}.result "ok"//设置属性为ok
setprop dhcp.${interface}.result "failed"
...
=============================================================================================================
inet_init、tcp_prot
sock->ops->sendmsg(iocb, sock, msg, size);
=>inetsw_array[]
=>inet_stream_ops
=>tcp_sendmsg
=============================================================================================================
wpa_cli.c
=>main
=>wpa_cli_interactive
=>wpa_cli_recv_pending(monitor_conn, 0, 0);//阻塞等待wpa_supplicant发送数据过来
=>如果action_monitor为true,那么将执行一些简单加工操作,否则将直接将wpa_supplicant发过来的数据打印到console上[luther.gliethttp].
============================================================================================================= 2:28 PM | Add a comment | Permalink | Blog it | Android浅析android下如何通过jni监控wifi(二)
//剔除前导控制字符,将" - "后面的描述字符串作为真实数据,继续处理
...
if (event == STATE_CHANGE) {
handleSupplicantStateChange(eventData);
} else if (event == DRIVER_STATE) {
handleDriverEvent(eventData);
} else {
handleEvent(event, eventData);//对于CONNECTED和DISCONNECTED等netlink事件将执行此操作来处理[luther.gliethttp]
// If supplicant is gone, exit the thread
if (event == TERMINATING) {
break;
}
}
...
void handleEvent(int event, String remainder) {
switch (event) {
case DISCONNECTED:
handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED, remainder);
break;
case CONNECTED:
handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder);//控制界面显示
break;
...
}
public class WifiStateTracker extends NetworkStateTracker {
...
public void startEventLoop() {
mWifiMonitor.startMonitoring();//启动上面的MonitorThread线程
}
...
}
java/services/com/android/server/WifiService.java
public class WifiService extends IWifiManager.Stub {
...
private boolean setWifiEnabledBlocking(boolean enable) {
final int eventualWifiState = enable ? WIFI_STATE_ENABLED : WIFI_STATE_DISABLED;
...
if (enable) {
if (WifiNative.loadDriver()) {
Log.e(TAG, "Failed to load Wi-Fi driver.");
updateWifiState(WIFI_STATE_UNKNOWN);
return false;
}
if (WifiNative.startSupplicant()) {
WifiNative.unloadDriver();
Log.e(TAG, "Failed to start supplicant daemon.");
updateWifiState(WIFI_STATE_UNKNOWN);
return false;
}
mWifiStateTracker.startEventLoop();
//启动MonitorThread线程,等待wpa_supplicant将netlink数据转发过来,然后根据netlink动作类型,进一步影响界面显示[luther.gliethttp].
}
...
}
java/android/android/net/wifi/WifiStateTracker.java
电源管理
private void handleConnectedState() {
...
mDhcpTarget.obtainMessage(EVENT_DHCP_START).sendToTarget();//传递到下面的handleMessage方法
...
}
public void onChange(boolean selfChange) {
...
handleConnectedState();
...
}
public class WifiStateTracker extends NetworkStateTracker {
...
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_SUPPLICANT_CONNECTION:
case EVENT_NETWORK_STATE_CHANGED:
handleConnectedState();//调用
...
private class DhcpHandler extends Handler {
private Handler mTarget;
public DhcpHandler(Looper looper, Handler target) {
super(looper);
mTarget = target;
}
public void handleMessage(Message msg) {
int event;
//private static final int DRIVER_POWER_MODE_AUTO = 0;
//private static final int DRIVER_POWER_MODE_ACTIVE = 1;
switch (msg.what) {
case EVENT_DHCP_START:
synchronized (this) {
WifiNative.setPowerModeCommand(DRIVER_POWER_MODE_ACTIVE);//设置电源模式,调用android_net_wifi_setPowerModeCommand
}
Log.d(TAG, "DhcpHandler: DHCP request started");
//libs/android_runtime/android_net_NetUtils.cpp
//static JNINativeMethod gNetworkUtilMethods[] = {
//{ "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpInfo;)Z", (void *)android_net_utils_runDhcp },
// ...
//};
if (NetworkUtils.runDhcp(mInterfaceName, mDhcpInfo)) {//执行dhcp申请ip地址操作
event = EVENT_INTERFACE_CONFIGURATION_SUCCEEDED;
if (LOCAL_LOGD) Log.v(TAG, "DhcpHandler: DHCP request succeeded");
} else {
event = EVENT_INTERFACE_CONFIGURATION_FAILED;
Log.i(TAG, "DhcpHandler: DHCP request failed: " +
NetworkUtils.getDhcpError());
//如果dhcpcd分配ip失败,那么Message.obtain(mTarget, event).sendToTarget();将执行
//WifiNative.disconnectCommand();即:static JNINativeMethod gWifiMethods[] = {
//android_net_wifi_disconnectCommand发送"DISCONNECT"字符串[luther.gliethttp]
//然后在wpa_supplicant服务端执行wpa_supplicant_ctrl_iface_process
//wpa_supplicant_disassociate
}
synchronized (this) {
WifiNative.setPowerModeCommand(DRIVER_POWER_MODE_AUTO);
}
Message.obtain(mTarget, event).sendToTarget();
break;
}
}
}
...
/**
* Send the tracker a notification that a connection to the supplicant
* daemon has been established.
*/
//在上面的public class WifiMonitor=>ensureSupplicantConnection
//=>
//while (!supplicantConnected) {
// boolean connected;
//synchronized (mWifiStateTracker) {
//connected = WifiNative.connectToSupplicant();//如果没有连接成功,那么while循环尝试,直到尝试成功,或者定义了oneShot,仅一次尝试
//=>mWifiStateTracker.notifySupplicantConnection();//如果WifiNative.connectToSupplicant()成功,那么将执行
//mWifiStateTracker.notifySupplicantConnection();的调用.
void notifySupplicantConnection() {//向对象发送message
Message.obtain(this, EVENT_SUPPLICANT_CONNECTION).sendToTarget();
}
void notifyStateChange(SupplicantState newState) {
Message.obtain(this, EVENT_SUPPLICANT_STATE_CHANGED, newState).sendToTarget();
}
...
}
static jboolean android_net_wifi_setPowerModeCommand(JNIEnv* env, jobject clazz, jint mode)
{
char cmdstr[256];
sprintf(cmdstr, "DRIVER POWERMODE %d", mode);
return doBooleanCommand(cmdstr, "OK");
}
android_net_wifi_setPowerModeCommand
=>doBooleanCommand
=>doCommand
=>wifi_command
=>wifi_send_command
=>wpa_ctrl_request
=>send给wpa_supplicant
然后wpa_supplicant将做如下接收操作:
system/extra/wpa_supplicant/main.c
=>wpa_supplicant_add_iface
=>wpa_supplicant_init_iface2
=>wpa_supplicant_ctrl_iface_init
=>注册ctrl_conn控制端口和monitor_conn监听端口的处理函数
eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, wpa_s, priv);//ctrl_conn端口的handler处理函数
wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);//monitor_conn端口的回调处理函数,处理netlink数据到所有monitor_conn监听端口
=>wpa_supplicant_ctrl_iface_receive//对于unix通信方式
=>wpa_supplicant_ctrl_iface_process
=>如果wpa_cli发送的是wpa_cli driver xxx形式的命令,那么调用这个函数
if (os_strncmp(buf, "DRIVER ", 7) == 0) {//掠过前7个,直接将命令传过去
reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply, reply_size);
=>wpa_supplicant_driver_cmd
=>wpa_drv_driver_cmd
=>自定义DRIVER扩展处理函数,所以对于java传递过来的power电源管理命令,wpa_drv_driver_cmd将收到"POWERMODE 0"或者"POWERMODE 1"字符串[luther.gliethttp]
=============================================================================================================
2:27 PM | Add a comment | Permalink | Blog it | Android浅析android下如何通过jni监控wifi(一)
浅析android下如何通过jni监控wifi网络连接、dhcpcd执行和power电源控制
=============================================================================================================
libs/android_runtime/android_net_wifi_Wifi.cpp
部分jni接口
static JNINativeMethod gWifiMethods[] = {
{ "loadDriver", "()Z", (void *)android_net_wifi_loadDriver },
{ "setPowerModeCommand", "(I)Z", (void*) android_net_wifi_setPowerModeCommand },//电源管理
{ "connectToSupplicant", "()Z", (void *)android_net_wifi_connectToSupplicant },
{ "waitForEvent", "()Ljava/lang/String;", (void*) android_net_wifi_waitForEvent },
{ "disconnectCommand", "()Z", (void *)android_net_wifi_disconnectCommand },
...
};
int register_android_net_wifi_WifiManager(JNIEnv* env)
{
...
return AndroidRuntime::registerNativeMethods(env,
WIFI_PKG_NAME, gWifiMethods, NELEM(gWifiMethods));//登记jni
}
libs/android_runtime/AndroidRuntime.cpp
static const RegJNIRec gRegJNI[] = {
...
REG_JNI(register_android_net_wifi_WifiManager),
...
};
int AndroidRuntime::startReg(JNIEnv* env)
{
...
register_jni_procs(gRegJNI, NELEM(gRegJNI), env);
...
}
AndroidRuntime::start
=>startReg(env)即调用方法int AndroidRuntime::startReg(JNIEnv* env)
=============================================================================================================
wifi_load_driver
wifi_start_supplicant
=>ensure_config_file_exists
//检查/data/misc/wifi/wpa_supplicant.conf文件是否存在,如果不存在,那么从/system/etc/wifi/wpa_supplicant.conf动态拷贝一份
android_net_wifi_connectToSupplicant
=>wifi_connect_to_supplicant
=>
ctrl_conn = wpa_ctrl_open(ifname);
monitor_conn = wpa_ctrl_open(ifname);
wpa_ctrl_attach(monitor_conn);
android_net_wifi_waitForEvent
=>wifi_wait_for_event
=>wpa_ctrl_recv(monitor_conn, buf, &nread);
=>recv(ctrl->s, reply, *reply_len, 0);//阻塞等待wpa_supplicant的netlink数据过来
=>如果接收的buf数据区,buf[0]为'<',那么说明有level级别信息,所以将'<'...'>'数据剔除,然后wifi_wait_for_event函数返回[luther.gliethttp].
java/android/android/net/wifi/WifiMonitor.java
public class WifiMonitor {
...
public void startMonitoring() {
new MonitorThread().start();//启动java线程
}
class MonitorThread extends Thread {
public MonitorThread() {
super("WifiMonitor");
}
public void run() {
for (;;) {
ensureSupplicantConnection();//=>WifiNative.connectToSupplicant调用jni函数android_net_wifi_connectToSupplicant
String eventStr = WifiNative.waitForEvent();//=>调用jni函数android_net_wifi_waitForEvent
//private static final int CONNECTED = 1;
//private static final int DISCONNECTED = 2;
//private static final String eventPrefix = "CTRL-EVENT-";
//private static final int eventPrefixLen = eventPrefix.length();
//private static final String connectedEvent = "CONNECTED";
//private static final String disconnectedEvent = "DISCONNECTED";
String eventName = eventStr.substring(eventPrefixLen);//去掉"CTRL-EVENT-"字符串
int nameEnd = eventName.indexOf(' ');//找到随后的空格位置,这在wpa_supplicant发送时
//#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED "中,已经内置空格了.
if (nameEnd != -1)
eventName = eventName.substring(0, nameEnd);
int event;
if (eventName.equals(connectedEvent))//检测netlink过来的字符串action类型
event = CONNECTED;
else if (eventName.equals(disconnectedEvent))
event = DISCONNECTED;
...
int ind = eventStr.indexOf(" - ");//CTRL-EVENT-CONNECTED - Connection to ...
if (ind != -1)
eventData = eventStr.substring(ind + 3);
2:26 PM | Add a comment | Permalink | Blog it | Android
浅析android下如何通过jni监控wifi(三)
jni
=>runDhcp
=>android_net_utils_runDhcp
libs/netutils/dhcp_utils.c
=>dhcp_do_request
=>
static const char DAEMON_NAME[] = "dhcpcd";
static const char DAEMON_PROP_NAME[] = "init.svc.dhcpcd";
static const char DHCP_PROP_NAME_PREFIX[] = "dhcp";
const char *ctrl_prop = "ctl.start";
const char *desired_status = "running";
snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
DHCP_PROP_NAME_PREFIX,
interface);
property_set(result_prop_name, "");//设置dhcp.eth0.result="";等到成功完成dhcp之后,
property_set(ctrl_prop, DAEMON_NAME);//向名字为dhcpcd的service,发送"ctrl.start"启动命令字,该service在init.rc中
//init.rc中dhcpcd服务进程命令字
//service dhcpcd /system/bin/dhcpcd eth0
// disabled
// oneshot
wait_for_property(DAEMON_PROP_NAME, desired_status, 10);
//init.c=>init进程
//=>handle_property_set_fd因为是"ctrl.start"命令字,所以调用handle_control_message处理控制信息
//=>handle_control_message
//=>msg_start
//=>
// struct service *svc = service_find_by_name(name);
// service_start(svc);//启动svc,即执行:/system/bin/dhcpcd eth0
//=>service_start
//=>pid = fork();
// if(pid == 0)execve(svc->args[0], (char**) svc->args, (char**) ENV);子进程执行execve运行/system/bin/dhcpcd,参数为eth0
//=>否则父进程,即init进程将
//=>notify_service_state(svc->name, "running");设置该svc的状态prop
// snprintf(pname, sizeof(pname), "init.svc.%s", name);
// property_set(pname, state);//所以这样上面wait_for_property(DAEMON_PROP_NAME, desired_status, 10);也才能够正常pass[luther.gliethttp].
wait_for_property(result_prop_name, NULL, 15);//等待dhcp.eth0.result=非空
=============================================================================================================
system/extra/dhcpcd-4.0.0-beta9/dhcpcd.c
dhcpcd
=>main
# define SYSCONFDIR "/system/etc/dhcpcd"
#define PACKAGE "dhcpcd"
# define CONFIG SYSCONFDIR "/" PACKAGE ".conf"
# define LIBEXECDIR "/system/etc/dhcpcd"
# define SCRIPT LIBEXECDIR "/" PACKAGE "-run-hooks"
=>strlcpy(options->script, SCRIPT, sizeof(options->script));//默认的options->script="/system/etc/dhcpcd/dhcpcd-run-hooks"
=>f = fopen(cf ? cf : CONFIG, "r");//如果没有指定.conf文件,那么使用默认.conf文件
=>parse_config_line//解析"/system/etc/dhcpcd/dhcpcd.conf"默认配置文件
=>parse_option
=>如果在"/system/etc/dhcpcd/dhcpcd.conf"有"script"这个节
=>那么执行strlcpy(options->script, oarg, sizeof(options->script));直接拷贝
/*
{"script", required_argument, NULL, 'c'},
{"option", required_argument, NULL, 'o'},
"/system/etc/dhcpcd/dhcpcd.conf"中的部分内容如下:
...
option domain_name_servers, domain_name, domain_search, host_name
...
*/
=>dhcp_run
=>handle_dhcp_packet
=>handle_dhcp
=>bind_dhcp
reason = "TIMEOUT";reason = "BOUND";reason = "REBIND";reason = "RENEW";
system/extra/dhcpcd-4.0.0-beta9/configure.c
=> configure(iface, reason, state->new, state->old, &state->lease, options, 1);
//如果dhcp超时或者dhcp成功,都会调用exec_script来执行脚本,
//执行setprop dhcp.${interface}.result "failed"或者
//执行setprop dhcp.${interface}.result "ok"
=>exec_script(options, iface->name, reason, NULL, old);
=>然后configure_env通过环境变量将reason传递到脚本中
int exec_script(const struct options *options, const char *iface, const char *reason,
const struct dhcp_message *dhcpn, const struct dhcp_message *dhcpo)
=>pid = fork();
=>if(pid == 0)execve(options->script, argv, env);//子进程执行脚本,默认"/system/etc/dhcpcd/dhcpcd-run-hooks"
//dhcpcd-run-hooks脚本会根据level值,决定是否执行system/etc/dhcpcd/dhcpcd-hook/*目录下的相应文件
//我们的系统在该system/etc/dhcpcd/dhcpcd-hook/*目录下有如下3个文件
//95-configured
//20-dns.conf
//01-test
=>父进程返回while (waitpid(pid, &status, 0) == -1)等待子进程脚本执行完成
system/extra/dhcpcd-4.0.0-beta9/dhcpcd-hooks/20-dns.conf
system/extra/dhcpcd-4.0.0-beta9/dhcpcd-hooks/95-configured
...
setprop dhcp.${interface}.ipaddress "${new_ip_address}"
setprop dhcp.${interface}.result "ok"//设置属性为ok
setprop dhcp.${interface}.result "failed"
...
=============================================================================================================
inet_init、tcp_prot
sock->ops->sendmsg(iocb, sock, msg, size);
=>inetsw_array[]
=>inet_stream_ops
=>tcp_sendmsg
=============================================================================================================
wpa_cli.c
=>main
=>wpa_cli_interactive
=>wpa_cli_recv_pending(monitor_conn, 0, 0);//阻塞等待wpa_supplicant发送数据过来
=>如果action_monitor为true,那么将执行一些简单加工操作,否则将直接将wpa_supplicant发过来的数据打印到console上[luther.gliethttp].
============================================================================================================= 2:28 PM | Add a comment | Permalink | Blog it | Android浅析android下如何通过jni监控wifi(二)
//剔除前导控制字符,将" - "后面的描述字符串作为真实数据,继续处理
...
if (event == STATE_CHANGE) {
handleSupplicantStateChange(eventData);
} else if (event == DRIVER_STATE) {
handleDriverEvent(eventData);
} else {
handleEvent(event, eventData);//对于CONNECTED和DISCONNECTED等netlink事件将执行此操作来处理[luther.gliethttp]
// If supplicant is gone, exit the thread
if (event == TERMINATING) {
break;
}
}
...
void handleEvent(int event, String remainder) {
switch (event) {
case DISCONNECTED:
handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED, remainder);
break;
case CONNECTED:
handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder);//控制界面显示
break;
...
}
public class WifiStateTracker extends NetworkStateTracker {
...
public void startEventLoop() {
mWifiMonitor.startMonitoring();//启动上面的MonitorThread线程
}
...
}
java/services/com/android/server/WifiService.java
public class WifiService extends IWifiManager.Stub {
...
private boolean setWifiEnabledBlocking(boolean enable) {
final int eventualWifiState = enable ? WIFI_STATE_ENABLED : WIFI_STATE_DISABLED;
...
if (enable) {
if (WifiNative.loadDriver()) {
Log.e(TAG, "Failed to load Wi-Fi driver.");
updateWifiState(WIFI_STATE_UNKNOWN);
return false;
}
if (WifiNative.startSupplicant()) {
WifiNative.unloadDriver();
Log.e(TAG, "Failed to start supplicant daemon.");
updateWifiState(WIFI_STATE_UNKNOWN);
return false;
}
mWifiStateTracker.startEventLoop();
//启动MonitorThread线程,等待wpa_supplicant将netlink数据转发过来,然后根据netlink动作类型,进一步影响界面显示[luther.gliethttp].
}
...
}
java/android/android/net/wifi/WifiStateTracker.java
电源管理
private void handleConnectedState() {
...
mDhcpTarget.obtainMessage(EVENT_DHCP_START).sendToTarget();//传递到下面的handleMessage方法
...
}
public void onChange(boolean selfChange) {
...
handleConnectedState();
...
}
public class WifiStateTracker extends NetworkStateTracker {
...
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_SUPPLICANT_CONNECTION:
case EVENT_NETWORK_STATE_CHANGED:
handleConnectedState();//调用
...
private class DhcpHandler extends Handler {
private Handler mTarget;
public DhcpHandler(Looper looper, Handler target) {
super(looper);
mTarget = target;
}
public void handleMessage(Message msg) {
int event;
//private static final int DRIVER_POWER_MODE_AUTO = 0;
//private static final int DRIVER_POWER_MODE_ACTIVE = 1;
switch (msg.what) {
case EVENT_DHCP_START:
synchronized (this) {
WifiNative.setPowerModeCommand(DRIVER_POWER_MODE_ACTIVE);//设置电源模式,调用android_net_wifi_setPowerModeCommand
}
Log.d(TAG, "DhcpHandler: DHCP request started");
//libs/android_runtime/android_net_NetUtils.cpp
//static JNINativeMethod gNetworkUtilMethods[] = {
//{ "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpInfo;)Z", (void *)android_net_utils_runDhcp },
// ...
//};
if (NetworkUtils.runDhcp(mInterfaceName, mDhcpInfo)) {//执行dhcp申请ip地址操作
event = EVENT_INTERFACE_CONFIGURATION_SUCCEEDED;
if (LOCAL_LOGD) Log.v(TAG, "DhcpHandler: DHCP request succeeded");
} else {
event = EVENT_INTERFACE_CONFIGURATION_FAILED;
Log.i(TAG, "DhcpHandler: DHCP request failed: " +
NetworkUtils.getDhcpError());
//如果dhcpcd分配ip失败,那么Message.obtain(mTarget, event).sendToTarget();将执行
//WifiNative.disconnectCommand();即:static JNINativeMethod gWifiMethods[] = {
//android_net_wifi_disconnectCommand发送"DISCONNECT"字符串[luther.gliethttp]
//然后在wpa_supplicant服务端执行wpa_supplicant_ctrl_iface_process
//wpa_supplicant_disassociate
}
synchronized (this) {
WifiNative.setPowerModeCommand(DRIVER_POWER_MODE_AUTO);
}
Message.obtain(mTarget, event).sendToTarget();
break;
}
}
}
...
/**
* Send the tracker a notification that a connection to the supplicant
* daemon has been established.
*/
//在上面的public class WifiMonitor=>ensureSupplicantConnection
//=>
//while (!supplicantConnected) {
// boolean connected;
//synchronized (mWifiStateTracker) {
//connected = WifiNative.connectToSupplicant();//如果没有连接成功,那么while循环尝试,直到尝试成功,或者定义了oneShot,仅一次尝试
//=>mWifiStateTracker.notifySupplicantConnection();//如果WifiNative.connectToSupplicant()成功,那么将执行
//mWifiStateTracker.notifySupplicantConnection();的调用.
void notifySupplicantConnection() {//向对象发送message
Message.obtain(this, EVENT_SUPPLICANT_CONNECTION).sendToTarget();
}
void notifyStateChange(SupplicantState newState) {
Message.obtain(this, EVENT_SUPPLICANT_STATE_CHANGED, newState).sendToTarget();
}
...
}
static jboolean android_net_wifi_setPowerModeCommand(JNIEnv* env, jobject clazz, jint mode)
{
char cmdstr[256];
sprintf(cmdstr, "DRIVER POWERMODE %d", mode);
return doBooleanCommand(cmdstr, "OK");
}
android_net_wifi_setPowerModeCommand
=>doBooleanCommand
=>doCommand
=>wifi_command
=>wifi_send_command
=>wpa_ctrl_request
=>send给wpa_supplicant
然后wpa_supplicant将做如下接收操作:
system/extra/wpa_supplicant/main.c
=>wpa_supplicant_add_iface
=>wpa_supplicant_init_iface2
=>wpa_supplicant_ctrl_iface_init
=>注册ctrl_conn控制端口和monitor_conn监听端口的处理函数
eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, wpa_s, priv);//ctrl_conn端口的handler处理函数
wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);//monitor_conn端口的回调处理函数,处理netlink数据到所有monitor_conn监听端口
=>wpa_supplicant_ctrl_iface_receive//对于unix通信方式
=>wpa_supplicant_ctrl_iface_process
=>如果wpa_cli发送的是wpa_cli driver xxx形式的命令,那么调用这个函数
if (os_strncmp(buf, "DRIVER ", 7) == 0) {//掠过前7个,直接将命令传过去
reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply, reply_size);
=>wpa_supplicant_driver_cmd
=>wpa_drv_driver_cmd
=>自定义DRIVER扩展处理函数,所以对于java传递过来的power电源管理命令,wpa_drv_driver_cmd将收到"POWERMODE 0"或者"POWERMODE 1"字符串[luther.gliethttp]
=============================================================================================================
2:27 PM | Add a comment | Permalink | Blog it | Android浅析android下如何通过jni监控wifi(一)
浅析android下如何通过jni监控wifi网络连接、dhcpcd执行和power电源控制
=============================================================================================================
libs/android_runtime/android_net_wifi_Wifi.cpp
部分jni接口
static JNINativeMethod gWifiMethods[] = {
{ "loadDriver", "()Z", (void *)android_net_wifi_loadDriver },
{ "setPowerModeCommand", "(I)Z", (void*) android_net_wifi_setPowerModeCommand },//电源管理
{ "connectToSupplicant", "()Z", (void *)android_net_wifi_connectToSupplicant },
{ "waitForEvent", "()Ljava/lang/String;", (void*) android_net_wifi_waitForEvent },
{ "disconnectCommand", "()Z", (void *)android_net_wifi_disconnectCommand },
...
};
int register_android_net_wifi_WifiManager(JNIEnv* env)
{
...
return AndroidRuntime::registerNativeMethods(env,
WIFI_PKG_NAME, gWifiMethods, NELEM(gWifiMethods));//登记jni
}
libs/android_runtime/AndroidRuntime.cpp
static const RegJNIRec gRegJNI[] = {
...
REG_JNI(register_android_net_wifi_WifiManager),
...
};
int AndroidRuntime::startReg(JNIEnv* env)
{
...
register_jni_procs(gRegJNI, NELEM(gRegJNI), env);
...
}
AndroidRuntime::start
=>startReg(env)即调用方法int AndroidRuntime::startReg(JNIEnv* env)
=============================================================================================================
wifi_load_driver
wifi_start_supplicant
=>ensure_config_file_exists
//检查/data/misc/wifi/wpa_supplicant.conf文件是否存在,如果不存在,那么从/system/etc/wifi/wpa_supplicant.conf动态拷贝一份
android_net_wifi_connectToSupplicant
=>wifi_connect_to_supplicant
=>
ctrl_conn = wpa_ctrl_open(ifname);
monitor_conn = wpa_ctrl_open(ifname);
wpa_ctrl_attach(monitor_conn);
android_net_wifi_waitForEvent
=>wifi_wait_for_event
=>wpa_ctrl_recv(monitor_conn, buf, &nread);
=>recv(ctrl->s, reply, *reply_len, 0);//阻塞等待wpa_supplicant的netlink数据过来
=>如果接收的buf数据区,buf[0]为'<',那么说明有level级别信息,所以将'<'...'>'数据剔除,然后wifi_wait_for_event函数返回[luther.gliethttp].
java/android/android/net/wifi/WifiMonitor.java
public class WifiMonitor {
...
public void startMonitoring() {
new MonitorThread().start();//启动java线程
}
class MonitorThread extends Thread {
public MonitorThread() {
super("WifiMonitor");
}
public void run() {
for (;;) {
ensureSupplicantConnection();//=>WifiNative.connectToSupplicant调用jni函数android_net_wifi_connectToSupplicant
String eventStr = WifiNative.waitForEvent();//=>调用jni函数android_net_wifi_waitForEvent
//private static final int CONNECTED = 1;
//private static final int DISCONNECTED = 2;
//private static final String eventPrefix = "CTRL-EVENT-";
//private static final int eventPrefixLen = eventPrefix.length();
//private static final String connectedEvent = "CONNECTED";
//private static final String disconnectedEvent = "DISCONNECTED";
String eventName = eventStr.substring(eventPrefixLen);//去掉"CTRL-EVENT-"字符串
int nameEnd = eventName.indexOf(' ');//找到随后的空格位置,这在wpa_supplicant发送时
//#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED "中,已经内置空格了.
if (nameEnd != -1)
eventName = eventName.substring(0, nameEnd);
int event;
if (eventName.equals(connectedEvent))//检测netlink过来的字符串action类型
event = CONNECTED;
else if (eventName.equals(disconnectedEvent))
event = DISCONNECTED;
...
int ind = eventStr.indexOf(" - ");//CTRL-EVENT-CONNECTED - Connection to ...
if (ind != -1)
eventData = eventStr.substring(ind + 3);
2:26 PM | Add a comment | Permalink | Blog it | Android
2009年10月22日 星期四
android usb mtp mode
android-porting USB mtp
1 vold.conf
2. init.rc setprop persist.service.mount.umsauto 1
1 vold.conf
2. init.rc setprop persist.service.mount.umsauto 1
2009年8月17日 星期一
Android 技术专题系列之十一 -- DRM(2009-04-26 13:10:45)
Android 技术专题系列之十一 -- DRM(2009-04-26 13:10:45)
标签:drm android it 分类:android
简而言之,DRM系统提供一套机制对用户使用手机上的媒体内容(如ringtong, mp3等)进行限制,如限制拷贝给第三方,限制使用次数或时限等,从而保护内容提供商的权利。建议读者可以阅读OMA DRM 的规范,以便更好的了解代码。
相关代码主要位于下列目录:
frameworks/base/media/java/android/drm/mobile1
frameworks/base/media/libdrm/moblile1
frameworks/base/media/libdrm/mobile2
packages/apps/Mms/src/com/android/mms/drm: drm
packages/providers/DrmProvider/src/com/android/providers/drm
下面先作简要分析:
frameworks/base/media/libdrm/moblile1应该是提供OMA DMA1.0的本地/c++ 实现
frameworks/base/media/libdrm/moblile2应该是提供OMA DAM2.0的本地/c++ 实现。
frameworks/base/media/java/android/drm/mobile1 对应用提供OMA DRM 1.0 (即frameworks/base/media/libdrm/moblile1)的java接口。目前尚没有OMA DRM 2.0的java接口,也就意味着OMA DRM 2.0在Android中尚未应用。
packages/apps/Mms/src/com/android/mms/drm 实现在MMS中如何使用DRM。
packages/providers/DrmProvider/src/com/android/providers/drm ?
下面再作具体介绍:
一 目录 frameworks/base/media/java/android/drm/mobile1
这个目录是OMA DRM 1.0的java 接口。
OMA DRM 1.0 定义了几个重要概念:
DRM消息(DRM message):用户下载的一条DRM内容。根据下面介绍的DRM内容 传输方式的不同,DRM消息中包含的内容亦有所不同,可能只包含一个未经加密的媒体对象;也可能即包含未加密的媒体对象,也包含一个权利对象;也可能只包含一个经过加密的媒体对象(.dcf)。
媒体对象 (media object):包含媒体资源,如一个mp3, ringtone等。
权利对象(Right object): 限制用户如何使用媒体对象。
OMA DRM 1.0 定义了DRM内容的四种传输方式:
1. Combined delivery: 这种传输方式中,媒体对象以未经加密的方式(plain) 与Right object打成一个包,一块传输。这个包下载到手机设备上后,不允许转发给其他设备。
2. Forward lock: 这种传输方式是combined delivery的一个特例。媒体对象没有对应的Rigth object。媒体对象不允许转发给其他设备
3. Separate delivery: 媒体对象和权利对象分别传输。媒体对象采用对称密钥加密,文件以.dcf为后缀。权利对象中则包含对应的密钥。
4. Superdistribution:类似separate delivery, 但媒体内容允许转发给其他设备。
相应地,本目录的代码中:
DrmConstraintInfo对象描述了(对媒体内容的)一组限制属性,如开始/结束使用日期,使用次数等;
DrmRights对象代表了一个OMA 权利对象。
DrmRightsManager管理设备上的Rigth Objects。所有下载的权利对象,不论是由separate delivery 还是 combined delivery,权利对象都要首先安装到设备上。
DrmRawContent代表一条DRM内容,分为两类:DRM_MIMETYPE_MESSAGE_STRING --DRM内容是经combined delivery 或 forward lock传输的 (也即媒体对象没有加密,没有或者有一个权利对象); DRM_MIMETYPE_CONTENT_STRING -- DRM内容是经 separate delivery传输的(也即媒体对象是经过加密的dcf格式,不包含权利对象)。
DrmInputStream:这个对象从一个DrmRawContent对象中读出经过权利对象验证并解密后的(需要的话)媒体对象内容。这个内容之后就可以传给相关应用输出给用户。
二 目录frameworks/base/media/libdrm/moblile1
本目录真正实现DRM DRM 1.0。
drm1_jni.c提供对DrmRawContent中方法的本地实现;
objmng目录下是具体实现。frameworks/base/media/libdrm/mobile1/include/objmng/svc_drm.h中有关于每个方法的详细解释,基本思路是每打开一个Drm 内容,就创建一个session,然后提供一系列方法,以此session为参数,对Drm进行各种操作,如获取属性,读取解密后内容等。这里不再赘述。
标签:drm android it 分类:android
简而言之,DRM系统提供一套机制对用户使用手机上的媒体内容(如ringtong, mp3等)进行限制,如限制拷贝给第三方,限制使用次数或时限等,从而保护内容提供商的权利。建议读者可以阅读OMA DRM 的规范,以便更好的了解代码。
相关代码主要位于下列目录:
frameworks/base/media/java/android/drm/mobile1
frameworks/base/media/libdrm/moblile1
frameworks/base/media/libdrm/mobile2
packages/apps/Mms/src/com/android/mms/drm: drm
packages/providers/DrmProvider/src/com/android/providers/drm
下面先作简要分析:
frameworks/base/media/libdrm/moblile1应该是提供OMA DMA1.0的本地/c++ 实现
frameworks/base/media/libdrm/moblile2应该是提供OMA DAM2.0的本地/c++ 实现。
frameworks/base/media/java/android/drm/mobile1 对应用提供OMA DRM 1.0 (即frameworks/base/media/libdrm/moblile1)的java接口。目前尚没有OMA DRM 2.0的java接口,也就意味着OMA DRM 2.0在Android中尚未应用。
packages/apps/Mms/src/com/android/mms/drm 实现在MMS中如何使用DRM。
packages/providers/DrmProvider/src/com/android/providers/drm ?
下面再作具体介绍:
一 目录 frameworks/base/media/java/android/drm/mobile1
这个目录是OMA DRM 1.0的java 接口。
OMA DRM 1.0 定义了几个重要概念:
DRM消息(DRM message):用户下载的一条DRM内容。根据下面介绍的DRM内容 传输方式的不同,DRM消息中包含的内容亦有所不同,可能只包含一个未经加密的媒体对象;也可能即包含未加密的媒体对象,也包含一个权利对象;也可能只包含一个经过加密的媒体对象(.dcf)。
媒体对象 (media object):包含媒体资源,如一个mp3, ringtone等。
权利对象(Right object): 限制用户如何使用媒体对象。
OMA DRM 1.0 定义了DRM内容的四种传输方式:
1. Combined delivery: 这种传输方式中,媒体对象以未经加密的方式(plain) 与Right object打成一个包,一块传输。这个包下载到手机设备上后,不允许转发给其他设备。
2. Forward lock: 这种传输方式是combined delivery的一个特例。媒体对象没有对应的Rigth object。媒体对象不允许转发给其他设备
3. Separate delivery: 媒体对象和权利对象分别传输。媒体对象采用对称密钥加密,文件以.dcf为后缀。权利对象中则包含对应的密钥。
4. Superdistribution:类似separate delivery, 但媒体内容允许转发给其他设备。
相应地,本目录的代码中:
DrmConstraintInfo对象描述了(对媒体内容的)一组限制属性,如开始/结束使用日期,使用次数等;
DrmRights对象代表了一个OMA 权利对象。
DrmRightsManager管理设备上的Rigth Objects。所有下载的权利对象,不论是由separate delivery 还是 combined delivery,权利对象都要首先安装到设备上。
DrmRawContent代表一条DRM内容,分为两类:DRM_MIMETYPE_MESSAGE_STRING --DRM内容是经combined delivery 或 forward lock传输的 (也即媒体对象没有加密,没有或者有一个权利对象); DRM_MIMETYPE_CONTENT_STRING -- DRM内容是经 separate delivery传输的(也即媒体对象是经过加密的dcf格式,不包含权利对象)。
DrmInputStream:这个对象从一个DrmRawContent对象中读出经过权利对象验证并解密后的(需要的话)媒体对象内容。这个内容之后就可以传给相关应用输出给用户。
二 目录frameworks/base/media/libdrm/moblile1
本目录真正实现DRM DRM 1.0。
drm1_jni.c提供对DrmRawContent中方法的本地实现;
objmng目录下是具体实现。frameworks/base/media/libdrm/mobile1/include/objmng/svc_drm.h中有关于每个方法的详细解释,基本思路是每打开一个Drm 内容,就创建一个session,然后提供一系列方法,以此session为参数,对Drm进行各种操作,如获取属性,读取解密后内容等。这里不再赘述。
Android 技术专题系列之九 -- 图形系统
Android 技术专题系列之九 -- 图形系统(2009-04-03 10:45:41)
本文试图讲述Android图形系统的底层实现。Android图形系统底层实现非常复杂,文档较少,没有使用比较流行的图形组建如X window, Cairo等。
Android中的图形系统采用Client/Server架构。Server (即SurfaceFlinger)主要由c++代码编写而成。Client端代码分为两部分,一部分是由Java提供的供应用使用的api,另一部分则是由c++写成的底层实现。下图概要介绍了android图形系统的架构以及使用到的主要组件。


Android图形系统中一个重要的概念和线索是surface。View及其子类(如TextView, Button)要画在surface上。每个surface创建一个Canvas对象 (但属性时常改变),用来管理view在surface上的绘图操作,如画点画线。每个canvas对象对应一个bitmap,存储画在surface上的内容。
每个Surface通常对应两个buffer,一个front buffer, 一个back buffer。其中,back buffer就是canvas绘图时对应的bitmap (研究android_view_Surface.cpp::lockCanvas)。因此,绘画总是在back buffer上,需要更新时,则将back buffer和front buffer互换。
The window is tied to a Surface and the ViewRoot asks the Surface for a
Canvas that is then used by the Views to draw onto. After View draw its data to canvas, ViewRoot
will call surface.unlockCanvasAndPost(canvas) to schedule surfaceFlinger::composeSurfaces() which do the actually display to display panel. SurfaceFlinger handles to transfers drawn data in canvas to surface front buffer or backbuffer
Except for SurfaceViews, different views within the same ViewRoot share the same surface.
Layer的概念:
有几个对象与Surface概念紧密相关:
1. Java Surface (frameworks/base/core/java/android/view/Surface.java)。该对象被应用间接调用(通过SurfaceView, ViewRoot等), 应用需要创建surface,(并同时创建canvas), 将图形绘制到这个对象上并最终投递到屏幕上。
2. C++ Surface (frameworks/base/libs/ui/Surface.cpp。 这个对象被Java Surface通过Jni 调用,实现Java Surface 的功能
3. ISurface (以及其派生类BnSurface)。这个对象是应用和server之间的接口。C++ Surface创建这个ISurface (BnSurface)并发送命令,如更新surface内容到屏幕上。Server端接受这个命令并执行相应操作。
研究一个surface如何创建的关键路径如下:
1. frameworks/base/core/java/android/view/Surface.java -- Surface::Surface ()
2. frameworks/base/core/jni/android_view_Surface.cpp -- Surface_init ()。在这个函数中SurfaceComposerClient 对象被创建。
3. frameworks/base/libs/ui/SurfaceComposerClient.cpp -- SurfaceComposerClient::SurfaceComposerClient (). 这个函数非常重要,在这里建立了client和server之间的桥梁。通过函数_get_surface_manager()获得了一个指向server的IBinder 对象(具有ISurfaceComposer接口),之后通过这个IBinder就可以跨进程访问Server的功能。接着调用ISurfaceComposer::createConnection()创建并返回了一个ISurfaceFlingerClient的IBinder。
4. frameworks/base/libs/ui/SurfaceComposerClient.cpp -- SurfaceComposerClient::createSurface().这个函数中,利用前面获得的ISurfaceFlingerClient的IBinder,调用其createSurface接口。
5.frameworks/base/libs/surfaceflinger/SurfaceFlinger.cpp -- BClient::createSurface ()。BClient由ISurfaceFlingerClient派生而来。
6. frameworks/base/libs/surfaceflinger/SurfaceFlinger.cpp -- SurfaceFlinger:: createSurface()。这个函数为Surface创建一个对应的Layer。
上述关键路径中,1,2,3,4运行于client进程中,而5,6运行与server进程中。server作为一个service提供给client访问。
与图形相关的代码主要位于下列目录:
1、frameworks/base/graphics/java/android/graphics
2、frameworks/base/core/java/android/view
3、frameworks/base/core/java/android/widget
4、frameworks/base/opengl/
5、frameworks/base/libs/ui
6、frameworks/base/libs/surfaceflinger
7、frameworks/base/core/jni/android/graphics
8、frameworks/base/core/jni/android/opengl
9、frameworks/base/core/jni/android/android_view_*.cpp
10、external/skia
一、下列目录中的部分代码:
1、frameworks/base/graphics/java/android/graphics
2、frameworks/base/core/java/android/view
3、frameworks/base/core/java/android/widget
android.graphics, android.view和android.widget功能和其他类似的图形库如Qt/Gtk+差不多,分别提供基本的图形原语(如画点画线,设置图形上下文等),事件机制,以及开发图形用户界面的控件等。canvas 用于开发2D图形, Surface 代表一个可供图形系统绘制的surface。可在其上绘制2D活3D图形。
二. frameworks/base/opengl/
这个目录包含opengel的接口以及软件实现。在http://developer.android.com/guide/topics/graphics/opengl.html有详细介绍如何使用android.opengl开发3d graphics。
三.external/skia,台湾的Jserv先生有一篇比较好的介绍,感兴趣的读者可以参考他的博文(http: //blog.linux.org.tw/~jserv/archives/002095.html)。简而言之,skia与cairo功能相当,封装底 层的图形硬件,为上面的图形库提供最基础的操作图形硬件的原语。
四. frameworks/base/libs/ui 和 frameworks/base/libs/surfaceflinger
ISurface 定义了基础的Surface接口,供图形系统客户端 (应用)和server端(即surfaceflinger)交互。
BpSurface是ISurface的派生类,提供接口供server 调用客户端功能;
BnSurface是ISurface的另一个派生类,提供接口供客户端调用server功能。当 server 收到来自客户端 (通过BnSurace)的调用请求后,如registerBuffers, postBuffer等,BnSurface::onTransact被触发。
Surface (LayerBaseClient的私有类)是BnSurface的派生类。
SurfaceBuffer (SurfaceBuffer的私有类)是Surface的派生类。
ISurfaceComposer 定义了基础的接口,供客户端和server端交互。
BpSurfaceComposer是一个派生类,提供接口供server调用客户端功能;
BnSurfaceComposer是另一派生类,提供接口供客户端调用server功能。类 SurfaceFlinger 由BnSurfaceComposer派生而来。
SurfaceComposerClient直接供客户端使用,调用ISurface (BnSurface)和 ISurfaceComposer (BnSurfaceComposer)以及 ISurfaceFlingerClient 接口,与server交互。
BClient 派生自ISurfaceFlingerClient (BnSurfaceFlingerClient),调用server的createSurface,真正创建一个surface。每个surface对应一个layer.
egl_native_window_t 定义了一个本地window类 。这个类提供了对本地window的所有描述以及用于egl (opengl 与本地图形系统的接口)操作本地windwo的所有方法。
EGLNativeSurface是egl_native_window_t的一个派生类。
EGLDisplaySurface是EGLNativeSurface的派生类。 EGLDisplaySurface 是一个非常重要的类,在这个类里,真正打开framebuffer设备(/dev/graphics/fb0 或者/dev/fb0),并将这个设备封装成EGLDisplaySurface的形式供server使用。函数mapFrameBuffer打开framebuffer, 创建两个缓冲区,(一个是on screen front 缓冲区, 另一个back buffer, 可能位于offscreen framebuffer,也可能位于系统内存)。 函数swapBuffers将back buffer内容拷贝到front buffer中。
DisplayHardware 类中初始化了egl系统,并为本地窗口对象EGLDisplaySurface 创建了对应的EGLSurface 对象。surfaceflinger 使用DisplayHardware去和本地窗口打交道。
五、下列目录中的部分代码
7、frameworks/base/core/jni/android/graphics
8、frameworks/base/core/jni/android/opengl
9、frameworks/base/core/jni/android/android_view_*.cpp
这些目录下的代码在Java层的graphics 组件和native (c++)组件之间衔接,将java层的功能调用转换到对应的本地调用。
hardware/libhardware实现了HAL(Hardware Abstraction Layer)层,copybit device是其中一个模块。
Android中的图形系统采用Client/Server架构。Server (即SurfaceFlinger)主要由c++代码编写而成。Client端代码分为两部分,一部分是由Java提供的供应用使用的api,另一部分则是由c++写成的底层实现。下图概要介绍了android图形系统的架构以及使用到的主要组件。
Android图形系统中一个重要的概念和线索是surface。View及其子类(如TextView, Button)要画在surface上。每个surface创建一个Canvas对象 (但属性时常改变),用来管理view在surface上的绘图操作,如画点画线。每个canvas对象对应一个bitmap,存储画在surface上的内容。
每个Surface通常对应两个buffer,一个front buffer, 一个back buffer。其中,back buffer就是canvas绘图时对应的bitmap (研究android_view_Surface.cpp::lockCanvas)。因此,绘画总是在back buffer上,需要更新时,则将back buffer和front buffer互换。
The window is tied to a Surface and the ViewRoot asks the Surface for a
Canvas that is then used by the Views to draw onto. After View draw its data to canvas, ViewRoot
will call surface.unlockCanvasAndPost(canvas) to schedule surfaceFlinger::composeSurfaces() which do the actually display to
Except for SurfaceViews, different views within the same ViewRoot share the same surface.
Layer的概念:
每个surface又对应一个layer, SurfaceFlinger负责将各个layer的front buffer合成(composite)绘制到屏幕上。
A Layer is something that can be composited by SurfaceFlinger (should have been called LayerFlinger). There are several types of Layers if you look in the code, in particular the regular ones (Layer.cpp) , they are backed by a Surface, and the LayerBuffer (very badly chosen name) which don't have a backing store, but receive one from their client. . Note that the GGLSurface type, should have been called GGLBuffer
Multiple layers are just composited to the final buffer intheir Z order.
有几个对象与Surface概念紧密相关:
1. Java Surface (frameworks/base/core/java/android/view/Surface.java)。该对象被应用间接调用(通过SurfaceView, ViewRoot等), 应用需要创建surface,(并同时创建canvas), 将图形绘制到这个对象上并最终投递到屏幕上。
2. C++ Surface (frameworks/base/libs/ui/Surface.cpp。 这个对象被Java Surface通过Jni 调用,实现Java Surface 的功能
3. ISurface (以及其派生类BnSurface)。这个对象是应用和server之间的接口。C++ Surface创建这个ISurface (BnSurface)并发送命令,如更新surface内容到屏幕上。Server端接受这个命令并执行相应操作。
研究一个surface如何创建的关键路径如下:
1. frameworks/base/core/java/android/view/Surface.java -- Surface::Surface ()
2. frameworks/base/core/jni/android_view_Surface.cpp -- Surface_init ()。在这个函数中SurfaceComposerClient 对象被创建。
3. frameworks/base/libs/ui/SurfaceComposerClient.cpp -- SurfaceComposerClient::SurfaceComposerClient (). 这个函数非常重要,在这里建立了client和server之间的桥梁。通过函数_get_surface_manager()获得了一个指向server的IBinder 对象(具有ISurfaceComposer接口),之后通过这个IBinder就可以跨进程访问Server的功能。接着调用ISurfaceComposer::createConnection()创建并返回了一个ISurfaceFlingerClient的IBinder。
4. frameworks/base/libs/ui/SurfaceComposerClient.cpp -- SurfaceComposerClient::createSurface().这个函数中,利用前面获得的ISurfaceFlingerClient的IBinder,调用其createSurface接口。
5.frameworks/base/libs/surfaceflinger/SurfaceFlinger.cpp -- BClient::createSurface ()。BClient由ISurfaceFlingerClient派生而来。
6. frameworks/base/libs/surfaceflinger/SurfaceFlinger.cpp -- SurfaceFlinger:: createSurface()。这个函数为Surface创建一个对应的Layer。
上述关键路径中,1,2,3,4运行于client进程中,而5,6运行与server进程中。server作为一个service提供给client访问。
与图形相关的代码主要位于下列目录:
1、frameworks/base/graphics/java/android/graphics
2、frameworks/base/core/java/android/view
3、frameworks/base/core/java/android/widget
4、frameworks/base/opengl/
5、frameworks/base/libs/ui
6、frameworks/base/libs/surfaceflinger
7、frameworks/base/core/jni/android/graphics
8、frameworks/base/core/jni/android/opengl
9、frameworks/base/core/jni/android/android_view_*.cpp
10、external/skia
一、下列目录中的部分代码:
1、frameworks/base/graphics/java/android/graphics
2、frameworks/base/core/java/android/view
3、frameworks/base/core/java/android/widget
android.graphics, android.view和android.widget功能和其他类似的图形库如Qt/Gtk+差不多,分别提供基本的图形原语(如画点画线,设置图形上下文等),事件机制,以及开发图形用户界面的控件等。canvas 用于开发2D图形, Surface 代表一个可供图形系统绘制的surface。可在其上绘制2D活3D图形。
二. frameworks/base/opengl/
这个目录包含opengel的接口以及软件实现。在http://developer.android.com/guide/topics/graphics/opengl.html有详细介绍如何使用android.opengl开发3d graphics。
三.external/skia,台湾的Jserv先生有一篇比较好的介绍,感兴趣的读者可以参考他的博文(http: //blog.linux.org.tw/~jserv/archives/002095.html)。简而言之,skia与cairo功能相当,封装底 层的图形硬件,为上面的图形库提供最基础的操作图形硬件的原语。
四. frameworks/base/libs/ui 和 frameworks/base/libs/surfaceflinger
ISurface 定义了基础的Surface接口,供图形系统客户端 (应用)和server端(即surfaceflinger)交互。
BpSurface是ISurface的派生类,提供接口供server 调用客户端功能;
BnSurface是ISurface的另一个派生类,提供接口供客户端调用server功能。当 server 收到来自客户端 (通过BnSurace)的调用请求后,如registerBuffers, postBuffer等,BnSurface::onTransact被触发。
Surface (LayerBaseClient的私有类)是BnSurface的派生类。
SurfaceBuffer (SurfaceBuffer的私有类)是Surface的派生类。
ISurfaceComposer 定义了基础的接口,供客户端和server端交互。
BpSurfaceComposer是一个派生类,提供接口供server调用客户端功能;
BnSurfaceComposer是另一派生类,提供接口供客户端调用server功能。类 SurfaceFlinger 由BnSurfaceComposer派生而来。
SurfaceComposerClient直接供客户端使用,调用ISurface (BnSurface)和 ISurfaceComposer (BnSurfaceComposer)以及 ISurfaceFlingerClient 接口,与server交互。
BClient 派生自ISurfaceFlingerClient (BnSurfaceFlingerClient),调用server的createSurface,真正创建一个surface。每个surface对应一个layer.
egl_native_window_t 定义了一个本地window类 。这个类提供了对本地window的所有描述以及用于egl (opengl 与本地图形系统的接口)操作本地windwo的所有方法。
EGLNativeSurface是egl_native_window_t的一个派生类。
EGLDisplaySurface是EGLNativeSurface的派生类。 EGLDisplaySurface 是一个非常重要的类,在这个类里,真正打开framebuffer设备(/dev/graphics/fb0 或者/dev/fb0),并将这个设备封装成EGLDisplaySurface的形式供server使用。函数mapFrameBuffer打开framebuffer, 创建两个缓冲区,(一个是on screen front 缓冲区, 另一个back buffer, 可能位于offscreen framebuffer,也可能位于系统内存)。 函数swapBuffers将back buffer内容拷贝到front buffer中。
DisplayHardware 类中初始化了egl系统,并为本地窗口对象EGLDisplaySurface 创建了对应的EGLSurface 对象。surfaceflinger 使用DisplayHardware去和本地窗口打交道。
五、下列目录中的部分代码
7、frameworks/base/core/jni/android/graphics
8、frameworks/base/core/jni/android/opengl
9、frameworks/base/core/jni/android/android_view_*.cpp
这些目录下的代码在Java层的graphics 组件和native (c++)组件之间衔接,将java层的功能调用转换到对应的本地调用。
hardware/libhardware实现了HAL(Hardware Abstraction Layer)层,copybit device是其中一个模块。
Android 技术专题系列之十 -- Audio manager
(2009-04-25 20:11:57)
Android的Audio Manager (即AudioFlinger)相对比较简单,代码主要集中在目录
frameworks/base/libs/audioflinger, frameworks/base/media 和 hardware/libhardware_legacy/include/hardware_legacy下面。 Audio Manager的主要功能如下
1. 接收来自各个track的PCM data, 如普通的audio playback, ringtone, voice call等,
2. 管理多个输入输出设备,如mic,handset, speaker, bluetooth等
3. 将一路track上的数据输出到某个输出设备上
4.将多路track上的数据混音(mix)后再输出到某个设备上。
5. 录音。
frameworks/base/libs/audioflinger,
1. 接收来自各个track的PCM data, 如普通的audio playback, ringtone, voice call等,
2. 管理多个输入输出设备,如mic,handset, speaker, bluetooth等
3. 将一路track上的数据输出到某个输出设备上
4.将多路track上的数据混音(mix)后再输出到某个设备上。
5. 录音。
訂閱:
文章 (Atom)