diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java index 2b4f6f867e038..f08e1ff16999d 100644 --- a/core/java/android/os/SystemProperties.java +++ b/core/java/android/os/SystemProperties.java @@ -26,6 +26,7 @@ import android.util.MutableInt; import com.android.internal.annotations.GuardedBy; +import dalvik.annotation.optimization.CriticalNative; import dalvik.annotation.optimization.FastNative; import libcore.util.HexEncoding; @@ -37,7 +38,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; - /** * Gives access to the system properties store. The system properties * store contains a list of string key-value pairs. @@ -118,6 +118,17 @@ public class SystemProperties { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private static native boolean native_get_boolean(String key, boolean def); + @FastNative + private static native long native_find(String name); + @FastNative + private static native String native_get(long handle); + @CriticalNative + private static native int native_get_int(long handle, int def); + @CriticalNative + private static native long native_get_long(long handle, long def); + @CriticalNative + private static native boolean native_get_boolean(long handle, boolean def); + // _NOT_ FastNative: native_set performs IPC and can block @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private static native void native_set(String key, String def); @@ -303,4 +314,60 @@ public class SystemProperties { @UnsupportedAppUsage private SystemProperties() { } + + /** + * Look up a property location by name. + * @name name of the property + * @return property handle or {@code null} if property isn't set + * @hide + */ + @Nullable public static Handle find(@NonNull String name) { + long nativeHandle = native_find(name); + if (nativeHandle == 0) { + return null; + } + return new Handle(nativeHandle); + } + + /** + * Handle to a pre-located property. Looking up a property handle in advance allows + * for optimal repeated lookup of a single property. + * @hide + */ + public static final class Handle { + + private final long mNativeHandle; + + /** + * @return Value of the property + */ + @NonNull public String get() { + return native_get(mNativeHandle); + } + /** + * @param def default value + * @return value or {@code def} on parse error + */ + public int getInt(int def) { + return native_get_int(mNativeHandle, def); + } + /** + * @param def default value + * @return value or {@code def} on parse error + */ + public long getLong(long def) { + return native_get_long(mNativeHandle, def); + } + /** + * @param def default value + * @return value or {@code def} on parse error + */ + public boolean getBoolean(boolean def) { + return native_get_boolean(mNativeHandle, def); + } + + private Handle(long nativeHandle) { + mNativeHandle = nativeHandle; + } + } } diff --git a/core/jni/android_os_SystemProperties.cpp b/core/jni/android_os_SystemProperties.cpp index 07617d600dbcf..7f8bec6ce5073 100644 --- a/core/jni/android_os_SystemProperties.cpp +++ b/core/jni/android_os_SystemProperties.cpp @@ -41,6 +41,8 @@ struct prop_info; namespace android { namespace { +using android::base::ParseBoolResult; + template void ReadProperty(const prop_info* prop, Functor&& functor) { @@ -102,14 +104,7 @@ T SystemProperties_get_integral(JNIEnv *env, jclass, jstring keyJ, return ret; } -jboolean SystemProperties_get_boolean(JNIEnv *env, jclass, jstring keyJ, - jboolean defJ) -{ - using android::base::ParseBoolResult; - ParseBoolResult parseResult; - ReadProperty(env, keyJ, [&](const char* value) { - parseResult = android::base::ParseBool(value); - }); +static jboolean jbooleanFromParseBoolResult(ParseBoolResult parseResult, jboolean defJ) { jboolean ret; switch (parseResult) { case ParseBoolResult::kError: @@ -125,6 +120,62 @@ jboolean SystemProperties_get_boolean(JNIEnv *env, jclass, jstring keyJ, return ret; } +jboolean SystemProperties_get_boolean(JNIEnv *env, jclass, jstring keyJ, + jboolean defJ) +{ + ParseBoolResult parseResult; + ReadProperty(env, keyJ, [&](const char* value) { + parseResult = android::base::ParseBool(value); + }); + return jbooleanFromParseBoolResult(parseResult, defJ); +} + +jlong SystemProperties_find(JNIEnv* env, jclass, jstring keyJ) +{ +#if defined(__BIONIC__) + ScopedUtfChars key(env, keyJ); + if (!key.c_str()) { + return 0; + } + const prop_info* prop = __system_property_find(key.c_str()); + return reinterpret_cast(prop); +#else + LOG(FATAL) << "fast property access supported only on device"; + __builtin_unreachable(); // Silence warning +#endif +} + +jstring SystemProperties_getH(JNIEnv* env, jclass clazz, jlong propJ) +{ + jstring ret; + auto prop = reinterpret_cast(propJ); + ReadProperty(prop, [&](const char* value) { + ret = env->NewStringUTF(value); + }); + return ret; +} + +template +T SystemProperties_get_integralH(CRITICAL_JNI_PARAMS_COMMA jlong propJ, T defJ) +{ + T ret = defJ; + auto prop = reinterpret_cast(propJ); + ReadProperty(prop, [&](const char* value) { + android::base::ParseInt(value, &ret); + }); + return ret; +} + +jboolean SystemProperties_get_booleanH(CRITICAL_JNI_PARAMS_COMMA jlong propJ, jboolean defJ) +{ + ParseBoolResult parseResult; + auto prop = reinterpret_cast(propJ); + ReadProperty(prop, [&](const char* value) { + parseResult = android::base::ParseBool(value); + }); + return jbooleanFromParseBoolResult(parseResult, defJ); +} + void SystemProperties_set(JNIEnv *env, jobject clazz, jstring keyJ, jstring valJ) { @@ -204,6 +255,18 @@ int register_android_os_SystemProperties(JNIEnv *env) (void*) SystemProperties_get_integral }, { "native_get_boolean", "(Ljava/lang/String;Z)Z", (void*) SystemProperties_get_boolean }, + { "native_find", + "(Ljava/lang/String;)J", + (void*) SystemProperties_find }, + { "native_get", + "(J)Ljava/lang/String;", + (void*) SystemProperties_getH }, + { "native_get_int", "(JI)I", + (void*) SystemProperties_get_integralH }, + { "native_get_long", "(JJ)J", + (void*) SystemProperties_get_integralH }, + { "native_get_boolean", "(JZ)Z", + (void*) SystemProperties_get_booleanH }, { "native_set", "(Ljava/lang/String;Ljava/lang/String;)V", (void*) SystemProperties_set }, { "native_add_change_callback", "()V", diff --git a/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java b/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java index 928351e7de8c1..b48ac3347093f 100644 --- a/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java +++ b/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java @@ -92,6 +92,27 @@ public class SystemPropertiesTest extends TestCase { assertEquals(expected, value); } + @SmallTest + private static void testHandle() throws Exception { + String value; + SystemProperties.Handle handle = SystemProperties.find("doesnotexist_2341431"); + assertNull(handle); + SystemProperties.set(KEY, "abc"); + handle = SystemProperties.find(KEY); + assertNotNull(handle); + value = handle.get(); + assertEquals("abc", value); + SystemProperties.set(KEY, "blarg"); + value = handle.get(); + assertEquals("blarg", value); + SystemProperties.set(KEY, "1"); + assertEquals(1, handle.getInt(-1)); + assertEquals(1, handle.getLong(-1)); + assertEquals(true, handle.getBoolean(false)); + SystemProperties.set(KEY, ""); + assertEquals(12345, handle.getInt(12345)); + } + @SmallTest public void testIntegralProperties() throws Exception { testInt("", 123, 123);