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 5 6 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 5 6 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 5 6 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 5 6 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_SYSTEM }, { " 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 5 6 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!