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 STATSD_DEBUG false  // STOPSHIP if true
18  #include "Log.h"
19  
20  #include "StatsPuller.h"
21  
22  #include "StatsPullerManager.h"
23  #include "guardrail/StatsdStats.h"
24  #include "puller_util.h"
25  #include "stats_log_util.h"
26  #include "utils/api_tracing.h"
27  
28  namespace android {
29  namespace os {
30  namespace statsd {
31  
32  using std::lock_guard;
33  
34  sp<UidMap> StatsPuller::mUidMap = nullptr;
SetUidMap(const sp<UidMap> & uidMap)35  void StatsPuller::SetUidMap(const sp<UidMap>& uidMap) { mUidMap = uidMap; }
36  
StatsPuller(const int tagId,const int64_t coolDownNs,const int64_t pullTimeoutNs,const std::vector<int> & additiveFields)37  StatsPuller::StatsPuller(const int tagId, const int64_t coolDownNs, const int64_t pullTimeoutNs,
38                           const std::vector<int>& additiveFields)
39      : mTagId(tagId),
40        mPullTimeoutNs(pullTimeoutNs),
41        mCoolDownNs(coolDownNs),
42        mAdditiveFields(additiveFields),
43        mLastPullTimeNs(0),
44        mLastEventTimeNs(0) {
45  }
46  
Pull(const int64_t eventTimeNs,std::vector<std::shared_ptr<LogEvent>> * data)47  PullErrorCode StatsPuller::Pull(const int64_t eventTimeNs,
48                                  std::vector<std::shared_ptr<LogEvent>>* data) {
49      ATRACE_CALL();
50      lock_guard<std::mutex> lock(mLock);
51      const int64_t elapsedTimeNs = getElapsedRealtimeNs();
52      const int64_t systemUptimeMillis = getSystemUptimeMillis();
53      StatsdStats::getInstance().notePull(mTagId);
54      const bool shouldUseCache =
55              (mLastEventTimeNs == eventTimeNs) || (elapsedTimeNs - mLastPullTimeNs < mCoolDownNs);
56      if (shouldUseCache) {
57          if (mHasGoodData) {
58              (*data) = mCachedData;
59              StatsdStats::getInstance().notePullFromCache(mTagId);
60  
61          }
62          return mHasGoodData ? PULL_SUCCESS : PULL_FAIL;
63      }
64      if (mLastPullTimeNs > 0) {
65          StatsdStats::getInstance().updateMinPullIntervalSec(
66                  mTagId, (elapsedTimeNs - mLastPullTimeNs) / NS_PER_SEC);
67      }
68      mCachedData.clear();
69      mLastPullTimeNs = elapsedTimeNs;
70      mLastEventTimeNs = eventTimeNs;
71      PullErrorCode status = PullInternal(&mCachedData);
72      mHasGoodData = (status == PULL_SUCCESS);
73      if (!mHasGoodData) {
74          return status;
75      }
76      const int64_t pullElapsedDurationNs = getElapsedRealtimeNs() - elapsedTimeNs;
77      const int64_t pullSystemUptimeDurationMillis = getSystemUptimeMillis() - systemUptimeMillis;
78      StatsdStats::getInstance().notePullTime(mTagId, pullElapsedDurationNs);
79      const bool pullTimeOut = pullElapsedDurationNs > mPullTimeoutNs;
80      if (pullTimeOut) {
81          // Something went wrong. Discard the data.
82          mCachedData.clear();
83          mHasGoodData = false;
84          StatsdStats::getInstance().notePullTimeout(
85                  mTagId, pullSystemUptimeDurationMillis, NanoToMillis(pullElapsedDurationNs));
86          ALOGW("Pull for atom %d exceeds timeout %lld nano seconds.", mTagId,
87                (long long)pullElapsedDurationNs);
88          return PULL_FAIL;
89      }
90  
91      if (mCachedData.size() > 0) {
92          mapAndMergeIsolatedUidsToHostUid(mCachedData, mUidMap, mTagId, mAdditiveFields);
93      }
94  
95      if (mCachedData.empty()) {
96          VLOG("Data pulled is empty");
97          StatsdStats::getInstance().noteEmptyData(mTagId);
98      }
99  
100      (*data) = mCachedData;
101      return PULL_SUCCESS;
102  }
103  
ForceClearCache()104  int StatsPuller::ForceClearCache() {
105      return clearCache();
106  }
107  
clearCache()108  int StatsPuller::clearCache() {
109      lock_guard<std::mutex> lock(mLock);
110      return clearCacheLocked();
111  }
112  
clearCacheLocked()113  int StatsPuller::clearCacheLocked() {
114      int ret = mCachedData.size();
115      mCachedData.clear();
116      mLastPullTimeNs = 0;
117      mLastEventTimeNs = 0;
118      return ret;
119  }
120  
ClearCacheIfNecessary(int64_t timestampNs)121  int StatsPuller::ClearCacheIfNecessary(int64_t timestampNs) {
122      if (timestampNs - mLastPullTimeNs > mCoolDownNs) {
123          return clearCache();
124      } else {
125          return 0;
126      }
127  }
128  
129  }  // namespace statsd
130  }  // namespace os
131  }  // namespace android
132