diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto index e62af74fd4392..bab4b6efd49d4 100644 --- a/core/proto/android/providers/settings.proto +++ b/core/proto/android/providers/settings.proto @@ -21,6 +21,7 @@ option java_multiple_files = true; option java_outer_classname = "SettingsServiceProto"; import "frameworks/base/core/proto/android/providers/settings/config.proto"; +import "frameworks/base/core/proto/android/providers/settings/generation.proto"; import "frameworks/base/core/proto/android/providers/settings/global.proto"; import "frameworks/base/core/proto/android/providers/settings/secure.proto"; import "frameworks/base/core/proto/android/providers/settings/system.proto"; @@ -37,6 +38,9 @@ message SettingsServiceDumpProto { // Config settings optional ConfigSettingsProto config_settings = 3; + + // Generation registry stats + optional GenerationRegistryProto generation_registry = 4; } message UserSettingsProto { diff --git a/core/proto/android/providers/settings/generation.proto b/core/proto/android/providers/settings/generation.proto new file mode 100644 index 0000000000000..9dcbad2c979f5 --- /dev/null +++ b/core/proto/android/providers/settings/generation.proto @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2023 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. + */ + +syntax = "proto2"; +package android.providers.settings; + +option java_multiple_files = true; + +import "frameworks/base/core/proto/android/privacy.proto"; + +message GenerationRegistryProto { + option (android.msg_privacy).dest = DEST_EXPLICIT; + optional int32 num_backing_stores = 1; + optional int32 num_max_backing_stores = 2; + repeated BackingStoreProto backing_stores = 3; +} + +message BackingStoreProto { + optional int32 key = 1; + optional int32 backing_store_size = 2; + optional int32 num_cached_entries = 3; + repeated CacheEntryProto cache_entries = 4; +} + +message CacheEntryProto { + optional string name = 1; + optional int32 generation = 2; +} \ No newline at end of file diff --git a/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java b/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java index 80030f7a7a47f..02ec486a02058 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java @@ -20,14 +20,19 @@ import android.annotation.NonNull; import android.os.Bundle; import android.os.UserHandle; import android.provider.Settings; +import android.providers.settings.BackingStoreProto; +import android.providers.settings.CacheEntryProto; +import android.providers.settings.GenerationRegistryProto; import android.util.ArrayMap; import android.util.MemoryIntArray; import android.util.Slog; +import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import java.io.IOException; +import java.io.PrintWriter; /** * This class tracks changes for config/global/secure/system tables @@ -292,4 +297,94 @@ final class GenerationRegistry { int getMaxNumBackingStores() { return mMaxNumBackingStore; } + + public void dumpProto(ProtoOutputStream proto) { + synchronized (mLock) { + final int numBackingStores = mKeyToBackingStoreMap.size(); + proto.write(GenerationRegistryProto.NUM_BACKING_STORES, numBackingStores); + proto.write(GenerationRegistryProto.NUM_MAX_BACKING_STORES, getMaxNumBackingStores()); + + for (int i = 0; i < numBackingStores; i++) { + final long token = proto.start(GenerationRegistryProto.BACKING_STORES); + final int key = mKeyToBackingStoreMap.keyAt(i); + proto.write(BackingStoreProto.KEY, key); + try { + proto.write(BackingStoreProto.BACKING_STORE_SIZE, + mKeyToBackingStoreMap.valueAt(i).size()); + } catch (IOException ignore) { + } + proto.write(BackingStoreProto.NUM_CACHED_ENTRIES, + mKeyToIndexMapMap.get(key).size()); + final ArrayMap indexMap = mKeyToIndexMapMap.get(key); + final MemoryIntArray backingStore = getBackingStoreLocked(key, + /* createIfNotExist= */ false); + if (indexMap == null || backingStore == null) { + continue; + } + for (String setting : indexMap.keySet()) { + try { + final int index = getKeyIndexLocked(key, setting, mKeyToIndexMapMap, + backingStore, /* createIfNotExist= */ false); + if (index < 0) { + continue; + } + final long cacheEntryToken = proto.start( + BackingStoreProto.CACHE_ENTRIES); + final int generation = backingStore.get(index); + proto.write(CacheEntryProto.NAME, + setting.equals(DEFAULT_MAP_KEY_FOR_UNSET_SETTINGS) + ? "UNSET" : setting); + proto.write(CacheEntryProto.GENERATION, generation); + proto.end(cacheEntryToken); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + proto.end(token); + } + + } + } + + public void dump(PrintWriter pw) { + pw.println("GENERATION REGISTRY"); + pw.println("Maximum number of backing stores:" + getMaxNumBackingStores()); + synchronized (mLock) { + final int numBackingStores = mKeyToBackingStoreMap.size(); + pw.println("Number of backing stores:" + numBackingStores); + for (int i = 0; i < numBackingStores; i++) { + final int key = mKeyToBackingStoreMap.keyAt(i); + pw.print("_Backing store for type:"); pw.print(SettingsState.settingTypeToString( + SettingsState.getTypeFromKey(key))); + pw.print(" user:"); pw.print(SettingsState.getUserIdFromKey(key)); + try { + pw.print(" size:" + mKeyToBackingStoreMap.valueAt(i).size()); + } catch (IOException ignore) { + } + pw.println(" cachedEntries:" + mKeyToIndexMapMap.get(key).size()); + final ArrayMap indexMap = mKeyToIndexMapMap.get(key); + final MemoryIntArray backingStore = getBackingStoreLocked(key, + /* createIfNotExist= */ false); + if (indexMap == null || backingStore == null) { + continue; + } + for (String setting : indexMap.keySet()) { + try { + final int index = getKeyIndexLocked(key, setting, mKeyToIndexMapMap, + backingStore, /* createIfNotExist= */ false); + if (index < 0) { + continue; + } + final int generation = backingStore.get(index); + pw.print(" setting: "); pw.print( + setting.equals(DEFAULT_MAP_KEY_FOR_UNSET_SETTINGS) + ? "UNSET" : setting); + pw.println(" generation:" + generation); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + } + } } \ No newline at end of file diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index d49627e5334a5..d3a9e91c3da80 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -120,6 +120,17 @@ class SettingsProtoDumpUtil { dumpProtoUserSettingsLocked(proto, SettingsServiceDumpProto.USER_SETTINGS, settingsRegistry, UserHandle.of(users.keyAt(i))); } + + // Generation registry + dumpProtoGenerationRegistryLocked(proto, SettingsServiceDumpProto.GENERATION_REGISTRY, + settingsRegistry); + } + + private static void dumpProtoGenerationRegistryLocked(@NonNull ProtoOutputStream proto, + long fieldId, SettingsProvider.SettingsRegistry settingsRegistry) { + final long token = proto.start(fieldId); + settingsRegistry.getGenerationRegistry().dumpProto(proto); + proto.end(token); } /** diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 721b3c49b17c5..330bd597140a5 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -900,6 +900,7 @@ public class SettingsProvider extends ContentProvider { } finally { Binder.restoreCallingIdentity(identity); } + mSettingsRegistry.mGenerationRegistry.dump(pw); } } @@ -5991,5 +5992,10 @@ public class SettingsProvider extends ContentProvider { return !a11yButtonTargetsSettings.isNull() && !TextUtils.isEmpty(a11yButtonTargetsSettings.getValue()); } + + @NonNull + public GenerationRegistry getGenerationRegistry() { + return mGenerationRegistry; + } } }