Loading proto/src/typed_features.proto 0 → 100644 +25 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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 com.android.service; option java_multiple_files = true; // This message is to specify feature params that are a list of strings. message StringListParamProto { repeated string element = 1; } No newline at end of file services/core/java/com/android/server/stats/pull/SettingsStatsUtil.java 0 → 100644 +220 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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 com.android.server.stats.pull; import static com.android.internal.util.FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_BOOL_TYPE; import static com.android.internal.util.FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_FLOAT_TYPE; import static com.android.internal.util.FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_INT_TYPE; import static com.android.internal.util.FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_STRING_TYPE; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ContentResolver; import android.content.Context; import android.provider.DeviceConfig; import android.provider.Settings; import android.text.TextUtils; import android.util.Base64; import android.util.Slog; import android.util.StatsEvent; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FrameworkStatsLog; import com.android.service.nano.StringListParamProto; import java.util.ArrayList; import java.util.List; /** * Utility methods for creating {@link StatsEvent} data. */ final class SettingsStatsUtil { private static final String TAG = "SettingsStatsUtil"; private static final FlagsData[] GLOBAL_SETTINGS = new FlagsData[]{ new FlagsData("GlobalFeature__boolean_whitelist", SETTING_SNAPSHOT__TYPE__ASSIGNED_BOOL_TYPE), new FlagsData("GlobalFeature__integer_whitelist", SETTING_SNAPSHOT__TYPE__ASSIGNED_INT_TYPE), new FlagsData("GlobalFeature__float_whitelist", SETTING_SNAPSHOT__TYPE__ASSIGNED_FLOAT_TYPE), new FlagsData("GlobalFeature__string_whitelist", SETTING_SNAPSHOT__TYPE__ASSIGNED_STRING_TYPE) }; private static final FlagsData[] SECURE_SETTINGS = new FlagsData[]{ new FlagsData("SecureFeature__boolean_whitelist", SETTING_SNAPSHOT__TYPE__ASSIGNED_BOOL_TYPE), new FlagsData("SecureFeature__integer_whitelist", SETTING_SNAPSHOT__TYPE__ASSIGNED_INT_TYPE), new FlagsData("SecureFeature__float_whitelist", SETTING_SNAPSHOT__TYPE__ASSIGNED_FLOAT_TYPE), new FlagsData("SecureFeature__string_whitelist", SETTING_SNAPSHOT__TYPE__ASSIGNED_STRING_TYPE) }; private static final FlagsData[] SYSTEM_SETTINGS = new FlagsData[]{ new FlagsData("SystemFeature__boolean_whitelist", SETTING_SNAPSHOT__TYPE__ASSIGNED_BOOL_TYPE), new FlagsData("SystemFeature__integer_whitelist", SETTING_SNAPSHOT__TYPE__ASSIGNED_INT_TYPE), new FlagsData("SystemFeature__float_whitelist", SETTING_SNAPSHOT__TYPE__ASSIGNED_FLOAT_TYPE), new FlagsData("SystemFeature__string_whitelist", SETTING_SNAPSHOT__TYPE__ASSIGNED_STRING_TYPE) }; @VisibleForTesting @NonNull static List<StatsEvent> logGlobalSettings(Context context, int atomTag, int userId) { final List<StatsEvent> output = new ArrayList<>(); final ContentResolver resolver = context.getContentResolver(); for (FlagsData flagsData : GLOBAL_SETTINGS) { StringListParamProto proto = getList(flagsData.mFlagName); if (proto == null) { continue; } for (String key : proto.element) { final String value = Settings.Global.getStringForUser(resolver, key, userId); output.add(createStatsEvent(atomTag, key, value, userId, flagsData.mDataType)); } } return output; } @NonNull static List<StatsEvent> logSystemSettings(Context context, int atomTag, int userId) { final List<StatsEvent> output = new ArrayList<>(); final ContentResolver resolver = context.getContentResolver(); for (FlagsData flagsData : SYSTEM_SETTINGS) { StringListParamProto proto = getList(flagsData.mFlagName); if (proto == null) { continue; } for (String key : proto.element) { final String value = Settings.System.getStringForUser(resolver, key, userId); output.add(createStatsEvent(atomTag, key, value, userId, flagsData.mDataType)); } } return output; } @NonNull static List<StatsEvent> logSecureSettings(Context context, int atomTag, int userId) { final List<StatsEvent> output = new ArrayList<>(); final ContentResolver resolver = context.getContentResolver(); for (FlagsData flagsData : SECURE_SETTINGS) { StringListParamProto proto = getList(flagsData.mFlagName); if (proto == null) { continue; } for (String key : proto.element) { final String value = Settings.Secure.getStringForUser(resolver, key, userId); output.add(createStatsEvent(atomTag, key, value, userId, flagsData.mDataType)); } } return output; } @VisibleForTesting @Nullable static StringListParamProto getList(String flag) { final String base64 = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, flag); if (TextUtils.isEmpty(base64)) { return null; } final byte[] decode = Base64.decode(base64, Base64.NO_PADDING | Base64.NO_WRAP); StringListParamProto list = null; try { list = StringListParamProto.parseFrom(decode); } catch (Exception e) { Slog.e(TAG, "Error parsing string list proto", e); } return list; } /** * Create {@link StatsEvent} for SETTING_SNAPSHOT atom */ @NonNull private static StatsEvent createStatsEvent(int atomTag, String key, String value, int userId, int type) { final StatsEvent.Builder builder = StatsEvent.newBuilder() .setAtomId(atomTag) .writeString(key); boolean booleanValue = false; int intValue = 0; float floatValue = 0; String stringValue = ""; if (TextUtils.isEmpty(value)) { builder.writeInt(FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__NOTASSIGNED) .writeBoolean(booleanValue) .writeInt(intValue) .writeFloat(floatValue) .writeString(stringValue) .writeInt(userId); } else { switch (type) { case SETTING_SNAPSHOT__TYPE__ASSIGNED_BOOL_TYPE: booleanValue = "1".equals(value); break; case FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_INT_TYPE: try { intValue = Integer.parseInt(value); } catch (NumberFormatException e) { Slog.w(TAG, "Can not parse value to float: " + value); } break; case SETTING_SNAPSHOT__TYPE__ASSIGNED_FLOAT_TYPE: try { floatValue = Float.parseFloat(value); } catch (NumberFormatException e) { Slog.w(TAG, "Can not parse value to float: " + value); } break; case FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_STRING_TYPE: stringValue = value; break; default: Slog.w(TAG, "Unexpected value type " + type); } builder.writeInt(type) .writeBoolean(booleanValue) .writeInt(intValue) .writeFloat(floatValue) .writeString(stringValue) .writeInt(userId); } return builder.build(); } /** Class for defining flag name and its data type. */ static final class FlagsData { /** {@link DeviceConfig} flag name, value of the flag is {@link StringListParamProto} */ String mFlagName; /** Data type of the value getting from {@link Settings} keys. */ int mDataType; FlagsData(String flagName, int dataType) { mFlagName = flagName; mDataType = dataType; } } } services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +40 −0 Original line number Diff line number Diff line Loading @@ -416,6 +416,8 @@ public class StatsPullAtomService extends SystemService { return pullHealthHal(atomTag, data); case FrameworkStatsLog.ATTRIBUTED_APP_OPS: return pullAttributedAppOps(atomTag, data); case FrameworkStatsLog.SETTING_SNAPSHOT: return pullSettingsStats(atomTag, data); default: throw new UnsupportedOperationException("Unknown tagId=" + atomTag); } Loading Loading @@ -580,6 +582,7 @@ public class StatsPullAtomService extends SystemService { registerFullBatteryCapacity(); registerBatteryVoltage(); registerBatteryCycleCount(); registerSettingsStats(); } /** Loading Loading @@ -3244,6 +3247,43 @@ public class StatsPullAtomService extends SystemService { return StatsManager.PULL_SUCCESS; } private void registerSettingsStats() { int tagId = FrameworkStatsLog.SETTING_SNAPSHOT; mStatsManager.setPullAtomCallback( tagId, null, // use default PullAtomMetadata values BackgroundThread.getExecutor(), mStatsCallbackImpl ); } int pullSettingsStats(int atomTag, List<StatsEvent> pulledData) { UserManager userManager = mContext.getSystemService(UserManager.class); if (userManager == null) { return StatsManager.PULL_SKIP; } final long token = Binder.clearCallingIdentity(); try { for (UserInfo user : userManager.getUsers()) { final int userId = user.getUserHandle().getIdentifier(); if (userId == UserHandle.USER_SYSTEM) { pulledData.addAll(SettingsStatsUtil.logGlobalSettings(mContext, atomTag, UserHandle.USER_SYSTEM)); } pulledData.addAll(SettingsStatsUtil.logSystemSettings(mContext, atomTag, userId)); pulledData.addAll(SettingsStatsUtil.logSecureSettings(mContext, atomTag, userId)); } } catch (Exception e) { Slog.e(TAG, "failed to pullSettingsStats", e); return StatsManager.PULL_SKIP; } finally { Binder.restoreCallingIdentity(token); } return StatsManager.PULL_SUCCESS; } // Thermal event received from vendor thermal management subsystem private static final class ThermalEventListener extends IThermalEventListener.Stub { @Override Loading services/tests/servicestests/src/com/android/server/stats/pull/SettingsStatsUtilTest.java 0 → 100644 +109 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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 com.android.server.stats.pull; import static android.os.UserHandle.USER_SYSTEM; import static com.android.internal.util.FrameworkStatsLog.SETTING_SNAPSHOT; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import android.content.Context; import android.provider.DeviceConfig; import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; /** * Build/Install/Run: * atest FrameworksServicesTests:SettingsStatsUtilTest */ @RunWith(AndroidJUnit4.class) public class SettingsStatsUtilTest { private static final String[] KEYS = new String[]{ "screen_auto_brightness_adj", "font_scale" }; private static final String ENCODED = "ChpzY3JlZW5fYXV0b19icmlnaHRuZXNzX2FkagoKZm9udF9zY2FsZQ"; private static final String FLAG = "testflag"; private Context mContext; @Before public void setUp() { DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, FLAG, "", false /* makeDefault*/); mContext = InstrumentationRegistry.getInstrumentation().getContext(); } @Test public void getList_emptyString_nullValue() { assertNull(SettingsStatsUtil.getList(FLAG)); } @Test public void getList_notValidString_nullValue() { DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, FLAG, "abcd", false); assertNull(SettingsStatsUtil.getList(FLAG)); } @Test public void getList_validString_correctValue() { DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, FLAG, ENCODED, false); assertArrayEquals(KEYS, SettingsStatsUtil.getList(FLAG).element); } @Test public void logGlobalSettings_noWhitelist_correctSize() { DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, "GlobalFeature__boolean_whitelist", "", false); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, "GlobalFeature__integer_whitelist", "", false); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, "GlobalFeature__float_whitelist", "", false); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, "GlobalFeature__string_whitelist", "", false); assertEquals(0, SettingsStatsUtil.logGlobalSettings(mContext, SETTING_SNAPSHOT, USER_SYSTEM).size()); } @Test public void logGlobalSettings_correctSize() { DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, "GlobalFeature__boolean_whitelist", ENCODED, false); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, "GlobalFeature__integer_whitelist", ENCODED, false); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, "GlobalFeature__float_whitelist", ENCODED, false); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, "GlobalFeature__string_whitelist", ENCODED, false); assertEquals(KEYS.length * 4, SettingsStatsUtil.logGlobalSettings(mContext, SETTING_SNAPSHOT, USER_SYSTEM).size()); } } Loading
proto/src/typed_features.proto 0 → 100644 +25 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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 com.android.service; option java_multiple_files = true; // This message is to specify feature params that are a list of strings. message StringListParamProto { repeated string element = 1; } No newline at end of file
services/core/java/com/android/server/stats/pull/SettingsStatsUtil.java 0 → 100644 +220 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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 com.android.server.stats.pull; import static com.android.internal.util.FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_BOOL_TYPE; import static com.android.internal.util.FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_FLOAT_TYPE; import static com.android.internal.util.FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_INT_TYPE; import static com.android.internal.util.FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_STRING_TYPE; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ContentResolver; import android.content.Context; import android.provider.DeviceConfig; import android.provider.Settings; import android.text.TextUtils; import android.util.Base64; import android.util.Slog; import android.util.StatsEvent; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FrameworkStatsLog; import com.android.service.nano.StringListParamProto; import java.util.ArrayList; import java.util.List; /** * Utility methods for creating {@link StatsEvent} data. */ final class SettingsStatsUtil { private static final String TAG = "SettingsStatsUtil"; private static final FlagsData[] GLOBAL_SETTINGS = new FlagsData[]{ new FlagsData("GlobalFeature__boolean_whitelist", SETTING_SNAPSHOT__TYPE__ASSIGNED_BOOL_TYPE), new FlagsData("GlobalFeature__integer_whitelist", SETTING_SNAPSHOT__TYPE__ASSIGNED_INT_TYPE), new FlagsData("GlobalFeature__float_whitelist", SETTING_SNAPSHOT__TYPE__ASSIGNED_FLOAT_TYPE), new FlagsData("GlobalFeature__string_whitelist", SETTING_SNAPSHOT__TYPE__ASSIGNED_STRING_TYPE) }; private static final FlagsData[] SECURE_SETTINGS = new FlagsData[]{ new FlagsData("SecureFeature__boolean_whitelist", SETTING_SNAPSHOT__TYPE__ASSIGNED_BOOL_TYPE), new FlagsData("SecureFeature__integer_whitelist", SETTING_SNAPSHOT__TYPE__ASSIGNED_INT_TYPE), new FlagsData("SecureFeature__float_whitelist", SETTING_SNAPSHOT__TYPE__ASSIGNED_FLOAT_TYPE), new FlagsData("SecureFeature__string_whitelist", SETTING_SNAPSHOT__TYPE__ASSIGNED_STRING_TYPE) }; private static final FlagsData[] SYSTEM_SETTINGS = new FlagsData[]{ new FlagsData("SystemFeature__boolean_whitelist", SETTING_SNAPSHOT__TYPE__ASSIGNED_BOOL_TYPE), new FlagsData("SystemFeature__integer_whitelist", SETTING_SNAPSHOT__TYPE__ASSIGNED_INT_TYPE), new FlagsData("SystemFeature__float_whitelist", SETTING_SNAPSHOT__TYPE__ASSIGNED_FLOAT_TYPE), new FlagsData("SystemFeature__string_whitelist", SETTING_SNAPSHOT__TYPE__ASSIGNED_STRING_TYPE) }; @VisibleForTesting @NonNull static List<StatsEvent> logGlobalSettings(Context context, int atomTag, int userId) { final List<StatsEvent> output = new ArrayList<>(); final ContentResolver resolver = context.getContentResolver(); for (FlagsData flagsData : GLOBAL_SETTINGS) { StringListParamProto proto = getList(flagsData.mFlagName); if (proto == null) { continue; } for (String key : proto.element) { final String value = Settings.Global.getStringForUser(resolver, key, userId); output.add(createStatsEvent(atomTag, key, value, userId, flagsData.mDataType)); } } return output; } @NonNull static List<StatsEvent> logSystemSettings(Context context, int atomTag, int userId) { final List<StatsEvent> output = new ArrayList<>(); final ContentResolver resolver = context.getContentResolver(); for (FlagsData flagsData : SYSTEM_SETTINGS) { StringListParamProto proto = getList(flagsData.mFlagName); if (proto == null) { continue; } for (String key : proto.element) { final String value = Settings.System.getStringForUser(resolver, key, userId); output.add(createStatsEvent(atomTag, key, value, userId, flagsData.mDataType)); } } return output; } @NonNull static List<StatsEvent> logSecureSettings(Context context, int atomTag, int userId) { final List<StatsEvent> output = new ArrayList<>(); final ContentResolver resolver = context.getContentResolver(); for (FlagsData flagsData : SECURE_SETTINGS) { StringListParamProto proto = getList(flagsData.mFlagName); if (proto == null) { continue; } for (String key : proto.element) { final String value = Settings.Secure.getStringForUser(resolver, key, userId); output.add(createStatsEvent(atomTag, key, value, userId, flagsData.mDataType)); } } return output; } @VisibleForTesting @Nullable static StringListParamProto getList(String flag) { final String base64 = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, flag); if (TextUtils.isEmpty(base64)) { return null; } final byte[] decode = Base64.decode(base64, Base64.NO_PADDING | Base64.NO_WRAP); StringListParamProto list = null; try { list = StringListParamProto.parseFrom(decode); } catch (Exception e) { Slog.e(TAG, "Error parsing string list proto", e); } return list; } /** * Create {@link StatsEvent} for SETTING_SNAPSHOT atom */ @NonNull private static StatsEvent createStatsEvent(int atomTag, String key, String value, int userId, int type) { final StatsEvent.Builder builder = StatsEvent.newBuilder() .setAtomId(atomTag) .writeString(key); boolean booleanValue = false; int intValue = 0; float floatValue = 0; String stringValue = ""; if (TextUtils.isEmpty(value)) { builder.writeInt(FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__NOTASSIGNED) .writeBoolean(booleanValue) .writeInt(intValue) .writeFloat(floatValue) .writeString(stringValue) .writeInt(userId); } else { switch (type) { case SETTING_SNAPSHOT__TYPE__ASSIGNED_BOOL_TYPE: booleanValue = "1".equals(value); break; case FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_INT_TYPE: try { intValue = Integer.parseInt(value); } catch (NumberFormatException e) { Slog.w(TAG, "Can not parse value to float: " + value); } break; case SETTING_SNAPSHOT__TYPE__ASSIGNED_FLOAT_TYPE: try { floatValue = Float.parseFloat(value); } catch (NumberFormatException e) { Slog.w(TAG, "Can not parse value to float: " + value); } break; case FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_STRING_TYPE: stringValue = value; break; default: Slog.w(TAG, "Unexpected value type " + type); } builder.writeInt(type) .writeBoolean(booleanValue) .writeInt(intValue) .writeFloat(floatValue) .writeString(stringValue) .writeInt(userId); } return builder.build(); } /** Class for defining flag name and its data type. */ static final class FlagsData { /** {@link DeviceConfig} flag name, value of the flag is {@link StringListParamProto} */ String mFlagName; /** Data type of the value getting from {@link Settings} keys. */ int mDataType; FlagsData(String flagName, int dataType) { mFlagName = flagName; mDataType = dataType; } } }
services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +40 −0 Original line number Diff line number Diff line Loading @@ -416,6 +416,8 @@ public class StatsPullAtomService extends SystemService { return pullHealthHal(atomTag, data); case FrameworkStatsLog.ATTRIBUTED_APP_OPS: return pullAttributedAppOps(atomTag, data); case FrameworkStatsLog.SETTING_SNAPSHOT: return pullSettingsStats(atomTag, data); default: throw new UnsupportedOperationException("Unknown tagId=" + atomTag); } Loading Loading @@ -580,6 +582,7 @@ public class StatsPullAtomService extends SystemService { registerFullBatteryCapacity(); registerBatteryVoltage(); registerBatteryCycleCount(); registerSettingsStats(); } /** Loading Loading @@ -3244,6 +3247,43 @@ public class StatsPullAtomService extends SystemService { return StatsManager.PULL_SUCCESS; } private void registerSettingsStats() { int tagId = FrameworkStatsLog.SETTING_SNAPSHOT; mStatsManager.setPullAtomCallback( tagId, null, // use default PullAtomMetadata values BackgroundThread.getExecutor(), mStatsCallbackImpl ); } int pullSettingsStats(int atomTag, List<StatsEvent> pulledData) { UserManager userManager = mContext.getSystemService(UserManager.class); if (userManager == null) { return StatsManager.PULL_SKIP; } final long token = Binder.clearCallingIdentity(); try { for (UserInfo user : userManager.getUsers()) { final int userId = user.getUserHandle().getIdentifier(); if (userId == UserHandle.USER_SYSTEM) { pulledData.addAll(SettingsStatsUtil.logGlobalSettings(mContext, atomTag, UserHandle.USER_SYSTEM)); } pulledData.addAll(SettingsStatsUtil.logSystemSettings(mContext, atomTag, userId)); pulledData.addAll(SettingsStatsUtil.logSecureSettings(mContext, atomTag, userId)); } } catch (Exception e) { Slog.e(TAG, "failed to pullSettingsStats", e); return StatsManager.PULL_SKIP; } finally { Binder.restoreCallingIdentity(token); } return StatsManager.PULL_SUCCESS; } // Thermal event received from vendor thermal management subsystem private static final class ThermalEventListener extends IThermalEventListener.Stub { @Override Loading
services/tests/servicestests/src/com/android/server/stats/pull/SettingsStatsUtilTest.java 0 → 100644 +109 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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 com.android.server.stats.pull; import static android.os.UserHandle.USER_SYSTEM; import static com.android.internal.util.FrameworkStatsLog.SETTING_SNAPSHOT; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import android.content.Context; import android.provider.DeviceConfig; import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; /** * Build/Install/Run: * atest FrameworksServicesTests:SettingsStatsUtilTest */ @RunWith(AndroidJUnit4.class) public class SettingsStatsUtilTest { private static final String[] KEYS = new String[]{ "screen_auto_brightness_adj", "font_scale" }; private static final String ENCODED = "ChpzY3JlZW5fYXV0b19icmlnaHRuZXNzX2FkagoKZm9udF9zY2FsZQ"; private static final String FLAG = "testflag"; private Context mContext; @Before public void setUp() { DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, FLAG, "", false /* makeDefault*/); mContext = InstrumentationRegistry.getInstrumentation().getContext(); } @Test public void getList_emptyString_nullValue() { assertNull(SettingsStatsUtil.getList(FLAG)); } @Test public void getList_notValidString_nullValue() { DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, FLAG, "abcd", false); assertNull(SettingsStatsUtil.getList(FLAG)); } @Test public void getList_validString_correctValue() { DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, FLAG, ENCODED, false); assertArrayEquals(KEYS, SettingsStatsUtil.getList(FLAG).element); } @Test public void logGlobalSettings_noWhitelist_correctSize() { DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, "GlobalFeature__boolean_whitelist", "", false); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, "GlobalFeature__integer_whitelist", "", false); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, "GlobalFeature__float_whitelist", "", false); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, "GlobalFeature__string_whitelist", "", false); assertEquals(0, SettingsStatsUtil.logGlobalSettings(mContext, SETTING_SNAPSHOT, USER_SYSTEM).size()); } @Test public void logGlobalSettings_correctSize() { DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, "GlobalFeature__boolean_whitelist", ENCODED, false); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, "GlobalFeature__integer_whitelist", ENCODED, false); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, "GlobalFeature__float_whitelist", ENCODED, false); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, "GlobalFeature__string_whitelist", ENCODED, false); assertEquals(KEYS.length * 4, SettingsStatsUtil.logGlobalSettings(mContext, SETTING_SNAPSHOT, USER_SYSTEM).size()); } }