您的位置:首页 > 移动开发 > Android开发

android系统启动时属性初始化过程

2012-04-13 13:46 344 查看
 所有属性可以通过getprop获取到,以下是属性初始化过程:

在init.c文件main函数中会调用start_property_service(),而它分别调用 load_properties_from_file函数读取PROP_PATH_SYSTEM_BUILD(/system/build.prop)、 PROP_PATH_SYSTEM_DEFAULT(/system/default.prop)和 PROP_PATH_LOCAL_OVERRIDE(/data/local.prop)存放系统属性的文件并设置到系统属性。

编译时由build/tool/buildinfo.sh文件写到文件build.prop,修改系统默认属性一般是改build/tool/buildinfo.sh文件

=======================================================================

修改Settings源码可修改系统设置项,Settings数据被存放于com.android.providers.settings/databases/settings.db 中,如果想修改系统启动后加载的默认值

一种方法是直接修改settings.db的值

另一种就是修改SettingsProvider默认值

Settings应用能够配置Android系统的各种设置,这些设置的默认值都是由frameworks中的SettingsProvider从数据库中读取的,那么第一次开机的时候这些数据都是从哪儿来的呢?

frameworks/base/packages/SettingsProvider/res/values/defaults.xml这个文件就是用来存储Android系统的默认设置
例如:
<integer name="def_screen_off_timeout">600000</integer>设置关屏超时时间的默认值
<integer name="def_screen_brightness">102</integer> 设置亮度的默认值

<bool name="def_install_non_market_apps">false</bool>设置是否允许安装非Market应用程序的默认值

如果想定义defaults.xml中没有的,在这里添加后,需修改frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java,加入自己的存储代码。

来电铃声:SD卡ringtones文件下,  支持音频文件(MP3、wav、ogg等格式)。

通知铃声:SD卡notifications,支持音频文件(MP3、wav、ogg等格式)。

闹钟铃声:SD卡alarms,支持音频文件(MP3、wav、ogg等格式)。

 附:系统自带铃声文件位置

      来电铃声:/system/media/audio/ringtones

      通知铃声:/system/media/audio/notifications

      闹钟铃声:/system/media/audio/alarms

      界面操作事件音:/system/media/audio/ui

==============================================================================================

 

每条属性包含了名字和其对应的值,两者都用字符串来描述。Android系统中大量的使用了属性系统用于记录系统的设置(注:和windows系统里的注册表类似),以及进程间的 信息交互。属性系统对于整个系统来说是全局的,也就是说每一个进程都可以获取和设置每条属性。

 

当系统初始化的时候,Android系统会分配一块共享内存用于存储属 性信息。这些操作是在"init"这个守护进程里完成的,其对应的源 代码目录在:device/system/init。"init"守护进程同时也启动了属性服务。属性
服务运行在init进程中(注:是线程?)。客户端需 要设置属性时,需要连接到属性服务上,同时发送消息给属性服务。这样属性服务就可以更新保存在共享内存中的属性信息。当客户端需要读取属性信息时,可以直 接访问共享内存,这样做可以提高性能。

 

客户端程序可以通过调用libcutils库里的API函数实现对属性的设置和读取的操作。

libcutils库对应的源代码存放在: device/libs/cutils。

这些API函数包括:

int property_get(const char *key, char *value, const char *default_value);

int property_set(const char *key, const char *value);
    libcutils库是通过调用libc库中的__system_property_xxx这一系列函数实现从共享内存中获取 属性的。对应的libc的源代码保存在:
device/system/bionic。
属性服务也会调用libc库中的函数__system_property_init来实现对共享内存的初始化。当启动 属性服务时会通过下面文件来加载默认的属性信息。

/default.prop
/system/build.prop
/system/default.prop
/data/local.prop
 
属性信息按照上面的顺序被加载。后加载的属性会覆盖前面的属性值(注:当属性名称相同的时候)。当上面加载完成后,最后加载的是驻留属性,保存在/data/property文件中。

 

特别的属性

如果属性是有”ro.”字符串开头,那么这条属性被看成 一个只读属性,一旦设置就不能被修改了。(注:初始化设置的时候是可写的)

如果属性是有“persist.”字符串开头,那么就认为是驻留属 性,当修改的时候同时也会被保存在/data/property文件中。

如果属性是有“net.”字符串开头,当设
4000
置这种属性的时 候,“net.change”这条属性也会被自动设置,其内容 设为最后更新过的属性名。

