blob: 0f01507c9f2e4c4b61bbd9f4e80f71c5e81616ac [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 Sharaienko3092c962021-02-01 23:38:12 +000025#include <log/log.h>
Vova Sharaienko88720f42023-01-28 05:55:18 +000026#include <stats_annotations.h>
27#include <stats_event.h>
Vova Sharaienko3092c962021-02-01 23:38:12 +000028#include <statslog.h>
29
Vova Sharaienko88720f42023-01-28 05:55:18 +000030#include <unordered_map>
31
Vova Sharaienko3092c962021-02-01 23:38:12 +000032namespace aidl {
33namespace android {
34namespace frameworks {
35namespace stats {
36
Vova Sharaienko88720f42023-01-28 05:55:18 +000037template <typename E>
38constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept {
39 return static_cast<typename std::underlying_type<E>::type>(e);
40}
41
Vova Sharaienko40dc2402023-01-28 05:51:00 +000042StatsHal::StatsHal() {
43}
Vova Sharaienko3092c962021-02-01 23:38:12 +000044
Vova Sharaienko88720f42023-01-28 05:55:18 +000045bool write_annotation(AStatsEvent* event, const Annotation& annotation) {
46 switch (annotation.value.getTag()) {
47 case AnnotationValue::boolValue: {
48 AStatsEvent_addBoolAnnotation(event, to_underlying(annotation.annotationId),
49 annotation.value.get<AnnotationValue::boolValue>());
50 break;
51 }
52 case AnnotationValue::intValue: {
53 AStatsEvent_addInt32Annotation(event, to_underlying(annotation.annotationId),
54 annotation.value.get<AnnotationValue::intValue>());
55 break;
56 }
57 default: {
58 return false;
59 }
60 }
61 return true;
62}
63
64bool write_atom_annotations(AStatsEvent* event,
65 const std::vector<std::optional<Annotation>>& annotations) {
66 for (const auto& atomAnnotation : annotations) {
67 if (!atomAnnotation) {
68 return false;
69 }
70 if (!write_annotation(event, *atomAnnotation)) {
71 return false;
72 }
73 }
74 return true;
75}
76
77bool write_field_annotations(AStatsEvent* event, const std::vector<Annotation>& annotations) {
78 for (const auto& fieldAnnotation : annotations) {
79 if (!write_annotation(event, fieldAnnotation)) {
80 return false;
81 }
82 }
83 return true;
84}
85
Vova Sharaienko3092c962021-02-01 23:38:12 +000086ndk::ScopedAStatus StatsHal::reportVendorAtom(const VendorAtom& vendorAtom) {
Vova Sharaienko3092c962021-02-01 23:38:12 +000087 if (vendorAtom.atomId < 100000 || vendorAtom.atomId >= 200000) {
Vova Sharaienko40dc2402023-01-28 05:51:00 +000088 ALOGE("Atom ID %ld is not a valid vendor atom ID", (long)vendorAtom.atomId);
Vova Sharaienko3092c962021-02-01 23:38:12 +000089 return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
Vova Sharaienko40dc2402023-01-28 05:51:00 +000090 -1, "Not a valid vendor atom ID");
Vova Sharaienko3092c962021-02-01 23:38:12 +000091 }
Vova Sharaienko5764fc12022-12-09 02:40:35 +000092 if (vendorAtom.reverseDomainName.length() > 50) {
93 ALOGE("Vendor atom reverse domain name %s is too long.",
Vova Sharaienko40dc2402023-01-28 05:51:00 +000094 vendorAtom.reverseDomainName.c_str());
Vova Sharaienko3092c962021-02-01 23:38:12 +000095 return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
Vova Sharaienko40dc2402023-01-28 05:51:00 +000096 -1, "Vendor atom reverse domain name is too long");
Vova Sharaienko3092c962021-02-01 23:38:12 +000097 }
98 AStatsEvent* event = AStatsEvent_obtain();
99 AStatsEvent_setAtomId(event, vendorAtom.atomId);
Vova Sharaienko88720f42023-01-28 05:55:18 +0000100
101 if (vendorAtom.atomAnnotations) {
102 if (!write_atom_annotations(event, *vendorAtom.atomAnnotations)) {
103 ALOGE("Atom ID %ld has incompatible atom level annotation", (long)vendorAtom.atomId);
104 AStatsEvent_release(event);
105 return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
106 -1, "invalid atom annotation");
107 }
108 }
109
110 // populate map for quickier access for VendorAtomValue associated annotations by value index
111 std::unordered_map<int, int> fieldIndexToAnnotationSetMap;
112 if (vendorAtom.valuesAnnotations) {
113 const std::vector<std::optional<AnnotationSet>>& valuesAnnotations =
114 *vendorAtom.valuesAnnotations;
115 for (int i = 0; i < valuesAnnotations.size(); i++) {
116 if (valuesAnnotations[i]) {
117 fieldIndexToAnnotationSetMap[valuesAnnotations[i]->valueIndex] = i;
118 }
119 }
120 }
121
Vova Sharaienko3092c962021-02-01 23:38:12 +0000122 AStatsEvent_writeString(event, vendorAtom.reverseDomainName.c_str());
Vova Sharaienko88720f42023-01-28 05:55:18 +0000123 size_t atomValueIdx = 0;
Vova Sharaienko3092c962021-02-01 23:38:12 +0000124 for (const auto& atomValue : vendorAtom.values) {
125 switch (atomValue.getTag()) {
126 case VendorAtomValue::intValue:
Vova Sharaienko40dc2402023-01-28 05:51:00 +0000127 AStatsEvent_writeInt32(event, atomValue.get<VendorAtomValue::intValue>());
Vova Sharaienko3092c962021-02-01 23:38:12 +0000128 break;
129 case VendorAtomValue::longValue:
Vova Sharaienko40dc2402023-01-28 05:51:00 +0000130 AStatsEvent_writeInt64(event, atomValue.get<VendorAtomValue::longValue>());
Vova Sharaienko3092c962021-02-01 23:38:12 +0000131 break;
132 case VendorAtomValue::floatValue:
Vova Sharaienko40dc2402023-01-28 05:51:00 +0000133 AStatsEvent_writeFloat(event, atomValue.get<VendorAtomValue::floatValue>());
Vova Sharaienko3092c962021-02-01 23:38:12 +0000134 break;
135 case VendorAtomValue::stringValue:
136 AStatsEvent_writeString(event,
Vova Sharaienko40dc2402023-01-28 05:51:00 +0000137 atomValue.get<VendorAtomValue::stringValue>().c_str());
Vova Sharaienko3092c962021-02-01 23:38:12 +0000138 break;
Vova Sharaienko5540ebc2022-04-08 05:53:43 +0000139 case VendorAtomValue::boolValue:
Vova Sharaienko40dc2402023-01-28 05:51:00 +0000140 AStatsEvent_writeBool(event, atomValue.get<VendorAtomValue::boolValue>());
Vova Sharaienko5540ebc2022-04-08 05:53:43 +0000141 break;
tsaichristine5f5f5792022-09-09 16:26:31 -0700142 case VendorAtomValue::repeatedIntValue: {
143 const std::optional<std::vector<int>>& repeatedIntValue =
144 atomValue.get<VendorAtomValue::repeatedIntValue>();
tsaichristinee83b5f22022-09-26 18:33:05 -0700145 if (!repeatedIntValue) {
146 AStatsEvent_writeInt32Array(event, {}, 0);
147 break;
148 }
tsaichristine5f5f5792022-09-09 16:26:31 -0700149 AStatsEvent_writeInt32Array(event, repeatedIntValue->data(),
150 repeatedIntValue->size());
151 break;
152 }
153 case VendorAtomValue::repeatedLongValue: {
154 const std::optional<std::vector<int64_t>>& repeatedLongValue =
155 atomValue.get<VendorAtomValue::repeatedLongValue>();
tsaichristinee83b5f22022-09-26 18:33:05 -0700156 if (!repeatedLongValue) {
157 AStatsEvent_writeInt64Array(event, {}, 0);
158 break;
159 }
tsaichristine5f5f5792022-09-09 16:26:31 -0700160 AStatsEvent_writeInt64Array(event, repeatedLongValue->data(),
161 repeatedLongValue->size());
162 break;
163 }
164 case VendorAtomValue::repeatedFloatValue: {
165 const std::optional<std::vector<float>>& repeatedFloatValue =
166 atomValue.get<VendorAtomValue::repeatedFloatValue>();
tsaichristinee83b5f22022-09-26 18:33:05 -0700167 if (!repeatedFloatValue) {
168 AStatsEvent_writeFloatArray(event, {}, 0);
169 break;
170 }
tsaichristine5f5f5792022-09-09 16:26:31 -0700171 AStatsEvent_writeFloatArray(event, repeatedFloatValue->data(),
172 repeatedFloatValue->size());
173 break;
174 }
175 case VendorAtomValue::repeatedStringValue: {
176 const std::optional<std::vector<std::optional<std::string>>>& repeatedStringValue =
177 atomValue.get<VendorAtomValue::repeatedStringValue>();
tsaichristinee83b5f22022-09-26 18:33:05 -0700178 if (!repeatedStringValue) {
179 AStatsEvent_writeStringArray(event, {}, 0);
180 break;
181 }
tsaichristine5f5f5792022-09-09 16:26:31 -0700182 const std::vector<std::optional<std::string>>& repeatedStringVector =
183 *repeatedStringValue;
184 const char* cStringArray[repeatedStringVector.size()];
185
186 for (int i = 0; i < repeatedStringVector.size(); ++i) {
tsaichristinee83b5f22022-09-26 18:33:05 -0700187 cStringArray[i] = repeatedStringVector[i].has_value()
Vova Sharaienko40dc2402023-01-28 05:51:00 +0000188 ? repeatedStringVector[i]->c_str()
189 : "";
tsaichristine5f5f5792022-09-09 16:26:31 -0700190 }
191
192 AStatsEvent_writeStringArray(event, cStringArray, repeatedStringVector.size());
193 break;
194 }
195 case VendorAtomValue::repeatedBoolValue: {
196 const std::optional<std::vector<bool>>& repeatedBoolValue =
197 atomValue.get<VendorAtomValue::repeatedBoolValue>();
tsaichristinee83b5f22022-09-26 18:33:05 -0700198 if (!repeatedBoolValue) {
199 AStatsEvent_writeBoolArray(event, {}, 0);
200 break;
201 }
tsaichristine5f5f5792022-09-09 16:26:31 -0700202 const std::vector<bool>& repeatedBoolVector = *repeatedBoolValue;
203 bool boolArray[repeatedBoolValue->size()];
204
205 for (int i = 0; i < repeatedBoolVector.size(); ++i) {
206 boolArray[i] = repeatedBoolVector[i];
207 }
208
209 AStatsEvent_writeBoolArray(event, boolArray, repeatedBoolVector.size());
210 break;
211 }
212 case VendorAtomValue::byteArrayValue: {
213 const std::optional<std::vector<uint8_t>>& byteArrayValue =
214 atomValue.get<VendorAtomValue::byteArrayValue>();
tsaichristinee83b5f22022-09-26 18:33:05 -0700215 if (!byteArrayValue) {
216 AStatsEvent_writeByteArray(event, {}, 0);
217 break;
218 }
tsaichristine5f5f5792022-09-09 16:26:31 -0700219 AStatsEvent_writeByteArray(event, byteArrayValue->data(), byteArrayValue->size());
220 break;
221 }
Vova Sharaienko88720f42023-01-28 05:55:18 +0000222 default: {
223 AStatsEvent_release(event);
224 ALOGE("Atom ID %ld has invalid atomValue.getTag", (long)vendorAtom.atomId);
225 return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
226 -1, "invalid atomValue.getTag");
227 break;
228 }
Vova Sharaienko3092c962021-02-01 23:38:12 +0000229 }
Vova Sharaienko88720f42023-01-28 05:55:18 +0000230
231 const auto& valueAnnotationIndex = fieldIndexToAnnotationSetMap.find(atomValueIdx);
232 if (valueAnnotationIndex != fieldIndexToAnnotationSetMap.end()) {
233 const std::vector<Annotation>& fieldAnnotations =
234 (*vendorAtom.valuesAnnotations)[valueAnnotationIndex->second]->annotations;
235 VLOG("Atom ID %ld has %ld annotations for field #%ld", (long)vendorAtom.atomId,
236 (long)fieldAnnotations.size(), (long)atomValueIdx + 2);
237 if (!write_field_annotations(event, fieldAnnotations)) {
238 ALOGE("Atom ID %ld has incompatible field level annotation for field #%ld",
239 (long)vendorAtom.atomId, (long)atomValueIdx + 2);
240 AStatsEvent_release(event);
241 return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
242 -1, "invalid atom field annotation");
243 }
244 }
245 atomValueIdx++;
Vova Sharaienko3092c962021-02-01 23:38:12 +0000246 }
247 AStatsEvent_build(event);
248 const int ret = AStatsEvent_write(event);
249 AStatsEvent_release(event);
Vova Sharaienko88720f42023-01-28 05:55:18 +0000250 if (ret <= 0) {
251 ALOGE("Error writing Atom ID %ld. Result: %d", (long)vendorAtom.atomId, ret);
252 }
Vova Sharaienko40dc2402023-01-28 05:51:00 +0000253 return ret <= 0 ? ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(ret,
254 "report atom failed")
255 : ndk::ScopedAStatus::ok();
Vova Sharaienko3092c962021-02-01 23:38:12 +0000256}
257
258} // namespace stats
259} // namespace frameworks
260} // namespace android
261} // namespace aidl