1 /*
2  * Copyright (C) 2023 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 #include "logd/logevent_util.h"
18 
19 namespace android {
20 namespace os {
21 namespace statsd {
22 
toSocketLossInfo(const LogEvent & event)23 std::optional<SocketLossInfo> toSocketLossInfo(const LogEvent& event) {
24     const std::vector<FieldValue>& logEventValues = event.getValues();
25 
26     // check that logEvent contains the minimum required number of values to represent
27     // SocketLossInfo atom data
28     if (logEventValues.size() < 7) {
29         // atom content is invalid
30         return std::nullopt;
31     }
32 
33     SocketLossInfo result;
34 
35     result.uid = event.GetUid();
36     if (logEventValues[1].mField.getPosAtDepth(0) == 2 &&
37         logEventValues[1].mValue.getType() == LONG) {
38         result.firstLossTsNanos = logEventValues[1].mValue.long_value;
39     } else {
40         // atom content is invalid
41         return std::nullopt;
42     }
43 
44     if (logEventValues[2].mField.getPosAtDepth(0) == 3 &&
45         logEventValues[2].mValue.getType() == LONG) {
46         result.lastLossTsNanos = logEventValues[2].mValue.long_value;
47     } else {
48         // atom content is invalid
49         return std::nullopt;
50     }
51 
52     if (logEventValues[3].mField.getPosAtDepth(0) == 4 &&
53         logEventValues[3].mValue.getType() == INT) {
54         result.overflowCounter = logEventValues[3].mValue.int_value;
55     } else {
56         // atom content is invalid
57         return std::nullopt;
58     }
59 
60     // skipping uid + first & last timestamps + overflowCounter
61     const int arraysOffset = 4;
62 
63     // expected to have 3 arrays of equal size
64     const size_t expectedEntriesCount = (logEventValues.size() - arraysOffset) / 3;
65 
66     // first array holds errors, then come tags & the 3rd array holds counts
67     result.errors.reserve(expectedEntriesCount);
68     result.atomIds.reserve(expectedEntriesCount);
69     result.counts.reserve(expectedEntriesCount);
70 
71     // scan over errors entries
72     std::vector<FieldValue>::const_iterator valuesIt = logEventValues.begin() + arraysOffset;
73     while (valuesIt != logEventValues.end() && valuesIt->mField.getPosAtDepth(0) == 5 &&
74            valuesIt->mValue.getType() == INT) {
75         result.errors.push_back(valuesIt->mValue.int_value);
76         valuesIt++;
77     }
78     if (result.errors.size() != expectedEntriesCount) {
79         // atom content is invalid
80         return std::nullopt;
81     }
82 
83     while (valuesIt != logEventValues.end() && valuesIt->mField.getPosAtDepth(0) == 6 &&
84            valuesIt->mValue.getType() == INT) {
85         result.atomIds.push_back(valuesIt->mValue.int_value);
86         valuesIt++;
87     }
88     if (result.atomIds.size() != expectedEntriesCount) {
89         // atom content is invalid
90         return std::nullopt;
91     }
92 
93     while (valuesIt != logEventValues.end() && valuesIt->mField.getPosAtDepth(0) == 7 &&
94            valuesIt->mValue.getType() == INT) {
95         result.counts.push_back(valuesIt->mValue.int_value);
96         valuesIt++;
97     }
98     if (result.counts.size() != expectedEntriesCount) {
99         // atom content is invalid
100         return std::nullopt;
101     }
102 
103     if (valuesIt != logEventValues.end()) {
104         // atom content is invalid, some extra values are present
105         return std::nullopt;
106     }
107 
108     return result;
109 }
110 
111 }  // namespace statsd
112 }  // namespace os
113 }  // namespace android
114