1 /*
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
17 #define DEBUG false // STOPSHIP if true
18 #define LOG_TAG "StatsAidl"
19
20 #define VLOG(...) \
21 if (DEBUG) ALOGD(__VA_ARGS__);
22
23 #include "StatsAidl.h"
24
25 #include <Counter.h>
26 #include <log/log.h>
27 #include <stats_annotations.h>
28 #include <stats_event.h>
29 #include <statslog.h>
30
31 #include <unordered_map>
32
33 namespace {
34 static const char* g_AtomErrorMetricName =
35 "statsd_errors.value_report_vendor_atom_errors_count";
36 }
37
38 namespace aidl {
39 namespace android {
40 namespace frameworks {
41 namespace stats {
42
43 using ::android::expresslog::Counter;
44
45 template <typename E>
to_underlying(E e)46 constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept {
47 return static_cast<typename std::underlying_type<E>::type>(e);
48 }
49
StatsHal()50 StatsHal::StatsHal() {
51 }
52
write_annotation(AStatsEvent * event,const Annotation & annotation)53 bool 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
write_atom_annotations(AStatsEvent * event,const std::vector<std::optional<Annotation>> & annotations)72 bool 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
write_field_annotations(AStatsEvent * event,const std::vector<Annotation> & annotations)85 bool 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
reportVendorAtom(const VendorAtom & vendorAtom)94 ndk::ScopedAStatus StatsHal::reportVendorAtom(const VendorAtom& vendorAtom) {
95 if (vendorAtom.atomId < 100000 || vendorAtom.atomId >= 200000) {
96 ALOGE("Atom ID %ld is not a valid vendor atom ID", (long)vendorAtom.atomId);
97 Counter::logIncrement(g_AtomErrorMetricName);
98 return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
99 -1, "Not a valid vendor atom ID");
100 }
101 if (vendorAtom.reverseDomainName.length() > 50) {
102 ALOGE("Vendor atom reverse domain name %s is too long.",
103 vendorAtom.reverseDomainName.c_str());
104 Counter::logIncrement(g_AtomErrorMetricName);
105 return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
106 -1, "Vendor atom reverse domain name is too long");
107 }
108 AStatsEvent* event = AStatsEvent_obtain();
109 AStatsEvent_setAtomId(event, vendorAtom.atomId);
110
111 if (vendorAtom.atomAnnotations) {
112 if (!write_atom_annotations(event, *vendorAtom.atomAnnotations)) {
113 AStatsEvent_release(event);
114 ALOGE("Atom ID %ld has incompatible atom level annotation", (long)vendorAtom.atomId);
115 Counter::logIncrement(g_AtomErrorMetricName);
116 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
133 AStatsEvent_writeString(event, vendorAtom.reverseDomainName.c_str());
134 size_t atomValueIdx = 0;
135 for (const auto& atomValue : vendorAtom.values) {
136 switch (atomValue.getTag()) {
137 case VendorAtomValue::intValue:
138 AStatsEvent_writeInt32(event, atomValue.get<VendorAtomValue::intValue>());
139 break;
140 case VendorAtomValue::longValue:
141 AStatsEvent_writeInt64(event, atomValue.get<VendorAtomValue::longValue>());
142 break;
143 case VendorAtomValue::floatValue:
144 AStatsEvent_writeFloat(event, atomValue.get<VendorAtomValue::floatValue>());
145 break;
146 case VendorAtomValue::stringValue:
147 AStatsEvent_writeString(event,
148 atomValue.get<VendorAtomValue::stringValue>().c_str());
149 break;
150 case VendorAtomValue::boolValue:
151 AStatsEvent_writeBool(event, atomValue.get<VendorAtomValue::boolValue>());
152 break;
153 case VendorAtomValue::repeatedIntValue: {
154 const std::optional<std::vector<int>>& repeatedIntValue =
155 atomValue.get<VendorAtomValue::repeatedIntValue>();
156 if (!repeatedIntValue) {
157 AStatsEvent_writeInt32Array(event, {}, 0);
158 break;
159 }
160 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>();
167 if (!repeatedLongValue) {
168 AStatsEvent_writeInt64Array(event, {}, 0);
169 break;
170 }
171 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>();
178 if (!repeatedFloatValue) {
179 AStatsEvent_writeFloatArray(event, {}, 0);
180 break;
181 }
182 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>();
189 if (!repeatedStringValue) {
190 AStatsEvent_writeStringArray(event, {}, 0);
191 break;
192 }
193 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) {
198 cStringArray[i] = repeatedStringVector[i].has_value()
199 ? repeatedStringVector[i]->c_str()
200 : "";
201 }
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>();
209 if (!repeatedBoolValue) {
210 AStatsEvent_writeBoolArray(event, {}, 0);
211 break;
212 }
213 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>();
226 if (!byteArrayValue) {
227 AStatsEvent_writeByteArray(event, {}, 0);
228 break;
229 }
230 AStatsEvent_writeByteArray(event, byteArrayValue->data(), byteArrayValue->size());
231 break;
232 }
233 default: {
234 AStatsEvent_release(event);
235 ALOGE("Atom ID %ld has invalid atomValue.getTag", (long)vendorAtom.atomId);
236 Counter::logIncrement(g_AtomErrorMetricName);
237 return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
238 -1, "invalid atomValue.getTag");
239 break;
240 }
241 }
242
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)) {
250 AStatsEvent_release(event);
251 ALOGE("Atom ID %ld has incompatible field level annotation for field #%ld",
252 (long)vendorAtom.atomId, (long)atomValueIdx + 2);
253 Counter::logIncrement(g_AtomErrorMetricName);
254 return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
255 -1, "invalid atom field annotation");
256 }
257 }
258 atomValueIdx++;
259 }
260 AStatsEvent_build(event);
261 const int ret = AStatsEvent_write(event);
262 AStatsEvent_release(event);
263 if (ret <= 0) {
264 ALOGE("Error writing Atom ID %ld. Result: %d", (long)vendorAtom.atomId, ret);
265 Counter::logIncrement(g_AtomErrorMetricName);
266 }
267 return ret <= 0 ? ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(ret,
268 "report atom failed")
269 : ndk::ScopedAStatus::ok();
270 }
271
272 } // namespace stats
273 } // namespace frameworks
274 } // namespace android
275 } // namespace aidl
276