一、Android4.4属性系统系列文章
Android4.4属性系统-初始化
Android4.4属性系统-系统服务
Android4.4属性系统-内存空间共享
Android4.4属性系统-属性获取
Android4.4属性系统-属性设置
Android4.4-属性的使用总结
二、属性的使用总结
前面的几篇文章都是分析了属性系统的运作流程,但是日常开发中用到最多的还是对属性的获取和设置,以及不同类型的属性有什么特点,可读可写的权限问题,这篇文章就很接地气,总结了如何在安卓系统开发中获取、设置和添加属性。
2.1 属性的获取
属性的获取可以从java层接口和C接口进行分类,当然对于framework和APP开发者来说,用得最多的自然是java/JNI的接口,而对于JNI开发或者c库的开发来说,用的最多的应该是c接口。
2.1.1 java获取属性接口
获取属性并不需要额外的权限,对于是否是系统应用也没有要求。
使用示例
import android.os.SystemProperties;
//获取自定义的属性"persist.flyscale.wifi",默认值为-1
//获取int值
int wifiInt = SystemProperties.getInt("persist.flyscale.wifi.int", -1);
//获取long值
int wifiLong = SystemProperties.getLong("persist.flyscale.wifi.long", -1);
//获取bool值
boolean wifiBool = SystemProperties.getBoolean("persist.flyscale.wifi", false);
//获取string,如果没有则返回空字符串""
String wifiStr1 = SystemProperties.getInt("persist.flyscale.wifi");
//获取string,如果没有则返回指定默认值"def"
String wifiStr2 = SystemProperties.getInt("persist.flyscale.wifi", "def");
如果需要使用到c接口获取属性,请参考Android4.4属性系统-属性获取。
2.2 安卓属性的设置
如果看过前面的Android4.4属性系统-属性设置,就容易得出结论:属性设置是有权限要求的,对于uid为root是绝对允许的,而对于其它用户则是禁止的,除非通过了白名单的权限检查。
2.2.1 property权限检查
在说明如何进行设置之前,必须首先了解property的权限检查机制,否则只能是云里雾里,不知所云。
看过Android4.4属性系统-属性设置的读者应该了解了,属性是有几种分类的:
2.2.1.1 控制类属性ctl.*
ctl.开头的,例如ctl.start=property_service
表示启动名为"property_service"的服务,也即属性服务,这样就明白了,ctl.开头的属性表示控制服务的属性,需要AID_ROOT和AID_SYSTEM权限,除此之外在control_perms白名单中的也可以通过权限检查,如下:
/*
* White list of UID that are allowed to start/stop services.
* Currently there are no user apps that require.
*/
struct {
const char *service;
unsigned int uid;
unsigned int gid;
} control_perms[] = {
{ "dumpstate",AID_SHELL, AID_LOG }, //表示允许AID_SHELL用户控制 "dumpstate"服务
{ "ril-daemon",AID_RADIO, AID_RADIO }, //表示允许AID_RADIO用户控制 "ril-daemon"服务
{NULL, 0, 0 }
};
除了白名单中的两种服务可以被ROOT和SYSTEM之外的AID_SHELL和AID_RADIO用户控制之外,其它的一概拒绝!!!
2.2.1.2 其它的属性
除了控制属性之外的属性也需要通过权限检查,一般来说ROOT用户是绝对是被允许的,但是系统中除了少数核心进程之外,大部分不是ROOT用户,它们是通过另外一个白名单property_perms来控制的,如下:
/* White list of permissions for setting property services. */
struct {
const char *prefix;
unsigned int uid;
unsigned int gid;
} property_perms[] = {
{ "net.rmnet0.", AID_RADIO, 0 }, //
{ "net.gprs.", AID_RADIO, 0 },
{ "net.ppp", AID_RADIO, 0 },
{ "net.qmi", AID_RADIO, 0 },
{ "net.lte", AID_RADIO, 0 },
{ "net.cdma", AID_RADIO, 0 },
{ "ril.", AID_RADIO, 0 },
{ "gsm.", AID_RADIO, 0 },
{ "persist.radio", AID_RADIO, 0 },
{ "persist.radio", AID_SYSTEM, 0 },
{ "net.dns", AID_RADIO, 0 },
{ "sys.usb.config", AID_RADIO, 0 },
{ "net.", AID_SYSTEM, 0 },
{ "dev.", AID_SYSTEM, 0 },
{ "runtime.", AID_SYSTEM, 0 },
{ "hw.", AID_SYSTEM, 0 },
{ "sys.", AID_SYSTEM, 0 },
{ "sys.powerctl", AID_SHELL, 0 },
{ "service.", AID_SYSTEM, 0 },
{ "wlan.", AID_SYSTEM, 0 },
{ "bluetooth.", AID_BLUETOOTH, 0 },
{ "dhcp.", AID_SYSTEM, 0 },
{ "dhcp.", AID_DHCP, 0 },
{ "debug.", AID_SYSTEM, 0 },
{ "debug.", AID_SHELL, 0 },
{ "log.", AID_SHELL, 0 },
{ "service.adb.root", AID_SHELL, 0 },
{ "service.adb.tcp.port", AID_SHELL, 0 },
{ "persist.sys.", AID_SYSTEM, 0 }, //系统类属性
{ "persist.msms.", AID_RADIO, 0 },//SPRD: add for dsds
{ "persist.msms.", AID_SYSTEM, 0 },
{ "persist.service.", AID_SYSTEM, 0 },
{ "persist.security.", AID_SYSTEM, 0 },
{ "media.", AID_MEDIA, 0 },
{ "persist.service.bdroid.", AID_BLUETOOTH, 0 },
{ "selinux." , AID_SYSTEM, 0 },
{ "persist.modem.", AID_RADIO, 0 },//SPRD: add for lte
{ NULL, 0, 0 }
};
看着很多,其实很好理解 ,就拿 { "persist.sys.", AID_SYSTEM, 0 },
来说吧,它表示以"persist.sys."开头的属性是允许AID_SYSTEM用户修改的,其它的类同。
还有很重要的一点,以ro.开头的表示只读属性,即使是AID_ROOT用户也是不允许修改的。
做一个小总结:如果需要修改/添加属性,那么修改属性的代码运行的进程必须要通过权限检查,否则会失败,权限检查的细节也已经分析过了,很简单吧,立即推==》一切难题都是纸老虎。
2.2.2 java接口设置属性
java层的设置接口API只有一个SystemProperties.set(String key, String value),也就是说所有的属性value值要转为字符串被设置进去。
2.2.2.1uid(权限)配置为system
首先要想成功设置你的APP uid为system,就需要做一些配置了。
- 在AndroidManifest.xml中,以系统应用的Settings为例,配置android:sharedUserId属性
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.settings"
coreApp="true"
android:sharedUserId="android.uid.system">
- 另外在对应的Android.mk中使用系统平台签名:
如果你有源码编译环境,对mk做如下配置
LOCAL_CERTIFICATE := platform
在模块目录下执行mm编译即可。
当然如果你没有源码环境,也是可以进行平台签名的,请参考的另一篇文章Android4.4-APP系统签名的实现方案,其最终目的是一样的
2.2.2.2 调用java接口
只是简单的接口调用,很简单了
import android.os.SystemProperties;
SystemProperties.set("persist.sys.volte.enable", "1");
2.2.3 案例分析
我预置的一个测试应用,测试代码如下,按上键获取"persist.sys.volte.enable",默认为false
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_UP:
Log.i("HomeActivity", "persist.sys.volte.enable=" + SystemProperties.getBoolean("persist.sys.volte. enable", false));
break;
case KeyEvent.KEYCODE_DPAD_DOWN:
SystemProperties.set("persist.sys.volte.enable", "false");
Log.i("HomeActivity", "persist.sys.volte.enable=" + SystemProperties.getBoolean("persist.sys.volte. enable", true));
break;
此时用户uid为radio,因为AndroidManifest.xml中配置了android:sharedUserId="android.uid.phone"
:
USER PID PPID VSIZE RSS WCHAN PC NAME
radio 845 145 222304 9032 ffffffff 00000000 S com.flyscale.launcher
先获取一次,再设置为1,再获取,输出结果如下:
com.flyscale.launcher I/HomeActivity: persist.sys.volte.enable=true //设置为false前
com.flyscale.launcher I/HomeActivity: persist.sys.volte.enable=true //设置为false后仍然为true
在设置属性的时候报错如下:
init: sys_prop: permission denied uid:1001 name:persist.sys.volte.enable=true
显然权限未通过啊。在经过之前两步配置uid后:
system 864 142 222796 11388 ffffffff 00000000 S com.flyscale.launcher
再次运行结果
com.flyscale.launcher I/HomeActivity: persist.sys.volte.enable=true //修改前
com.flyscale.launcher I/HomeActivity: persist.sys.volte.enable=false //修改后
修改成功!
2.3属性的添加
在代码中添加属性与设置属性的接口是一样的,也需要注意权限检查。如果该属性存在就会更新,如果不存在就会创建,但是要注意,属性是不能被删除的。
另外我们经常在安卓源码中预置一些属性配置,那么都在哪些地方可以配置属性呢,要注意些什么呢?
-
注意权限检查
例如我要添加一个属性persist.flyscale.wifi=0
,那么它肯定是无法通过权限检查的,因为它不在白名单中,那么怎么办呢?可以改成persist.sys.flyscale.wifi=0
,这样就可以了,因为白名单中有persist.sys.
开头的属性,是可以被AID_SYSTEM修改的。 -
可以在源码中默认配置的文件
首先工程目录下的system.prop是可以直接添加的,如下:
device/***/scx35l/sp9820w_poc_780/system.prop
#add for test
persist.sys.flyscale.wifi=0
另外在工程编译的mk文件中也可以配置,但是要使用PRODUCT_PROPERTY_OVERRIDES语句
PRODUCT_PROPERTY_OVERRIDES += persist.sys.volte.enable=true
以上为本人使用中的总结,欢迎指正和补充,谢谢大家!
网友评论