1 /*
2  * Copyright (C) 2023 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.safetycenter.logging;
18 
19 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED;
20 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__ACTION__ISSUE_PRIMARY_ACTION_CLICKED;
21 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__ACTION__ISSUE_SECONDARY_ACTION_CLICKED;
22 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__ACTION__NOTIFICATION_DISMISSED;
23 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__ACTION__NOTIFICATION_POSTED;
24 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__ISSUE_STATE__ACTIVE;
25 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__NAVIGATION_SOURCE__SOURCE_UNKNOWN;
26 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_MANAGED;
27 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_PERSONAL;
28 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_PRIVATE;
29 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_UNKNOWN;
30 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SENSOR__SENSOR_UNKNOWN;
31 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_CRITICAL_WARNING;
32 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_OK;
33 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_RECOMMENDATION;
34 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_UNSPECIFIED;
35 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__VIEW_TYPE__VIEW_TYPE_NOTIFICATION;
36 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED;
37 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__COMPLETE_GET_NEW_DATA;
38 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__COMPLETE_RESCAN;
39 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_UNKNOWN;
40 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__INLINE_ACTION;
41 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__SINGLE_SOURCE_GET_NEW_DATA;
42 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__SINGLE_SOURCE_RESCAN;
43 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__ERROR;
44 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__SUCCESS;
45 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__TIMEOUT;
46 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_MANAGED;
47 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_PERSONAL;
48 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_PRIVATE;
49 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_UNKNOWN;
50 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED;
51 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__COLLECTION_TYPE__AUTOMATIC;
52 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__COLLECTION_TYPE__SOURCE_UPDATED;
53 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_MANAGED;
54 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_PERSONAL;
55 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_PRIVATE;
56 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_UNKNOWN;
57 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_CRITICAL_WARNING;
58 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_LEVEL_UNKNOWN;
59 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_OK;
60 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_RECOMMENDATION;
61 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_UNSPECIFIED;
62 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__DATA_PROVIDED;
63 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__NO_DATA_PROVIDED;
64 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__REFRESH_ERROR;
65 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__REFRESH_TIMEOUT;
66 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__SOURCE_CLEARED;
67 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__SOURCE_ERROR;
68 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__SOURCE_STATE_UNKNOWN;
69 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__UPDATE_TYPE__REFRESH_RESPONSE;
70 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__UPDATE_TYPE__SELF_INITIATED;
71 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__UPDATE_TYPE__UPDATE_TYPE_UNKNOWN;
72 import static com.android.permission.PermissionStatsLog.SAFETY_STATE;
73 import static com.android.permission.PermissionStatsLog.SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_CRITICAL_WARNING;
74 import static com.android.permission.PermissionStatsLog.SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_LEVEL_UNKNOWN;
75 import static com.android.permission.PermissionStatsLog.SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_OK;
76 import static com.android.permission.PermissionStatsLog.SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_RECOMMENDATION;
77 import static com.android.safetycenter.UserProfileGroup.PROFILE_TYPE_MANAGED;
78 import static com.android.safetycenter.UserProfileGroup.PROFILE_TYPE_PRIMARY;
79 import static com.android.safetycenter.UserProfileGroup.PROFILE_TYPE_PRIVATE;
80 
81 import android.annotation.ElapsedRealtimeLong;
82 import android.annotation.IntDef;
83 import android.safetycenter.SafetyCenterManager;
84 import android.safetycenter.SafetyCenterManager.RefreshRequestType;
85 import android.safetycenter.SafetyCenterStatus;
86 import android.safetycenter.SafetyEvent;
87 import android.safetycenter.SafetySourceData;
88 import android.util.Log;
89 import android.util.StatsEvent;
90 
91 import androidx.annotation.Nullable;
92 
93 import com.android.permission.PermissionStatsLog;
94 import com.android.safetycenter.SafetyCenterFlags;
95 import com.android.safetycenter.UserProfileGroup.ProfileType;
96 
97 import java.lang.annotation.Retention;
98 import java.lang.annotation.RetentionPolicy;
99 import java.math.BigInteger;
100 import java.security.MessageDigest;
101 import java.security.NoSuchAlgorithmException;
102 import java.time.Duration;
103 
104 /**
105  * Marshalls and writes statsd atoms. Contains implementation details of how atom parameters are
106  * encoded and provides a better-typed interface for other classes to call.
107  *
108  * @hide
109  */
110 public final class SafetyCenterStatsdLogger {
111 
112     private static final String TAG = "SafetyCenterStatsdLog";
113     private static final long UNSET_SOURCE_ID = 0;
114     private static final long UNSET_ISSUE_TYPE_ID = 0;
115     private static final long UNSET_SESSION_ID = 0;
116     private static final long UNSET_SOURCE_GROUP_ID = 0;
117     private static final long UNSET_REFRESH_REASON = 0L;
118     private static final boolean UNSET_DATA_CHANGED = false;
119     private static final long UNSET_LAST_UPDATED_ELAPSED_TIME_MILLIS = 0L;
120 
121     /**
122      * The different results for a system event reported by Safety Center.
123      *
124      * @hide
125      */
126     @IntDef(
127             prefix = {"SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__"},
128             value = {
129                 SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__SUCCESS,
130                 SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__ERROR,
131                 SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__TIMEOUT
132             })
133     @Retention(RetentionPolicy.SOURCE)
134     public @interface SystemEventResult {}
135 
136     /**
137      * The different results for a system event reported by Safety Center.
138      *
139      * @hide
140      */
141     @IntDef(
142             prefix = {"SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__"},
143             value = {
144                 SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__SOURCE_STATE_UNKNOWN,
145                 SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__DATA_PROVIDED,
146                 SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__NO_DATA_PROVIDED,
147                 SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__REFRESH_TIMEOUT,
148                 SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__REFRESH_ERROR,
149                 SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__SOURCE_ERROR,
150                 SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__SOURCE_CLEARED
151             })
152     @Retention(RetentionPolicy.SOURCE)
153     public @interface SourceState {}
154 
155     /**
156      * Creates a {@link PermissionStatsLog#SAFETY_STATE} {@link StatsEvent} with the given
157      * parameters.
158      */
createSafetyStateEvent( @afetyCenterStatus.OverallSeverityLevel int severityLevel, long openIssueCount, long dismissedIssueCount)159     static StatsEvent createSafetyStateEvent(
160             @SafetyCenterStatus.OverallSeverityLevel int severityLevel,
161             long openIssueCount,
162             long dismissedIssueCount) {
163         return PermissionStatsLog.buildStatsEvent(
164                 SAFETY_STATE,
165                 toSafetyStateOverallSeverityLevel(severityLevel),
166                 openIssueCount,
167                 dismissedIssueCount);
168     }
169 
170     /** Writes a {@link PermissionStatsLog#SAFETY_SOURCE_STATE_COLLECTED} atom. */
writeSafetySourceStateCollected( String sourceId, @ProfileType int profileType, @Nullable @SafetySourceData.SeverityLevel Integer sourceSeverityLevel, long openIssuesCount, long dismissedIssuesCount, long duplicateFilteredOutIssuesCount, @SourceState int sourceState, @Nullable SafetyEvent safetyEvent, @Nullable @SafetyCenterManager.RefreshReason Integer refreshReason, boolean dataChanged, @Nullable @ElapsedRealtimeLong Long lastUpdatedElapsedTimeMillis)171     public static void writeSafetySourceStateCollected(
172             String sourceId,
173             @ProfileType int profileType,
174             @Nullable @SafetySourceData.SeverityLevel Integer sourceSeverityLevel,
175             long openIssuesCount,
176             long dismissedIssuesCount,
177             long duplicateFilteredOutIssuesCount,
178             @SourceState int sourceState,
179             @Nullable SafetyEvent safetyEvent,
180             @Nullable @SafetyCenterManager.RefreshReason Integer refreshReason,
181             boolean dataChanged,
182             @Nullable @ElapsedRealtimeLong Long lastUpdatedElapsedTimeMillis) {
183         if (!SafetyCenterFlags.getAllowStatsdLogging()) {
184             return;
185         }
186         int collectionType =
187                 safetyEvent != null
188                         ? SAFETY_SOURCE_STATE_COLLECTED__COLLECTION_TYPE__SOURCE_UPDATED
189                         : SAFETY_SOURCE_STATE_COLLECTED__COLLECTION_TYPE__AUTOMATIC;
190         PermissionStatsLog.write(
191                 SAFETY_SOURCE_STATE_COLLECTED,
192                 idStringToLong(sourceId),
193                 toSourceStateCollectedProfileType(profileType),
194                 toSafetySourceStateCollectedSeverityLevel(sourceSeverityLevel),
195                 openIssuesCount,
196                 dismissedIssuesCount,
197                 duplicateFilteredOutIssuesCount,
198                 sourceState,
199                 collectionType,
200                 toSafetySourceStateCollectedCollectionType(safetyEvent),
201                 refreshReason != null ? refreshReason : UNSET_REFRESH_REASON,
202                 dataChanged,
203                 lastUpdatedElapsedTimeMillis != null
204                         ? lastUpdatedElapsedTimeMillis
205                         : UNSET_LAST_UPDATED_ELAPSED_TIME_MILLIS);
206     }
207 
208     /**
209      * Writes a {@link PermissionStatsLog#SAFETY_CENTER_SYSTEM_EVENT_REPORTED} atom of type {@code
210      * SINGLE_SOURCE_RESCAN} or {@code SINGLE_SOURCE_GET_DATA}.
211      */
writeSourceRefreshSystemEvent( @efreshRequestType int refreshType, String sourceId, @ProfileType int profileType, Duration duration, @SystemEventResult int result, long refreshReason, boolean dataChanged)212     public static void writeSourceRefreshSystemEvent(
213             @RefreshRequestType int refreshType,
214             String sourceId,
215             @ProfileType int profileType,
216             Duration duration,
217             @SystemEventResult int result,
218             long refreshReason,
219             boolean dataChanged) {
220         if (!SafetyCenterFlags.getAllowStatsdLogging()) {
221             return;
222         }
223         PermissionStatsLog.write(
224                 SAFETY_CENTER_SYSTEM_EVENT_REPORTED,
225                 toSourceRefreshEventType(refreshType),
226                 idStringToLong(sourceId),
227                 toSystemEventProfileType(profileType),
228                 UNSET_ISSUE_TYPE_ID,
229                 duration.toMillis(),
230                 result,
231                 refreshReason,
232                 dataChanged);
233     }
234 
235     /**
236      * Writes a {@link PermissionStatsLog#SAFETY_CENTER_SYSTEM_EVENT_REPORTED} atom of type {@code
237      * COMPLETE_RESCAN} or {@code COMPLETE_GET_DATA}.
238      */
writeWholeRefreshSystemEvent( @efreshRequestType int refreshType, Duration duration, @SystemEventResult int result, long refreshReason, boolean dataChanged)239     public static void writeWholeRefreshSystemEvent(
240             @RefreshRequestType int refreshType,
241             Duration duration,
242             @SystemEventResult int result,
243             long refreshReason,
244             boolean dataChanged) {
245         if (!SafetyCenterFlags.getAllowStatsdLogging()) {
246             return;
247         }
248         PermissionStatsLog.write(
249                 SAFETY_CENTER_SYSTEM_EVENT_REPORTED,
250                 toWholeRefreshEventType(refreshType),
251                 UNSET_SOURCE_ID,
252                 SAFETY_CENTER_SYSTEM_EVENT_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_UNKNOWN,
253                 UNSET_ISSUE_TYPE_ID,
254                 duration.toMillis(),
255                 result,
256                 refreshReason,
257                 dataChanged);
258     }
259 
260     /**
261      * Writes a {@link PermissionStatsLog#SAFETY_CENTER_SYSTEM_EVENT_REPORTED} atom of type {@code
262      * INLINE_ACTION}.
263      */
writeInlineActionSystemEvent( String sourceId, @ProfileType int profileType, @Nullable String issueTypeId, Duration duration, @SystemEventResult int result)264     public static void writeInlineActionSystemEvent(
265             String sourceId,
266             @ProfileType int profileType,
267             @Nullable String issueTypeId,
268             Duration duration,
269             @SystemEventResult int result) {
270         if (!SafetyCenterFlags.getAllowStatsdLogging()) {
271             return;
272         }
273         PermissionStatsLog.write(
274                 SAFETY_CENTER_SYSTEM_EVENT_REPORTED,
275                 SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__INLINE_ACTION,
276                 idStringToLong(sourceId),
277                 toSystemEventProfileType(profileType),
278                 issueTypeId == null ? UNSET_ISSUE_TYPE_ID : idStringToLong(issueTypeId),
279                 duration.toMillis(),
280                 result,
281                 UNSET_REFRESH_REASON,
282                 UNSET_DATA_CHANGED);
283     }
284 
285     /**
286      * Writes a {@link PermissionStatsLog#SAFETY_CENTER_INTERACTION_REPORTED} atom with the action
287      * {@code NOTIFICATION_POSTED}.
288      */
writeNotificationPostedEvent( String sourceId, @ProfileType int profileType, String issueTypeId, @SafetySourceData.SeverityLevel int sourceSeverityLevel)289     public static void writeNotificationPostedEvent(
290             String sourceId,
291             @ProfileType int profileType,
292             String issueTypeId,
293             @SafetySourceData.SeverityLevel int sourceSeverityLevel) {
294         writeNotificationInteractionReportedEvent(
295                 SAFETY_CENTER_INTERACTION_REPORTED__ACTION__NOTIFICATION_POSTED,
296                 sourceId,
297                 profileType,
298                 issueTypeId,
299                 sourceSeverityLevel);
300     }
301 
302     /**
303      * Writes a {@link PermissionStatsLog#SAFETY_CENTER_INTERACTION_REPORTED} atom with the action
304      * {@code NOTIFICATION_DISMISSED}.
305      */
writeNotificationDismissedEvent( String sourceId, @ProfileType int profileType, String issueTypeId, @SafetySourceData.SeverityLevel int sourceSeverityLevel)306     public static void writeNotificationDismissedEvent(
307             String sourceId,
308             @ProfileType int profileType,
309             String issueTypeId,
310             @SafetySourceData.SeverityLevel int sourceSeverityLevel) {
311         writeNotificationInteractionReportedEvent(
312                 SAFETY_CENTER_INTERACTION_REPORTED__ACTION__NOTIFICATION_DISMISSED,
313                 sourceId,
314                 profileType,
315                 issueTypeId,
316                 sourceSeverityLevel);
317     }
318 
319     /**
320      * Writes a {@link PermissionStatsLog#SAFETY_CENTER_INTERACTION_REPORTED} atom with the action
321      * {@code ISSUE_PRIMARY_ACTION_CLICKED} or {@code ISSUE_SECONDARY_ACTION_CLICKED}.
322      */
writeNotificationActionClickedEvent( String sourceId, @ProfileType int profileType, String issueTypeId, @SafetySourceData.SeverityLevel int sourceSeverityLevel, boolean isPrimaryAction)323     public static void writeNotificationActionClickedEvent(
324             String sourceId,
325             @ProfileType int profileType,
326             String issueTypeId,
327             @SafetySourceData.SeverityLevel int sourceSeverityLevel,
328             boolean isPrimaryAction) {
329         int action =
330                 isPrimaryAction
331                         ? SAFETY_CENTER_INTERACTION_REPORTED__ACTION__ISSUE_PRIMARY_ACTION_CLICKED
332                         : SAFETY_CENTER_INTERACTION_REPORTED__ACTION__ISSUE_SECONDARY_ACTION_CLICKED;
333         writeNotificationInteractionReportedEvent(
334                 action, sourceId, profileType, issueTypeId, sourceSeverityLevel);
335     }
336 
writeNotificationInteractionReportedEvent( int interactionReportedAction, String sourceId, @ProfileType int profileType, String issueTypeId, @SafetySourceData.SeverityLevel int sourceSeverityLevel)337     private static void writeNotificationInteractionReportedEvent(
338             int interactionReportedAction,
339             String sourceId,
340             @ProfileType int profileType,
341             String issueTypeId,
342             @SafetySourceData.SeverityLevel int sourceSeverityLevel) {
343         if (!SafetyCenterFlags.getAllowStatsdLogging()) {
344             return;
345         }
346         PermissionStatsLog.write(
347                 SAFETY_CENTER_INTERACTION_REPORTED,
348                 UNSET_SESSION_ID,
349                 interactionReportedAction,
350                 SAFETY_CENTER_INTERACTION_REPORTED__VIEW_TYPE__VIEW_TYPE_NOTIFICATION,
351                 SAFETY_CENTER_INTERACTION_REPORTED__NAVIGATION_SOURCE__SOURCE_UNKNOWN,
352                 toInteractionReportedSeverityLevel(sourceSeverityLevel),
353                 idStringToLong(sourceId),
354                 toInteractionReportedProfileType(profileType),
355                 idStringToLong(issueTypeId),
356                 SAFETY_CENTER_INTERACTION_REPORTED__SENSOR__SENSOR_UNKNOWN,
357                 UNSET_SOURCE_GROUP_ID,
358                 SAFETY_CENTER_INTERACTION_REPORTED__ISSUE_STATE__ACTIVE);
359     }
360 
361     /**
362      * Returns a {@link SystemEventResult} based on whether the given operation was {@code
363      * successful}.
364      */
365     @SystemEventResult
toSystemEventResult(boolean success)366     public static int toSystemEventResult(boolean success) {
367         return success
368                 ? SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__SUCCESS
369                 : SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__ERROR;
370     }
371 
toSourceRefreshEventType(@efreshRequestType int refreshType)372     private static int toSourceRefreshEventType(@RefreshRequestType int refreshType) {
373         switch (refreshType) {
374             case SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_GET_DATA:
375                 return SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__SINGLE_SOURCE_GET_NEW_DATA;
376             case SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA:
377                 return SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__SINGLE_SOURCE_RESCAN;
378         }
379         Log.w(TAG, "Unexpected SafetyCenterManager.RefreshRequestType: " + refreshType);
380         return SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_UNKNOWN;
381     }
382 
toWholeRefreshEventType(@efreshRequestType int refreshType)383     private static int toWholeRefreshEventType(@RefreshRequestType int refreshType) {
384         switch (refreshType) {
385             case SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_GET_DATA:
386                 return SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__COMPLETE_GET_NEW_DATA;
387             case SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA:
388                 return SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__COMPLETE_RESCAN;
389         }
390         Log.w(TAG, "Unexpected SafetyCenterManager.RefreshRequestType: " + refreshType);
391         return SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_UNKNOWN;
392     }
393 
toSourceStateCollectedProfileType(@rofileType int profileType)394     private static int toSourceStateCollectedProfileType(@ProfileType int profileType) {
395         switch (profileType) {
396             case PROFILE_TYPE_PRIMARY:
397                 return SAFETY_SOURCE_STATE_COLLECTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_PERSONAL;
398             case PROFILE_TYPE_MANAGED:
399                 return SAFETY_SOURCE_STATE_COLLECTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_MANAGED;
400             case PROFILE_TYPE_PRIVATE:
401                 return SAFETY_SOURCE_STATE_COLLECTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_PRIVATE;
402         }
403         Log.w(TAG, "state collect arg requested for unknown profile type " + profileType);
404         return SAFETY_SOURCE_STATE_COLLECTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_UNKNOWN;
405     }
406 
toSystemEventProfileType(@rofileType int profileType)407     private static int toSystemEventProfileType(@ProfileType int profileType) {
408         switch (profileType) {
409             case PROFILE_TYPE_PRIMARY:
410                 return SAFETY_CENTER_SYSTEM_EVENT_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_PERSONAL;
411             case PROFILE_TYPE_MANAGED:
412                 return SAFETY_CENTER_SYSTEM_EVENT_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_MANAGED;
413             case PROFILE_TYPE_PRIVATE:
414                 return SAFETY_CENTER_SYSTEM_EVENT_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_PRIVATE;
415         }
416         Log.w(TAG, "system event arg requested for unknown profile type " + profileType);
417         return SAFETY_CENTER_SYSTEM_EVENT_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_UNKNOWN;
418     }
419 
toInteractionReportedProfileType(@rofileType int profileType)420     private static int toInteractionReportedProfileType(@ProfileType int profileType) {
421         switch (profileType) {
422             case PROFILE_TYPE_PRIMARY:
423                 return SAFETY_CENTER_INTERACTION_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_PERSONAL;
424             case PROFILE_TYPE_MANAGED:
425                 return SAFETY_CENTER_INTERACTION_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_MANAGED;
426             case PROFILE_TYPE_PRIVATE:
427                 return SAFETY_CENTER_INTERACTION_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_PRIVATE;
428         }
429         Log.w(TAG, "interaction enum requested for unknown profile type " + profileType);
430         return SAFETY_CENTER_INTERACTION_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_UNKNOWN;
431     }
432 
433     /**
434      * Converts a {@link String} ID (e.g. a Safety Source ID) to a {@code long} suitable for logging
435      * to statsd.
436      */
idStringToLong(String id)437     private static long idStringToLong(String id) {
438         MessageDigest messageDigest;
439         try {
440             messageDigest = MessageDigest.getInstance("MD5");
441         } catch (NoSuchAlgorithmException e) {
442             Log.w(TAG, "Couldn't encode safety source id: " + id, e);
443             return 0;
444         }
445         messageDigest.update(id.getBytes());
446         return new BigInteger(messageDigest.digest()).longValue();
447     }
448 
toSafetyStateOverallSeverityLevel( @afetyCenterStatus.OverallSeverityLevel int severityLevel)449     private static int toSafetyStateOverallSeverityLevel(
450             @SafetyCenterStatus.OverallSeverityLevel int severityLevel) {
451         switch (severityLevel) {
452             case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN:
453                 return SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_LEVEL_UNKNOWN;
454             case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK:
455                 return SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_OK;
456             case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION:
457                 return SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_RECOMMENDATION;
458             case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING:
459                 return SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_CRITICAL_WARNING;
460         }
461         Log.w(TAG, "Unexpected SafetyCenterStatus.OverallSeverityLevel: " + severityLevel);
462         return SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_LEVEL_UNKNOWN;
463     }
464 
toSafetySourceStateCollectedSeverityLevel( @ullable @afetySourceData.SeverityLevel Integer safetySourceSeverityLevel)465     private static int toSafetySourceStateCollectedSeverityLevel(
466             @Nullable @SafetySourceData.SeverityLevel Integer safetySourceSeverityLevel) {
467         if (safetySourceSeverityLevel == null) {
468             return SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_LEVEL_UNKNOWN;
469         }
470         switch (safetySourceSeverityLevel) {
471             case SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED:
472                 return SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_UNSPECIFIED;
473             case SafetySourceData.SEVERITY_LEVEL_INFORMATION:
474                 return SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_OK;
475             case SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION:
476                 return SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_RECOMMENDATION;
477             case SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING:
478                 return SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_CRITICAL_WARNING;
479         }
480         Log.w(TAG, "Unexpected SafetySourceData.SeverityLevel: " + safetySourceSeverityLevel);
481         return SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_LEVEL_UNKNOWN;
482     }
483 
toInteractionReportedSeverityLevel( @afetySourceData.SeverityLevel int severityLevel)484     private static int toInteractionReportedSeverityLevel(
485             @SafetySourceData.SeverityLevel int severityLevel) {
486         switch (severityLevel) {
487             case SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED:
488                 return SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_UNSPECIFIED;
489             case SafetySourceData.SEVERITY_LEVEL_INFORMATION:
490                 return SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_OK;
491             case SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION:
492                 return SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_RECOMMENDATION;
493             case SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING:
494                 return SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_CRITICAL_WARNING;
495         }
496         Log.w(TAG, "Unexpected SafetySourceData.SeverityLevel: " + severityLevel);
497         return SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_LEVEL_UNKNOWN;
498     }
499 
toSafetySourceStateCollectedCollectionType( @ullable SafetyEvent safetyEvent)500     private static int toSafetySourceStateCollectedCollectionType(
501             @Nullable SafetyEvent safetyEvent) {
502         if (safetyEvent == null) {
503             return SAFETY_SOURCE_STATE_COLLECTED__UPDATE_TYPE__UPDATE_TYPE_UNKNOWN;
504         }
505         if (safetyEvent.getType() == SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED) {
506             return SAFETY_SOURCE_STATE_COLLECTED__UPDATE_TYPE__REFRESH_RESPONSE;
507         } else {
508             return SAFETY_SOURCE_STATE_COLLECTED__UPDATE_TYPE__SELF_INITIATED;
509         }
510     }
511 }
512