• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.stats.pull;
18 
19 import static com.android.internal.util.FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_BOOL_TYPE;
20 import static com.android.internal.util.FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_FLOAT_TYPE;
21 import static com.android.internal.util.FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_INT_TYPE;
22 import static com.android.internal.util.FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_STRING_TYPE;
23 
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.content.ContentResolver;
27 import android.content.Context;
28 import android.provider.DeviceConfig;
29 import android.provider.Settings;
30 import android.text.TextUtils;
31 import android.util.Base64;
32 import android.util.Slog;
33 import android.util.StatsEvent;
34 
35 import com.android.internal.annotations.VisibleForTesting;
36 import com.android.internal.util.FrameworkStatsLog;
37 import com.android.service.nano.StringListParamProto;
38 
39 import java.util.ArrayList;
40 import java.util.List;
41 
42 /**
43  * Utility methods for creating {@link StatsEvent} data.
44  */
45 final class SettingsStatsUtil {
46     private static final String TAG = "SettingsStatsUtil";
47     private static final FlagsData[] GLOBAL_SETTINGS = new FlagsData[]{
48             new FlagsData("GlobalFeature__boolean_whitelist",
49                     SETTING_SNAPSHOT__TYPE__ASSIGNED_BOOL_TYPE),
50             new FlagsData("GlobalFeature__integer_whitelist",
51                     SETTING_SNAPSHOT__TYPE__ASSIGNED_INT_TYPE),
52             new FlagsData("GlobalFeature__float_whitelist",
53                     SETTING_SNAPSHOT__TYPE__ASSIGNED_FLOAT_TYPE),
54             new FlagsData("GlobalFeature__string_whitelist",
55                     SETTING_SNAPSHOT__TYPE__ASSIGNED_STRING_TYPE)
56     };
57     private static final FlagsData[] SECURE_SETTINGS = new FlagsData[]{
58             new FlagsData("SecureFeature__boolean_whitelist",
59                     SETTING_SNAPSHOT__TYPE__ASSIGNED_BOOL_TYPE),
60             new FlagsData("SecureFeature__integer_whitelist",
61                     SETTING_SNAPSHOT__TYPE__ASSIGNED_INT_TYPE),
62             new FlagsData("SecureFeature__float_whitelist",
63                     SETTING_SNAPSHOT__TYPE__ASSIGNED_FLOAT_TYPE),
64             new FlagsData("SecureFeature__string_whitelist",
65                     SETTING_SNAPSHOT__TYPE__ASSIGNED_STRING_TYPE)
66     };
67     private static final FlagsData[] SYSTEM_SETTINGS = new FlagsData[]{
68             new FlagsData("SystemFeature__boolean_whitelist",
69                     SETTING_SNAPSHOT__TYPE__ASSIGNED_BOOL_TYPE),
70             new FlagsData("SystemFeature__integer_whitelist",
71                     SETTING_SNAPSHOT__TYPE__ASSIGNED_INT_TYPE),
72             new FlagsData("SystemFeature__float_whitelist",
73                     SETTING_SNAPSHOT__TYPE__ASSIGNED_FLOAT_TYPE),
74             new FlagsData("SystemFeature__string_whitelist",
75                     SETTING_SNAPSHOT__TYPE__ASSIGNED_STRING_TYPE)
76     };
77 
78     @VisibleForTesting
79     @NonNull
logGlobalSettings(Context context, int atomTag, int userId)80     static List<StatsEvent> logGlobalSettings(Context context, int atomTag, int userId) {
81         final List<StatsEvent> output = new ArrayList<>();
82         final ContentResolver resolver = context.getContentResolver();
83 
84         for (FlagsData flagsData : GLOBAL_SETTINGS) {
85             StringListParamProto proto = getList(flagsData.mFlagName);
86             if (proto == null) {
87                 continue;
88             }
89             for (String key : proto.element) {
90                 final String value = Settings.Global.getStringForUser(resolver, key, userId);
91                 output.add(createStatsEvent(atomTag, key, value, userId,
92                         flagsData.mDataType));
93             }
94         }
95         return output;
96     }
97 
98     @NonNull
logSystemSettings(Context context, int atomTag, int userId)99     static List<StatsEvent> logSystemSettings(Context context, int atomTag, int userId) {
100         final List<StatsEvent> output = new ArrayList<>();
101         final ContentResolver resolver = context.getContentResolver();
102 
103         for (FlagsData flagsData : SYSTEM_SETTINGS) {
104             StringListParamProto proto = getList(flagsData.mFlagName);
105             if (proto == null) {
106                 continue;
107             }
108             for (String key : proto.element) {
109                 final String value = Settings.System.getStringForUser(resolver, key, userId);
110                 final String telemetryValue = RawSettingsTelemetryUtils
111                         .getTelemetrySettingFromRawVal(context, key, value);
112                 output.add(createStatsEvent(atomTag, key, telemetryValue, userId,
113                         flagsData.mDataType));
114             }
115         }
116         return output;
117     }
118 
119     @NonNull
logSecureSettings(Context context, int atomTag, int userId)120     static List<StatsEvent> logSecureSettings(Context context, int atomTag, int userId) {
121         final List<StatsEvent> output = new ArrayList<>();
122         final ContentResolver resolver = context.getContentResolver();
123 
124         for (FlagsData flagsData : SECURE_SETTINGS) {
125             StringListParamProto proto = getList(flagsData.mFlagName);
126             if (proto == null) {
127                 continue;
128             }
129             for (String key : proto.element) {
130                 final String value = Settings.Secure.getStringForUser(resolver, key, userId);
131                 output.add(createStatsEvent(atomTag, key, value, userId,
132                         flagsData.mDataType));
133             }
134         }
135         return output;
136     }
137 
138     @VisibleForTesting
139     @Nullable
getList(String flag)140     static StringListParamProto getList(String flag) {
141         final String base64 = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, flag);
142         if (TextUtils.isEmpty(base64)) {
143             return null;
144         }
145         final byte[] decode = Base64.decode(base64, Base64.NO_PADDING | Base64.NO_WRAP);
146         StringListParamProto list = null;
147         try {
148             list = StringListParamProto.parseFrom(decode);
149         } catch (Exception e) {
150             Slog.e(TAG, "Error parsing string list proto", e);
151         }
152         return list;
153     }
154 
155     /**
156      * Create {@link StatsEvent} for SETTING_SNAPSHOT atom
157      */
158     @NonNull
createStatsEvent(int atomTag, String key, String value, int userId, int type)159     private static StatsEvent createStatsEvent(int atomTag, String key, String value, int userId,
160             int type) {
161         final StatsEvent.Builder builder = StatsEvent.newBuilder()
162                 .setAtomId(atomTag)
163                 .writeString(key);
164         boolean booleanValue = false;
165         int intValue = 0;
166         float floatValue = 0;
167         String stringValue = "";
168         if (TextUtils.isEmpty(value)) {
169             builder.writeInt(FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__NOTASSIGNED)
170                     .writeBoolean(booleanValue)
171                     .writeInt(intValue)
172                     .writeFloat(floatValue)
173                     .writeString(stringValue)
174                     .writeInt(userId);
175         } else {
176             switch (type) {
177                 case SETTING_SNAPSHOT__TYPE__ASSIGNED_BOOL_TYPE:
178                     booleanValue = "1".equals(value);
179                     break;
180                 case FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_INT_TYPE:
181                     try {
182                         intValue = Integer.parseInt(value);
183                     } catch (NumberFormatException e) {
184                         Slog.w(TAG, "Can not parse value to float: " + value);
185                     }
186                     break;
187                 case SETTING_SNAPSHOT__TYPE__ASSIGNED_FLOAT_TYPE:
188                     try {
189                         floatValue = Float.parseFloat(value);
190                     } catch (NumberFormatException e) {
191                         Slog.w(TAG, "Can not parse value to float: " + value);
192                     }
193                     break;
194                 case FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_STRING_TYPE:
195                     stringValue = value;
196                     break;
197                 default:
198                     Slog.w(TAG, "Unexpected value type " + type);
199             }
200             builder.writeInt(type)
201                     .writeBoolean(booleanValue)
202                     .writeInt(intValue)
203                     .writeFloat(floatValue)
204                     .writeString(stringValue)
205                     .writeInt(userId);
206         }
207         return builder.build();
208     }
209 
210     /** Class for defining flag name and its data type. */
211     static final class FlagsData {
212         /** {@link DeviceConfig} flag name, value of the flag is {@link StringListParamProto} */
213         String mFlagName;
214         /** Data type of the value getting from {@link Settings} keys. */
215         int mDataType;
216 
FlagsData(String flagName, int dataType)217         FlagsData(String flagName, int dataType) {
218             mFlagName = flagName;
219             mDataType = dataType;
220         }
221     }
222 }
223