StatsLogProcessor.cpp revision 7c334a129e93e405a72e8299a1cd928af079d14f
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 sp<AnomalyMonitor>& anomalyMonitor, 54 const std::function<void(const ConfigKey&)>& sendBroadcast) 55 : mUidMap(uidMap), mAnomalyMonitor(anomalyMonitor), mSendBroadcast(sendBroadcast) { 56} 57 58StatsLogProcessor::~StatsLogProcessor() { 59} 60 61void StatsLogProcessor::onAnomalyAlarmFired( 62 const uint64_t timestampNs, 63 unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> anomalySet) { 64 for (const auto& anomaly : anomalySet) { 65 for (const auto& itr : mMetricsManagers) { 66 itr.second->onAnomalyAlarmFired(timestampNs, anomaly); 67 } 68 } 69} 70 71// TODO: what if statsd service restarts? How do we know what logs are already processed before? 72void StatsLogProcessor::OnLogEvent(const LogEvent& msg) { 73 // pass the event to metrics managers. 74 for (auto& pair : mMetricsManagers) { 75 pair.second->onLogEvent(msg); 76 flushIfNecessary(msg.GetTimestampNs(), pair.first, pair.second); 77 } 78 79 // Hard-coded logic to update the isolated uid's in the uid-map. 80 // The field numbers need to be currently updated by hand with atoms.proto 81 if (msg.GetTagId() == android::util::ISOLATED_UID_CHANGED) { 82 status_t err = NO_ERROR, err2 = NO_ERROR, err3 = NO_ERROR; 83 bool is_create = msg.GetBool(3, &err); 84 auto parent_uid = int(msg.GetLong(1, &err2)); 85 auto isolated_uid = int(msg.GetLong(2, &err3)); 86 if (err == NO_ERROR && err2 == NO_ERROR && err3 == NO_ERROR) { 87 if (is_create) { 88 mUidMap->assignIsolatedUid(isolated_uid, parent_uid); 89 } else { 90 mUidMap->removeIsolatedUid(isolated_uid, parent_uid); 91 } 92 } 93 } 94} 95 96void StatsLogProcessor::OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config) { 97 auto it = mMetricsManagers.find(key); 98 if (it != mMetricsManagers.end()) { 99 it->second->finish(); 100 } 101 102 ALOGD("Updated configuration for key %s", key.ToString().c_str()); 103 104 unique_ptr<MetricsManager> newMetricsManager = std::make_unique<MetricsManager>(config); 105 if (newMetricsManager->isConfigValid()) { 106 mUidMap->OnConfigUpdated(key); 107 newMetricsManager->setAnomalyMonitor(mAnomalyMonitor); 108 mMetricsManagers[key] = std::move(newMetricsManager); 109 // Why doesn't this work? mMetricsManagers.insert({key, std::move(newMetricsManager)}); 110 ALOGD("StatsdConfig valid"); 111 } else { 112 // If there is any error in the config, don't use it. 113 ALOGD("StatsdConfig NOT valid"); 114 } 115} 116 117size_t StatsLogProcessor::GetMetricsSize(const ConfigKey& key) const { 118 auto it = mMetricsManagers.find(key); 119 if (it == mMetricsManagers.end()) { 120 ALOGW("Config source %s does not exist", key.ToString().c_str()); 121 return 0; 122 } 123 return it->second->byteSize(); 124} 125 126void StatsLogProcessor::onDumpReport(const ConfigKey& key, vector<uint8_t>* outData) { 127 auto it = mMetricsManagers.find(key); 128 if (it == mMetricsManagers.end()) { 129 ALOGW("Config source %s does not exist", key.ToString().c_str()); 130 return; 131 } 132 133 // This allows another broadcast to be sent within the rate-limit period if we get close to 134 // filling the buffer again soon. 135 mBroadcastTimesMutex.lock(); 136 mLastBroadcastTimes.erase(key); 137 mBroadcastTimesMutex.unlock(); 138 139 ProtoOutputStream proto; 140 141 // Fill in ConfigKey. 142 long long configKeyToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_CONFIG_KEY); 143 proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID, key.GetUid()); 144 proto.write(FIELD_TYPE_STRING | FIELD_ID_NAME, key.GetName()); 145 proto.end(configKeyToken); 146 147 // Fill in StatsLogReport's. 148 for (auto& m : it->second->onDumpReport()) { 149 // Add each vector of StatsLogReport into a repeated field. 150 proto.write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_METRICS, 151 reinterpret_cast<char*>(m.get()->data()), m.get()->size()); 152 } 153 154 // Fill in UidMap. 155 auto uidMap = mUidMap->getOutput(key); 156 const int uidMapSize = uidMap.ByteSize(); 157 char uidMapBuffer[uidMapSize]; 158 uidMap.SerializeToArray(&uidMapBuffer[0], uidMapSize); 159 proto.write(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP, uidMapBuffer, uidMapSize); 160 161 if (outData != nullptr) { 162 outData->clear(); 163 outData->resize(proto.size()); 164 size_t pos = 0; 165 auto iter = proto.data(); 166 while (iter.readBuffer() != NULL) { 167 size_t toRead = iter.currentToRead(); 168 std::memcpy(&((*outData)[pos]), iter.readBuffer(), toRead); 169 pos += toRead; 170 iter.rp()->move(toRead); 171 } 172 } 173} 174 175void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) { 176 auto it = mMetricsManagers.find(key); 177 if (it != mMetricsManagers.end()) { 178 it->second->finish(); 179 mMetricsManagers.erase(it); 180 mUidMap->OnConfigRemoved(key); 181 } 182 183 std::lock_guard<std::mutex> lock(mBroadcastTimesMutex); 184 mLastBroadcastTimes.erase(key); 185} 186 187void StatsLogProcessor::flushIfNecessary(uint64_t timestampNs, 188 const ConfigKey& key, 189 const unique_ptr<MetricsManager>& metricsManager) { 190 std::lock_guard<std::mutex> lock(mBroadcastTimesMutex); 191 192 size_t totalBytes = metricsManager->byteSize(); 193 if (totalBytes > .9 * kMaxSerializedBytes) { // Send broadcast so that receivers can pull data. 194 auto lastFlushNs = mLastBroadcastTimes.find(key); 195 if (lastFlushNs != mLastBroadcastTimes.end()) { 196 if (timestampNs - lastFlushNs->second < kMinBroadcastPeriod) { 197 return; 198 } 199 } 200 mLastBroadcastTimes[key] = timestampNs; 201 ALOGD("StatsD requesting broadcast for %s", key.ToString().c_str()); 202 mSendBroadcast(key); 203 } else if (totalBytes > kMaxSerializedBytes) { // Too late. We need to start clearing data. 204 // We ignore the return value so we force each metric producer to clear its contents. 205 metricsManager->onDumpReport(); 206 ALOGD("StatsD had to toss out metrics for %s", key.ToString().c_str()); 207 } 208} 209 210} // namespace statsd 211} // namespace os 212} // namespace android 213