Add new SystemProperties.Handle interface

This new interface allows Java code to look up property values without
paying for the name->prop_info mapping and, in the case of looking up
scalars, without doing any allocation.

Bug: 140788621
Test: added tests
Test: atest FrameworksCoreSystemPropertiesTests
Change-Id: I46d12f62499e9e124fe9add588376d724b364d5d
This commit is contained in:
Daniel Colascione
2019-11-14 13:22:31 -08:00
parent 5e8ba5f05a
commit 6e2cff7fa1
3 changed files with 160 additions and 9 deletions

View File

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

View File

@@ -41,6 +41,8 @@ struct prop_info;
namespace android {
namespace {
using android::base::ParseBoolResult;
template<typename Functor>
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<jlong>(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<const prop_info*>(propJ);
ReadProperty(prop, [&](const char* value) {
ret = env->NewStringUTF(value);
});
return ret;
}
template <typename T>
T SystemProperties_get_integralH(CRITICAL_JNI_PARAMS_COMMA jlong propJ, T defJ)
{
T ret = defJ;
auto prop = reinterpret_cast<const prop_info*>(propJ);
ReadProperty(prop, [&](const char* value) {
android::base::ParseInt<T>(value, &ret);
});
return ret;
}
jboolean SystemProperties_get_booleanH(CRITICAL_JNI_PARAMS_COMMA jlong propJ, jboolean defJ)
{
ParseBoolResult parseResult;
auto prop = reinterpret_cast<const prop_info*>(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<jlong> },
{ "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<jint> },
{ "native_get_long", "(JJ)J",
(void*) SystemProperties_get_integralH<jlong> },
{ "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",

View File

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