属性“ctrl.start”和“ctrl.stop”用于启动和停止服务。这些服务必须在文件/init.rc中被定义。在系统启动的时候,init守护进程会解析init.rc文件,然后启动属性服务。一旦收到
了“ctrl.start”这个属性的设置请求,属性服务会 根据该属性的值作为服务名,在列表中找到服务对象并启动。服务启动的结果会反映在“init.svc.<service name>”这个属性之中。客户端程序可以轮 询该属性值来判断服务的启动结果。

 

Android 工具箱

Android 工具箱提供了2个应用程序:setprop
和 getprop用于读取和设置属性项目。使用方法是:

getprop <property name>
setprop <property name> <property value> 

 

Java

Java程序可以通过使用函数System.getProperty()
和 System.setProperty()获取和设置属性条目。

 

动作

默认情况下设置属性只会触发init进程对共享内存进行操作,并不会执 行任何脚本和程序。但是你可以修改文件init.rc,这样在属性值发生变化的时候来触 发你定义的动作。例如在默认的init.rc文件中你可以找到下面这部分:

# adbd on at boot in emulator

on property:ro.kernel.qemu=1

    start adbd

 

on property:persist.service.adb.enable=1

    start adbd

 

on property:persist.service.adb.enable=0

    stop adbd

所以当属性条目persist.service.adb.enable被设置成1的时候,init守护进程知道他需要启动adbd服务。
 
另一篇:

Android 的系统属性包括两部分:文件保存的持久属性和每次开机导入的cache属性。前者主要保存在下面几个文件中:

bionic / libc / include / sys / _system_properties.h

1
2
3
4
5

#define  PROP_SERVICE_NAME "property_service"
#define  PROP_PATH_RAMDISK_DEFAULT  "/default.prop"
#define  PROP_PATH_SYSTEM_BUILD     "/system/build.prop"
#define  PROP_PATH_SYSTEM_DEFAULT   "/system/default.prop"
#define  PROP_PATH_LOCAL_OVERRIDE   "/data/local.prop"

后者则通过frameworks/base/core/java/android/os/SystemProperties.java的接口定义,

1
2
3
4
56
7
8
9
10
11
12
13

private   static   native  String native_get(String key);
private   static   native  String native_get(String key, String def);
private   static   native   void  native_set(String key, String def);
public   static   void  set(String key, String val) {
if  (key.length()  >  PROP_NAME_MAX) {
throw   new  IllegalArgumentException( " key.length >  "   +  PROP_NAME_MAX);
}
if  (val  !=   null   &&  val.length()  >  PROP_VALUE_MAX) {
throw   new  IllegalArgumentException( " val.length >  "   +
PROP_VALUE_MAX);
}
native_set(key, val);
}

该接口类在初始化运行环境中注册对应的cpp接口android_os_SystemProperties.cpp,实际操作通过JNI调用的是cpp文件对应的接口:

frameworks/base/core/jni/AndroidRuntime.cpp

1
2
3

namespace  android {
extern   int  register_android_os_SystemProperties(JNIEnv  * env);
}

frameworks/base/core/jni/android_os_SystemProperties.cpp

1
2
3
4
56
7
8
9
10
11
12
13
14
15
16
17

static   void  SystemProperties_set(JNIEnv  * env, jobject clazz, jstring keyJ, jstring valJ)
{
int  err;
const   char *  key;
const   char *  val;
key  =  env -> GetStringUTFChars(keyJ, NULL);
if  (valJ  ==  NULL) {
val  =   "" ;        /*  NULL pointer not allowed here  */
}  else  {
val  =  env -> GetStringUTFChars(valJ, NULL);
}
err  =  property_set(key, val);
env -> ReleaseStringUTFChars(keyJ, key);
if  (valJ  !=  NULL) {
env -> ReleaseStringUTFChars(valJ, val);
}
}

设置key的value时,需要作鉴权,根据设置程序所在进程的fd获知uid值,比如system server进程可以设置net打头的key,不可以设置gsm打头的key,相关的定义如下:

system/core/include/private/android_filesystem_config.h

1
2
3
4
56
7

#define  AID_ROOT             0  /* traditional unix root user */
#define  AID_SYSTEM        1000  /* system server */
#define  AID_RADIO         1001  /* telephony subsystem, RIL */
#define  AID_DHCP          1014  /* dhcp client */
#define  AID_SHELL         2000  /* adb and debug shell user */
#define  AID_CACHE         2001  /* cache access */
#define  AID_APP          10000 /* first app user */

