1. 程式人生 > >Android呼叫巨集的三種方式

Android呼叫巨集的三種方式

在工程專案中,為什麼vendor目錄下的platformconfigs.xml檔案可以對部分手機的屬性特性進行設定?

答:在framework目錄下,android.provider.Settings檔案為這種方式提供了可能。通過官方文件對其描述:“The Settings provider contains global system-level device preferences.”。即android.provider.Setttings類是為裝置系統提供全域性的、系統級別的裝置屬性。在Settings類中,包含五個外部可以訪問的內部類:    Setttings.Global: 為裝置系統提供全域性的系統屬性,該屬性特性對裝置上的任何使用者都是無差別的。    Settings.NameValueTable: 根據key-value的組合,作為資料庫中表的公共基礎。

    public static class NameValueTable implements BaseColumns {
        public static final String NAME = "name";
        public static final String VALUE = "value";

        protected static boolean putString(ContentResolver resolver, Uri uri,
                String name, String value) {
            // The database will take care of replacing duplicates.
            try {
                ContentValues values = new ContentValues();
                values.put(NAME, name);
                values.put(VALUE, value);
                resolver.insert(uri, values);
                return true;
            } catch (SQLException e) {
                Log.w(TAG, "Can't set key " + name + " in " + uri, e);
                return false;
            }
        }

        public static Uri getUriFor(Uri uri, String name) {
            return Uri.withAppendedPath(uri, name);
        }
    }

Settings:Secure: 僅僅只有讀許可權,而沒有寫許可權的系統屬性。 Settings.SettingNotFoundException: 未找到系統屬性的異常處理, Settings.System: 各類的系統系統屬性。

如果想新增一個系統屬性,既可以在該檔案中進行新增相應的屬性內容。比如:希望新增一個全域性性的屬性,即可以在Settings.Global類進行處理: ``` public static final String AIRPLANE_MODE_ON = "airplane_mode_on";

public static final String[] SETTINGS_TO_BACKUP = {             ~~~~~             AIRPLANE_MODE_ON,             ~~~~~ ``` 可以通過 ``` Settings.Global.getInt(getContentResolver(), Settings.Global.AIRPLANE_MODE_ON,0); Settings.Global.putInt(getContentResolver(), Settings.Global.AIRPLANE_MODE_ON,0); ``` 去得到和設定“AIRPLANE_MODE_ON”的屬性值。那麼,PlatformConfigs.xml檔案中的屬性值,是如何寫入到系統級檔案build.prop檔案中的呢?    答:在build/core/Makefile中,可以發現有這樣一段內容:

# platform properties, which will be writen to build.prop
PLATFORM_PROPERTIES_SH := $(PWD)/vendor/tinno/platform/configs/$(TARGET_PRODUCT)/$(PROJECT_NAME)/PlatformConfigs


    # add for platform configs
    @if [ -f "$(PLATFORM_PROPERTIES_SH)" ]; then \
            echo 'PLATFORM_PROPERTIES_SH exits'; \
            echo >> [email protected]; \
      echo "#" >> [email protected]; \
      echo "# PLATFORM_PROPERTIES START" >> [email protected]; \
      echo "#" >> [email protected]; \
            while read word; do \
                    if [ -n "$$word" ]; then \
                        echo "the word = $$word"; \
                        key=`echo "$$word" | cut -d = -f 1`; \
                        echo "the key = $$key"; \
                        value=`echo "$$word" | cut -d = -f 2`; \
                        echo "the value = $$value"; \
                        sed -i "/^$$key=/d" [email protected]; \
                        echo "$$word" >> [email protected];    \
                    fi; \
            done < $(PLATFORM_PROPERTIES_SH); \
      echo "#" >> [email protected]; \
      echo "# PLATFORM_PROPERTIES END" >> [email protected]; \
      echo "#" >> [email protected]; \
    fi;

從這段指令碼可以發現,其將PlatformConfig.xml的屬性值寫到build.prop檔案上。

1. Android裡擁有很多屬性,每一個屬性都有一個名稱和值,類似於Map的方式。這些屬性可以在開機啟動時預先設定,亦可以是動態載入的。 系統啟動時,將分別以相面的次序載入預先設定的Android屬性。如果出現了重名屬性,那麼後者可以覆蓋前者的屬性值,即後者的優先順序高於前者。

