diff --git a/apct-tests/perftests/settingsprovider/Android.bp b/apct-tests/perftests/settingsprovider/Android.bp
new file mode 100644
index 0000000000000..43ec0e0b4620b
--- /dev/null
+++ b/apct-tests/perftests/settingsprovider/Android.bp
@@ -0,0 +1,39 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "SettingsProviderPerfTests",
+
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+
+ static_libs: [
+ "platform-compat-test-rules",
+ "androidx.appcompat_appcompat",
+ "androidx.test.rules",
+ "androidx.test.ext.junit",
+ "androidx.annotation_annotation",
+ "apct-perftests-utils",
+ "collector-device-lib-platform",
+ "cts-install-lib-java",
+ "services.core",
+ ],
+
+ libs: ["android.test.base"],
+
+ platform_apis: true,
+
+ test_suites: ["device-tests"],
+
+ data: [":perfetto_artifacts"],
+
+ certificate: "platform",
+}
diff --git a/apct-tests/perftests/settingsprovider/AndroidManifest.xml b/apct-tests/perftests/settingsprovider/AndroidManifest.xml
new file mode 100644
index 0000000000000..140c280115b61
--- /dev/null
+++ b/apct-tests/perftests/settingsprovider/AndroidManifest.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apct-tests/perftests/settingsprovider/src/android/provider/SettingsProviderPerfTest.java b/apct-tests/perftests/settingsprovider/src/android/provider/SettingsProviderPerfTest.java
new file mode 100644
index 0000000000000..e31162f37cf88
--- /dev/null
+++ b/apct-tests/perftests/settingsprovider/src/android/provider/SettingsProviderPerfTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.provider;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public final class SettingsProviderPerfTest {
+ private static final String NAMESPACE = "test@namespace";
+ private static final String SETTING_NAME1 = "test:setting1";
+ private static final String SETTING_NAME2 = "test-setting2";
+
+ private final ContentResolver mContentResolver;
+
+ @Rule
+ public final PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ public SettingsProviderPerfTest() {
+ final Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ mContentResolver = context.getContentResolver();
+ }
+
+ @Before
+ public void setUp() {
+ Settings.Secure.putString(mContentResolver, SETTING_NAME1, "1");
+ Settings.Config.putString(NAMESPACE, SETTING_NAME1, "1", true);
+ Settings.Config.putString(NAMESPACE, SETTING_NAME2, "2", true);
+ }
+
+ @After
+ public void destroy() {
+ Settings.Secure.putString(mContentResolver, SETTING_NAME1, "null");
+ Settings.Config.deleteString(NAMESPACE, SETTING_NAME1);
+ Settings.Config.deleteString(NAMESPACE, SETTING_NAME2);
+ }
+
+ @Test
+ public void testSettingsValueConsecutiveRead() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ int i = 0;
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ // Writing to setting2 should not invalidate setting1's cache
+ Settings.Secure.putString(mContentResolver, SETTING_NAME2, Integer.toString(i));
+ i++;
+ state.resumeTiming();
+ Settings.Secure.getString(mContentResolver, SETTING_NAME1);
+ }
+ }
+
+ @Test
+ public void testSettingsValueConsecutiveReadAfterWrite() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ int i = 0;
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ // Triggering the invalidation of setting1's cache
+ Settings.Secure.putString(mContentResolver, SETTING_NAME1, Integer.toString(i));
+ i++;
+ state.resumeTiming();
+ Settings.Secure.getString(mContentResolver, SETTING_NAME1);
+ }
+ }
+
+ @Test
+ public void testSettingsNamespaceConsecutiveRead() {
+ final List names = new ArrayList<>();
+ names.add(SETTING_NAME1);
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Settings.Config.getStrings(mContentResolver, NAMESPACE, names);
+ }
+ }
+
+ @Test
+ public void testSettingsNamespaceConsecutiveReadAfterWrite() {
+ final List names = new ArrayList<>();
+ names.add(SETTING_NAME1);
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ int i = 0;
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ // Triggering the invalidation of the list's cache
+ Settings.Config.putString(NAMESPACE, SETTING_NAME2, Integer.toString(i), true);
+ i++;
+ state.resumeTiming();
+ Settings.Config.getStrings(mContentResolver, NAMESPACE, names);
+ }
+ }
+}