1.什么是Android属性?
属性(property)系统对Android来说是一个重要的功能。他作为一个系统服务管理着系统的配置和状态,所有的这些系统配置和状态都是属性(property)。属性(property)是一对键/值(key/value)组合,键和值都是字符串类型。总体感觉属性系统非常像Windows的注册表的功能。Androd中非常多的应用程序和库直接或者间接的依赖于属性系统,并由此决定其运行期的行为。例如:adbd进程通过属性来决定是否当前运行在模拟器中。再比如:java.io.File.pathSeparator方法返回存储在属性服务中的值。
Android属性系统由有三个进程,一组属性文件和一块共享内存组成。这块共享内存保存着系统中所有的属性记录,只有Property service能写这块共享内存,并且Property service负责将属性文件中的属性记录加载到共享内存中。
2.ROM源码里的属性初始值
请参见:http://www.ibm.com/developerworks/cn/opensource/os-cn-android-build/
在/build/target/product目录下每个文件定义了一个组合,我们只要继承这些预置的定义,然后再覆盖自己想要的变量定义即可。例如:
继承 full_base.mk 文件中的定义
(callinherit−product,
(SRC_TARGET_DIR)/product/full_base.mk)
# 覆盖其中已经定义的一些变量
PRODUCT_NAME := full_lt26
PRODUCT_DEVICE := lt26
PRODUCT_BRAND := Android
PRODUCT_MODEL := Full Android on LT26
产品版本定义文件中的变量及其说明
常量 说明
PRODUCT_NAME 最终用户将看到的完整产品名,会出现在“关于手机”信息中。
PRODUCT_MODEL 产品的型号,这也是最终用户将看到的。
PRODUCT_LOCALES 该产品支持的地区,以空格分格,
例如:en_GB de_DE es_ES fr_CA。
PRODUCT_PACKAGES 该产品版本中包含的 APK 应用程序,以空格分格,
例如:Calendar Contacts。
PRODUCT_DEVICE 该产品的工业设计的名称。
PRODUCT_MANUFACTURER 制造商的名称。
PRODUCT_BRAND 该产品专门定义的商标(如果有的话)。
PRODUCT_PROPERTY_OVERRIDES 对于商品属性的定义。
PRODUCT_COPY_FILES 编译该产品时需要拷贝的文件,以“源路径 : 目标路径”的形式。
PRODUCT_OTA_PUBLIC_KEYS 对于该产品的 OTA 公开 key 的列表。
PRODUCT_POLICY 产品使用的策略。
PRODUCT_PACKAGE_OVERLAYS 指出是否要使用默认的资源或添加产品特定定义来覆盖。
PRODUCT_CONTRIBUTORS_FILE HTML 文件,其中包含项目的贡献者。
PRODUCT_TAGS 该产品的标签,以空格分格。
3.Android系统里读取流程
属性读取进程(property consumer)把这块共享内存映射到自己的进程空间,然后直接读取它。属性设置进程(property setter)也加载这块共享到他的进程空间,但是他不能直接写这块共享内存。当他需要增加或者修改属性的时候,通过Unix Socket发生属性给Property service,Property service将代表设置进程写入共享内存和属性文件。
Property service运行于init进程中。init进程首先创建一块共享内存,并把他的句柄fd存放在这块内存中,init进程通过mmap带MAP_SHARE标志的系统调用,把这块内存映射到他的虚拟空间中,最终这块内存所有的更新将会被所有映射这块共享内存的进程看到。共享内存句柄fd和共享内存大小存储在系统环境变量“ANDROID_PROPERTY_WORKSPACE”中,所有的进程包括属性设置进程和属性读取进程都将通过这个系统环境变量获得共享内存的句柄fd和大小,然后把这块内存映射到他们自己的虚拟空间。
然后,init进程将会从以下文件中加载属性:
1: /default.prop
2: /system/build.prop
3: /system/default.prop
4: /data/local.prop
下一步是启动Property service。这步中,将会创建一个Unix Socket服务器,这个Socket有一个闻名的名称“/dev/socket/property_service”。最后init进入死循环,等待socket的连接请求。
在读取进程中,当它初始化libc库的时候,将会获得属性系统共享内存的句柄和大小(bionic/libc/bionic/libc_init_common.c __libc_init_common函数)。并把这块共享内存映射到自己的进程虚拟空间中(bionic/libc/bionic/system_properties.c __system_properties_init函数)。这样读取进程将会向访问普通内存一样访问属性系统的共享内存了。
当前,属性不能被删除。也就是说一旦属性被创建,将不可以被删除,但是它们可以被修改。
3.怎样获得和设置属性
在Android中有三种方式来设置和获取属性,两种方式读取:
1、Native代码
当编写Native的程序时,可以使用property_get和property_set API来获得和设置属性。使用这两个API必须要包含头文件cutils/properties.h和链接libcutil库。
2、Java代码
Android在Java库中提供System.getProperty和System.setProperty方法,我们Java程序可以通过他们来设置和获得属性。
但是请注意!虽然从语法上面看Java的代码和Native代码非常相近,但是Java版本存储把属性存在其他地方,而不是我们上面提到的属性系统中。在JVM中有一个hash表来维护Java的属性。所以Java属性和Android属性是不同的,不能用Java API(System.getProperty和System.setProperty)来设置系统属性。也不能通过Native的方法(property_get和property_set)设置Java的属性。
Andrew指出android.os.SystemProperties可以操作Android系统属性(虽然这个类倾向于内部使用)。这个类通过JNI调用Native的property_get和property_set方法来获得和设置属性。
3、Shell脚本
Android提供了命令行工具setprop和getprop来设置和获取属性,他们可以在脚本中被使用。
Shell脚本:
adb shell getprop
看到结果(所有值):
……
adb shell getprop ro.product.brand
rockchip
即可以看到brand属性。
代码里实现见Demo:
4、直接读取文件
// 获取build.prop中的指定属性
public String GetBuildProproperties(String PropertiesName) {
String name = "";
try
{
InputStream is = new BufferedInputStream(new FileInputStream(new File("/system/build.prop")));
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String strTemp = "";
while ((strTemp = br.readLine()) != null)
{// 如果文件没有读完则继续
if (strTemp.indexOf(PropertiesName) != -1) {
name = strTemp.substring(strTemp.indexOf("=") + 1);
break;
}
}
br.close();
is.close();
}catch (Exception e){
if (e.getMessage() != null)
System.out.println( e.getMessage());
else
e.printStackTrace();
}
return name;
}
5.使用系统方法:android.os.Build(只读)
客户端在代码里如下方法即可读取,(需要注意的是,修改了文件之后,不能立即读取,需要重启设备才能起作用):
public String systembuildInfo() {
return android.os.Build.BRAND;
/*
String phoneInfo = "Product: " + android.os.Build.PRODUCT;
phoneInfo += ", CPU_ABI: " + android.os.Build.CPU_ABI;
phoneInfo += ", TAGS: " + android.os.Build.TAGS;
phoneInfo += ", VERSION_CODES.BASE: " + android.os.Build.VERSION_CODES.BASE;
phoneInfo += ", MODEL: " + android.os.Build.MODEL;
phoneInfo += ", SDK: " + android.os.Build.VERSION.SDK;
phoneInfo += ", VERSION.RELEASE: " + android.os.Build.VERSION.RELEASE;
phoneInfo += ", DEVICE: " + android.os.Build.DEVICE;
phoneInfo += ", DISPLAY: " + android.os.Build.DISPLAY;
phoneInfo += ", BRAND: " + android.os.Build.BRAND;
phoneInfo += ", BOARD: " + android.os.Build.BOARD;
phoneInfo += ", FINGERPRINT: " + android.os.Build.FINGERPRINT;
phoneInfo += ", ID: " + android.os.Build.ID;
phoneInfo += ", MANUFACTURER: " + android.os.Build.MANUFACTURER;
phoneInfo += ", USER: " + android.os.Build.USER;
return phoneInfo;*/
}
--致谢导师贾丽 .