/default.prop -> /system/build.prop -> /system/default.prop ->  /data/local.prop -> /data/property/* 

persist.*  : 以persist開始的屬性會在 /data/property 存一個副本。也就是說,如果程式呼叫property_set設以persist為字首的屬性,系統會在 /data/property/* 記錄下這個屬性的副本,重啟以後,這個屬性依然存在。有點類似於持久化技術。如果呼叫property_set以非 persist 為字首的屬性,這個屬性僅僅存在於手機運存中,在手機重啟後,這個屬性就初始化了。(pt)

ro.* : 不能修改,即表示系統屬性。當然手機開發者可以對原始碼進行修改。(read only)

2. 在應用程式屬性使用方法

``` import android.os.SystemProperties;  SystemProperties.set("persist.sys.country",”china”);  ``` 在java裡取得屬性: ``` String vmHeapSize = SystemProperties.get("dalvik.vm.heapgrowthlimit", "24m");  ``` 也可以用SystemProperties.getBoolean,getInt等

3. 屬性初始化的入口點是property_init ,在system/core/init/property_service.c中定義。它的主要工作是申請32k共享記憶體,其中前1k是屬性區的頭,後面31k可以存247個屬性(受前1k頭的限制)。property_init初始化完property以後,載入/default.prop的屬性定義。 

其它的系統屬性(build.prop, local.prop,…)在start_property_service中載入。載入完屬性服務建立一個socket和其他 程序通訊(設定或讀取屬性)。 

> Init程序poll屬性的socket,等待和處理屬性請求。如果有請求到來,則呼叫handle_property_set_fd來處理這個請求。在這個函式裡,首先檢查請求者的uid/gid看看是否有許可權,如果有許可權則調property_service.c中的property_set函式。 

>  在property_set函式中,它先查詢就沒有這個屬性,如果找到,更改屬性。如果找不到,則新增新屬性。更改時還會判斷是不是“ro”屬性,如果是,則不能更改。如果是persist的話還會寫到/data/property/<name>中。 

>  最後它會調property_changed,把事件掛到佇列裡,如果有人註冊這個屬性的話(比如init.rc中on property:ro.kernel.qemu=1),最終會調它的會調函式。 

當然,對於在PlatformConfigs.xml檔案中,有些屬性可以使用**SystemProperties**(SystemProperties位於frameworks/base/core/java/android/os中)來進行管理。如果使用者需要對某些屬性進行全域性的處理,即可以在PlatformConfigs.xml檔案中新增相應的巨集。示例: java程式碼: ```     import android.os.SystemProperties;     String value = SystemProperties.get("ro.pt.show_photos_name", "false"); ```

PlatformConfigs.xml ``` <!-- 設定,camera 顯示標題 -->   <feature id="SHOW_LAST" title="show not class CameraActivity"> <string name="ro.pt.show_photos_name" value="true"></string> </feature> ```

再來看看原始碼:

package android.os;
import java.util.ArrayList;

public class SystemProperties
{
    public static final int PROP_NAME_MAX = 31;
    public static final int PROP_VALUE_MAX = 91;

    private static final ArrayList<Runnable> sChangeCallbacks = new ArrayList<Runnable>();

    private static native String native_get(String key);
    private static native String native_get(String key, String def);
    private static native int native_get_int(String key, int def);
    private static native long native_get_long(String key, long def);
    private static native boolean native_get_boolean(String key, boolean def);
    private static native void native_set(String key, String def);
    private static native void native_add_change_callback();

    public static String get(String key) {
        if (key.length() > PROP_NAME_MAX) {
            throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
        }
        return native_get(key);
    }

    public static String get(String key, String def) {
        if (key.length() > PROP_NAME_MAX) {
            throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
        }
        return native_get(key, def);
    }

    public static boolean is_target(final String s) {
    return get("ro.target", "").equals(s);
    }

    public static boolean is_project(final String s) {
    return get("ro.project", "").equals(s);
    }

    /* qmb_pk */
    public static boolean is_qmb_pk() {
        return is_project("qmb_pk");
    }

    public static int getInt(String key, int def) {
        if (key.length() > PROP_NAME_MAX) {
            throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
        }
        return native_get_int(key, def);
    }

    public static long getLong(String key, long def) {
        if (key.length() > PROP_NAME_MAX) {
            throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
        }
        return native_get_long(key, def);
    }

    public static boolean getBoolean(String key, boolean def) {
        if (key.length() > PROP_NAME_MAX) {
            throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
        }
        return native_get_boolean(key, 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);
    }

    public static void addChangeCallback(Runnable callback) {
        synchronized (sChangeCallbacks) {
            if (sChangeCallbacks.size() == 0) {
                native_add_change_callback();
            }
            sChangeCallbacks.add(callback);
        }
    }

    static void callChangeCallbacks() {
        synchronized (sChangeCallbacks) {
            //Log.i("foo", "Calling " + sChangeCallbacks.size() + " change callbacks!");
            if (sChangeCallbacks.size() == 0) {
                return;
            }
            ArrayList<Runnable> callbacks = new ArrayList<Runnable>(sChangeCallbacks);
            for (int i=0; i<callbacks.size(); i++) {
                callbacks.get(i).run();
            }
        }
    }
}

---  

除了SystemProperties可以增加全域性巨集控外,還可以使用Context.getResource()方法,來處理相應模組的屬性設定。該方法先在strings.xml、config.xml檔案中定義各種字元型別,然後在java原始碼中呼叫。

``` <res> <bool  name="test_about">boolean_value</bool>

<java> boolean str= getResources().getBoolean(R.bool.test_about); ```