system/core/init/property_service.c

1
2
3
4
56
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

#define  PERSISTENT_PROPERTY_DIR  "/data/property"
struct  {
const   char   * prefix;
unsigned  int  uid;
} property_perms[]  =  {
{  " net.rmnet0. " ,    AID_RADIO },
{  " net.gprs. " ,      AID_RADIO },
{  " ril. " ,           AID_RADIO },
{  " gsm. " ,           AID_RADIO },
{  " net.dns " ,        AID_RADIO },
{  " net.usb0 " ,       AID_RADIO },
{  " net. " ,           AID_SYSTEM },
{  " dev. " ,           AID_SYSTEM },
{  " runtime. " ,       AID_SYSTEM },
{  " hw. " ,            AID_SYSTEM },
{  " sys. " ,        AID_SYSTEM },
{  " service. " ,    AID_SYSTE
da82
M },
{  " wlan. " ,        AID_SYSTEM },
{  " dhcp. " ,        AID_SYSTEM },
{  " dhcp. " ,        AID_DHCP },
{  " debug. " ,        AID_SHELL },
{  " log. " ,        AID_SHELL },
{  " service.adb.root " ,    AID_SHELL },
{  " persist.sys. " ,    AID_SYSTEM },
{  " persist.service. " ,   AID_SYSTEM },
{ NULL,  0  }
};
int  property_set( const   char   * name,  const   char   * value)
{
property_changed(name, value);
return   0 ;
}
int  start_property_service( void )
{
int  fd;
 
load_properties_from_file(PROP_PATH_SYSTEM_BUILD);
load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);
load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE);
/*  Read persistent properties after all default values have been loaded.  */
load_persistent_properties();
 
fd  =  create_socket(PROP_SERVICE_NAME, SOCK_STREAM,  0666 ,  0 ,  0 );
if (fd  <   0 )  return   - 1 ;
fcntl(fd, F_SETFD, FD_CLOEXEC);
fcntl(fd, F_SETFL, O_NONBLOCK);
 
listen(fd,  8 );
return  fd;
}
void  handle_property_set_fd( int  fd)
{
switch (msg.cmd) {
case  PROP_MSG_SETPROP:
msg.name[PROP_NAME_MAX - 1 ]  =   0 ;
msg.value[PROP_VALUE_MAX - 1 ]  =   0 ;
 
if (memcmp(msg.name, " ctl. " , 4 )  ==   0 ) {
if  (check_control_perms(msg.value, cr.uid)) {
handle_control_message(( char * ) msg.name  +   4 , ( char * ) msg.value);
}  else  {
ERROR( " sys_prop: Unable to %s service ctl [%s] uid: %d pid:%d\n " ,
msg.name  +   4 , msg.value, cr.uid, cr.pid);
}
}  else  {
if  (check_perms(msg.name, cr.uid)) {
property_set(( char * ) msg.name, ( char * ) msg.value);
}  else  {
ERROR( " sys_prop: permission denied uid:%d  name:%s\n " ,
cr.uid, msg.name);
}
}
break ;
 
default :
break ;
}
}

在开机启动后的init操作中,会执行一个loop循环,当检测到有新的设置时,进入设置流程,鉴权失败会提示相关的异常,如sys_prop: permission denied uid:1000  name:gsm.phone.id

system/core/init/init.c

1
2
3
4
56
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

void  property_changed( const   char   * name,  const   char   * value)
{
if  (property_triggers_enabled) {
queue_property_triggers(name, value);
drain_action_queue();
}
}
int  main( int  argc,  char   ** argv)
{
parse_config_file( " /init.rc " );
qemu_init();
device_fd  =  device_init();
property_init();
fd  =  open(console_name, O_RDWR);
property_set_fd  =  start_property_service();
ufds[ 0 ].fd  =  device_fd;
ufds[ 0 ].events  =  POLLIN;
ufds[ 1 ].fd  =  property_set_fd;
ufds[ 1 ].events  =  POLLIN;
ufds[ 2 ].fd  =  signal_recv_fd;
ufds[ 2 ].events  =  POLLIN;
fd_count  =   3 ;
for (;;) {
if  (ufds[ 0 ].revents  ==  POLLIN)
handle_device_fd(device_fd);
 
if  (ufds[ 1 ].revents  ==  POLLIN)
handle_property_set_fd(property_set_fd);
if  (ufds[ 3 ].revents  ==  POLLIN)
handle_keychord(keychord_fd);
}
return   0 ;
}

OVER!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息