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.svc.<服務名>“屬性中 。客戶端應用程式可以輪詢那個屬性值,以確定結果。
3、Android 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
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.1 Properties 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_RADIO 1001 /* telephony subsystem, RIL */ #define AID_BLUETOOTH 1002 /* bluetooth subsystem */ #define AID_GRAPHICS 1003 /* graphics devices */ #define AID_INPUT 1004 /* input devices */ #define AID_AUDIO 1005 /* audio devices */ #define AID_CAMERA 1006 /* camera devices */ #define AID_LOG 1007 /* log devices */ #define AID_COMPASS 1008 /* compass device */ #define AID_MOUNT 1009 /* 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_MEDIA 1013 /* 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_KEYSTORE 1017 /* keystore subsystem */ #define AID_USB 1018 /* USB devices */ #define AID_DRM 1019 /* DRM server */ #define AID_MDNSR 1020 /* MulticastDNSResponder (service discovery) */ #define AID_GPS 1021 /* GPS daemon */ #define AID_UNUSED1 1022 /* deprecated, DO NOT USE */ #define AID_MEDIA_RW 1023 /* 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_R 1028 /* 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_PICS 1033 /* 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中:
<resources> <bool name="def_dim_screen">true</bool> <integer name="def_screen_off_timeout">60000</integer> <bool name="def_airplane_mode_on">false</bool> <!-- Comma-separated list of bluetooth, wifi, and cell. --> <string name="def_airplane_mode_radios" translatable="false">cell,bluetooth,wifi</string> <string name="airplane_mode_toggleable_radios" translatable="false">wifi</string> <bool name="def_auto_time">true</bool> <bool name="def_accelerometer_rotation">true</bool> <!-- Default screen brightness, from 0 to 255. 102 is 40%. --> <integer name="def_screen_brightness">102</integer> <bool name="def_screen_brightness_automatic_mode">false</bool> <fraction name="def_window_animation_scale">0%</fraction> <fraction name="def_window_transition_scale">0%</fraction> <bool name="def_haptic_feedback">true</bool> <bool name="def_bluetooth_on">false</bool> <bool name="def_install_non_market_apps">false</bool> <!-- Comma-separated list of location providers. Network location is off by default because it requires user opt-in via Setup Wizard or Settings. --> <string name="def_location_providers_allowed" translatable="false">gps</string> <bool name="assisted_gps_enabled">true</bool> <!-- 0 == mobile, 1 == wifi. --> <integer name="def_network_preference">1</integer> <bool name="def_usb_mass_storage_enabled">true</bool> <bool name="def_wifi_on">false</bool> <bool name="def_networks_available_notification_on">true</bool> <bool name="def_backup_enabled">false</bool> <string name="def_backup_transport" translatable="false"></string> <!-- Default value for whether or not to pulse the notification LED when there is a pending notification --> <bool name="def_notification_pulse">true</bool> <bool name="def_mount_play_notification_snd">true</bool> <bool name="def_mount_ums_autostart">false</bool> <bool name="def_mount_ums_prompt">true</bool> <bool name="def_mount_ums_notify_enabled">true</bool> <!-- user interface sound effects --> <integer name="def_power_sounds_enabled">1</integer> <string name="def_low_battery_sound" translatable="false"> /system/media/audio/ui/LowBattery.ogg </string> <integer name="def_dock_sounds_enabled">0</integer> <string name="def_desk_dock_sound" translatable="false"> /system/media/audio/ui/Dock.ogg </string> <string name="def_desk_undock_sound" translatable="false"> /system/media/audio/ui/Undock.ogg </string> <string name="def_car_dock_sound" translatable="false"> /system/media/audio/ui/Dock.ogg </string> <string name="def_car_undock_sound" translatable="false"> /system/media/audio/ui/Undock.ogg </string> <integer name="def_lockscreen_sounds_enabled">0</integer> <string name="def_lock_sound" translatable="false"> /system/media/audio/ui/Lock.ogg </string> <string name="def_unlock_sound" translatable="false"> /system/media/audio/ui/Unlock.ogg </string> <!-- Default for Settings.System.VIBRATE_IN_SILENT --> <bool name="def_vibrate_in_silent">true</bool> </resources>
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 編譯進去後,您將發現您可以自由的切