在android 系統中,爲統一管理系統的屬性,設計了一個統一的屬性系統。每一個屬性都有一個名稱和值,他們都是字符串格式。屬性被大量使用在Android系統中,用來記錄系統設置或進程之間的信息交換。屬性是在整個系統中全局可見的。每一個進程能夠get/set屬性。在編譯的過程當中會將各類系統參數彙總到build.proc 以及default.proc 這兩個文件中,主要屬性集中在build.proc中。系統在開機後將讀取配置信息並構建共享緩衝區,加快查詢速度。另一個方面,SettingsProvider會在系統第一次初始化時(刷機第一次啓動)後,將從Defaults.xml中讀取數據而後寫入數據庫Settings.db 目錄。並構建一個緩衝系統供其餘應用查詢。下面將詳細講述。java
系統屬性根據不一樣的應用類型,分爲不可變型,持久型,網絡型,啓動和中止服務等。linux
特別屬性:android
屬性名稱以「ro.」開頭,那麼這個屬性被視爲只讀屬性。一旦設置,屬性值不能改變。ios
屬性名稱以「persist.」開頭,當設置這個屬性時,其值也將寫入/data/property。正則表達式
屬性名稱以「net.」開頭,當設置這個屬性時,「net.change」屬性將會自動設置,以加入到最後修改的屬性名。(這是很巧妙的。 netresolve模塊的使用這個屬性來追蹤在net.*屬性上的任何變化。)數據庫
屬性「 ctrl.start 」和「 ctrl.stop 」是用來啓動和中止服務。每一項服務必須在/init.rc中定義.系統啓動時,與init守護進程將解析init.rc和啓動屬性服務。一旦收到設置「 ctrl.start 」屬性的請求,屬性服務將使用該屬性值做爲服務名找到該服務,啓動該服務。這項服務的啓動結果將會放入「 init.svc.<服務名>「屬性中 。客戶端應用程序能夠輪詢那個屬性值,以肯定結果。緩存
Android toolbox程序提供了兩個工具: setprop和getprop獲取和設置屬性。其使用方法:安全
getprop <屬性名>cookie
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
原則上,屬性的設置能夠出如今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 開頭的屬性都會保存副本在這個目錄下
在linux kernel 啓動時,Android將分配一個共享內存區來存儲的屬性。這些是由「init」守護進程完成的,其源代碼位於:device/system /init。「init」守護進程將啓動一個屬性服務。屬性服務在「init」守護進程中運行。每個客戶端想要設置屬性時,必須鏈接屬性服務,再向其發送信息。屬性服務將會在共享內存區中修改和建立屬性。客戶端想得到屬性信息,能夠從共享內存直接讀取。這提升了讀取性能。
客戶端應用程序能夠調用libcutils中的API函數以GET/SET屬性信息。libcutils的源代碼位於:device/libs/cutils。獲取和設置屬性的代碼在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 / init/ 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函數完成內核的初始化工做。
若是在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進行訪問。
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))
在system properties 中提供兩個特殊的key, ctl.start 和 ctl.stop 來啓動和關閉服務。
其API 描述是:
SystemProperties.set(「ctl.start」,serviceName);
SystemProperties.set(「ctl.stop」,serviceName);
注意的是,這個serviceName 可在init.rc 中查詢
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]
做爲一個共享的緩存系統,並不是任何AP 均可以隨意去修改其中的屬性,針對這些屬性,若是進行更改時,會有UID上的約束。
具體的UID 映射爲:
即如persist.sys 開頭的屬性,只能有system user(包括root) 進行修改,其餘用戶沒法進行修改。
這個user id 表定義在 \system\core\include\private\android_filesystem_config.h 文件中
在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 中的配置文件便可。
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 下,全部的版本信息即在該文件的第一行,而後使用了一個正則表達式過濾了版本信息中一些字符。
在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 了。