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)23std::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