• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define DEBUG false  // STOPSHIP if true
18 #include "Log.h"
19 #include "MetricProducer.h"
20 
21 using android::util::FIELD_COUNT_REPEATED;
22 using android::util::FIELD_TYPE_ENUM;
23 using android::util::FIELD_TYPE_INT32;
24 using android::util::FIELD_TYPE_INT64;
25 using android::util::FIELD_TYPE_MESSAGE;
26 using android::util::ProtoOutputStream;
27 
28 namespace android {
29 namespace os {
30 namespace statsd {
31 
32 using std::map;
33 
34 // for ActiveMetric
35 const int FIELD_ID_ACTIVE_METRIC_ID = 1;
36 const int FIELD_ID_ACTIVE_METRIC_ACTIVATION = 2;
37 
38 // for ActiveEventActivation
39 const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_ATOM_MATCHER_INDEX = 1;
40 const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS = 2;
41 const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE = 3;
42 
onMatchedLogEventLocked(const size_t matcherIndex,const LogEvent & event)43 void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) {
44     if (!mIsActive) {
45         return;
46     }
47     int64_t eventTimeNs = event.GetElapsedTimestampNs();
48     // this is old event, maybe statsd restarted?
49     if (eventTimeNs < mTimeBaseNs) {
50         return;
51     }
52 
53     bool condition;
54     ConditionKey conditionKey;
55     std::unordered_set<HashableDimensionKey> dimensionKeysInCondition;
56     if (mConditionSliced) {
57         for (const auto& link : mMetric2ConditionLinks) {
58             getDimensionForCondition(event.getValues(), link, &conditionKey[link.conditionId]);
59         }
60         auto conditionState =
61             mWizard->query(mConditionTrackerIndex, conditionKey, mDimensionsInCondition,
62                            !mSameConditionDimensionsInTracker,
63                            !mHasLinksToAllConditionDimensionsInTracker,
64                            &dimensionKeysInCondition);
65         condition = (conditionState == ConditionState::kTrue);
66     } else {
67         // TODO: The unknown condition state is not handled here, we should fix it.
68         condition = mCondition == ConditionState::kTrue;
69     }
70 
71     if (mDimensionsInCondition.empty() && condition) {
72         dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY);
73     }
74 
75     HashableDimensionKey dimensionInWhat;
76     filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat);
77     MetricDimensionKey metricKey(dimensionInWhat, DEFAULT_DIMENSION_KEY);
78     for (const auto& conditionDimensionKey : dimensionKeysInCondition) {
79         metricKey.setDimensionKeyInCondition(conditionDimensionKey);
80         onMatchedLogEventInternalLocked(
81                 matcherIndex, metricKey, conditionKey, condition, event);
82     }
83     if (dimensionKeysInCondition.empty()) {
84         onMatchedLogEventInternalLocked(
85                 matcherIndex, metricKey, conditionKey, condition, event);
86     }
87 }
88 
evaluateActiveStateLocked(int64_t elapsedTimestampNs)89 bool MetricProducer::evaluateActiveStateLocked(int64_t elapsedTimestampNs) {
90     bool isActive = mEventActivationMap.empty();
91     for (auto& it : mEventActivationMap) {
92         if (it.second->state == ActivationState::kActive &&
93             elapsedTimestampNs > it.second->ttl_ns + it.second->start_ns) {
94             it.second->state = ActivationState::kNotActive;
95         }
96         if (it.second->state == ActivationState::kActive) {
97             isActive = true;
98         }
99     }
100     return isActive;
101 }
102 
flushIfExpire(int64_t elapsedTimestampNs)103 void MetricProducer::flushIfExpire(int64_t elapsedTimestampNs) {
104     std::lock_guard<std::mutex> lock(mMutex);
105     if (!mIsActive) {
106         return;
107     }
108     mIsActive = evaluateActiveStateLocked(elapsedTimestampNs);
109     if (!mIsActive) {
110         onActiveStateChangedLocked(elapsedTimestampNs);
111     }
112 }
113 
addActivation(int activationTrackerIndex,const ActivationType & activationType,int64_t ttl_seconds,int deactivationTrackerIndex)114 void MetricProducer::addActivation(int activationTrackerIndex, const ActivationType& activationType,
115         int64_t ttl_seconds, int deactivationTrackerIndex) {
116     std::lock_guard<std::mutex> lock(mMutex);
117     // When a metric producer does not depend on any activation, its mIsActive is true.
118     // Therefore, if this is the 1st activation, mIsActive will turn to false. Otherwise it does not
119     // change.
120     if  (mEventActivationMap.empty()) {
121         mIsActive = false;
122     }
123     std::shared_ptr<Activation> activation =
124             std::make_shared<Activation>(activationType, ttl_seconds * NS_PER_SEC);
125     mEventActivationMap.emplace(activationTrackerIndex, activation);
126     if (-1 != deactivationTrackerIndex) {
127         auto& deactivationList = mEventDeactivationMap[deactivationTrackerIndex];
128         deactivationList.push_back(activation);
129     }
130 }
131 
activateLocked(int activationTrackerIndex,int64_t elapsedTimestampNs)132 void MetricProducer::activateLocked(int activationTrackerIndex, int64_t elapsedTimestampNs) {
133     auto it = mEventActivationMap.find(activationTrackerIndex);
134     if (it == mEventActivationMap.end()) {
135         return;
136     }
137     auto& activation = it->second;
138     if (ACTIVATE_ON_BOOT == activation->activationType) {
139         if (ActivationState::kNotActive == activation->state) {
140             activation->state = ActivationState::kActiveOnBoot;
141         }
142         // If the Activation is already active or set to kActiveOnBoot, do nothing.
143         return;
144     }
145     activation->start_ns = elapsedTimestampNs;
146     activation->state = ActivationState::kActive;
147     bool oldActiveState = mIsActive;
148     mIsActive = true;
149     if (!oldActiveState) { // Metric went from not active to active.
150         onActiveStateChangedLocked(elapsedTimestampNs);
151     }
152 }
153 
cancelEventActivationLocked(int deactivationTrackerIndex)154 void MetricProducer::cancelEventActivationLocked(int deactivationTrackerIndex) {
155     auto it = mEventDeactivationMap.find(deactivationTrackerIndex);
156     if (it == mEventDeactivationMap.end()) {
157         return;
158     }
159     for (auto activationToCancelIt : it->second)  {
160         activationToCancelIt->state = ActivationState::kNotActive;
161     }
162 }
163 
loadActiveMetricLocked(const ActiveMetric & activeMetric,int64_t currentTimeNs)164 void MetricProducer::loadActiveMetricLocked(const ActiveMetric& activeMetric,
165                                             int64_t currentTimeNs) {
166     if (mEventActivationMap.size() == 0) {
167         return;
168     }
169     for (int i = 0; i < activeMetric.activation_size(); i++) {
170         const auto& activeEventActivation = activeMetric.activation(i);
171         auto it = mEventActivationMap.find(activeEventActivation.atom_matcher_index());
172         if (it == mEventActivationMap.end()) {
173             ALOGE("Saved event activation not found");
174             continue;
175         }
176         auto& activation = it->second;
177         // If the event activation does not have a state, assume it is active.
178         if (!activeEventActivation.has_state() ||
179                 activeEventActivation.state() == ActiveEventActivation::ACTIVE) {
180             // We don't want to change the ttl for future activations, so we set the start_ns
181             // such that start_ns + ttl_ns == currentTimeNs + remaining_ttl_nanos
182             activation->start_ns =
183                 currentTimeNs + activeEventActivation.remaining_ttl_nanos() - activation->ttl_ns;
184             activation->state = ActivationState::kActive;
185             mIsActive = true;
186         } else if (activeEventActivation.state() == ActiveEventActivation::ACTIVATE_ON_BOOT) {
187             activation->state = ActivationState::kActiveOnBoot;
188         }
189     }
190 }
191 
writeActiveMetricToProtoOutputStream(int64_t currentTimeNs,const DumpReportReason reason,ProtoOutputStream * proto)192 void MetricProducer::writeActiveMetricToProtoOutputStream(
193         int64_t currentTimeNs, const DumpReportReason reason, ProtoOutputStream* proto) {
194     proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_METRIC_ID, (long long)mMetricId);
195     for (auto& it : mEventActivationMap) {
196         const int atom_matcher_index = it.first;
197         const std::shared_ptr<Activation>& activation = it.second;
198 
199         if (ActivationState::kNotActive == activation->state ||
200                 (ActivationState::kActive == activation->state &&
201                  activation->start_ns + activation->ttl_ns < currentTimeNs)) {
202             continue;
203         }
204 
205         const uint64_t activationToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
206                 FIELD_ID_ACTIVE_METRIC_ACTIVATION);
207         proto->write(FIELD_TYPE_INT32 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_ATOM_MATCHER_INDEX,
208                 atom_matcher_index);
209         if (ActivationState::kActive == activation->state) {
210             const int64_t remainingTtlNs =
211                     activation->start_ns + activation->ttl_ns - currentTimeNs;
212             proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS,
213                     (long long)remainingTtlNs);
214             proto->write(FIELD_TYPE_ENUM | FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE,
215                     ActiveEventActivation::ACTIVE);
216 
217         } else if (ActivationState::kActiveOnBoot == activation->state) {
218             if (reason == DEVICE_SHUTDOWN || reason == TERMINATION_SIGNAL_RECEIVED) {
219                 proto->write(
220                         FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS,
221                         (long long)activation->ttl_ns);
222                 proto->write(FIELD_TYPE_ENUM | FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE,
223                                     ActiveEventActivation::ACTIVE);
224             } else if (reason == STATSCOMPANION_DIED) {
225                 // We are saving because of system server death, not due to a device shutdown.
226                 // Next time we load, we do not want to activate metrics that activate on boot.
227                 proto->write(FIELD_TYPE_ENUM | FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE,
228                                                     ActiveEventActivation::ACTIVATE_ON_BOOT);
229             }
230         }
231         proto->end(activationToken);
232     }
233 }
234 
235 }  // namespace statsd
236 }  // namespace os
237 }  // namespace android
238