Android开发中关于属性系统的简单介绍
1、简介
在android中,为统一管理系统的属性,设计了一个统一的属性系统。每个属性都有一个名称和值,他们都是字符串格式。属性被大量使用在android系统中,用来记录系统设置或进程之间的信息交换。属性是在整个系统中全局可见的。每个进程可以get/set属性。在编译的过程中会将各种系统参数汇总到build.proc以及default.proc这两个文件中,主要属性集中在build.proc中。系统在开机后将读取配置信息并构建共享缓冲区,加快查询速度。另外一个方面,settingsprovider会在系统第一次初始化时(刷机第一次启动)后,将从defaults.xml中读取数据然后写入settings.db目录。并构建一个缓冲系统供其他应用查询。下面将详细讲述。
2、properties type
系统属性根据不同的应用类型,分为不可变型,持久型,网络型,启动和停止服务等。
特别属性:
属性名称以“ro.”开头,那么这个属性被视为只读属性。一旦设置,属性值不能改变。
属性名称以“persist.”开头,当设置这个属性时,其值也将写入/data/property。
属性名称以“net.”开头,当设置这个属性时,“net.change”属性将会自动设置,以加入到最后修改的属性名。(这是很巧妙的。netresolve模块的使用这个属性来追踪在net.*属性上的任何变化。)
属性“ ctrl.start ”和“ ctrl.stop ”是用来启动和停止服务。每一项服务必须在/init.rc中定义.系统启动时,与init守护进程将解析init.rc和启动属性服务。一旦收到设置“ ctrl.start ”属性的请求,属性服务将使用该属性值作为服务名找到该服务,启动该服务。这项服务的启动结果将会放入“ init.s.<服务名>“属性中。客户端应用程序可以轮询那个属性值,以确定结果。
3、android toolbox
android toolbox程序提供了两个工具:setprop和getprop获取和设置属性。其使用方法:
getprop <属性名>
setprop <属性名> <属性值>
在java应用程序可以使用system.getproperty()和system.setproperty()函数获取和设置属性。
action
默认情况下,设置属性只会使"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
4、properties source
原则上,属性的设置可以出现在make android的任何环节。目前properties的设置以oppo版本为例:
alps\build\target\board\generic_arm64\ system.prop
alps\build\target\product\core.mk
alps\build\tools\buildinfo.sh
编译好后,被设置的系统属性主要存放在:
这样,如果你设置persist.service.adb.enable为1,"init"守护程序就知道需要采取行动:开启adbd服务。
\ default.prop手机厂商自己定制使用
\system\build.prop 系统属性主要存放处
\system\default.prop default properties,有存放与security相关的属性
\data\local.prop目前还没有看到有内置的情况
\data\property下有4个prop文件:persist.sys.timezone, persist.sys.language, persist.sys.country, persist.sys.localevar,里面保存着属性名称以“persist.”开头的属性值。用户的persist开头的属性都会保存副本在这个目录下
5、properties run
5.1properties init.
在linux kernel启动时,android将分配一个共享内存区来存储的属性。这些是由“init”守护进程完成的,其源代码位于:system/core/init。“init”守护进程将启动一个属性服务。属性服务在“init”守护进程中运行。每一个客户端想要设置属性时,必须连接属性服务,再向其发送信息。属性服务将会在共享内存区中修改和创建属性。客户端想获得属性信息,可以从共享内存直接读取。这提高了读取性能。
客户端应用程序可以调用libcutils中的api函数以get/set属性信息。libcutils的源代码位于:system/core/ibcutils。获取和设置属性的代码在properties.c里面,读取属性通过读共享内存得到,设置属性通过发送请求到property_service进行设置。api函数是:
int property_get(const char *key, char *value, const char *default_value); int property_set(const char *key, const char *value); int property_list(void(*propfn)(const char * key, const char * value, void * cookie), void * cookie); system/core/init. c= > main( ) 进程将调用 = > property_init = > init_property_area void property_init( void ) { //ashmem_area - android shared memory area是android共享内容存的一种方式 //打开ashmem设备,申请一段size大小的kernel空间内存,不去释放,以便供所有用户空间进程共享. //内核驱动位于linux/mm/ashmem.c文件[luther.gliethttp]. init_property_area( ) ; //#define prop_path_ramdisk_default "/default.prop" //从ramdisk中读取default.prop文件,将文件中的所有java环境中使用到的propt释放到 //这个共享内存中. load_properties_from_file( prop_path_ramdisk_default) ; }
后面将调用properties_service.c,启动最原始的properties service.
然后通过libc_init_common. c,的__system_properties_init函数完成内核的初始化工作。
5.2、属性的访问
如果在c/c++层次,则可以使用libcutils的下列函数来访问。
int property_get(const char *key, char *value, const char *default_value); int property_set(const char *key, const char *value); int property_list(void(*propfn)(const char * key, const char * value, void * cookie), void * cookie);
如果在java层次,则可以使用system.getproperties/setproperties.该方法(set/get)实际将调用systemproperties.java进行访问,而systemproperties.java通过jni调用libcutils进行访问。
5.3、enlarge system property
android default system property默认是可以存储247笔properties.但因为我司有大量的数据被写入到这个system property中,导致容易出现system property mmap到kernel ashmem中的缓存ashmem溢出。一方面需要确认数据是否确实有必要写入system property,另外一方面,可以扩大缓存的区间。
缓存区间可以分成两大部分(byte), info area , array area. info area又分成header和name mapping area.
8 header *4 |
every property name mapping * 4 |
every value row and the max length is 127 |
因为,给出固定的最大笔数n.缓存定义上要求
#define pa_count_max n #define pa_info_start((8+pa_count_max) * 4) 最好保证这个值为32的整数倍 #define pa_sze (pa_info_start + (128 * pa_count_max))
5.4、控制属性
在system properties中提供两个特殊的key, ctl.start和ctl.stop来启动和关闭服务。
其api描述是:
systemproperties.set(“ctl.start”,servicename); systemproperties.set(“ctl.stop”,servicename);
注意的是,这个servicename可在init.rc中查询
5.5、init属性
init属性是system properties中的一种特殊的属性,由init.c定义,init会监控定义在init.rc中的服务,并定义init.svc.xxxx的system properties.
具体实现,可参考init.c中的notify_service_state函数。
我们除了直接ps来查看这些进程信息外,还可以直接通过查看system properties来确认这些服务的状态,如
[init.svc.bootlogoupdater]: [stopped] [init.svc.pvrsrvinit]: [stopped] [init.svc.servicemanager]: [running] [init.svc.vold]: [running] [init.svc.netd]: [running] [init.svc.netdiag]: [running] [init.svc.hald]: [running] [init.svc.debuggerd]: [running] [init.svc.zygote]: [running] [init.svc.drmserver]: [running] [init.svc.media]: [running] [init.svc.dbus]: [running] [init.svc.installd]: [running] [init.svc.keystore]: [running] [init.svc.console]: [running] [init.svc.adbd]: [running] [init.svc.ril-daemon]: [running]
5.6、属性安全性
作为一个共享的缓存系统,并非任何ap都可以随意去修改其中的属性,针对这些属性,如果进行更改时,会有uid上的约束。
/* 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 }, { "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 }, { "gps.", aid_gps,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.logd.size",aid_system,0 }, { "persist.sys.", aid_system,0 }, { "persist.service.", aid_system,0 }, { "persist.security.", aid_system,0 }, { "persist.gps.",aid_gps,0 }, { "persist.service.bdroid.", aid_bluetooth,0 }, { "selinux.", aid_system,0 }, { "wc_transport.", aid_bluetooth,aid_system }, { "build.fingerprint", aid_system,0 }, { "partition." , aid_system,0}, #ifdef dolby_udc { "dolby.audio",aid_media, 0 }, #endif // dolby_udc #ifdef dolby_dap // used for setting dolby specific properties { "dolby.", aid_system,0 }, #endif // dolby_dap { "sys.audio.init",aid_media, 0 }, { null, 0, 0 } };
具体的uid映射为:
#define aid_radio1001 /* telephony subsystem, ril */ #define aid_bluetooth 1002 /* bluetooth subsystem */ #define aid_graphics1003 /* graphics devices */ #define aid_input1004 /* input devices */ #define aid_audio1005 /* audio devices */ #define aid_camera 1006 /* camera devices */ #define aid_log 1007 /* log devices */ #define aid_compass 1008 /* compass device */ #define aid_mount1009 /* mountd socket */ #define aid_wifi 1010 /* wifi subsystem */ #define aid_adb 1011 /* android debug bridge (adbd) */ #define aid_install 1012 /* group for installing packages */ #define aid_media1013 /* mediaserver process */ #define aid_dhcp 1014 /* dhcp client */ #define aid_sdcard_rw 1015 /* external storage write access */ #define aid_vpn 1016 /* vpn system */ #define aid_keystore1017 /* keystore subsystem */ #define aid_usb 1018 /* usb devices */ #define aid_drm 1019 /* drm server */ #define aid_mdnsr1020 /* multicastdnsresponder (service discovery) */ #define aid_gps 1021 /* gps daemon */ #define aid_unused1 1022 /* deprecated, do not use */ #define aid_media_rw1023 /* internal media storage write access */ #define aid_mtp 1024 /* mtp usb driver access */ #define aid_unused2 1025 /* deprecated, do not use */ #define aid_drmrpc 1026 /* group for drm rpc */ #define aid_nfc 1027 /* nfc subsystem */ #define aid_sdcard_r1028 /* external storage read access */ #define aid_clat 1029 /* clat part of nat464 */ #define aid_loop_radio 1030 /* loop radio devices */ #define aid_media_drm 1031 /* mediadrm plugins */ #define aid_package_info 1032 /* access to installed package details */ #define aid_sdcard_pics1033 /* external storage photos access */ #define aid_sdcard_av 1034 /* external storage audio/video access */ #define aid_sdcard_all 1035 /* access all users external storage */ #define aid_logd 1036 /* log daemon */ #define aid_shared_relro 1037 /* creator of shared gnu relro files */
即如persist.sys开头的属性,只能有system user(包括root)进行修改,其他用户无法进行修改。
这个user id表定义在\system\core\init\property_service.c和\system\core\include\private\android_filesystem_config.h文件中
6、setting provider
在android framework中还定义了setting provider来对一些比较通用的数据进行初始化,并将数据写入settings.db.其中直接在setting provider中被初始化的属性写在defaults.xml中:
true 60000 false cell,bluetooth,wifi wifi true true 102 false 0% 0% true false false gps true 1 true false true false true true false true true 1 /system/media/audio/ui/lowbattery.ogg 0 /system/media/audio/ui/dock.ogg /system/media/audio/ui/undock.ogg /system/media/audio/ui/dock.ogg /system/media/audio/ui/undock.ogg 0 /system/media/audio/ui/lock.ogg /system/media/audio/ui/unlock.ogg true
settingsprovider将通过databasehelper将这些数据读入settings.db,同时settingsprovider作为控制settings.db的provider,所有对该数据库的操作都要通过它来进行。
其他具体的属性的描述都在settings.java这个类中描述。
settings为提高访问的效率,建立了cache,只有当cache中找不到时,才会调用settingsprovider去查询settings.db数据库。
具体的setiings.db中包括的数据库表有:
关键的system表中的数据有:
一般通过修改defaults.xml和make中的配置文件即可。
7、about phone properties.
about phone中的一些关键属性通过buildinfo.sh来焊接(make - build),经过测试,可修改alps\build\tools\buildinfo.sh来修改显示的情况,整理一下如下:
修改echo "ro.build.display.id=$build_display_id",把 $build_display_id 修改成其他的名称可改变 build nubmer. 注意此时要去除$.
修改echo "ro.product.model=$product_model",把 $product_model 修改成其他的名称可改变 model nubmer.注意此时要去除$
修改echo "ro.build.version.release=2.1" ,中的2.1 可改变显示的firmware version,这个不建议修改。
baseband version直接写在modem.img中,开机后modem自动推送到android端,需要专门的tool才能修改。
kernel version为linux编译过程中产生,按照标准的linux格式生成(compile.h),最后版本信息写在文件/proc/version下,所有的版本信息即在该文件的第一行,然后使用了一个正则表达式过滤了版本信息中一些字符。
8、about user build and eng build
在user <-> eng版本中*切换。
郑重声明:在出厂正式版本的时候,请务必关闭该feature,不然将导致机器异常容易被root.
1.首先说明一下user eng版本之间的差异
eng this is the default flavor. a plain make is the same as make eng.
installs modules tagged with: eng, debug, user, and/or development.
installs non-apk modules that have no tags specified.
installs apks according to the product definition files, in addition to tagged apks.
ro.secure=0
ro.debuggable=1
ro.kernel.android.checkjni=1
adb is enabled by default.
setupwizard is optional
user make user
this is the flavor intended to be the final release bits.
installs modules tagged with user.
installs non-apk modules that have no tags specified.
installs apks according to the product definition files; tags are ignored for apk modules.
ro.secure=1
ro.debuggable=0
adb is disabled by default.
enable dex pre-optimization for all target projects in default to speed up device first boot-up
userdebug make userdebug
the same as user, except:
also installs modules tagged with debug.
ro.debuggable=1
adb is enabled by default.
2.从安全角度来将,其差别主要是四个system properties的设置,在正常情况下,如果不更新boot image,那么
ro.secure
ro.allow.mock.location
ro.debuggable
是无法被修改的,即在编译的时候就已经决定了
3.要使得这几个值能够被修改,那么必须修改system properties的实现,system properties的实现上,driver是ashmem,上次实现是property_service.c,需要修改的地方有两处。
3.1 check_perms函数中,增加下面一段,放在这个函数的最前面
//add for user -> root
if(!strcmp(name,"ro.secure") || !strcmp(name,"ro.allow.mock.location") || !strcmp(name,"ro.debuggable") || !strcmp(name,"persist.service.adb.enable")){
return 1;
}
3.2 property_set函数中屏蔽
/* ro.* properties may never be modified once set */
//for user -> root
// if(!strncmp(name, "ro.", 3)) return -1;
至此,我们已经完全开放了property中这四个property的控制权,当然如果您还想稍微加以控制,您可以增加pid, uid等的控制,减小这个权限范围。
4.编写一个application,来实现*调控,您可以创建一个简单的application,里面包括这个activity即可。
package com.example.user2root; import android.app.activity; import android.os.bundle; import android.os.systemproperties; import android.view.view; import android.view.view.onclicklistener; import android.widget.button; import android.widget.toast; /** * * this is a demo for user to root. * if you use this app, you must open system properties write security. * */ public class user2rootactivity extends activity { /** called when the activity is first created. */ private button mrootbutton; private button muserbutton; private static final string ro_secure = "ro.secure"; private static final string ro_allow_mock_location="ro.allow.mock.location"; private static final string ro_debug = "ro.debuggable"; private static final string adb_enable = "persist.service.adb.enable"; private onclicklistener mrootlistener = new button.onclicklistener(){ @override public void onclick(view v) { systemproperties.set(adb_enable, "1"); systemproperties.set(ro_secure, "0"); systemproperties.set(ro_allow_mock_location,"1" ); systemproperties.set(ro_debug, "1"); toast.maketext(user2rootactivity.this, "update to root success", toast.length_long).show(); } }; private onclicklistener muserlistener = new button.onclicklistener(){ @override public void onclick(view v) { systemproperties.set(adb_enable, "0"); systemproperties.set(ro_secure, "1"); systemproperties.set(ro_allow_mock_location,"0" ); systemproperties.set(ro_debug, "0"); toast.maketext(user2rootactivity.this, "update to user success", toast.length_long).show(); } }; protected void findviews(){ this.mrootbutton = (button) this.findviewbyid(r.id.root); this.muserbutton = (button) this.findviewbyid(r.id.user); } protected void setactionlistener() { this.mrootbutton.setonclicklistener(this.mrootlistener); this.muserbutton.setonclicklistener(this.muserlistener); } @override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); this.findviews(); this.setactionlistener(); } }
至此已经完成了全部的工作,把这个apk编译进去后,您将发现您可以*的切换user eng了。
上一篇: 这样的同志可放心