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