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

Commit 123815ce authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Store system properties when native binder stat config is set" into main

parents 64671271 54cf10a8
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -398,6 +398,7 @@ java_defaults {
        "bouncycastle-repackaged-unbundled",
        "com.android.sysprop.foldlockbehavior",
        "com.android.sysprop.view",
        "com.android.sysprop.nativebinderstats",
        "framework-internal-utils",
        "dropboxmanager_aidl-java",
        "dynamic_instrumentation_manager_aidl-java",
+63 −1
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.provider.Settings;
import android.sysprop.NativeBinderStatsProperties;
import android.util.KeyValueListParser;
import android.util.Slog;

@@ -74,10 +75,18 @@ public class NativeBinderStats {

    private final Context mContext;

    private final PropertiesWrapper mPropertiesWrapper;

    private final SettingsObserver mSettingsObserver;

    public NativeBinderStats(Context context) {
        this(context, new PropertiesWrapper());
    }

    @VisibleForTesting
    public NativeBinderStats(Context context, PropertiesWrapper propertiesWrapper) {
        mContext = context;
        mPropertiesWrapper = propertiesWrapper;
        mSettingsObserver = new SettingsObserver(context);
    }

@@ -86,6 +95,51 @@ public class NativeBinderStats {
        mSettingsObserver.register();
    }

    /**
     * A wrapper around System properties for testability.
     */
    @VisibleForTesting
    public static class PropertiesWrapper {
        /** Sets the enabled property. */
        public void setEnabled(boolean value) {
            NativeBinderStatsProperties.enabled(value);
        }

        /** Sets the process_sharding property. */
        public void setProcessSharding(int value) {
            NativeBinderStatsProperties.process_sharding(value);
        }

        /**
         * Sets the spam_sharding property.
         */
        public void setSpamSharding(int value) {
            NativeBinderStatsProperties.spam_sharding(value);
        }

        /**
         * Sets the call_sharding property.
         */
        public void setCallSharding(int value) {
            NativeBinderStatsProperties.call_sharding(value);
        }

        /** Like {@link #setProcessSharding} but for system_server. */
        public void setSystemProcessSharding(int value) {
            NativeBinderStatsProperties.system_process_sharding(value);
        }

        /** Like {@link #setSpamSharding} but for system_server. */
        public void setSystemSpamSharding(int value) {
            NativeBinderStatsProperties.system_spam_sharding(value);
        }

        /** Like {@link #setCallSharding} but for system_server. */
        public void setSystemCallSharding(int value) {
            NativeBinderStatsProperties.system_call_sharding(value);
        }
    }

    @VisibleForTesting
    public class SettingsObserver extends ContentObserver {
        private static final String KEY_ENABLED = "enabled";
@@ -138,7 +192,15 @@ public class NativeBinderStats {
                    mParser.getInt(KEY_SYSTEM_SPAM_SHARDING, DEFAULT_SYSTEM_SPAM_SHARDING);
            mSystemCallSharding =
                    mParser.getInt(KEY_SYSTEM_CALL_SHARDING, DEFAULT_SYSTEM_CALL_SHARDING);
            // TODO(b/407694522): If settings change, propagate to other processes.

            mPropertiesWrapper.setEnabled(mEnabled);
            mPropertiesWrapper.setProcessSharding(mProcessSharding);
            mPropertiesWrapper.setSpamSharding(mSpamSharding);
            mPropertiesWrapper.setCallSharding(mCallSharding);
            mPropertiesWrapper.setSystemProcessSharding(mSystemProcessSharding);
            mPropertiesWrapper.setSystemSpamSharding(mSystemSpamSharding);
            mPropertiesWrapper.setSystemCallSharding(mSystemCallSharding);

            Slog.i(
                    TAG,
                    String.format(
+7 −0
Original line number Diff line number Diff line
@@ -50,3 +50,10 @@ sysprop_library {
    property_owner: "Platform",
    api_packages: ["android.sysprop"],
}

sysprop_library {
    name: "com.android.sysprop.nativebinderstats",
    srcs: ["NativeBinderStatsProperties.sysprop"],
    property_owner: "Platform",
    api_packages: ["android.sysprop"],
}
+80 −0
Original line number Diff line number Diff line
# This file is used to define system properties for native binder stats.
# The properties are used to control the collection of binder stats.
# The properties are set by the NativeBinderStats class.

# The module that owns this property.
module: "android.sysprop.NativeBinderStatsProperties"

# Whether native binder stats are enabled.
prop {
    api_name: "enabled"
    type: Boolean
    prop_name: "persist.sys.native_binder_stats.enabled"
    scope: Internal
    access: ReadWrite
}

# The inverse probability that a given process will track binder stats. E.g. 100 means that
# 1% of the processes will report stats. 0 is a special value that means no process will
# report stats.
prop {
    api_name: "process_sharding"
    type: Integer
    prop_name: "persist.sys.native_binder_stats.process_sharding"
    scope: Internal
    access: ReadWrite
}

# The inverse probability that a given AIDL method will be selected for spam detection and
# reporting (provided the containing process is selected for stats). 0 means no spam
# tracking.
prop {
    api_name: "spam_sharding"
    type: Integer
    prop_name: "persist.sys.native_binder_stats.spam_sharding"
    scope: Internal
    access: ReadWrite
}

# The inverse probability that a given AIDL method will be selected for call stats
# (provided the containing process is selected for stats). 0 means no call stats.
prop {
    api_name: "call_sharding"
    type: Integer
    prop_name: "persist.sys.native_binder_stats.call_sharding"
    scope: Internal
    access: ReadWrite
}

# The inverse probability that a given process will track binder stats. E.g. 100 means that
# 1% of the processes will report stats. 0 is a special value that means no process will
# report stats. This property is for system_server.
prop {
    api_name: "system_process_sharding"
    type: Integer
    prop_name: "persist.sys.native_binder_stats.system_process_sharding"
    scope: Internal
    access: ReadWrite
}

# The inverse probability that a given AIDL method will be selected for spam detection and
# reporting (provided the containing process is selected for stats). 0 means no spam
# tracking. This property is for system_server.
prop {
    api_name: "system_spam_sharding"
    type: Integer
    prop_name: "persist.sys.native_binder_stats.system_spam_sharding"
    scope: Internal
    access: ReadWrite
}

# The inverse probability that a given AIDL method will be selected for call stats
# (provided the containing process is selected for stats). 0 means no call stats.
# This property is for system_server.
prop {
    api_name: "system_call_sharding"
    type: Integer
    prop_name: "persist.sys.native_binder_stats.system_call_sharding"
    scope: Internal
    access: ReadWrite
}
+135 −5
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.internal.os;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

@@ -38,6 +39,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;

@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -46,6 +48,7 @@ import org.junit.runner.RunWith;
public class NativeBinderStatsTest {
    private Context mContext;
    private MockContentResolver mResolver;
    private NativeBinderStats.PropertiesWrapper mMockPropertiesWrapper;

    @Before
    public void setup() {
@@ -53,6 +56,7 @@ public class NativeBinderStatsTest {
        mContext = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
        mResolver = new MockContentResolver(mContext);
        mResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
        mMockPropertiesWrapper = mock(NativeBinderStats.PropertiesWrapper.class);
        when(mContext.getContentResolver()).thenReturn(mResolver);
    }

@@ -63,16 +67,36 @@ public class NativeBinderStatsTest {

    @Test
    public void testSettingsObserver_disabledByDefault() {
        NativeBinderStats nativeBinderStats = new NativeBinderStats(mContext);
        NativeBinderStats nativeBinderStats =
                new NativeBinderStats(mContext, mMockPropertiesWrapper);
        nativeBinderStats.systemReady();

        // Verify that the injector was called with default values
        Mockito.verify(mMockPropertiesWrapper).setEnabled(NativeBinderStats.DEFAULT_ENABLED);
        Mockito.verify(mMockPropertiesWrapper)
                .setProcessSharding(NativeBinderStats.DEFAULT_PROCESS_SHARDING);
        Mockito.verify(mMockPropertiesWrapper)
                .setSpamSharding(NativeBinderStats.DEFAULT_SPAM_SHARDING);
        Mockito.verify(mMockPropertiesWrapper)
                .setCallSharding(NativeBinderStats.DEFAULT_CALL_SHARDING);
        Mockito.verify(mMockPropertiesWrapper)
                .setSystemProcessSharding(NativeBinderStats.DEFAULT_SYSTEM_PROCESS_SHARDING);
        Mockito.verify(mMockPropertiesWrapper)
                .setSystemSpamSharding(NativeBinderStats.DEFAULT_SYSTEM_SPAM_SHARDING);
        Mockito.verify(mMockPropertiesWrapper)
                .setSystemCallSharding(NativeBinderStats.DEFAULT_SYSTEM_CALL_SHARDING);

        assertThat(nativeBinderStats.mEnabled).isFalse();
    }

    @Test
    public void testSettingsObserver_enabled() {
        Settings.Global.putString(mResolver, Settings.Global.NATIVE_BINDER_STATS, "enabled=true");
        NativeBinderStats nativeBinderStats = new NativeBinderStats(mContext);
        // Reset mock to clear previous interactions from setup (if any)
        Mockito.reset(mMockPropertiesWrapper);

        NativeBinderStats nativeBinderStats =
                new NativeBinderStats(mContext, mMockPropertiesWrapper);
        nativeBinderStats.systemReady();

        assertThat(nativeBinderStats.mEnabled).isTrue();
@@ -88,24 +112,58 @@ public class NativeBinderStatsTest {
                .isEqualTo(NativeBinderStats.DEFAULT_SYSTEM_SPAM_SHARDING);
        assertThat(nativeBinderStats.mSystemCallSharding)
                .isEqualTo(NativeBinderStats.DEFAULT_SYSTEM_CALL_SHARDING);
        // Verify that the injector was called correctly
        Mockito.verify(mMockPropertiesWrapper).setEnabled(true);
        Mockito.verify(mMockPropertiesWrapper)
                .setProcessSharding(NativeBinderStats.DEFAULT_PROCESS_SHARDING);
        Mockito.verify(mMockPropertiesWrapper)
                .setSpamSharding(NativeBinderStats.DEFAULT_SPAM_SHARDING);
        Mockito.verify(mMockPropertiesWrapper)
                .setCallSharding(NativeBinderStats.DEFAULT_CALL_SHARDING);
        Mockito.verify(mMockPropertiesWrapper)
                .setSystemProcessSharding(NativeBinderStats.DEFAULT_SYSTEM_PROCESS_SHARDING);
        Mockito.verify(mMockPropertiesWrapper)
                .setSystemSpamSharding(NativeBinderStats.DEFAULT_SYSTEM_SPAM_SHARDING);
        Mockito.verify(mMockPropertiesWrapper)
                .setSystemCallSharding(NativeBinderStats.DEFAULT_SYSTEM_CALL_SHARDING);
    }

    @Test
    public void testSettingsObserver_disabled() {
        Settings.Global.putString(mResolver, Settings.Global.NATIVE_BINDER_STATS, "enabled=false");
        NativeBinderStats nativeBinderStats = new NativeBinderStats(mContext);
        NativeBinderStats nativeBinderStats =
                new NativeBinderStats(mContext, mMockPropertiesWrapper);
        nativeBinderStats.systemReady();

        assertThat(nativeBinderStats.mEnabled).isFalse();
        // Verify that the injector was called correctly
        Mockito.verify(mMockPropertiesWrapper).setEnabled(false);
    }

    @Test
    public void testSettingsObserver_changed() {
        Settings.Global.putString(mResolver, Settings.Global.NATIVE_BINDER_STATS, "enabled=true");
        NativeBinderStats nativeBinderStats = new NativeBinderStats(mContext);
        NativeBinderStats nativeBinderStats =
                new NativeBinderStats(mContext, mMockPropertiesWrapper);
        nativeBinderStats.systemReady();

        assertThat(nativeBinderStats.mEnabled).isTrue();
        Mockito.verify(mMockPropertiesWrapper).setEnabled(true);
        Mockito.verify(mMockPropertiesWrapper)
                .setProcessSharding(NativeBinderStats.DEFAULT_PROCESS_SHARDING);
        Mockito.verify(mMockPropertiesWrapper)
                .setSpamSharding(NativeBinderStats.DEFAULT_SPAM_SHARDING);
        Mockito.verify(mMockPropertiesWrapper)
                .setCallSharding(NativeBinderStats.DEFAULT_CALL_SHARDING);
        Mockito.verify(mMockPropertiesWrapper)
                .setSystemProcessSharding(NativeBinderStats.DEFAULT_SYSTEM_PROCESS_SHARDING);
        Mockito.verify(mMockPropertiesWrapper)
                .setSystemSpamSharding(NativeBinderStats.DEFAULT_SYSTEM_SPAM_SHARDING);
        Mockito.verify(mMockPropertiesWrapper)
                .setSystemCallSharding(NativeBinderStats.DEFAULT_SYSTEM_CALL_SHARDING);

        // Reset mock to clear previous interactions
        Mockito.reset(mMockPropertiesWrapper);

        Settings.Global.putString(mResolver, Settings.Global.NATIVE_BINDER_STATS, "enabled=false");
        // FakeSettingsProvider doesn't support notifications, so we need to notify manually.
@@ -115,6 +173,19 @@ public class NativeBinderStatsTest {
                false, Settings.Global.getUriFor(Settings.Global.NATIVE_BINDER_STATS), 0);

        assertThat(nativeBinderStats.mEnabled).isFalse();
        Mockito.verify(mMockPropertiesWrapper).setEnabled(false);
        Mockito.verify(mMockPropertiesWrapper)
                .setProcessSharding(NativeBinderStats.DEFAULT_PROCESS_SHARDING);
        Mockito.verify(mMockPropertiesWrapper)
                .setSpamSharding(NativeBinderStats.DEFAULT_SPAM_SHARDING);
        Mockito.verify(mMockPropertiesWrapper)
                .setCallSharding(NativeBinderStats.DEFAULT_CALL_SHARDING);
        Mockito.verify(mMockPropertiesWrapper)
                .setSystemProcessSharding(NativeBinderStats.DEFAULT_SYSTEM_PROCESS_SHARDING);
        Mockito.verify(mMockPropertiesWrapper)
                .setSystemSpamSharding(NativeBinderStats.DEFAULT_SYSTEM_SPAM_SHARDING);
        Mockito.verify(mMockPropertiesWrapper)
                .setSystemCallSharding(NativeBinderStats.DEFAULT_SYSTEM_CALL_SHARDING);
    }

    @Test
@@ -124,7 +195,8 @@ public class NativeBinderStatsTest {
                Settings.Global.NATIVE_BINDER_STATS,
                "enabled=true,process_sharding=5,spam_sharding=1,call_sharding=2,"
                    + "system_process_sharding=1,system_spam_sharding=5,system_call_sharding=10");
        NativeBinderStats nativeBinderStats = new NativeBinderStats(mContext);
        NativeBinderStats nativeBinderStats =
                new NativeBinderStats(mContext, mMockPropertiesWrapper);
        nativeBinderStats.systemReady();

        assertThat(nativeBinderStats.mEnabled).isTrue();
@@ -134,5 +206,63 @@ public class NativeBinderStatsTest {
        assertThat(nativeBinderStats.mSystemProcessSharding).isEqualTo(1);
        assertThat(nativeBinderStats.mSystemSpamSharding).isEqualTo(5);
        assertThat(nativeBinderStats.mSystemCallSharding).isEqualTo(10);
        // Verify that the injector was called with required values
        Mockito.verify(mMockPropertiesWrapper).setEnabled(true);
        Mockito.verify(mMockPropertiesWrapper).setProcessSharding(5);
        Mockito.verify(mMockPropertiesWrapper).setSpamSharding(1);
        Mockito.verify(mMockPropertiesWrapper).setCallSharding(2);
        Mockito.verify(mMockPropertiesWrapper).setSystemProcessSharding(1);
        Mockito.verify(mMockPropertiesWrapper).setSystemSpamSharding(5);
        Mockito.verify(mMockPropertiesWrapper).setSystemCallSharding(10);
    }

    @Test
    public void testSettingsObserver_badInput() {
        Settings.Global.putString(mResolver, Settings.Global.NATIVE_BINDER_STATS,
                "enabled=truepxrocess_sharding=5,spam_sharding=1,call_sharding=2,"
                        + "system_process_sharding=1,system_spam_sharding=5,system_call_sharding="
                        + "10");

        NativeBinderStats nativeBinderStats =
                new NativeBinderStats(mContext, mMockPropertiesWrapper);
        nativeBinderStats.systemReady();

        // Verify that the injector was called with default values
        Mockito.verify(mMockPropertiesWrapper).setEnabled(NativeBinderStats.DEFAULT_ENABLED);
        Mockito.verify(mMockPropertiesWrapper)
                .setProcessSharding(NativeBinderStats.DEFAULT_PROCESS_SHARDING);
        // Verify that correctly got values were set
        Mockito.verify(mMockPropertiesWrapper).setSpamSharding(1);
        Mockito.verify(mMockPropertiesWrapper).setCallSharding(2);
        Mockito.verify(mMockPropertiesWrapper).setSystemProcessSharding(1);
        Mockito.verify(mMockPropertiesWrapper).setSystemSpamSharding(5);
        Mockito.verify(mMockPropertiesWrapper).setSystemCallSharding(10);

        assertThat(nativeBinderStats.mEnabled).isFalse();
    }

    @Test
    public void testSettingsObserver_triggerInputException() {
        Settings.Global.putString(
                mResolver, Settings.Global.NATIVE_BINDER_STATS, "Lorem,ipsum,enable123");

        NativeBinderStats nativeBinderStats =
                new NativeBinderStats(mContext, mMockPropertiesWrapper);
        nativeBinderStats.systemReady();

        // Verify that the injector was called with default values
        Mockito.verify(mMockPropertiesWrapper).setEnabled(NativeBinderStats.DEFAULT_ENABLED);
        Mockito.verify(mMockPropertiesWrapper)
                .setProcessSharding(NativeBinderStats.DEFAULT_PROCESS_SHARDING);
        Mockito.verify(mMockPropertiesWrapper)
                .setSpamSharding(NativeBinderStats.DEFAULT_SPAM_SHARDING);
        Mockito.verify(mMockPropertiesWrapper)
                .setCallSharding(NativeBinderStats.DEFAULT_CALL_SHARDING);
        Mockito.verify(mMockPropertiesWrapper)
                .setSystemProcessSharding(NativeBinderStats.DEFAULT_SYSTEM_PROCESS_SHARDING);
        Mockito.verify(mMockPropertiesWrapper)
                .setSystemSpamSharding(NativeBinderStats.DEFAULT_SYSTEM_SPAM_SHARDING);
        Mockito.verify(mMockPropertiesWrapper)
                .setSystemCallSharding(NativeBinderStats.DEFAULT_SYSTEM_CALL_SHARDING);
    }
}