• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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