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
30 #include <map>
31
32 namespace {
33 static const char* g_AtomErrorMetricName =
34 "statsd_errors.value_report_vendor_atom_errors_count";
35 }
36
37 namespace aidl {
38 namespace android {
39 namespace frameworks {
40 namespace stats {
41
42 using ::android::expresslog::Counter;
43
44 template <typename E>
to_underlying(E e)45 constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept {
46 return static_cast<typename std::underlying_type<E>::type>(e);
47 }
48
StatsHal()49 StatsHal::StatsHal() {
50 }
51
write_annotation(AStatsEvent * event,const Annotation & annotation)52 bool write_annotation(AStatsEvent* event, const Annotation& annotation) {
53 switch (annotation.value.getTag()) {
54 case AnnotationValue::boolValue: {
55 AStatsEvent_addBoolAnnotation(event, to_underlying(annotation.annotationId),
56 annotation.value.get<AnnotationValue::boolValue>());
57 break;
58 }
59 case AnnotationValue::intValue: {
60 AStatsEvent_addInt32Annotation(event, to_underlying(annotation.annotationId),
61 annotation.value.get<AnnotationValue::intValue>());
62 break;
63 }
64 default: {
65 return false;
66 }
67 }
68 return true;
69 }
70
write_atom_annotations(AStatsEvent * event,const std::vector<std::optional<Annotation>> & annotations)71 bool write_atom_annotations(AStatsEvent* event,
72 const std::vector<std::optional<Annotation>>& annotations) {
73 for (const auto& atomAnnotation : annotations) {
74 if (!atomAnnotation) {
75 return false;
76 }
77 if (!write_annotation(event, *atomAnnotation)) {
78 return false;
79 }
80 }
81 return true;
82 }
83
write_field_annotations(AStatsEvent * event,const std::vector<Annotation> & annotations)84 bool write_field_annotations(AStatsEvent* event, const std::vector<Annotation>& annotations) {
85 for (const auto& fieldAnnotation : annotations) {
86 if (!write_annotation(event, fieldAnnotation)) {
87 return false;
88 }
89 }
90 return true;
91 }
92
reportVendorAtom(const VendorAtom & vendorAtom)93 ndk::ScopedAStatus StatsHal::reportVendorAtom(const VendorAtom& vendorAtom) {
94 if (vendorAtom.atomId < 100000 || vendorAtom.atomId >= 200000) {
95 ALOGE("Atom ID %ld is not a valid vendor atom ID", (long)vendorAtom.atomId);
96 Counter::logIncrement(g_AtomErrorMetricName);
97 return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
98 -1, "Not a valid vendor atom ID");
99 }
100 if (vendorAtom.reverseDomainName.length() > 50) {
101 ALOGE("Vendor atom reverse domain name %s is too long.",
102 vendorAtom.reverseDomainName.c_str());
103 Counter::logIncrement(g_AtomErrorMetricName);
104 return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
105 -1, "Vendor atom reverse domain name is too long");
106 }
107 AStatsEvent* event = AStatsEvent_obtain();
108 AStatsEvent_setAtomId(event, vendorAtom.atomId);
109
110 if (vendorAtom.atomAnnotations) {
111 if (!write_atom_annotations(event, *vendorAtom.atomAnnotations)) {
112 AStatsEvent_release(event);
113 ALOGE("Atom ID %ld has incompatible atom level annotation", (long)vendorAtom.atomId);
114 Counter::logIncrement(g_AtomErrorMetricName);
115 return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
116 -1, "invalid atom annotation");
117 }
118 }
119
120 // populate map for quicker access for VendorAtomValue associated annotations by value index
121 std::map<int, int> fieldIndexToAnnotationSetMap;
122 if (vendorAtom.valuesAnnotations) {
123 const std::vector<std::optional<AnnotationSet>>& valuesAnnotations =
124 *vendorAtom.valuesAnnotations;
125 for (int i = 0; i < valuesAnnotations.size(); i++) {
126 if (valuesAnnotations[i]) {
127 fieldIndexToAnnotationSetMap[valuesAnnotations[i]->valueIndex] = i;
128 }
129 }
130 }
131
132 AStatsEvent_writeString(event, vendorAtom.reverseDomainName.c_str());
133 size_t atomValueIdx = 0;
134 for (const auto& atomValue : vendorAtom.values) {
135 switch (atomValue.getTag()) {
136 case VendorAtomValue::intValue:
137 AStatsEvent_writeInt32(event, atomValue.get<VendorAtomValue::intValue>());
138 break;
139 case VendorAtomValue::longValue:
140 AStatsEvent_writeInt64(event, atomValue.get<VendorAtomValue::longValue>());
141 break;
142 case VendorAtomValue::floatValue:
143 AStatsEvent_writeFloat(event, atomValue.get<VendorAtomValue::floatValue>());
144 break;
145 case VendorAtomValue::stringValue:
146 AStatsEvent_writeString(event,
147 atomValue.get<VendorAtomValue::stringValue>().c_str());
148 break;
149 case VendorAtomValue::boolValue:
150 AStatsEvent_writeBool(event, atomValue.get<VendorAtomValue::boolValue>());
151 break;
152 case VendorAtomValue::repeatedIntValue: {
153 const std::optional<std::vector<int>>& repeatedIntValue =
154 atomValue.get<VendorAtomValue::repeatedIntValue>();
155 if (!repeatedIntValue) {
156 AStatsEvent_writeInt32Array(event, {}, 0);
157 break;
158 }
159 AStatsEvent_writeInt32Array(event, repeatedIntValue->data(),
160 repeatedIntValue->size());
161 break;
162 }
163 case VendorAtomValue::repeatedLongValue: {
164 const std::optional<std::vector<int64_t>>& repeatedLongValue =
165 atomValue.get<VendorAtomValue::repeatedLongValue>();
166 if (!repeatedLongValue) {
167 AStatsEvent_writeInt64Array(event, {}, 0);
168 break;
169 }
170 AStatsEvent_writeInt64Array(event, repeatedLongValue->data(),
171 repeatedLongValue->size());
172 break;
173 }
174 case VendorAtomValue::repeatedFloatValue: {
175 const std::optional<std::vector<float>>& repeatedFloatValue =
176 atomValue.get<VendorAtomValue::repeatedFloatValue>();
177 if (!repeatedFloatValue) {
178 AStatsEvent_writeFloatArray(event, {}, 0);
179 break;
180 }
181 AStatsEvent_writeFloatArray(event, repeatedFloatValue->data(),
182 repeatedFloatValue->size());
183 break;
184 }
185 case VendorAtomValue::repeatedStringValue: {
186 const std::optional<std::vector<std::optional<std::string>>>& repeatedStringValue =
187 atomValue.get<VendorAtomValue::repeatedStringValue>();
188 if (!repeatedStringValue) {
189 AStatsEvent_writeStringArray(event, {}, 0);
190 break;
191 }
192 const std::vector<std::optional<std::string>>& repeatedStringVector =
193 *repeatedStringValue;
194 const char* cStringArray[repeatedStringVector.size()];
195
196 for (int i = 0; i < repeatedStringVector.size(); ++i) {
197 cStringArray[i] = repeatedStringVector[i].has_value()
198 ? repeatedStringVector[i]->c_str()
199 : "";
200 }
201
202 AStatsEvent_writeStringArray(event, cStringArray, repeatedStringVector.size());
203 break;
204 }
205 case VendorAtomValue::repeatedBoolValue: {
206 const std::optional<std::vector<bool>>& repeatedBoolValue =
207 atomValue.get<VendorAtomValue::repeatedBoolValue>();
208 if (!repeatedBoolValue) {
209 AStatsEvent_writeBoolArray(event, {}, 0);
210 break;
211 }
212 const std::vector<bool>& repeatedBoolVector = *repeatedBoolValue;
213 bool boolArray[repeatedBoolValue->size()];
214
215 for (int i = 0; i < repeatedBoolVector.size(); ++i) {
216 boolArray[i] = repeatedBoolVector[i];
217 }
218
219 AStatsEvent_writeBoolArray(event, boolArray, repeatedBoolVector.size());
220 break;
221 }
222 case VendorAtomValue::byteArrayValue: {
223 const std::optional<std::vector<uint8_t>>& byteArrayValue =
224 atomValue.get<VendorAtomValue::byteArrayValue>();
225 if (!byteArrayValue) {
226 AStatsEvent_writeByteArray(event, {}, 0);
227 break;
228 }
229 AStatsEvent_writeByteArray(event, byteArrayValue->data(), byteArrayValue->size());
230 break;
231 }
232 default: {
233 AStatsEvent_release(event);
234 ALOGE("Atom ID %ld has invalid atomValue.getTag", (long)vendorAtom.atomId);
235 Counter::logIncrement(g_AtomErrorMetricName);
236 return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
237 -1, "invalid atomValue.getTag");
238 break;
239 }
240 }
241
242 const auto& valueAnnotationIndex = fieldIndexToAnnotationSetMap.find(atomValueIdx);
243 if (valueAnnotationIndex != fieldIndexToAnnotationSetMap.end()) {
244 const std::vector<Annotation>& fieldAnnotations =
245 (*vendorAtom.valuesAnnotations)[valueAnnotationIndex->second]->annotations;
246 VLOG("Atom ID %ld has %ld annotations for field #%ld", (long)vendorAtom.atomId,
247 (long)fieldAnnotations.size(), (long)atomValueIdx + 2);
248 if (!write_field_annotations(event, fieldAnnotations)) {
249 AStatsEvent_release(event);
250 ALOGE("Atom ID %ld has incompatible field level annotation for field #%ld",
251 (long)vendorAtom.atomId, (long)atomValueIdx + 2);
252 Counter::logIncrement(g_AtomErrorMetricName);
253 return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
254 -1, "invalid atom field annotation");
255 }
256 }
257 atomValueIdx++;
258 }
259 AStatsEvent_build(event);
260 const int ret = AStatsEvent_write(event);
261 AStatsEvent_release(event);
262 if (ret <= 0) {
263 ALOGE("Error writing Atom ID %ld. Result: %d", (long)vendorAtom.atomId, ret);
264 Counter::logIncrement(g_AtomErrorMetricName);
265 }
266 return ret <= 0 ? ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(ret,
267 "report atom failed")
268 : ndk::ScopedAStatus::ok();
269 }
270
271 } // namespace stats
272 } // namespace frameworks
273 } // namespace android
274 } // namespace aidl
275