• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.server.healthconnect.logging;
18 
19 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED;
20 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__API_METHOD__API_METHOD_UNKNOWN;
21 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__API_METHOD__CREATE_MEDICAL_DATA_SOURCE;
22 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__API_METHOD__DELETE_DATA;
23 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__API_METHOD__DELETE_MEDICAL_DATA_SOURCE_WITH_DATA;
24 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__API_METHOD__DELETE_MEDICAL_RESOURCES_BY_IDS;
25 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__API_METHOD__DELETE_MEDICAL_RESOURCES_BY_REQUESTS;
26 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__API_METHOD__GET_CHANGES;
27 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__API_METHOD__GET_CHANGES_TOKEN;
28 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__API_METHOD__GET_GRANTED_PERMISSIONS;
29 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__API_METHOD__GET_MEDICAL_DATA_SOURCES_BY_IDS;
30 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__API_METHOD__GET_MEDICAL_DATA_SOURCES_BY_REQUESTS;
31 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__API_METHOD__INSERT_DATA;
32 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__API_METHOD__READ_AGGREGATED_DATA;
33 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__API_METHOD__READ_DATA;
34 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__API_METHOD__READ_MEDICAL_RESOURCES_BY_IDS;
35 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__API_METHOD__READ_MEDICAL_RESOURCES_BY_REQUESTS;
36 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__API_METHOD__REVOKE_ALL_PERMISSIONS;
37 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__API_METHOD__UPDATE_DATA;
38 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__API_METHOD__UPSERT_MEDICAL_RESOURCES;
39 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__API_STATUS__ERROR;
40 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__API_STATUS__STATUS_UNKNOWN;
41 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__API_STATUS__SUCCESS;
42 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__CALLER_FOREGROUND_STATE__BACKGROUND;
43 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__CALLER_FOREGROUND_STATE__FOREGROUND;
44 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__CALLER_FOREGROUND_STATE__UNSPECIFIED;
45 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__RATE_LIMIT__NOT_DEFINED;
46 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__RATE_LIMIT__NOT_USED;
47 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_BACKGROUND_15_MIN_ABOVE_3000;
48 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_BACKGROUND_15_MIN_BW_1000_TO_2000;
49 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_BACKGROUND_15_MIN_BW_2000_TO_3000;
50 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_BACKGROUND_15_MIN_BW_500_TO_1000;
51 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_BACKGROUND_15_MIN_UNDER_500;
52 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_BACKGROUND_24_HRS_ABOVE_5000;
53 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_BACKGROUND_24_HRS_BW_1000_TO_2000;
54 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_BACKGROUND_24_HRS_BW_2000_TO_3000;
55 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_BACKGROUND_24_HRS_BW_3000_TO_4000;
56 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_BACKGROUND_24_HRS_BW_4000_TO_5000;
57 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_BACKGROUND_24_HRS_UNDER_1000;
58 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_FOREGROUND_15_MIN_ABOVE_4000;
59 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_FOREGROUND_15_MIN_BW_1000_TO_2000;
60 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_FOREGROUND_15_MIN_BW_2000_TO_3000;
61 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_FOREGROUND_15_MIN_BW_3000_TO_4000;
62 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_FOREGROUND_15_MIN_UNDER_1000;
63 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_FOREGROUND_24_HRS_ABOVE_6000;
64 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_FOREGROUND_24_HRS_BW_2000_TO_3000;
65 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_FOREGROUND_24_HRS_BW_3000_TO_4000;
66 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_FOREGROUND_24_HRS_BW_4000_TO_5000;
67 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_FOREGROUND_24_HRS_BW_5000_TO_6000;
68 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_FOREGROUND_24_HRS_UNDER_2000;
69 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED;
70 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__ACTIVE_CALORIES_BURNED;
71 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__BASAL_BODY_TEMPERATURE;
72 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__BASAL_METABOLIC_RATE;
73 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__BLOOD_GLUCOSE;
74 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__BLOOD_PRESSURE;
75 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__BODY_FAT;
76 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__BODY_TEMPERATURE;
77 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__BODY_WATER_MASS;
78 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__BONE_MASS;
79 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__CERVICAL_MUCUS;
80 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__CYCLING_PEDALING_CADENCE;
81 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__DATA_TYPE_NOT_ASSIGNED;
82 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__DATA_TYPE_UNKNOWN;
83 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__DISTANCE;
84 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__ELEVATION_GAINED;
85 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__EXERCISE_SESSION;
86 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__FLOORS_CLIMBED;
87 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__HEART_RATE;
88 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__HEART_RATE_VARIABILITY_RMSSD;
89 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__HEIGHT;
90 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__HYDRATION;
91 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__INTERMENSTRUAL_BLEEDING;
92 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__LEAN_BODY_MASS;
93 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__MENSTRUATION_FLOW;
94 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__MENSTRUATION_PERIOD;
95 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__MINDFULNESS_SESSION;
96 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__NUTRITION;
97 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__OVULATION_TEST;
98 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__OXYGEN_SATURATION;
99 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__PLANNED_EXERCISE_SESSION;
100 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__POWER;
101 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__RESPIRATORY_RATE;
102 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__RESTING_HEART_RATE;
103 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__SEXUAL_ACTIVITY;
104 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__SKIN_TEMPERATURE;
105 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__SLEEP_SESSION;
106 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__SPEED;
107 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__STEPS;
108 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__STEPS_CADENCE;
109 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__TOTAL_CALORIES_BURNED;
110 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__VO2_MAX;
111 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__WEIGHT;
112 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__WHEELCHAIR_PUSHES;
113 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_PHR_API_INVOKED;
114 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES;
115 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_CONDITIONS;
116 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_LABORATORY_RESULTS;
117 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_MEDICATIONS;
118 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_PERSONAL_DETAILS;
119 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_PRACTITIONER_DETAILS;
120 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_PREGNANCY;
121 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_PROCEDURES;
122 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_SOCIAL_HISTORY;
123 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_UNKNOWN;
124 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_VACCINES;
125 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_VISITS;
126 import static android.health.HealthFitnessStatsLog.HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_VITAL_SIGNS;
127 import static android.health.connect.datatypes.MedicalResource.MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES;
128 import static android.health.connect.datatypes.MedicalResource.MEDICAL_RESOURCE_TYPE_CONDITIONS;
129 import static android.health.connect.datatypes.MedicalResource.MEDICAL_RESOURCE_TYPE_LABORATORY_RESULTS;
130 import static android.health.connect.datatypes.MedicalResource.MEDICAL_RESOURCE_TYPE_MEDICATIONS;
131 import static android.health.connect.datatypes.MedicalResource.MEDICAL_RESOURCE_TYPE_PERSONAL_DETAILS;
132 import static android.health.connect.datatypes.MedicalResource.MEDICAL_RESOURCE_TYPE_PRACTITIONER_DETAILS;
133 import static android.health.connect.datatypes.MedicalResource.MEDICAL_RESOURCE_TYPE_PREGNANCY;
134 import static android.health.connect.datatypes.MedicalResource.MEDICAL_RESOURCE_TYPE_PROCEDURES;
135 import static android.health.connect.datatypes.MedicalResource.MEDICAL_RESOURCE_TYPE_SOCIAL_HISTORY;
136 import static android.health.connect.datatypes.MedicalResource.MEDICAL_RESOURCE_TYPE_VACCINES;
137 import static android.health.connect.datatypes.MedicalResource.MEDICAL_RESOURCE_TYPE_VISITS;
138 import static android.health.connect.datatypes.MedicalResource.MEDICAL_RESOURCE_TYPE_VITAL_SIGNS;
139 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_ACTIVE_CALORIES_BURNED;
140 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_BASAL_BODY_TEMPERATURE;
141 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_BASAL_METABOLIC_RATE;
142 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_BLOOD_GLUCOSE;
143 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_BLOOD_PRESSURE;
144 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_BODY_FAT;
145 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_BODY_TEMPERATURE;
146 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_BODY_WATER_MASS;
147 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_BONE_MASS;
148 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_CERVICAL_MUCUS;
149 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_CYCLING_PEDALING_CADENCE;
150 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_DISTANCE;
151 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_ELEVATION_GAINED;
152 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_EXERCISE_SESSION;
153 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_FLOORS_CLIMBED;
154 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_HEART_RATE;
155 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_HEART_RATE_VARIABILITY_RMSSD;
156 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_HEIGHT;
157 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_HYDRATION;
158 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_INTERMENSTRUAL_BLEEDING;
159 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_LEAN_BODY_MASS;
160 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_MENSTRUATION_FLOW;
161 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_MENSTRUATION_PERIOD;
162 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_MINDFULNESS_SESSION;
163 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_NUTRITION;
164 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_OVULATION_TEST;
165 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_OXYGEN_SATURATION;
166 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_PLANNED_EXERCISE_SESSION;
167 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_POWER;
168 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_RESPIRATORY_RATE;
169 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_RESTING_HEART_RATE;
170 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_SEXUAL_ACTIVITY;
171 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_SKIN_TEMPERATURE;
172 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_SLEEP_SESSION;
173 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_SPEED;
174 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_STEPS;
175 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_STEPS_CADENCE;
176 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_TOTAL_CALORIES_BURNED;
177 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_UNKNOWN;
178 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_VO2_MAX;
179 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_WEIGHT;
180 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_WHEELCHAIR_PUSHES;
181 import static android.health.connect.ratelimiter.RateLimiter.QuotaBucket.QUOTA_BUCKET_READS_PER_15M_BACKGROUND;
182 import static android.health.connect.ratelimiter.RateLimiter.QuotaBucket.QUOTA_BUCKET_READS_PER_15M_FOREGROUND;
183 import static android.health.connect.ratelimiter.RateLimiter.QuotaBucket.QUOTA_BUCKET_READS_PER_24H_BACKGROUND;
184 import static android.health.connect.ratelimiter.RateLimiter.QuotaBucket.QUOTA_BUCKET_READS_PER_24H_FOREGROUND;
185 import static android.health.connect.ratelimiter.RateLimiter.QuotaBucket.QUOTA_BUCKET_WRITES_PER_15M_BACKGROUND;
186 import static android.health.connect.ratelimiter.RateLimiter.QuotaBucket.QUOTA_BUCKET_WRITES_PER_15M_FOREGROUND;
187 import static android.health.connect.ratelimiter.RateLimiter.QuotaBucket.QUOTA_BUCKET_WRITES_PER_24H_BACKGROUND;
188 import static android.health.connect.ratelimiter.RateLimiter.QuotaBucket.QUOTA_BUCKET_WRITES_PER_24H_FOREGROUND;
189 
190 import static com.android.healthfitness.flags.Flags.personalHealthRecordTelemetry;
191 import static com.android.healthfitness.flags.Flags.personalHealthRecordTelemetryPrivateWw;
192 import static com.android.server.healthconnect.logging.HealthConnectServiceLogger.ApiMethods.CREATE_MEDICAL_DATA_SOURCE;
193 import static com.android.server.healthconnect.logging.HealthConnectServiceLogger.ApiMethods.DELETE_MEDICAL_DATA_SOURCE_WITH_DATA;
194 import static com.android.server.healthconnect.logging.HealthConnectServiceLogger.ApiMethods.DELETE_MEDICAL_RESOURCES_BY_IDS;
195 import static com.android.server.healthconnect.logging.HealthConnectServiceLogger.ApiMethods.DELETE_MEDICAL_RESOURCES_BY_REQUESTS;
196 import static com.android.server.healthconnect.logging.HealthConnectServiceLogger.ApiMethods.GET_MEDICAL_DATA_SOURCES_BY_IDS;
197 import static com.android.server.healthconnect.logging.HealthConnectServiceLogger.ApiMethods.GET_MEDICAL_DATA_SOURCES_BY_REQUESTS;
198 import static com.android.server.healthconnect.logging.HealthConnectServiceLogger.ApiMethods.READ_MEDICAL_RESOURCES_BY_IDS;
199 import static com.android.server.healthconnect.logging.HealthConnectServiceLogger.ApiMethods.READ_MEDICAL_RESOURCES_BY_REQUESTS;
200 import static com.android.server.healthconnect.logging.HealthConnectServiceLogger.ApiMethods.UPSERT_MEDICAL_RESOURCES;
201 
202 import android.annotation.IntDef;
203 import android.health.HealthFitnessStatsLog;
204 import android.health.connect.datatypes.MedicalResource;
205 import android.health.connect.internal.datatypes.RecordInternal;
206 import android.health.connect.ratelimiter.RateLimiter;
207 
208 import com.android.internal.annotations.VisibleForTesting;
209 import com.android.server.healthconnect.storage.utils.InternalHealthConnectMappings;
210 
211 import java.lang.annotation.Retention;
212 import java.lang.annotation.RetentionPolicy;
213 import java.util.ArrayList;
214 import java.util.Arrays;
215 import java.util.HashMap;
216 import java.util.HashSet;
217 import java.util.List;
218 import java.util.Map;
219 import java.util.Map.Entry;
220 import java.util.Objects;
221 import java.util.Set;
222 
223 /**
224  * Class to log metrics from HealthConnectService
225  *
226  * @hide
227  */
228 public class HealthConnectServiceLogger {
229 
230     private final HealthFitnessStatsLog mStatsLog;
231     private final int mHealthDataServiceApiMethod;
232     private final int mHealthDataServiceApiStatus;
233     private final int mErrorCode;
234     private final long mDuration;
235     private final boolean mHoldsDataManagementPermission;
236     private final int mRateLimit;
237     private final int mNumberOfRecords;
238     private final int[] mRecordTypes;
239     private Set<Integer> mMedicalResourceTypes;
240     private final String mPackageName;
241     private final int mCallerForegroundState;
242     private static final int MAX_NUMBER_OF_LOGGED_DATA_TYPES = 6;
243     private static final int RECORD_TYPE_NOT_ASSIGNED_DEFAULT_VALUE = -1;
244 
245     @VisibleForTesting
246     public static final int MEDICAL_RESOURCE_TYPE_NOT_ASSIGNED_DEFAULT_VALUE = -1;
247 
248     /**
249      * HealthConnectService ApiMethods supported by logging.
250      *
251      * @hide
252      */
253     public static final class ApiMethods {
254 
255         public static final int API_METHOD_UNKNOWN =
256                 HEALTH_CONNECT_API_CALLED__API_METHOD__API_METHOD_UNKNOWN;
257         public static final int DELETE_DATA = HEALTH_CONNECT_API_CALLED__API_METHOD__DELETE_DATA;
258         public static final int GET_CHANGES = HEALTH_CONNECT_API_CALLED__API_METHOD__GET_CHANGES;
259         public static final int GET_CHANGES_TOKEN =
260                 HEALTH_CONNECT_API_CALLED__API_METHOD__GET_CHANGES_TOKEN;
261         public static final int GET_GRANTED_PERMISSIONS =
262                 HEALTH_CONNECT_API_CALLED__API_METHOD__GET_GRANTED_PERMISSIONS;
263         public static final int INSERT_DATA = HEALTH_CONNECT_API_CALLED__API_METHOD__INSERT_DATA;
264         public static final int READ_AGGREGATED_DATA =
265                 HEALTH_CONNECT_API_CALLED__API_METHOD__READ_AGGREGATED_DATA;
266         public static final int READ_DATA = HEALTH_CONNECT_API_CALLED__API_METHOD__READ_DATA;
267         public static final int REVOKE_ALL_PERMISSIONS =
268                 HEALTH_CONNECT_API_CALLED__API_METHOD__REVOKE_ALL_PERMISSIONS;
269         public static final int UPDATE_DATA = HEALTH_CONNECT_API_CALLED__API_METHOD__UPDATE_DATA;
270         // PHR data source APIs
271         public static final int CREATE_MEDICAL_DATA_SOURCE =
272                 HEALTH_CONNECT_API_CALLED__API_METHOD__CREATE_MEDICAL_DATA_SOURCE;
273         public static final int GET_MEDICAL_DATA_SOURCES_BY_IDS =
274                 HEALTH_CONNECT_API_CALLED__API_METHOD__GET_MEDICAL_DATA_SOURCES_BY_IDS;
275         public static final int GET_MEDICAL_DATA_SOURCES_BY_REQUESTS =
276                 HEALTH_CONNECT_API_CALLED__API_METHOD__GET_MEDICAL_DATA_SOURCES_BY_REQUESTS;
277         public static final int DELETE_MEDICAL_DATA_SOURCE_WITH_DATA =
278                 HEALTH_CONNECT_API_CALLED__API_METHOD__DELETE_MEDICAL_DATA_SOURCE_WITH_DATA;
279         // PHR medical resource APIs
280         public static final int UPSERT_MEDICAL_RESOURCES =
281                 HEALTH_CONNECT_API_CALLED__API_METHOD__UPSERT_MEDICAL_RESOURCES;
282         public static final int READ_MEDICAL_RESOURCES_BY_IDS =
283                 HEALTH_CONNECT_API_CALLED__API_METHOD__READ_MEDICAL_RESOURCES_BY_IDS;
284         public static final int READ_MEDICAL_RESOURCES_BY_REQUESTS =
285                 HEALTH_CONNECT_API_CALLED__API_METHOD__READ_MEDICAL_RESOURCES_BY_REQUESTS;
286         public static final int DELETE_MEDICAL_RESOURCES_BY_IDS =
287                 HEALTH_CONNECT_API_CALLED__API_METHOD__DELETE_MEDICAL_RESOURCES_BY_IDS;
288         public static final int DELETE_MEDICAL_RESOURCES_BY_REQUESTS =
289                 HEALTH_CONNECT_API_CALLED__API_METHOD__DELETE_MEDICAL_RESOURCES_BY_REQUESTS;
290 
291         @IntDef({
292             API_METHOD_UNKNOWN,
293             DELETE_DATA,
294             GET_CHANGES,
295             GET_CHANGES_TOKEN,
296             GET_GRANTED_PERMISSIONS,
297             INSERT_DATA,
298             READ_AGGREGATED_DATA,
299             READ_DATA,
300             REVOKE_ALL_PERMISSIONS,
301             UPDATE_DATA,
302             // PHR data source APIs
303             CREATE_MEDICAL_DATA_SOURCE,
304             GET_MEDICAL_DATA_SOURCES_BY_IDS,
305             GET_MEDICAL_DATA_SOURCES_BY_REQUESTS,
306             DELETE_MEDICAL_DATA_SOURCE_WITH_DATA,
307             // PHR medical resource APIs
308             UPSERT_MEDICAL_RESOURCES,
309             READ_MEDICAL_RESOURCES_BY_IDS,
310             READ_MEDICAL_RESOURCES_BY_REQUESTS,
311             DELETE_MEDICAL_RESOURCES_BY_IDS,
312             DELETE_MEDICAL_RESOURCES_BY_REQUESTS
313         })
314         @Retention(RetentionPolicy.SOURCE)
315         public @interface ApiMethod {}
316     }
317 
318     private static final Set<Integer> PHR_APIS =
319             Set.of(
320                     // PHR data source APIs
321                     CREATE_MEDICAL_DATA_SOURCE,
322                     GET_MEDICAL_DATA_SOURCES_BY_IDS,
323                     GET_MEDICAL_DATA_SOURCES_BY_REQUESTS,
324                     DELETE_MEDICAL_DATA_SOURCE_WITH_DATA,
325                     // PHR medical resource APIs
326                     UPSERT_MEDICAL_RESOURCES,
327                     READ_MEDICAL_RESOURCES_BY_IDS,
328                     READ_MEDICAL_RESOURCES_BY_REQUESTS,
329                     DELETE_MEDICAL_RESOURCES_BY_IDS,
330                     DELETE_MEDICAL_RESOURCES_BY_REQUESTS);
331 
332     /**
333      * Rate limiting ranges differentiated by Foreground/Background.
334      *
335      * @hide
336      */
337     public static final class RateLimitingRanges {
338 
339         public static final int NOT_USED = HEALTH_CONNECT_API_CALLED__RATE_LIMIT__NOT_USED;
340         public static final int NOT_DEFINED = HEALTH_CONNECT_API_CALLED__RATE_LIMIT__NOT_DEFINED;
341         public static final int FOREGROUND_15_MIN_UNDER_1000 =
342                 HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_FOREGROUND_15_MIN_UNDER_1000;
343         public static final int FOREGROUND_15_MIN_BW_1000_TO_2000 =
344                 HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_FOREGROUND_15_MIN_BW_1000_TO_2000;
345         public static final int FOREGROUND_15_MIN_BW_2000_TO_3000 =
346                 HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_FOREGROUND_15_MIN_BW_2000_TO_3000;
347         public static final int FOREGROUND_15_MIN_BW_3000_TO_4000 =
348                 HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_FOREGROUND_15_MIN_BW_3000_TO_4000;
349         public static final int FOREGROUND_15_MIN_ABOVE_4000 =
350                 HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_FOREGROUND_15_MIN_ABOVE_4000;
351         public static final int BACKGROUND_15_MIN_UNDER_500 =
352                 HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_BACKGROUND_15_MIN_UNDER_500;
353         public static final int BACKGROUND_15_MIN_BW_500_TO_1000 =
354                 HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_BACKGROUND_15_MIN_BW_500_TO_1000;
355         public static final int BACKGROUND_15_MIN_BW_1000_TO_2000 =
356                 HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_BACKGROUND_15_MIN_BW_1000_TO_2000;
357         public static final int BACKGROUND_15_MIN_BW_2000_TO_3000 =
358                 HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_BACKGROUND_15_MIN_BW_2000_TO_3000;
359         public static final int BACKGROUND_15_MIN_ABOVE_3000 =
360                 HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_BACKGROUND_15_MIN_ABOVE_3000;
361         public static final int FOREGROUND_24_HRS_UNDER_2000 =
362                 HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_FOREGROUND_24_HRS_UNDER_2000;
363         public static final int FOREGROUND_24_HRS_BW_2000_TO_3000 =
364                 HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_FOREGROUND_24_HRS_BW_2000_TO_3000;
365         public static final int FOREGROUND_24_HRS_BW_3000_TO_4000 =
366                 HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_FOREGROUND_24_HRS_BW_3000_TO_4000;
367         public static final int FOREGROUND_24_HRS_BW_4000_TO_5000 =
368                 HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_FOREGROUND_24_HRS_BW_4000_TO_5000;
369         public static final int FOREGROUND_24_HRS_BW_5000_TO_6000 =
370                 HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_FOREGROUND_24_HRS_BW_5000_TO_6000;
371         public static final int FOREGROUND_24_HRS_ABOVE_6000 =
372                 HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_FOREGROUND_24_HRS_ABOVE_6000;
373         public static final int BACKGROUND_24_HRS_UNDER_1000 =
374                 HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_BACKGROUND_24_HRS_UNDER_1000;
375         public static final int BACKGROUND_24_HRS_BW_1000_TO_2000 =
376                 HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_BACKGROUND_24_HRS_BW_1000_TO_2000;
377         public static final int BACKGROUND_24_HRS_BW_2000_TO_3000 =
378                 HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_BACKGROUND_24_HRS_BW_2000_TO_3000;
379         public static final int BACKGROUND_24_HRS_BW_3000_TO_4000 =
380                 HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_BACKGROUND_24_HRS_BW_3000_TO_4000;
381         public static final int BACKGROUND_24_HRS_BW_4000_TO_5000 =
382                 HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_BACKGROUND_24_HRS_BW_4000_TO_5000;
383         public static final int BACKGROUND_24_HRS_ABOVE_5000 =
384                 HEALTH_CONNECT_API_CALLED__RATE_LIMIT__RATE_LIMIT_BACKGROUND_24_HRS_ABOVE_5000;
385 
386         private static final Map<Integer, Integer> sForeground15min =
387                 Map.of(
388                         0,
389                         FOREGROUND_15_MIN_UNDER_1000,
390                         1,
391                         FOREGROUND_15_MIN_BW_1000_TO_2000,
392                         2,
393                         BACKGROUND_15_MIN_BW_2000_TO_3000,
394                         3,
395                         FOREGROUND_15_MIN_BW_3000_TO_4000);
396 
397         private static final Map<Integer, Integer> sForeground24hour =
398                 Map.of(
399                         0,
400                         FOREGROUND_24_HRS_UNDER_2000,
401                         1,
402                         FOREGROUND_24_HRS_UNDER_2000,
403                         2,
404                         FOREGROUND_24_HRS_BW_2000_TO_3000,
405                         3,
406                         FOREGROUND_24_HRS_BW_3000_TO_4000,
407                         4,
408                         FOREGROUND_24_HRS_BW_4000_TO_5000,
409                         5,
410                         FOREGROUND_24_HRS_BW_5000_TO_6000);
411 
412         private static final Map<Integer, Integer> sBackground15Min =
413                 Map.of(
414                         0,
415                         BACKGROUND_15_MIN_BW_500_TO_1000,
416                         1,
417                         BACKGROUND_15_MIN_BW_1000_TO_2000,
418                         2,
419                         BACKGROUND_15_MIN_BW_2000_TO_3000);
420 
421         private static final Map<Integer, Integer> sBackground24Hour =
422                 Map.of(
423                         0,
424                         BACKGROUND_24_HRS_UNDER_1000,
425                         1,
426                         BACKGROUND_24_HRS_BW_1000_TO_2000,
427                         2,
428                         BACKGROUND_24_HRS_BW_2000_TO_3000,
429                         3,
430                         BACKGROUND_24_HRS_BW_3000_TO_4000,
431                         4,
432                         BACKGROUND_24_HRS_BW_4000_TO_5000);
433 
434         @IntDef({
435             NOT_USED,
436             FOREGROUND_15_MIN_UNDER_1000,
437             FOREGROUND_15_MIN_BW_1000_TO_2000,
438             FOREGROUND_15_MIN_BW_2000_TO_3000,
439             FOREGROUND_15_MIN_BW_3000_TO_4000,
440             FOREGROUND_15_MIN_ABOVE_4000,
441             BACKGROUND_15_MIN_UNDER_500,
442             BACKGROUND_15_MIN_BW_500_TO_1000,
443             BACKGROUND_15_MIN_BW_1000_TO_2000,
444             BACKGROUND_15_MIN_BW_2000_TO_3000,
445             BACKGROUND_15_MIN_ABOVE_3000,
446             FOREGROUND_24_HRS_UNDER_2000,
447             FOREGROUND_24_HRS_BW_2000_TO_3000,
448             FOREGROUND_24_HRS_BW_3000_TO_4000,
449             FOREGROUND_24_HRS_BW_4000_TO_5000,
450             FOREGROUND_24_HRS_BW_5000_TO_6000,
451             FOREGROUND_24_HRS_ABOVE_6000,
452             BACKGROUND_24_HRS_UNDER_1000,
453             BACKGROUND_24_HRS_BW_1000_TO_2000,
454             BACKGROUND_24_HRS_BW_2000_TO_3000,
455             BACKGROUND_24_HRS_BW_3000_TO_4000,
456             BACKGROUND_24_HRS_BW_4000_TO_5000,
457             BACKGROUND_24_HRS_ABOVE_5000
458         })
459         @Retention(RetentionPolicy.SOURCE)
460         public @interface RateLimit {}
461     }
462 
463     /**
464      * Builder for HealthConnectServiceLogger
465      *
466      * @hide
467      */
468     public static class Builder {
469 
470         private final long mStartTime;
471         private final int mHealthDataServiceApiMethod;
472         private HealthFitnessStatsLog mStatsLog;
473         private int mHealthDataServiceApiStatus;
474         private int mErrorCode;
475         private long mDuration;
476         private int mRateLimit;
477         private int mNumberOfRecords;
478         private final boolean mHoldsDataManagementPermission;
479         private int[] mRecordTypes;
480         private Set<Integer> mMedicalResourceTypes;
481         private String mPackageName;
482         private int mCallerForegroundState;
483 
Builder(boolean holdsDataManagementPermission, @ApiMethods.ApiMethod int apiMethod)484         public Builder(boolean holdsDataManagementPermission, @ApiMethods.ApiMethod int apiMethod) {
485             mStatsLog = new HealthFitnessStatsLog();
486             mStartTime = System.currentTimeMillis();
487             mHealthDataServiceApiMethod = apiMethod;
488             mHealthDataServiceApiStatus = HEALTH_CONNECT_API_CALLED__API_STATUS__STATUS_UNKNOWN;
489             mErrorCode = 0; // Means no error
490             mHoldsDataManagementPermission = holdsDataManagementPermission;
491             mRateLimit = RateLimitingRanges.NOT_USED;
492             mNumberOfRecords = 0;
493             mRecordTypes = new int[MAX_NUMBER_OF_LOGGED_DATA_TYPES];
494             Arrays.fill(mRecordTypes, RECORD_TYPE_NOT_ASSIGNED_DEFAULT_VALUE);
495             mMedicalResourceTypes = new HashSet<>();
496             mPackageName = "UNKNOWN";
497             mCallerForegroundState =
498                     HEALTH_CONNECT_API_CALLED__CALLER_FOREGROUND_STATE__UNSPECIFIED;
499         }
500 
501         /** Set the class to write logs to. */
setHealthFitnessStatsLog(HealthFitnessStatsLog logger)502         public Builder setHealthFitnessStatsLog(HealthFitnessStatsLog logger) {
503             mStatsLog = logger;
504             return this;
505         }
506 
507         /** Set the API was called successfully. */
setHealthDataServiceApiStatusSuccess()508         public Builder setHealthDataServiceApiStatusSuccess() {
509             this.mHealthDataServiceApiStatus = HEALTH_CONNECT_API_CALLED__API_STATUS__SUCCESS;
510             return this;
511         }
512 
513         /**
514          * Set the API threw error.
515          *
516          * @param errorCode Error code thrown by the API.
517          */
setHealthDataServiceApiStatusError(int errorCode)518         public Builder setHealthDataServiceApiStatusError(int errorCode) {
519             this.mErrorCode = errorCode;
520             this.mHealthDataServiceApiStatus = HEALTH_CONNECT_API_CALLED__API_STATUS__ERROR;
521             return this;
522         }
523 
524         /**
525          * Set the rate limiting range if used.
526          *
527          * @param quotaBucket Quota bucket.
528          * @param quotaLimit Bucket limit.
529          */
setRateLimit( @ateLimiter.QuotaBucket.Type int quotaBucket, float quotaLimit)530         public Builder setRateLimit(
531                 @RateLimiter.QuotaBucket.Type int quotaBucket, float quotaLimit) {
532             this.mRateLimit = calculateRateLimitEnum(quotaBucket, quotaLimit);
533             return this;
534         }
535 
536         /**
537          * Set the number of records involved in the API call.
538          *
539          * @param numberOfRecords Number of records.
540          */
setNumberOfRecords(int numberOfRecords)541         public Builder setNumberOfRecords(int numberOfRecords) {
542             this.mNumberOfRecords = numberOfRecords;
543             return this;
544         }
545 
546         /**
547          * Set the types of records.
548          *
549          * @param recordInternals List of records.
550          */
setDataTypesFromRecordInternals(List<RecordInternal<?>> recordInternals)551         public Builder setDataTypesFromRecordInternals(List<RecordInternal<?>> recordInternals) {
552             Objects.requireNonNull(recordInternals);
553             Map<Integer, Integer> recordTypeToNumberOfRecords = new HashMap<>();
554             for (RecordInternal<?> recordInternal : recordInternals) {
555                 int recordType = getDataTypeEnumFromRecordType(recordInternal.getRecordType());
556                 int numberOfRecords = recordTypeToNumberOfRecords.getOrDefault(recordType, 0);
557                 numberOfRecords++;
558                 recordTypeToNumberOfRecords.put(recordType, numberOfRecords);
559             }
560             List<Entry<Integer, Integer>> recordTypeSortedByNumberOfRecords =
561                     new ArrayList<>(recordTypeToNumberOfRecords.entrySet());
562             recordTypeSortedByNumberOfRecords.sort(Entry.comparingByValue());
563             for (int i = 0;
564                     i
565                             < Math.min(
566                                     recordTypeSortedByNumberOfRecords.size(),
567                                     MAX_NUMBER_OF_LOGGED_DATA_TYPES);
568                     i++) {
569                 mRecordTypes[i] = recordTypeSortedByNumberOfRecords.get(i).getKey();
570             }
571             return this;
572         }
573 
574         /** Sets medical resource types to be logged. */
setMedicalResourceTypes(Set<Integer> medicalResourceTypes)575         public Builder setMedicalResourceTypes(Set<Integer> medicalResourceTypes) {
576             mMedicalResourceTypes = new HashSet<>(medicalResourceTypes);
577             return this;
578         }
579 
580         /**
581          * Set the types of records.
582          *
583          * @param recordTypesList List of record types.
584          */
setDataTypesFromRecordTypes(List<Integer> recordTypesList)585         public Builder setDataTypesFromRecordTypes(List<Integer> recordTypesList) {
586             if (recordTypesList == null || recordTypesList.size() == 0) {
587                 return this;
588             }
589             HashSet<Integer> recordTypes = new HashSet<>();
590             for (Integer recordType : recordTypesList) {
591                 recordTypes.add(getDataTypeEnumFromRecordType(recordType));
592             }
593 
594             int index = 0;
595             for (int recordType : recordTypes) {
596                 mRecordTypes[index++] = recordType;
597                 if (index == MAX_NUMBER_OF_LOGGED_DATA_TYPES) {
598                     break;
599                 }
600             }
601             return this;
602         }
603 
604         /**
605          * Set the types of records.
606          *
607          * @param packageName Package name of the caller.
608          */
setPackageName(String packageName)609         public Builder setPackageName(String packageName) {
610             if (packageName == null || packageName.isBlank()) {
611                 return this;
612             }
613             mPackageName = packageName;
614             return this;
615         }
616 
617         /**
618          * Sets the caller's foreground state.
619          *
620          * @param isCallerInForeground whether the caller is in foreground or background.
621          */
setCallerForegroundState(boolean isCallerInForeground)622         public Builder setCallerForegroundState(boolean isCallerInForeground) {
623             mCallerForegroundState =
624                     isCallerInForeground
625                             ? HEALTH_CONNECT_API_CALLED__CALLER_FOREGROUND_STATE__FOREGROUND
626                             : HEALTH_CONNECT_API_CALLED__CALLER_FOREGROUND_STATE__BACKGROUND;
627             return this;
628         }
629 
630         /** Returns an object of {@link HealthConnectServiceLogger}. */
build()631         public HealthConnectServiceLogger build() {
632             mDuration = System.currentTimeMillis() - mStartTime;
633             return new HealthConnectServiceLogger(this);
634         }
635 
calculateRateLimitEnum( @ateLimiter.QuotaBucket.Type int quotaBucket, float quotaLimit)636         private int calculateRateLimitEnum(
637                 @RateLimiter.QuotaBucket.Type int quotaBucket, float quotaLimit) {
638             int quotient = (int) (quotaLimit / 1000);
639             switch (quotaBucket) {
640                 case QUOTA_BUCKET_READS_PER_15M_FOREGROUND:
641                 case QUOTA_BUCKET_WRITES_PER_15M_FOREGROUND:
642                     return RateLimitingRanges.sForeground15min.getOrDefault(
643                             quotient, RateLimitingRanges.FOREGROUND_15_MIN_ABOVE_4000);
644                 case QUOTA_BUCKET_READS_PER_24H_FOREGROUND:
645                 case QUOTA_BUCKET_WRITES_PER_24H_FOREGROUND:
646                     return RateLimitingRanges.sForeground24hour.getOrDefault(
647                             quotient, RateLimitingRanges.FOREGROUND_24_HRS_ABOVE_6000);
648                 case QUOTA_BUCKET_READS_PER_15M_BACKGROUND:
649                 case QUOTA_BUCKET_WRITES_PER_15M_BACKGROUND:
650                     if (quotaLimit < 500) {
651                         return RateLimitingRanges.BACKGROUND_15_MIN_UNDER_500;
652                     }
653                     return RateLimitingRanges.sBackground15Min.getOrDefault(
654                             quotient, RateLimitingRanges.BACKGROUND_15_MIN_ABOVE_3000);
655                 case QUOTA_BUCKET_READS_PER_24H_BACKGROUND:
656                 case QUOTA_BUCKET_WRITES_PER_24H_BACKGROUND:
657                     return RateLimitingRanges.sBackground24Hour.getOrDefault(
658                             quotient, RateLimitingRanges.BACKGROUND_24_HRS_ABOVE_5000);
659             }
660             return RateLimitingRanges.NOT_DEFINED;
661         }
662 
663         /**
664          * Public so that it can be used by {@link InternalHealthConnectMappings}.
665          *
666          * @deprecated Use {@link InternalHealthConnectMappings#getLoggingEnumForRecordTypeId(int)}.
667          */
668         @Deprecated
getDataTypeEnumFromRecordType(int recordType)669         public static int getDataTypeEnumFromRecordType(int recordType) {
670             switch (recordType) {
671                 case RECORD_TYPE_STEPS:
672                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__STEPS;
673                 case RECORD_TYPE_HEART_RATE:
674                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__HEART_RATE;
675                 case RECORD_TYPE_BASAL_METABOLIC_RATE:
676                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__BASAL_METABOLIC_RATE;
677                 case RECORD_TYPE_CYCLING_PEDALING_CADENCE:
678                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__CYCLING_PEDALING_CADENCE;
679                 case RECORD_TYPE_POWER:
680                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__POWER;
681                 case RECORD_TYPE_SPEED:
682                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__SPEED;
683                 case RECORD_TYPE_STEPS_CADENCE:
684                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__STEPS_CADENCE;
685                 case RECORD_TYPE_DISTANCE:
686                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__DISTANCE;
687                 case RECORD_TYPE_WHEELCHAIR_PUSHES:
688                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__WHEELCHAIR_PUSHES;
689                 case RECORD_TYPE_TOTAL_CALORIES_BURNED:
690                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__TOTAL_CALORIES_BURNED;
691                 case RECORD_TYPE_FLOORS_CLIMBED:
692                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__FLOORS_CLIMBED;
693                 case RECORD_TYPE_ELEVATION_GAINED:
694                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__ELEVATION_GAINED;
695                 case RECORD_TYPE_ACTIVE_CALORIES_BURNED:
696                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__ACTIVE_CALORIES_BURNED;
697                 case RECORD_TYPE_HYDRATION:
698                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__HYDRATION;
699                 case RECORD_TYPE_NUTRITION:
700                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__NUTRITION;
701                 case RECORD_TYPE_RESPIRATORY_RATE:
702                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__RESPIRATORY_RATE;
703                 case RECORD_TYPE_BONE_MASS:
704                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__BONE_MASS;
705                 case RECORD_TYPE_RESTING_HEART_RATE:
706                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__RESTING_HEART_RATE;
707                 case RECORD_TYPE_BODY_FAT:
708                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__BODY_FAT;
709                 case RECORD_TYPE_VO2_MAX:
710                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__VO2_MAX;
711                 case RECORD_TYPE_CERVICAL_MUCUS:
712                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__CERVICAL_MUCUS;
713                 case RECORD_TYPE_BASAL_BODY_TEMPERATURE:
714                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__BASAL_BODY_TEMPERATURE;
715                 case RECORD_TYPE_MENSTRUATION_FLOW:
716                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__MENSTRUATION_FLOW;
717                 case RECORD_TYPE_OXYGEN_SATURATION:
718                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__OXYGEN_SATURATION;
719                 case RECORD_TYPE_BLOOD_PRESSURE:
720                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__BLOOD_PRESSURE;
721                 case RECORD_TYPE_HEIGHT:
722                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__HEIGHT;
723                 case RECORD_TYPE_BLOOD_GLUCOSE:
724                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__BLOOD_GLUCOSE;
725                 case RECORD_TYPE_WEIGHT:
726                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__WEIGHT;
727                 case RECORD_TYPE_LEAN_BODY_MASS:
728                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__LEAN_BODY_MASS;
729                 case RECORD_TYPE_SEXUAL_ACTIVITY:
730                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__SEXUAL_ACTIVITY;
731                 case RECORD_TYPE_BODY_TEMPERATURE:
732                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__BODY_TEMPERATURE;
733                 case RECORD_TYPE_OVULATION_TEST:
734                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__OVULATION_TEST;
735                 case RECORD_TYPE_EXERCISE_SESSION:
736                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__EXERCISE_SESSION;
737                 case RECORD_TYPE_SKIN_TEMPERATURE:
738                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__SKIN_TEMPERATURE;
739                 case RECORD_TYPE_PLANNED_EXERCISE_SESSION:
740                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__PLANNED_EXERCISE_SESSION;
741                 case RECORD_TYPE_MINDFULNESS_SESSION:
742                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__MINDFULNESS_SESSION;
743                 case RECORD_TYPE_BODY_WATER_MASS:
744                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__BODY_WATER_MASS;
745                 case RECORD_TYPE_HEART_RATE_VARIABILITY_RMSSD:
746                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__HEART_RATE_VARIABILITY_RMSSD;
747                 case RECORD_TYPE_INTERMENSTRUAL_BLEEDING:
748                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__INTERMENSTRUAL_BLEEDING;
749                 case RECORD_TYPE_MENSTRUATION_PERIOD:
750                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__MENSTRUATION_PERIOD;
751                 case RECORD_TYPE_SLEEP_SESSION:
752                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__SLEEP_SESSION;
753                 case RECORD_TYPE_UNKNOWN:
754                 default:
755                     return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__DATA_TYPE_UNKNOWN;
756             }
757         }
758     }
759 
HealthConnectServiceLogger(HealthConnectServiceLogger.Builder builder)760     private HealthConnectServiceLogger(HealthConnectServiceLogger.Builder builder) {
761         Objects.requireNonNull(builder);
762 
763         mHealthDataServiceApiMethod = builder.mHealthDataServiceApiMethod;
764         mHealthDataServiceApiStatus = builder.mHealthDataServiceApiStatus;
765         mErrorCode = builder.mErrorCode;
766         mDuration = builder.mDuration;
767         mHoldsDataManagementPermission = builder.mHoldsDataManagementPermission;
768         mRateLimit = builder.mRateLimit;
769         mNumberOfRecords = builder.mNumberOfRecords;
770         mRecordTypes = builder.mRecordTypes;
771         mMedicalResourceTypes = builder.mMedicalResourceTypes;
772         mPackageName = builder.mPackageName;
773         mCallerForegroundState = builder.mCallerForegroundState;
774         mStatsLog = builder.mStatsLog;
775     }
776 
777     /** Log to statsd. */
log()778     public void log() {
779         // Do not log API calls made from the controller
780         if (mHoldsDataManagementPermission) {
781             return;
782         }
783 
784         boolean isPhrApi = PHR_APIS.contains(mHealthDataServiceApiMethod);
785         if (isPhrApi) {
786             writePhrLogs();
787             return;
788         }
789 
790         mStatsLog.write(
791                 HEALTH_CONNECT_API_CALLED,
792                 mHealthDataServiceApiMethod,
793                 mHealthDataServiceApiStatus,
794                 mErrorCode,
795                 mDuration,
796                 mNumberOfRecords,
797                 mRateLimit,
798                 mCallerForegroundState,
799                 mPackageName);
800 
801         // For private logging, max 6 data types per request are being logged
802         // rest will be ignored
803         mStatsLog.write(
804                 HEALTH_CONNECT_API_INVOKED,
805                 mHealthDataServiceApiMethod,
806                 mHealthDataServiceApiStatus,
807                 mErrorCode,
808                 mDuration,
809                 mPackageName,
810                 getRecordTypeEnumToLog(mRecordTypes, 0),
811                 getRecordTypeEnumToLog(mRecordTypes, 1),
812                 getRecordTypeEnumToLog(mRecordTypes, 2),
813                 getRecordTypeEnumToLog(mRecordTypes, 3),
814                 getRecordTypeEnumToLog(mRecordTypes, 4),
815                 getRecordTypeEnumToLog(mRecordTypes, 5));
816     }
817 
writePhrLogs()818     private void writePhrLogs() {
819         if (personalHealthRecordTelemetry()) { // normal WW
820             mStatsLog.write(
821                     HEALTH_CONNECT_API_CALLED,
822                     mHealthDataServiceApiMethod,
823                     mHealthDataServiceApiStatus,
824                     mErrorCode,
825                     mDuration,
826                     mNumberOfRecords,
827                     mRateLimit,
828                     mCallerForegroundState,
829                     mPackageName);
830         }
831 
832         if (personalHealthRecordTelemetryPrivateWw()) { // private WW
833             if (mMedicalResourceTypes.isEmpty()) {
834                 writePhrApiInvoked(MEDICAL_RESOURCE_TYPE_NOT_ASSIGNED_DEFAULT_VALUE);
835             } else {
836                 for (int medicalResourceType : mMedicalResourceTypes) {
837                     writePhrApiInvoked(getMedicalResourceTypeLoggingEnum(medicalResourceType));
838                 }
839             }
840         }
841     }
842 
writePhrApiInvoked(int medicalResourceTypeLoggingEnum)843     private void writePhrApiInvoked(int medicalResourceTypeLoggingEnum) {
844         mStatsLog.write(
845                 HEALTH_CONNECT_PHR_API_INVOKED,
846                 mHealthDataServiceApiMethod,
847                 mHealthDataServiceApiStatus,
848                 mPackageName,
849                 medicalResourceTypeLoggingEnum);
850     }
851 
getMedicalResourceTypeLoggingEnum( @edicalResource.MedicalResourceType int medicalResourceType)852     private static int getMedicalResourceTypeLoggingEnum(
853             @MedicalResource.MedicalResourceType int medicalResourceType) {
854         return switch (medicalResourceType) {
855             case MEDICAL_RESOURCE_TYPE_VACCINES ->
856                     HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_VACCINES;
857             case MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES ->
858                     HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES;
859             case MEDICAL_RESOURCE_TYPE_PREGNANCY ->
860                     HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_PREGNANCY;
861             case MEDICAL_RESOURCE_TYPE_SOCIAL_HISTORY ->
862                     HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_SOCIAL_HISTORY;
863             case MEDICAL_RESOURCE_TYPE_VITAL_SIGNS ->
864                     HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_VITAL_SIGNS;
865             case MEDICAL_RESOURCE_TYPE_LABORATORY_RESULTS ->
866                     HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_LABORATORY_RESULTS;
867             case MEDICAL_RESOURCE_TYPE_CONDITIONS ->
868                     HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_CONDITIONS;
869             case MEDICAL_RESOURCE_TYPE_PROCEDURES ->
870                     HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_PROCEDURES;
871             case MEDICAL_RESOURCE_TYPE_MEDICATIONS ->
872                     HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_MEDICATIONS;
873             case MEDICAL_RESOURCE_TYPE_PERSONAL_DETAILS ->
874                     HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_PERSONAL_DETAILS;
875             case MEDICAL_RESOURCE_TYPE_PRACTITIONER_DETAILS ->
876                     HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_PRACTITIONER_DETAILS;
877             case MEDICAL_RESOURCE_TYPE_VISITS ->
878                     HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_VISITS;
879             default ->
880                     HEALTH_CONNECT_PHR_API_INVOKED__MEDICAL_RESOURCE_TYPE__MEDICAL_RESOURCE_TYPE_UNKNOWN;
881         };
882     }
883 
getRecordTypeEnumToLog(int[] recordTypes, int index)884     private int getRecordTypeEnumToLog(int[] recordTypes, int index) {
885         if (recordTypes[index] == RECORD_TYPE_NOT_ASSIGNED_DEFAULT_VALUE) {
886             return HEALTH_CONNECT_API_INVOKED__DATA_TYPE_ONE__DATA_TYPE_NOT_ASSIGNED;
887         }
888         return recordTypes[index];
889     }
890 }
891