blob: 0b9dd52925976413917678bdd711202853c807d2 [file] [log] [blame]
Tej Singhc03d0092019-11-21 12:47:37 -08001/*
2 * Copyright (C) 2019, 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 <map>
Ruchir Rastogi223dadb2020-01-24 18:21:36 -080018#include <thread>
Tej Singhc03d0092019-11-21 12:47:37 -080019#include <vector>
20
21#include <stats_event.h>
22#include <stats_pull_atom_callback.h>
23
Ruchir Rastogi223dadb2020-01-24 18:21:36 -080024#include <aidl/android/os/BnPullAtomCallback.h>
25#include <aidl/android/os/IPullAtomResultReceiver.h>
26#include <aidl/android/os/IStatsd.h>
27#include <aidl/android/util/StatsEventParcel.h>
28#include <android/binder_auto_utils.h>
29#include <android/binder_ibinder.h>
30#include <android/binder_manager.h>
Tej Singh518d77d2020-01-13 17:56:58 -080031
Ruchir Rastogi223dadb2020-01-24 18:21:36 -080032using Status = ::ndk::ScopedAStatus;
33using aidl::android::os::BnPullAtomCallback;
34using aidl::android::os::IPullAtomResultReceiver;
35using aidl::android::os::IStatsd;
36using aidl::android::util::StatsEventParcel;
37using ::ndk::SharedRefBase;
Tej Singhc03d0092019-11-21 12:47:37 -080038
Tej Singha8fd39d2020-01-14 13:46:27 -080039struct AStatsEventList {
40 std::vector<AStatsEvent*> data;
Tej Singhc03d0092019-11-21 12:47:37 -080041};
42
Tej Singha8fd39d2020-01-14 13:46:27 -080043AStatsEvent* AStatsEventList_addStatsEvent(AStatsEventList* pull_data) {
44 AStatsEvent* event = AStatsEvent_obtain();
Tej Singhc03d0092019-11-21 12:47:37 -080045 pull_data->data.push_back(event);
46 return event;
47}
48
Tej Singhc06f1472020-03-13 19:14:05 -070049static const int64_t DEFAULT_COOL_DOWN_MILLIS = 1000LL; // 1 second.
Tej Singh00ffb6c2020-05-21 19:34:09 -070050static const int64_t DEFAULT_TIMEOUT_MILLIS = 2000LL; // 2 seconds.
Tej Singhc03d0092019-11-21 12:47:37 -080051
Tej Singha8fd39d2020-01-14 13:46:27 -080052struct AStatsManager_PullAtomMetadata {
Tej Singhc06f1472020-03-13 19:14:05 -070053 int64_t cool_down_millis;
54 int64_t timeout_millis;
Tej Singha8fd39d2020-01-14 13:46:27 -080055 std::vector<int32_t> additive_fields;
56};
57
58AStatsManager_PullAtomMetadata* AStatsManager_PullAtomMetadata_obtain() {
59 AStatsManager_PullAtomMetadata* metadata = new AStatsManager_PullAtomMetadata();
Tej Singhc06f1472020-03-13 19:14:05 -070060 metadata->cool_down_millis = DEFAULT_COOL_DOWN_MILLIS;
61 metadata->timeout_millis = DEFAULT_TIMEOUT_MILLIS;
Tej Singha8fd39d2020-01-14 13:46:27 -080062 metadata->additive_fields = std::vector<int32_t>();
63 return metadata;
64}
65
66void AStatsManager_PullAtomMetadata_release(AStatsManager_PullAtomMetadata* metadata) {
67 delete metadata;
68}
69
Tej Singhc06f1472020-03-13 19:14:05 -070070void AStatsManager_PullAtomMetadata_setCoolDownMillis(AStatsManager_PullAtomMetadata* metadata,
71 int64_t cool_down_millis) {
72 metadata->cool_down_millis = cool_down_millis;
Tej Singha8fd39d2020-01-14 13:46:27 -080073}
74
Tej Singhc06f1472020-03-13 19:14:05 -070075int64_t AStatsManager_PullAtomMetadata_getCoolDownMillis(AStatsManager_PullAtomMetadata* metadata) {
76 return metadata->cool_down_millis;
77}
78
79void AStatsManager_PullAtomMetadata_setTimeoutMillis(AStatsManager_PullAtomMetadata* metadata,
80 int64_t timeout_millis) {
81 metadata->timeout_millis = timeout_millis;
82}
83
84int64_t AStatsManager_PullAtomMetadata_getTimeoutMillis(AStatsManager_PullAtomMetadata* metadata) {
85 return metadata->timeout_millis;
Tej Singha8fd39d2020-01-14 13:46:27 -080086}
87
88void AStatsManager_PullAtomMetadata_setAdditiveFields(AStatsManager_PullAtomMetadata* metadata,
Tej Singhc06f1472020-03-13 19:14:05 -070089 int32_t* additive_fields,
90 int32_t num_fields) {
Tej Singha8fd39d2020-01-14 13:46:27 -080091 metadata->additive_fields.assign(additive_fields, additive_fields + num_fields);
92}
93
Tej Singhc06f1472020-03-13 19:14:05 -070094int32_t AStatsManager_PullAtomMetadata_getNumAdditiveFields(
95 AStatsManager_PullAtomMetadata* metadata) {
96 return metadata->additive_fields.size();
97}
98
99void AStatsManager_PullAtomMetadata_getAdditiveFields(AStatsManager_PullAtomMetadata* metadata,
100 int32_t* fields) {
101 std::copy(metadata->additive_fields.begin(), metadata->additive_fields.end(), fields);
Tej Singhc06f1472020-03-13 19:14:05 -0700102}
103
Ruchir Rastogi223dadb2020-01-24 18:21:36 -0800104class StatsPullAtomCallbackInternal : public BnPullAtomCallback {
Tej Singhc03d0092019-11-21 12:47:37 -0800105 public:
Tej Singha8fd39d2020-01-14 13:46:27 -0800106 StatsPullAtomCallbackInternal(const AStatsManager_PullAtomCallback callback, void* cookie,
Tej Singhc06f1472020-03-13 19:14:05 -0700107 const int64_t coolDownMillis, const int64_t timeoutMillis,
Tej Singhc03d0092019-11-21 12:47:37 -0800108 const std::vector<int32_t> additiveFields)
109 : mCallback(callback),
110 mCookie(cookie),
Tej Singhc06f1472020-03-13 19:14:05 -0700111 mCoolDownMillis(coolDownMillis),
112 mTimeoutMillis(timeoutMillis),
Tej Singhc03d0092019-11-21 12:47:37 -0800113 mAdditiveFields(additiveFields) {}
114
Ruchir Rastogi223dadb2020-01-24 18:21:36 -0800115 Status onPullAtom(int32_t atomTag,
116 const std::shared_ptr<IPullAtomResultReceiver>& resultReceiver) override {
Tej Singha8fd39d2020-01-14 13:46:27 -0800117 AStatsEventList statsEventList;
Tej Singhdab324f2020-01-13 16:03:15 -0800118 int successInt = mCallback(atomTag, &statsEventList, mCookie);
Tej Singha8fd39d2020-01-14 13:46:27 -0800119 bool success = successInt == AStatsManager_PULL_SUCCESS;
Ruchir Rastogi9ecc9862019-12-06 12:42:27 -0800120
121 // Convert stats_events into StatsEventParcels.
Ruchir Rastogi223dadb2020-01-24 18:21:36 -0800122 std::vector<StatsEventParcel> parcels;
Ruchir Rastogi9ecc9862019-12-06 12:42:27 -0800123 for (int i = 0; i < statsEventList.data.size(); i++) {
124 size_t size;
Tej Singha8fd39d2020-01-14 13:46:27 -0800125 uint8_t* buffer = AStatsEvent_getBuffer(statsEventList.data[i], &size);
Ruchir Rastogi9ecc9862019-12-06 12:42:27 -0800126
Ruchir Rastogi223dadb2020-01-24 18:21:36 -0800127 StatsEventParcel p;
Ruchir Rastogi9ecc9862019-12-06 12:42:27 -0800128 // vector.assign() creates a copy, but this is inevitable unless
129 // stats_event.h/c uses a vector as opposed to a buffer.
130 p.buffer.assign(buffer, buffer + size);
131 parcels.push_back(std::move(p));
132 }
133
134 resultReceiver->pullFinished(atomTag, success, parcels);
Tej Singhc03d0092019-11-21 12:47:37 -0800135 for (int i = 0; i < statsEventList.data.size(); i++) {
Tej Singha8fd39d2020-01-14 13:46:27 -0800136 AStatsEvent_release(statsEventList.data[i]);
Tej Singhc03d0092019-11-21 12:47:37 -0800137 }
Ruchir Rastogi223dadb2020-01-24 18:21:36 -0800138 return Status::ok();
Tej Singhc03d0092019-11-21 12:47:37 -0800139 }
140
Tej Singhc06f1472020-03-13 19:14:05 -0700141 int64_t getCoolDownMillis() const { return mCoolDownMillis; }
142 int64_t getTimeoutMillis() const { return mTimeoutMillis; }
Tej Singhc03d0092019-11-21 12:47:37 -0800143 const std::vector<int32_t>& getAdditiveFields() const { return mAdditiveFields; }
144
145 private:
Tej Singha8fd39d2020-01-14 13:46:27 -0800146 const AStatsManager_PullAtomCallback mCallback;
Tej Singhdab324f2020-01-13 16:03:15 -0800147 void* mCookie;
Tej Singhc06f1472020-03-13 19:14:05 -0700148 const int64_t mCoolDownMillis;
149 const int64_t mTimeoutMillis;
Tej Singhc03d0092019-11-21 12:47:37 -0800150 const std::vector<int32_t> mAdditiveFields;
151};
152
153static std::mutex pullAtomMutex;
Ruchir Rastogi223dadb2020-01-24 18:21:36 -0800154static std::shared_ptr<IStatsd> sStatsd = nullptr;
Tej Singhc03d0092019-11-21 12:47:37 -0800155
Ruchir Rastogi223dadb2020-01-24 18:21:36 -0800156static std::map<int32_t, std::shared_ptr<StatsPullAtomCallbackInternal>> mPullers;
157static std::shared_ptr<IStatsd> getStatsService();
Tej Singhc03d0092019-11-21 12:47:37 -0800158
Ruchir Rastogi223dadb2020-01-24 18:21:36 -0800159static void binderDied(void* /*cookie*/) {
160 {
161 std::lock_guard<std::mutex> lock(pullAtomMutex);
162 sStatsd = nullptr;
Tej Singhc03d0092019-11-21 12:47:37 -0800163 }
Tej Singhc03d0092019-11-21 12:47:37 -0800164
Ruchir Rastogi223dadb2020-01-24 18:21:36 -0800165 std::shared_ptr<IStatsd> statsService = getStatsService();
166 if (statsService == nullptr) {
167 return;
168 }
Tej Singhc03d0092019-11-21 12:47:37 -0800169
Ruchir Rastogi223dadb2020-01-24 18:21:36 -0800170 // Since we do not want to make an IPC with the lock held, we first create a
171 // copy of the data with the lock held before iterating through the map.
172 std::map<int32_t, std::shared_ptr<StatsPullAtomCallbackInternal>> pullersCopy;
173 {
174 std::lock_guard<std::mutex> lock(pullAtomMutex);
175 pullersCopy = mPullers;
176 }
177 for (const auto& it : pullersCopy) {
Tej Singhc06f1472020-03-13 19:14:05 -0700178 statsService->registerNativePullAtomCallback(it.first, it.second->getCoolDownMillis(),
179 it.second->getTimeoutMillis(),
Ruchir Rastogi223dadb2020-01-24 18:21:36 -0800180 it.second->getAdditiveFields(), it.second);
181 }
182}
183
184static ::ndk::ScopedAIBinder_DeathRecipient sDeathRecipient(
185 AIBinder_DeathRecipient_new(binderDied));
186
187static std::shared_ptr<IStatsd> getStatsService() {
Tej Singh518d77d2020-01-13 17:56:58 -0800188 std::lock_guard<std::mutex> lock(pullAtomMutex);
Tej Singhc03d0092019-11-21 12:47:37 -0800189 if (!sStatsd) {
Ruchir Rastogi223dadb2020-01-24 18:21:36 -0800190 // Fetch statsd
191 ::ndk::SpAIBinder binder(AServiceManager_getService("stats"));
192 sStatsd = IStatsd::fromBinder(binder);
193 if (sStatsd) {
194 AIBinder_linkToDeath(binder.get(), sDeathRecipient.get(), /*cookie=*/nullptr);
Tej Singhc03d0092019-11-21 12:47:37 -0800195 }
Tej Singhc03d0092019-11-21 12:47:37 -0800196 }
197 return sStatsd;
198}
199
Tej Singh518d77d2020-01-13 17:56:58 -0800200void registerStatsPullAtomCallbackBlocking(int32_t atomTag,
Ruchir Rastogi223dadb2020-01-24 18:21:36 -0800201 std::shared_ptr<StatsPullAtomCallbackInternal> cb) {
202 const std::shared_ptr<IStatsd> statsService = getStatsService();
Tej Singh518d77d2020-01-13 17:56:58 -0800203 if (statsService == nullptr) {
204 // Statsd not available
205 return;
206 }
207
Tej Singhc06f1472020-03-13 19:14:05 -0700208 statsService->registerNativePullAtomCallback(
209 atomTag, cb->getCoolDownMillis(), cb->getTimeoutMillis(), cb->getAdditiveFields(), cb);
Tej Singh518d77d2020-01-13 17:56:58 -0800210}
211
212void unregisterStatsPullAtomCallbackBlocking(int32_t atomTag) {
Ruchir Rastogi223dadb2020-01-24 18:21:36 -0800213 const std::shared_ptr<IStatsd> statsService = getStatsService();
Tej Singh518d77d2020-01-13 17:56:58 -0800214 if (statsService == nullptr) {
215 // Statsd not available
216 return;
217 }
218
219 statsService->unregisterNativePullAtomCallback(atomTag);
220}
221
Tej Singhc06f1472020-03-13 19:14:05 -0700222void AStatsManager_setPullAtomCallback(int32_t atom_tag, AStatsManager_PullAtomMetadata* metadata,
223 AStatsManager_PullAtomCallback callback, void* cookie) {
224 int64_t coolDownMillis =
225 metadata == nullptr ? DEFAULT_COOL_DOWN_MILLIS : metadata->cool_down_millis;
226 int64_t timeoutMillis = metadata == nullptr ? DEFAULT_TIMEOUT_MILLIS : metadata->timeout_millis;
Tej Singhc03d0092019-11-21 12:47:37 -0800227
228 std::vector<int32_t> additiveFields;
Tej Singha8fd39d2020-01-14 13:46:27 -0800229 if (metadata != nullptr) {
230 additiveFields = metadata->additive_fields;
Tej Singhc03d0092019-11-21 12:47:37 -0800231 }
232
Ruchir Rastogi223dadb2020-01-24 18:21:36 -0800233 std::shared_ptr<StatsPullAtomCallbackInternal> callbackBinder =
Tej Singhc06f1472020-03-13 19:14:05 -0700234 SharedRefBase::make<StatsPullAtomCallbackInternal>(callback, cookie, coolDownMillis,
235 timeoutMillis, additiveFields);
Tej Singhdab324f2020-01-13 16:03:15 -0800236
Tej Singh518d77d2020-01-13 17:56:58 -0800237 {
238 std::lock_guard<std::mutex> lg(pullAtomMutex);
239 // Always add to the map. If statsd is dead, we will add them when it comes back.
240 mPullers[atom_tag] = callbackBinder;
Tej Singhdab324f2020-01-13 16:03:15 -0800241 }
242
Tej Singh518d77d2020-01-13 17:56:58 -0800243 std::thread registerThread(registerStatsPullAtomCallbackBlocking, atom_tag, callbackBinder);
244 registerThread.detach();
Tej Singhc03d0092019-11-21 12:47:37 -0800245}
Tej Singhdab324f2020-01-13 16:03:15 -0800246
Tej Singhc06f1472020-03-13 19:14:05 -0700247void AStatsManager_clearPullAtomCallback(int32_t atom_tag) {
Tej Singh518d77d2020-01-13 17:56:58 -0800248 {
249 std::lock_guard<std::mutex> lg(pullAtomMutex);
250 // Always remove the puller from our map.
251 // If statsd is down, we will not register it when it comes back.
252 mPullers.erase(atom_tag);
Tej Singhdab324f2020-01-13 16:03:15 -0800253 }
Tej Singh518d77d2020-01-13 17:56:58 -0800254 std::thread unregisterThread(unregisterStatsPullAtomCallbackBlocking, atom_tag);
255 unregisterThread.detach();
Tej Singhdab324f2020-01-13 16:03:15 -0800256}