StatsLogProcessor.cpp revision ae2df01aae2ee7076af875c04e991140f685f733
1/* 2 * Copyright (C) 2017 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 "Log.h" 18#include "statslog.h" 19 20#include "StatsLogProcessor.h" 21#include "metrics/CountMetricProducer.h" 22#include "stats_util.h" 23 24#include <log/log_event_list.h> 25#include <utils/Errors.h> 26 27using namespace android; 28using android::util::FIELD_COUNT_REPEATED; 29using android::util::FIELD_TYPE_BOOL; 30using android::util::FIELD_TYPE_FLOAT; 31using android::util::FIELD_TYPE_INT32; 32using android::util::FIELD_TYPE_INT64; 33using android::util::FIELD_TYPE_MESSAGE; 34using android::util::FIELD_TYPE_STRING; 35using android::util::ProtoOutputStream; 36using std::make_unique; 37using std::unique_ptr; 38using std::vector; 39 40namespace android { 41namespace os { 42namespace statsd { 43 44// for ConfigMetricsReport 45const int FIELD_ID_CONFIG_KEY = 1; 46const int FIELD_ID_METRICS = 2; 47const int FIELD_ID_UID_MAP = 3; 48// for ConfigKey 49const int FIELD_ID_UID = 1; 50const int FIELD_ID_NAME = 2; 51 52StatsLogProcessor::StatsLogProcessor(const sp<UidMap>& uidMap, 53 const std::function<void(const vector<uint8_t>&)>& pushLog) 54 : mUidMap(uidMap), mPushLog(pushLog) { 55} 56 57StatsLogProcessor::~StatsLogProcessor() { 58} 59 60// TODO: what if statsd service restarts? How do we know what logs are already processed before? 61void StatsLogProcessor::OnLogEvent(const LogEvent& msg) { 62 // pass the event to metrics managers. 63 for (auto& pair : mMetricsManagers) { 64 pair.second->onLogEvent(msg); 65 flushIfNecessary(msg.GetTimestampNs(), pair.first, pair.second); 66 } 67 68 // Hard-coded logic to update the isolated uid's in the uid-map. 69 // The field numbers need to be currently updated by hand with atoms.proto 70 if (msg.GetTagId() == android::util::ISOLATED_UID_CHANGED) { 71 status_t err = NO_ERROR, err2 = NO_ERROR, err3 = NO_ERROR; 72 bool is_create = msg.GetBool(3, &err); 73 auto parent_uid = int(msg.GetLong(1, &err2)); 74 auto isolated_uid = int(msg.GetLong(2, &err3)); 75 if (err == NO_ERROR && err2 == NO_ERROR && err3 == NO_ERROR) { 76 if (is_create) { 77 mUidMap->assignIsolatedUid(isolated_uid, parent_uid); 78 } else { 79 mUidMap->removeIsolatedUid(isolated_uid, parent_uid); 80 } 81 } 82 } 83} 84 85void StatsLogProcessor::OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config) { 86 auto it = mMetricsManagers.find(key); 87 if (it != mMetricsManagers.end()) { 88 it->second->finish(); 89 } 90 91 ALOGD("Updated configuration for key %s", key.ToString().c_str()); 92 93 unique_ptr<MetricsManager> newMetricsManager = std::make_unique<MetricsManager>(config); 94 if (newMetricsManager->isConfigValid()) { 95 mUidMap->OnConfigUpdated(key); 96 mMetricsManagers[key] = std::move(newMetricsManager); 97 // Why doesn't this work? mMetricsManagers.insert({key, std::move(newMetricsManager)}); 98 ALOGD("StatsdConfig valid"); 99 } else { 100 // If there is any error in the config, don't use it. 101 ALOGD("StatsdConfig NOT valid"); 102 } 103} 104 105vector<uint8_t> StatsLogProcessor::onDumpReport(const ConfigKey& key) { 106 auto it = mMetricsManagers.find(key); 107 if (it == mMetricsManagers.end()) { 108 ALOGW("Config source %s does not exist", key.ToString().c_str()); 109 return vector<uint8_t>(); 110 } 111 112 ProtoOutputStream proto; 113 114 // Fill in ConfigKey. 115 long long configKeyToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_CONFIG_KEY); 116 proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID, key.GetUid()); 117 proto.write(FIELD_TYPE_STRING | FIELD_ID_NAME, key.GetName()); 118 proto.end(configKeyToken); 119 120 // Fill in StatsLogReport's. 121 for (auto& m : it->second->onDumpReport()) { 122 // Add each vector of StatsLogReport into a repeated field. 123 proto.write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_METRICS, 124 reinterpret_cast<char*>(m.get()->data()), m.get()->size()); 125 } 126 127 // Fill in UidMap. 128 auto uidMap = mUidMap->getOutput(key); 129 const int uidMapSize = uidMap.ByteSize(); 130 char uidMapBuffer[uidMapSize]; 131 uidMap.SerializeToArray(&uidMapBuffer[0], uidMapSize); 132 proto.write(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP, uidMapBuffer, uidMapSize); 133 134 vector<uint8_t> buffer(proto.size()); 135 size_t pos = 0; 136 auto iter = proto.data(); 137 while (iter.readBuffer() != NULL) { 138 size_t toRead = iter.currentToRead(); 139 std::memcpy(&buffer[pos], iter.readBuffer(), toRead); 140 pos += toRead; 141 iter.rp()->move(toRead); 142 } 143 144 return buffer; 145} 146 147void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) { 148 auto it = mMetricsManagers.find(key); 149 if (it != mMetricsManagers.end()) { 150 it->second->finish(); 151 mMetricsManagers.erase(it); 152 mUidMap->OnConfigRemoved(key); 153 } 154 auto flushTime = mLastFlushTimes.find(key); 155 if (flushTime != mLastFlushTimes.end()) { 156 mLastFlushTimes.erase(flushTime); 157 } 158} 159 160void StatsLogProcessor::flushIfNecessary(uint64_t timestampNs, 161 const ConfigKey& key, 162 const unique_ptr<MetricsManager>& metricsManager) { 163 auto lastFlushNs = mLastFlushTimes.find(key); 164 if (lastFlushNs != mLastFlushTimes.end()) { 165 if (timestampNs - lastFlushNs->second < kMinFlushPeriod) { 166 return; 167 } 168 } 169 170 size_t totalBytes = metricsManager->byteSize(); 171 if (totalBytes > kMaxSerializedBytes) { 172 flush(); 173 mLastFlushTimes[key] = std::move(timestampNs); 174 } 175} 176 177void StatsLogProcessor::flush() { 178 // TODO: Take ConfigKey as an argument and flush metrics related to the 179 // ConfigKey. Also, create a wrapper that holds a repeated field of 180 // StatsLogReport's. 181 /* 182 StatsLogReport logReport; 183 const int numBytes = logReport.ByteSize(); 184 vector<uint8_t> logReportBuffer(numBytes); 185 logReport.SerializeToArray(&logReportBuffer[0], numBytes); 186 mPushLog(logReportBuffer); 187 */ 188} 189 190} // namespace statsd 191} // namespace os 192} // namespace android 193