Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 950697a4 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Ravenwood support for `SystemProperties`.

One of our final missing pieces of foundational functionality is
the SystemProperties key/value store.  Over the years, this key/value
store has been (ab)used to configure very obscure parts of the OS.

As tempting as it might be to simply let code rely on default return
values when a key is undefined, we'd like to ensure that code owners
carefully confirm any assumed behaviors.  To accomplish this, we
default to blocking both read/write access to keys until their use
has been explicitly audited.

Based on our guiding principles, as code owners support their APIs
under Ravenwood, they're expected to bring along all relevant tests,
which will uncover SystemProperties usage that needs triage, reducing
the risk of downstream clients uncovering that usage.

Tests can explicitly allow read/write access to specific properties
via their RavenwoodRule.Builder definition, which is also how we
ensure that all values are consistently reset between tests.

Bug: 319647875
Test: atest FrameworksCoreSystemPropertiesTestsRavenwood
Test: atest FrameworksCoreTestsRavenwood CtsOsTestCasesRavenwood
Change-Id: I6510e06c33ee8b2bf31b58f35faa07127ecd16b7
parent ff93fc40
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.app.ActivityThread;
import android.app.Application;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.ravenwood.annotation.RavenwoodKeepWholeClass;
import android.sysprop.DeviceProperties;
import android.sysprop.SocProperties;
import android.sysprop.TelephonyProperties;
@@ -47,6 +48,7 @@ import java.util.stream.Collectors;
/**
 * Information about the current build, extracted from system properties.
 */
