Android屬性系統簡介


 

  1、簡介

  在android 系統中,為統一管理系統的屬性,設計了一個統一的屬性系統。每個屬性都有一個名稱和值,他們都是字符串格式。屬性被大量使用在Android系統中,用來記錄系統設置或進程之間的信息交換。屬性是在整個系統中全局可見的。每個進程可以get/set屬性。在編譯的過程中會將各種系統參數匯總到build.proc 以及default.proc 這兩個文件中,主要屬性集中在build.proc中。系統在開機后將讀取配置信息並構建共享緩沖區,加快查詢速度。另外一個方面,SettingsProvider會在系統第一次初始化時(刷機第一次啟動)后,將從Defaults.xml中讀取數據然后寫入數據庫Settings.db 目錄。並構建一個緩沖系統供其他應用查詢。下面將詳細講述。

  2Properties Type

  系統屬性根據不同的應用類型,分為不可變型,持久型,網絡型,啟動和停止服務等。

   特別屬性:

  屬性名稱以“ro.”開頭,那么這個屬性被視為只讀屬性。一旦設置,屬性值不能改變。

  屬性名稱以“persist.”開頭,當設置這個屬性時,其值也將寫入/data/property。

  屬性名稱以“net.”開頭,當設置這個屬性時,“net.change”屬性將會自動設置,以加入到最后修改的屬性名。(這是很巧妙的。 netresolve模塊的使用這個屬性來追蹤在net.*屬性上的任何變化。)

  屬性“ ctrl.start ”和“ ctrl.stop ”是用來啟動和停止服務。每一項服務必須在/init.rc中定義.系統啟動時,與init守護進程將解析init.rc和啟動屬性服務。一旦收到設置“ ctrl.start ”屬性的請求,屬性服務將使用該屬性值作為服務名找到該服務,啟動該服務。這項服務的啟動結果將會放入“ init.svc.<服務名>“屬性中 。客戶端應用程序可以輪詢那個屬性值,以確定結果。

  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.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 編譯進去后,您將發現您可以自由的切換user eng 了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM