Home | History | Annotate | Download | only in metrics
      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