blob: b22f903654acd9f1f6e83c87d90fb33162cf1905 [file] [log] [blame]
Vova Sharaienko3092c962021-02-01 23:38:12 +00001/*
2 * Copyright (C) 2021 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
Vova Sharaienko40dc2402023-01-28 05:51:00 +000017#define DEBUG false // STOPSHIP if true
Vova Sharaienko3092c962021-02-01 23:38:12 +000018#define LOG_TAG "StatsAidl"
19
Vova Sharaienko88720f42023-01-28 05:55:18 +000020#define VLOG(...) \
21 if (DEBUG) ALOGD(__VA_ARGS__);
22
Vova Sharaienko40dc2402023-01-28 05:51:00 +000023#include "StatsAidl.h"
24
Vova Sharaienko606eafd2023-03-25 01:32:03 +000025#include <Counter.h>
Vova Sharaienko3092c962021-02-01 23:38:12 +000026#include <log/log.h>
Vova Sharaienko88720f42023-01-28 05:55:18 +000027#include <stats_annotations.h>
28#include <stats_event.h>
Vova Sharaienko3092c962021-02-01 23:38:12 +000029#include <statslog.h>
30
Vova Sharaienko88720f42023-01-28 05:55:18 +000031#include <unordered_map>
32
Vova Sharaienko606eafd2023-03-25 01:32:03 +000033namespace {
34 static const char* g_AtomErrorMetricName =
35 "statsd_errors.value_report_vendor_atom_errors_count";
36}
37
Vova Sharaienko3092c962021-02-01 23:38:12 +000038namespace aidl {
39namespace android {
40namespace frameworks {
41namespace stats {
42
Vova Sharaienko606eafd2023-03-25 01:32:03 +000043using ::android::expresslog::Counter;
44
Vova Sharaienko88720f42023-01-28 05:55:18 +000045template <typename E>
46constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept {
47 return static_cast<typename std::underlying_type<E>::type>(e);
48}
49
Vova Sharaienko40dc2402023-01-28 05:51:00 +000050StatsHal::StatsHal() {
51}
Vova Sharaienko3092c962021-02-01 23:38:12 +000052
Vova Sharaienko88720f42023-01-28 05:55:18 +000053bool write_annotation(AStatsEvent* event, const Annotation& annotation) {
54 switch (annotation.value.getTag()) {
55 case AnnotationValue::boolValue: {
56 AStatsEvent_addBoolAnnotation(event, to_underlying(annotation.annotationId),
57 annotation.value.get<AnnotationValue::boolValue>());
58 break;
59 }
60 case AnnotationValue::intValue: {
61 AStatsEvent_addInt32Annotation(event, to_underlying(annotation.annotationId),
62 annotation.value.get<AnnotationValue::intValue>());
63 break;
64 }
65 default: {
66 return false;
67 }
68 }
69 return true;
70}
71
72bool write_atom_annotations(AStatsEvent* event,
73 const std::vector<std::optional<Annotation>>& annotations) {
74 for (const auto& atomAnnotation : annotations) {
75 if (!atomAnnotation) {
76 return false;
77 }
78 if (!write_annotation(event, *atomAnnotation)) {
79 return false;
80 }
81 }
82 return true;
83}
84
85bool write_field_annotations(AStatsEvent* event, const std::vector<Annotation>& annotations) {
86 for (const auto& fieldAnnotation : annotations) {
87 if (!write_annotation(event, fieldAnnotation)) {
88 return false;
89 }
90 }
91 return true;
92}
93
Vova Sharaienko3092c962021-02-01 23:38:12 +000094ndk::ScopedAStatus StatsHal::reportVendorAtom(const VendorAtom& vendorAtom) {
Vova Sharaienko3092c962021-02-01 23:38:12 +000095 if (vendorAtom.atomId < 100000 || vendorAtom.atomId >= 200000) {
Vova Sharaienko40dc2402023-01-28 05:51:00 +000096 ALOGE("Atom ID %ld is not a valid vendor atom ID", (long)vendorAtom.atomId);
Vova Sharaienko606eafd2023-03-25 01:32:03 +000097 Counter::logIncrement(g_AtomErrorMetricName);
Vova Sharaienko3092c962021-02-01 23:38:12 +000098 return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
Vova Sharaienko40dc2402023-01-28 05:51:00 +000099 -1, "Not a valid vendor atom ID");
Vova Sharaienko3092c962021-02-01 23:38:12 +0000100 }
Vova Sharaienko5764fc12022-12-09 02:40:35 +0000101 if (vendorAtom.reverseDomainName.length() > 50) {
102 ALOGE("Vendor atom reverse domain name %s is too long.",
Vova Sharaienko40dc2402023-01-28 05:51:00 +0000103 vendorAtom.reverseDomainName.c_str());
Vova Sharaienko606eafd2023-03-25 01:32:03 +0000104 Counter::logIncrement(g_AtomErrorMetricName);
Vova Sharaienko3092c962021-02-01 23:38:12 +0000105 return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
Vova Sharaienko40dc2402023-01-28 05:51:00 +0000106 -1, "Vendor atom reverse domain name is too long");
Vova Sharaienko3092c962021-02-01 23:38:12 +0000107 }
108 AStatsEvent* event = AStatsEvent_obtain();
109 AStatsEvent_setAtomId(event, vendorAtom.atomId);
Vova Sharaienko88720f42023-01-28 05:55:18 +0000110
111 if (vendorAtom.atomAnnotations) {
112 if (!write_atom_annotations(event, *vendorAtom.atomAnnotations)) {
Vova Sharaienko88720f42023-01-28 05:55:18 +0000113 AStatsEvent_release(event);
Vova Sharaienko606eafd2023-03-25 01:32:03 +0000114 ALOGE("Atom ID %ld has incompatible atom level annotation", (long)vendorAtom.atomId);
115 Counter::logIncrement(g_AtomErrorMetricName);
Vova Sharaienko88720f42023-01-28 05:55:18 +0000116 return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
117 -1, "invalid atom annotation");
118 }
119 }
120
121 // populate map for quickier access for VendorAtomValue associated annotations by value index
122 std::unordered_map<int, int> fieldIndexToAnnotationSetMap;
123 if (vendorAtom.valuesAnnotations) {
124 const std::vector<std::optional<AnnotationSet>>& valuesAnnotations =
125 *vendorAtom.valuesAnnotations;
126 for (int i = 0; i < valuesAnnotations.size(); i++) {
127 if (valuesAnnotations[i]) {
128 fieldIndexToAnnotationSetMap[valuesAnnotations[i]->valueIndex] = i;
129 }
130 }
131 }
132
Vova Sharaienko3092c962021-02-01 23:38:12 +0000133 AStatsEvent_writeString(event, vendorAtom.reverseDomainName.c_str());
Vova Sharaienko88720f42023-01-28 05:55:18 +0000134 size_t atomValueIdx = 0;
Vova Sharaienko3092c962021-02-01 23:38:12 +0000135 for (const auto& atomValue : vendorAtom.values) {
136 switch (atomValue.getTag()) {
137 case VendorAtomValue::intValue:
Vova Sharaienko40dc2402023-01-28 05:51:00 +0000138 AStatsEvent_writeInt32(event, atomValue.get<VendorAtomValue::intValue>());
Vova Sharaienko3092c962021-02-01 23:38:12 +0000139 break;
140 case VendorAtomValue::longValue:
Vova Sharaienko40dc2402023-01-28 05:51:00 +0000141 AStatsEvent_writeInt64(event, atomValue.get<VendorAtomValue::longValue>());
Vova Sharaienko3092c962021-02-01 23:38:12 +0000142 break;
143 case VendorAtomValue::floatValue:
Vova Sharaienko40dc2402023-01-28 05:51:00 +0000144 AStatsEvent_writeFloat(event, atomValue.get<VendorAtomValue::floatValue>());
Vova Sharaienko3092c962021-02-01 23:38:12 +0000145 break;
146 case VendorAtomValue::stringValue:
147 AStatsEvent_writeString(event,
Vova Sharaienko40dc2402023-01-28 05:51:00 +0000148 atomValue.get<VendorAtomValue::stringValue>().c_str());
Vova Sharaienko3092c962021-02-01 23:38:12 +0000149 break;
Vova Sharaienko5540ebc2022-04-08 05:53:43 +0000150 case VendorAtomValue::boolValue:
Vova Sharaienko40dc2402023-01-28 05:51:00 +0000151 AStatsEvent_writeBool(event, atomValue.get<VendorAtomValue::boolValue>());
Vova Sharaienko5540ebc2022-04-08 05:53:43 +0000152 break;
tsaichristine5f5f5792022-09-09 16:26:31 -0700153 case VendorAtomValue::repeatedIntValue: {
154 const std::optional<std::vector<int>>& repeatedIntValue =
155 atomValue.get<VendorAtomValue::repeatedIntValue>();
tsaichristinee83b5f22022-09-26 18:33:05 -0700156 if (!repeatedIntValue) {
157 AStatsEvent_writeInt32Array(event, {}, 0);
158 break;
159 }
tsaichristine5f5f5792022-09-09 16:26:31 -0700160 AStatsEvent_writeInt32Array(event, repeatedIntValue->data(),
161 repeatedIntValue->size());
162 break;
163 }
164 case VendorAtomValue::repeatedLongValue: {
165 const std::optional<std::vector<int64_t>>& repeatedLongValue =
166 atomValue.get<VendorAtomValue::repeatedLongValue>();
tsaichristinee83b5f22022-09-26 18:33:05 -0700167 if (!repeatedLongValue) {
168 AStatsEvent_writeInt64Array(event, {}, 0);
169 break;
170 }
tsaichristine5f5f5792022-09-09 16:26:31 -0700171 AStatsEvent_writeInt64Array(event, repeatedLongValue->data(),
172 repeatedLongValue->size());
173 break;
174 }
175 case VendorAtomValue::repeatedFloatValue: {
176 const std::optional<std::vector<float>>& repeatedFloatValue =
177 atomValue.get<VendorAtomValue::repeatedFloatValue>();
tsaichristinee83b5f22022-09-26 18:33:05 -0700178 if (!repeatedFloatValue) {
179 AStatsEvent_writeFloatArray(event, {}, 0);
180 break;
181 }
tsaichristine5f5f5792022-09-09 16:26:31 -0700182 AStatsEvent_writeFloatArray(event, repeatedFloatValue->data(),
183 repeatedFloatValue->size());
184 break;
185 }
186 case VendorAtomValue::repeatedStringValue: {
187 const std::optional<std::vector<std::optional<std::string>>>& repeatedStringValue =
188 atomValue.get<VendorAtomValue::repeatedStringValue>();
tsaichristinee83b5f22022-09-26 18:33:05 -0700189 if (!repeatedStringValue) {
190 AStatsEvent_writeStringArray(event, {}, 0);
191 break;
192 }
tsaichristine5f5f5792022-09-09 16:26:31 -0700193 const std::vector<std::optional<std::string>>& repeatedStringVector =
194 *repeatedStringValue;
195 const char* cStringArray[repeatedStringVector.size()];
196
197 for (int i = 0; i < repeatedStringVector.size(); ++i) {
tsaichristinee83b5f22022-09-26 18:33:05 -0700198 cStringArray[i] = repeatedStringVector[i].has_value()
Vova Sharaienko40dc2402023-01-28 05:51:00 +0000199 ? repeatedStringVector[i]->c_str()
200 : "";
tsaichristine5f5f5792022-09-09 16:26:31 -0700201 }
202
203 AStatsEvent_writeStringArray(event, cStringArray, repeatedStringVector.size());
204 break;
205 }
206 case VendorAtomValue::repeatedBoolValue: {
207 const std::optional<std::vector<bool>>& repeatedBoolValue =
208 atomValue.get<VendorAtomValue::repeatedBoolValue>();
tsaichristinee83b5f22022-09-26 18:33:05 -0700209 if (!repeatedBoolValue) {
210 AStatsEvent_writeBoolArray(event, {}, 0);
211 break;
212 }
tsaichristine5f5f5792022-09-09 16:26:31 -0700213 const std::vector<bool>& repeatedBoolVector = *repeatedBoolValue;
214 bool boolArray[repeatedBoolValue->size()];
215
216 for (int i = 0; i < repeatedBoolVector.size(); ++i) {
217 boolArray[i] = repeatedBoolVector[i];
218 }
219
220 AStatsEvent_writeBoolArray(event, boolArray, repeatedBoolVector.size());
221 break;
222 }
223 case VendorAtomValue::byteArrayValue: {
224 const std::optional<std::vector<uint8_t>>& byteArrayValue =
225 atomValue.get<VendorAtomValue::byteArrayValue>();
tsaichristinee83b5f22022-09-26 18:33:05 -0700226 if (!byteArrayValue) {
227 AStatsEvent_writeByteArray(event, {}, 0);
228 break;
229 }
tsaichristine5f5f5792022-09-09 16:26:31 -0700230 AStatsEvent_writeByteArray(event, byteArrayValue->data(), byteArrayValue->size());
231 break;
232 }
Vova Sharaienko88720f42023-01-28 05:55:18 +0000233 default: {
234 AStatsEvent_release(event);
235 ALOGE("Atom ID %ld has invalid atomValue.getTag", (long)vendorAtom.atomId);
Vova Sharaienko606eafd2023-03-25 01:32:03 +0000236 Counter::logIncrement(g_AtomErrorMetricName);
Vova Sharaienko88720f42023-01-28 05:55:18 +0000237 return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
238 -1, "invalid atomValue.getTag");
239 break;
240 }
Vova Sharaienko3092c962021-02-01 23:38:12 +0000241 }
Vova Sharaienko88720f42023-01-28 05:55:18 +0000242
243 const auto& valueAnnotationIndex = fieldIndexToAnnotationSetMap.find(atomValueIdx);
244 if (valueAnnotationIndex != fieldIndexToAnnotationSetMap.end()) {
245 const std::vector<Annotation>& fieldAnnotations =
246 (*vendorAtom.valuesAnnotations)[valueAnnotationIndex->second]->annotations;
247 VLOG("Atom ID %ld has %ld annotations for field #%ld", (long)vendorAtom.atomId,
248 (long)fieldAnnotations.size(), (long)atomValueIdx + 2);
249 if (!write_field_annotations(event, fieldAnnotations)) {
Vova Sharaienko606eafd2023-03-25 01:32:03 +0000250 AStatsEvent_release(event);
Vova Sharaienko88720f42023-01-28 05:55:18 +0000251 ALOGE("Atom ID %ld has incompatible field level annotation for field #%ld",
252 (long)vendorAtom.atomId, (long)atomValueIdx + 2);
Vova Sharaienko606eafd2023-03-25 01:32:03 +0000253 Counter::logIncrement(g_AtomErrorMetricName);
Vova Sharaienko88720f42023-01-28 05:55:18 +0000254 return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
255 -1, "invalid atom field annotation");
256 }
257 }
258 atomValueIdx++;
Vova Sharaienko3092c962021-02-01 23:38:12 +0000259 }
260 AStatsEvent_build(event);
261 const int ret = AStatsEvent_write(event);
262 AStatsEvent_release(event);
Vova Sharaienko88720f42023-01-28 05:55:18 +0000263 if (ret <= 0) {
264 ALOGE("Error writing Atom ID %ld. Result: %d", (long)vendorAtom.atomId, ret);
Vova Sharaienko606eafd2023-03-25 01:32:03 +0000265 Counter::logIncrement(g_AtomErrorMetricName);
Vova Sharaienko88720f42023-01-28 05:55:18 +0000266 }
Vova Sharaienko40dc2402023-01-28 05:51:00 +0000267 return ret <= 0 ? ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(ret,
268 "report atom failed")
269 : ndk::ScopedAStatus::ok();
Vova Sharaienko3092c962021-02-01 23:38:12 +0000270}
271
272} // namespace stats
273} // namespace frameworks
274} // namespace android
275} // namespace aidl