在展訊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屬性系統)這篇文章。