欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android开发中关于属性系统的简单介绍

程序员文章站 2022-03-23 14:25:50
1、简介 在android中,为统一管理系统的属性,设计了一个统一的属性系统。每个属性都有一个名称和值,他们都是字符串格式。属性被大量使用在android系统中,用来记录系统设置或进程之间的信息交换...

1、简介

在android中,为统一管理系统的属性,设计了一个统一的属性系统。每个属性都有一个名称和值,他们都是字符串格式。属性被大量使用在android系统中,用来记录系统设置或进程之间的信息交换。属性是在整个系统中全局可见的。每个进程可以get/set属性。在编译的过程中会将各种系统参数汇总到build.proc以及default.proc这两个文件中,主要属性集中在build.proc中。系统在开机后将读取配置信息并构建共享缓冲区,加快查询速度。另外一个方面,settingsprovider会在系统第一次初始化时(刷机第一次启动)后,将从defaults.xml中读取数据然后写入settings.db目录。并构建一个缓冲系统供其他应用查询。下面将详细讲述。

Android开发中关于属性系统的简单介绍

2properties type

系统属性根据不同的应用类型,分为不可变型,持久型,网络型,启动和停止服务等。

特别属性:

属性名称以“ro.”开头,那么这个属性被视为只读属性。一旦设置,属性值不能改变。

属性名称以“persist.”开头,当设置这个属性时,其值也将写入/data/property。

属性名称以“net.”开头,当设置这个属性时,“net.change”属性将会自动设置,以加入到最后修改的属性名。(这是很巧妙的。netresolve模块的使用这个属性来追踪在net.*属性上的任何变化。)

属性“ ctrl.start ”和“ ctrl.stop ”是用来启动和停止服务。每一项服务必须在/init.rc中定义.系统启动时,与init守护进程将解析init.rc和启动属性服务。一旦收到设置“ ctrl.start ”属性的请求,属性服务将使用该属性值作为服务名找到该服务,启动该服务。这项服务的启动结果将会放入“ init.s.<服务名>“属性中。客户端应用程序可以轮询那个属性值,以确定结果。

  3android toolbox

android toolbox程序提供了两个工具:setprop和getprop获取和设置属性。其使用方法:

getprop <属性名>

setprop <属性名> <属性值>

java

在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

  4properties 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开头的属性都会保存副本在这个目录下

  5properties 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了。