@RavenwoodKeepWholeClass
public class Build {
    private static final String TAG = "Build";

@@ -307,7 +309,7 @@ public class Build {
         * compatibility.
         */
        final String[] abiList;
        if (VMRuntime.getRuntime().is64Bit()) {
        if (android.os.Process.is64Bit()) {
            abiList = SUPPORTED_64_BIT_ABIS;
        } else {
            abiList = SUPPORTED_32_BIT_ABIS;
+31 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.ravenwood.annotation.RavenwoodKeepWholeClass;
import android.ravenwood.annotation.RavenwoodNativeSubstitutionClass;
import android.util.Log;
import android.util.MutableInt;

@@ -36,6 +38,8 @@ import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Predicate;

/**
 * Gives access to the system properties store.  The system properties
@@ -51,6 +55,8 @@ import java.util.HashMap;
 * {@hide}
 */
@SystemApi
@RavenwoodKeepWholeClass
@RavenwoodNativeSubstitutionClass("com.android.hoststubgen.nativesubstitution.SystemProperties_host")
public class SystemProperties {
    private static final String TAG = "SystemProperties";
    private static final boolean TRACK_KEY_ACCESS = false;
@@ -94,6 +100,31 @@ public class SystemProperties {
        }
    }

    /** @hide */
    public static void init$ravenwood(Map<String, String> values,
            Predicate<String> keyReadablePredicate, Predicate<String> keyWritablePredicate) {
        native_init$ravenwood(values, keyReadablePredicate, keyWritablePredicate,
                SystemProperties::callChangeCallbacks);
        synchronized (sChangeCallbacks) {
            sChangeCallbacks.clear();
        }
    }

    /** @hide */
    public static void reset$ravenwood() {
        native_reset$ravenwood();
        synchronized (sChangeCallbacks) {
            sChangeCallbacks.clear();
        }
    }

    // These native methods are currently only implemented by Ravenwood, as it's the only
    // mechanism we have to jump to our RavenwoodNativeSubstitutionClass
    private static native void native_init$ravenwood(Map<String, String> values,
            Predicate<String> keyReadablePredicate, Predicate<String> keyWritablePredicate,
            Runnable changeCallback);
    private static native void native_reset$ravenwood();

    // The one-argument version of native_get used to be a regular native function. Nowadays,
    // we use the two-argument form of native_get all the time, but we can't just delete the
    // one-argument overload: apps use it via reflection, as the UnsupportedAppUsage annotation
+0 −2
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import android.platform.test.annotations.IgnoreUnderRavenwood;
import android.platform.test.flag.junit.SetFlagsRule;
import android.platform.test.ravenwood.RavenwoodRule;

@@ -71,7 +70,6 @@ public class BuildTest {
     */
    @Test
    @SmallTest
    @IgnoreUnderRavenwood(blockedBy = Build.class)
    public void testBuildFields() throws Exception {
        assertNotEmpty("ID", Build.ID);
        assertNotEmpty("DISPLAY", Build.DISPLAY);
+22 −0
Original line number Diff line number Diff line
@@ -15,6 +15,9 @@ android_test {
    static_libs: [
        "android-common",
        "frameworks-core-util-lib",
        "androidx.test.rules",
        "androidx.test.ext.junit",
        "ravenwood-junit",
    ],
    libs: [
        "android.test.runner",
@@ -23,3 +26,22 @@ android_test {
    platform_apis: true,
    certificate: "platform",
}

android_ravenwood_test {
    name: "FrameworksCoreSystemPropertiesTestsRavenwood",
    static_libs: [
        "android-common",
        "frameworks-core-util-lib",
        "androidx.test.rules",
        "androidx.test.ext.junit",
        "ravenwood-junit",
    ],
    libs: [
        "android.test.runner",
        "android.test.base",
    ],
    srcs: [
        "src/**/*.java",
    ],
    auto_gen_config: true,
}
+27 −2
Original line number Diff line number Diff line
@@ -16,19 +16,36 @@

package android.os;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import android.platform.test.ravenwood.RavenwoodRule;
import android.test.suitebuilder.annotation.SmallTest;

import junit.framework.TestCase;
import org.junit.Rule;
import org.junit.Test;

import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class SystemPropertiesTest extends TestCase {
public class SystemPropertiesTest {
    @Rule
    public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
            .setSystemPropertyMutable(KEY, null)
            .setSystemPropertyMutable(UNSET_KEY, null)
            .setSystemPropertyMutable(PERSIST_KEY, null)
            .build();

    private static final String KEY = "sys.testkey";
    private static final String UNSET_KEY = "Aiw7woh6ie4toh7W";
    private static final String PERSIST_KEY = "persist.sys.testkey";

    @Test
    @SmallTest
    public void testStressPersistPropertyConsistency() throws Exception {
        for (int i = 0; i < 100; ++i) {
@@ -38,6 +55,7 @@ public class SystemPropertiesTest extends TestCase {
        }
    }

    @Test
    @SmallTest
    public void testStressMemoryPropertyConsistency() throws Exception {
        for (int i = 0; i < 100; ++i) {
@@ -47,6 +65,7 @@ public class SystemPropertiesTest extends TestCase {
        }
    }

    @Test
    @SmallTest
    public void testProperties() throws Exception {
        String value;
@@ -93,6 +112,7 @@ public class SystemPropertiesTest extends TestCase {
      assertEquals(expected, value);
    }

    @Test
    @SmallTest
    public void testHandle() throws Exception {
        String value;
@@ -114,6 +134,7 @@ public class SystemPropertiesTest extends TestCase {
        assertEquals(12345, handle.getInt(12345));
    }

    @Test
    @SmallTest
    public void testIntegralProperties() throws Exception {
        testInt("", 123, 123);
@@ -133,6 +154,7 @@ public class SystemPropertiesTest extends TestCase {
        testLong("-3147483647", 124, -3147483647L);
    }

    @Test
    @SmallTest
    public void testUnset() throws Exception {
        assertEquals("abc", SystemProperties.get(UNSET_KEY, "abc"));
@@ -142,6 +164,7 @@ public class SystemPropertiesTest extends TestCase {
        assertEquals(-10, SystemProperties.getLong(UNSET_KEY, -10));
    }

    @Test
    @SmallTest
    @SuppressWarnings("null")
    public void testNullKey() throws Exception {
@@ -176,6 +199,7 @@ public class SystemPropertiesTest extends TestCase {
        }
    }

    @Test
    @SmallTest
    public void testCallbacks() {
        // Latches are not really necessary, but are easy to use.
@@ -220,6 +244,7 @@ public class SystemPropertiesTest extends TestCase {
        }
    }

    @Test
    @SmallTest
    public void testDigestOf() {
        final String empty = SystemProperties.digestOf();
Loading