展訊平臺Android(2.3)屬性的訪問與設置

  在展訊6820代碼中customize\customer_cfg\sp6820a\res\system.prop文件中添加ro.floatkey.show = true屬性值, 最後編譯完成後,在idh.code\out\target\product\hsdroid\system\build.prop會添加ro.floatkey.show = true屬性值, 我們在android應用程序中如何訪問屬性值呢?

 SystemProperties.getBoolean("ro.floatkey.show", false);// 得到系統屬性的值

 SystemProperties.set("ro.floatkey.show", false);// 設置系統屬性的值

SystemProperties是如何訪問到系統屬性值的呢, 我們可以在SystemProperties.java(framework\base\core

\java\android\os)文件中看到

   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);
    }

最後調用的是JNI函數native_get_boolean(), 這個函數最終實現在framework/base/core/jni/android_os_

SystemProperties.cpp文件中, SystemProperties_get_boolean()與這個函數對應。

static jboolean SystemProperties_get_boolean(JNIEnv *env, jobject clazz, jstring keyJ, jboolean defJ)
{
    int len;
    const char* key;
    char buf[PROPERTY_VALUE_MAX];
    jboolean result = defJ;

    if (keyJ == NULL) {
        jniThrowException(env, "java/lang/NullPointerException", "key must not be null.");
        goto error;
    }

    key = env->GetStringUTFChars(keyJ, NULL);
    len = property_get(key, buf, "");
    if (len == 1) {
        char ch = buf[0];
        if (ch == '0' || ch == 'n')
            result = false;
        else if (ch == '1' || ch == 'y')
            result = true;
    } else if (len > 1) {
         if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) {
            result = false;
        } else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on")) {
            result = true;
        }
    }

    env->ReleaseStringUTFChars(keyJ, key);

error:
    return result;
}

最後實際調用的是property_get(key, buf, ""), 從這裏我們可以看到, 如果我們在native層中想獲得系統的屬性值, 可以調用property_get()函數來獲取。


property_get()如何獲得系統的屬性值, 可以到這個函數實現的地方看看。 property_get()實現在文件properties.c(system\core\libcutils)中,

int property_get(const char *key, char *value, const char *default_value)
{
    char sendBuf[1+PROPERTY_KEY_MAX];
    char recvBuf[1+PROPERTY_VALUE_MAX];
    int len = -1;

    pthread_once(&gInitOnce, init);
    if (gPropFd < 0) {
        /* this mimics the behavior of the device implementation */
        if (default_value != NULL) {
            strcpy(value, default_value);
            len = strlen(value);
        }
        return len;
    }

    if (strlen(key) >= PROPERTY_KEY_MAX) return -1;

    memset(sendBuf, 0xdd, sizeof(sendBuf));    // placate valgrind
    sendBuf[0] = (char) kSystemPropertyGet;
    strcpy(sendBuf+1, key);

    pthread_mutex_lock(&gPropertyFdLock);
    if (write(gPropFd, sendBuf, sizeof(sendBuf)) != sizeof(sendBuf)) {
        pthread_mutex_unlock(&gPropertyFdLock);
        return -1;
    }

    if (read(gPropFd, recvBuf, sizeof(recvBuf)) != sizeof(recvBuf)) {
        pthread_mutex_unlock(&gPropertyFdLock);
        return -1;
    }
    pthread_mutex_unlock(&gPropertyFdLock);

    /* first byte is 0 if value not defined, 1 if found */
    if (recvBuf[0] == 0) {
        if (default_value != NULL) {
            strcpy(value, default_value);
            len = strlen(value);
        } else {
            value[0] = '\0';
            len = 0;
        }
    } else if (recvBuf[0] == 1) {
        strcpy(value, recvBuf+1);
        len = strlen(value);
    } else {
        LOGE("Got strange response to property_get request (%d)\n",
            recvBuf[0]);
        assert(0);
        return -1;
    }
    //LOGV("PROP [found=%d def='%s'] (%d) [%s]: [%s]\n",
    //    recvBuf[0], default_value, len, key, value);

    return len;
}

從上面的函數中我們可以看出, 我們是通過gPropFd來將key值先寫入, 然後通過read函數得到的系統屬性值。至於gPropFd是個什麼東西, 我們在init()函數可以看到

static void init(void)
{
    assert(gPropFd == -1);

    gPropFd = connectToServer(SYSTEM_PROPERTY_PIPE_NAME);
    if (gPropFd < 0) {
        //LOGW("not connected to system property server\n");
    } else {
        //LOGV("Connected to system property server\n");
    }
}

static int connectToServer(const char* fileName)
{
    int sock = -1;
    int cc;
    struct sockaddr_un addr;
    
    sock = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sock < 0) {
        LOGW("UNIX domain socket create failed (errno=%d)\n", errno);
        return -1;
    }

    /* connect to socket; fails if file doesn't exist */
    strcpy(addr.sun_path, fileName);    // max 108 bytes
    addr.sun_family = AF_UNIX;
    cc = connect(sock, (struct sockaddr*) &addr, SUN_LEN(&addr));
    if (cc < 0) {
        // ENOENT means socket file doesn't exist
        // ECONNREFUSED means socket exists but nobody is listening
        //LOGW("AF_UNIX connect failed for '%s': %s\n",
        //    fileName, strerror(errno));
        close(sock);
        return -1;
    }

    return sock;
}


關於SystemProperties.set()函數功能, 需要補充說明一下, 使用這個函數需要一定的權限, android屬性名稱是有一定的格式要求的, 前綴必須用system\core\init\property_service.c中定義的前綴, 進行屬性設置的程序也必須有system或root權限。

如何將android程序的權限提升到system權限, 可以使用下面的方法:

1. 在AndroidManifest.xml中再manifest加入android:sharedUserId="android.uid.system"

2. 在Android.mk中將LOCAL_CERTIFICATE := XXX 修改爲 LOCAL_CERTIFICATE := PLATFORM.


實際是通過socket通信來得到值。具體如何得到的值, 請參考http://www.blogjava.net/MEYE/articles/359773.html(Android屬性系統)這篇文章。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章