summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Song Chun Fan <schfan@google.com> 2024-01-18 00:17:20 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2024-01-18 00:17:20 +0000
commit24fad9ca51c5d22e896f7e58cd2b1bba66505295 (patch)
tree2d268d6c9a0e08db3bff326e682f6a3d376f07dc
parentc6b4b1592d03b11588f5379874a802a76868c6fa (diff)
parentd05c0ff623ce7362ad718e51b378805450928fe9 (diff)
Merge "[SettingsProvider] use per-prefix caches for Config.getStrings queries" into main
-rw-r--r--core/java/android/provider/Settings.java93
1 files changed, 42 insertions, 51 deletions
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7d84bb390853..04d8a4900042 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3236,9 +3236,17 @@ public final class Settings {
private static final String NAME_EQ_PLACEHOLDER = "name=?";
+ // Cached values of queried settings.
+ // Key is the setting's name, value is the setting's value.
// Must synchronize on 'this' to access mValues and mValuesVersion.
private final ArrayMap<String, String> mValues = new ArrayMap<>();
+ // Cached values for queried prefixes.
+ // Key is the prefix, value is all of the settings under the prefix, mapped from a setting's
+ // name to a setting's value. The name string doesn't include the prefix.
+ // Must synchronize on 'this' to access.
+ private final ArrayMap<String, ArrayMap<String, String>> mPrefixToValues = new ArrayMap<>();
+
private final Uri mUri;
@UnsupportedAppUsage
private final ContentProviderHolder mProviderHolder;
@@ -3583,15 +3591,13 @@ public final class Settings {
|| applicationInfo.isSignedWithPlatformKey();
}
- private ArrayMap<String, String> getStringsForPrefixStripPrefix(
- ContentResolver cr, String prefix, String[] names) {
+ private Map<String, String> getStringsForPrefixStripPrefix(
+ ContentResolver cr, String prefix, List<String> names) {
String namespace = prefix.substring(0, prefix.length() - 1);
ArrayMap<String, String> keyValues = new ArrayMap<>();
int substringLength = prefix.length();
-
int currentGeneration = -1;
boolean needsGenerationTracker = false;
-
synchronized (NameValueCache.this) {
final GenerationTracker generationTracker = mGenerationTrackers.get(prefix);
if (generationTracker != null) {
@@ -3605,40 +3611,22 @@ public final class Settings {
// generation tracker and request a new one
generationTracker.destroy();
mGenerationTrackers.remove(prefix);
- for (int i = mValues.size() - 1; i >= 0; i--) {
- String key = mValues.keyAt(i);
- if (key.startsWith(prefix)) {
- mValues.remove(key);
- }
- }
+ mPrefixToValues.remove(prefix);
needsGenerationTracker = true;
} else {
- boolean prefixCached = mValues.containsKey(prefix);
- if (prefixCached) {
- if (DEBUG) {
- Log.i(TAG, "Cache hit for prefix:" + prefix);
- }
- if (names.length > 0) {
+ final ArrayMap<String, String> cachedSettings = mPrefixToValues.get(prefix);
+ if (cachedSettings != null) {
+ if (!names.isEmpty()) {
for (String name : names) {
- // mValues can contain "null" values, need to use containsKey.
- if (mValues.containsKey(name)) {
+ // The cache can contain "null" values, need to use containsKey.
+ if (cachedSettings.containsKey(name)) {
keyValues.put(
- name.substring(substringLength),
- mValues.get(name));
+ name,
+ cachedSettings.get(name));
}
}
} else {
- for (int i = 0; i < mValues.size(); ++i) {
- String key = mValues.keyAt(i);
- // Explicitly exclude the prefix as it is only there to
- // signal that the prefix has been cached.
- if (key.startsWith(prefix) && !key.equals(prefix)) {
- String value = mValues.valueAt(i);
- keyValues.put(
- key.substring(substringLength),
- value);
- }
- }
+ keyValues.putAll(cachedSettings);
}
return keyValues;
}
@@ -3648,7 +3636,6 @@ public final class Settings {
needsGenerationTracker = true;
}
}
-
if (mCallListCommand == null) {
// No list command specified, return empty map
return keyValues;
@@ -3693,20 +3680,23 @@ public final class Settings {
}
// All flags for the namespace
- Map<String, String> flagsToValues =
+ HashMap<String, String> flagsToValues =
(HashMap) b.getSerializable(Settings.NameValueTable.VALUE, java.util.HashMap.class);
+ if (flagsToValues == null) {
+ return keyValues;
+ }
// Only the flags requested by the caller
- if (names.length > 0) {
+ if (!names.isEmpty()) {
for (String name : names) {
// flagsToValues can contain "null" values, need to use containsKey.
- if (flagsToValues.containsKey(name)) {
+ final String key = Config.createCompositeName(namespace, name);
+ if (flagsToValues.containsKey(key)) {
keyValues.put(
- name.substring(substringLength),
- flagsToValues.get(name));
+ name,
+ flagsToValues.get(key));
}
}
} else {
- keyValues.ensureCapacity(keyValues.size() + flagsToValues.size());
for (Map.Entry<String, String> flag : flagsToValues.entrySet()) {
keyValues.put(
flag.getKey().substring(substringLength),
@@ -3740,10 +3730,18 @@ public final class Settings {
if (DEBUG) {
Log.i(TAG, "Updating cache for prefix:" + prefix);
}
- // cache the complete list of flags for the namespace
- mValues.putAll(flagsToValues);
- // Adding the prefix as a signal that the prefix is cached.
- mValues.put(prefix, null);
+ // Cache the complete list of flags for the namespace for bulk queries.
+ // In this cached list, the setting's name doesn't include the prefix.
+ ArrayMap<String, String> namesToValues =
+ new ArrayMap<>(flagsToValues.size() + 1);
+ for (Map.Entry<String, String> flag : flagsToValues.entrySet()) {
+ namesToValues.put(
+ flag.getKey().substring(substringLength),
+ flag.getValue());
+ }
+ // Legacy behavior, we return <"", null> when queried with name = ""
+ namesToValues.put("", null);
+ mPrefixToValues.put(prefix, namesToValues);
}
}
return keyValues;
@@ -19907,16 +19905,9 @@ public final class Settings {
@RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
public static Map<String, String> getStrings(@NonNull ContentResolver resolver,
@NonNull String namespace, @NonNull List<String> names) {
- String[] compositeNames = new String[names.size()];
- for (int i = 0, size = names.size(); i < size; ++i) {
- compositeNames[i] = createCompositeName(namespace, names.get(i));
- }
-
String prefix = createPrefix(namespace);
- ArrayMap<String, String> keyValues = sNameValueCache.getStringsForPrefixStripPrefix(
- resolver, prefix, compositeNames);
- return keyValues;
+ return sNameValueCache.getStringsForPrefixStripPrefix(resolver, prefix, names);
}
/**
@@ -20238,7 +20229,7 @@ public final class Settings {
}
}
- private static String createCompositeName(@NonNull String namespace, @NonNull String name) {
+ static String createCompositeName(@NonNull String namespace, @NonNull String name) {
Preconditions.checkNotNull(namespace);
Preconditions.checkNotNull(name);
var sb = new StringBuilder(namespace.length() + 1 + name.length());