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 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 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 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 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 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 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 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 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