blob: 9c497b8ea551d4379444632aec7a4a46b05de217 [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>
18#include <vector>
19
20#include <stats_event.h>
21#include <stats_pull_atom_callback.h>
22
23#include <android/os/BnPullAtomCallback.h>
24#include <android/os/IPullAtomResultReceiver.h>
Jeffrey Huang666510a2019-12-11 14:46:14 -080025#include <android/os/IStatsd.h>
Ruchir Rastogi9ecc9862019-12-06 12:42:27 -080026#include <android/util/StatsEventParcel.h>
Tej Singhc03d0092019-11-21 12:47:37 -080027#include <binder/IServiceManager.h>
Tej Singh518d77d2020-01-13 17:56:58 -080028
29#include <thread>
Tej Singhc03d0092019-11-21 12:47:37 -080030
Tej Singha8fd39d2020-01-14 13:46:27 -080031struct AStatsEventList {
32 std::vector<AStatsEvent*> data;
Tej Singhc03d0092019-11-21 12:47:37 -080033};
34
Tej Singha8fd39d2020-01-14 13:46:27 -080035AStatsEvent* AStatsEventList_addStatsEvent(AStatsEventList* pull_data) {
36 AStatsEvent* event = AStatsEvent_obtain();
Tej Singhc03d0092019-11-21 12:47:37 -080037 pull_data->data.push_back(event);
38 return event;
39}
40
41static const int64_t DEFAULT_COOL_DOWN_NS = 1000000000LL; // 1 second.
42static const int64_t DEFAULT_TIMEOUT_NS = 10000000000LL; // 10 seconds.
43
Tej Singha8fd39d2020-01-14 13:46:27 -080044struct AStatsManager_PullAtomMetadata {
45 int64_t cool_down_ns;
46 int64_t timeout_ns;
47 std::vector<int32_t> additive_fields;
48};
49
50AStatsManager_PullAtomMetadata* AStatsManager_PullAtomMetadata_obtain() {
51 AStatsManager_PullAtomMetadata* metadata = new AStatsManager_PullAtomMetadata();
52 metadata->cool_down_ns = DEFAULT_COOL_DOWN_NS;
53 metadata->timeout_ns = DEFAULT_TIMEOUT_NS;
54 metadata->additive_fields = std::vector<int32_t>();
55 return metadata;
56}
57
58void AStatsManager_PullAtomMetadata_release(AStatsManager_PullAtomMetadata* metadata) {
59 delete metadata;
60}
61
62void AStatsManager_PullAtomMetadata_setCoolDownNs(AStatsManager_PullAtomMetadata* metadata,
63 int64_t cool_down_ns) {
64 metadata->cool_down_ns = cool_down_ns;
65}
66
67void AStatsManager_PullAtomMetadata_setTimeoutNs(AStatsManager_PullAtomMetadata* metadata,
68 int64_t timeout_ns) {
69 metadata->timeout_ns = timeout_ns;
70}
71
72void AStatsManager_PullAtomMetadata_setAdditiveFields(AStatsManager_PullAtomMetadata* metadata,
73 int* additive_fields, int num_fields) {
74 metadata->additive_fields.assign(additive_fields, additive_fields + num_fields);
75}
76
Tej Singhc03d0092019-11-21 12:47:37 -080077class StatsPullAtomCallbackInternal : public android::os::BnPullAtomCallback {
78 public:
Tej Singha8fd39d2020-01-14 13:46:27 -080079 StatsPullAtomCallbackInternal(const AStatsManager_PullAtomCallback callback, void* cookie,
Tej Singhc03d0092019-11-21 12:47:37 -080080 const int64_t coolDownNs, const int64_t timeoutNs,
81 const std::vector<int32_t> additiveFields)
82 : mCallback(callback),
83 mCookie(cookie),
84 mCoolDownNs(coolDownNs),
85 mTimeoutNs(timeoutNs),
86 mAdditiveFields(additiveFields) {}
87
88 ::android::binder::Status onPullAtom(
89 int32_t atomTag,
90 const ::android::sp<::android::os::IPullAtomResultReceiver>& resultReceiver) override {
Tej Singha8fd39d2020-01-14 13:46:27 -080091 AStatsEventList statsEventList;
92 statsEventList.data.clear();
Tej Singhdab324f2020-01-13 16:03:15 -080093 int successInt = mCallback(atomTag, &statsEventList, mCookie);
Tej Singha8fd39d2020-01-14 13:46:27 -080094 bool success = successInt == AStatsManager_PULL_SUCCESS;
Ruchir Rastogi9ecc9862019-12-06 12:42:27 -080095
96 // Convert stats_events into StatsEventParcels.
97 std::vector<android::util::StatsEventParcel> parcels;
98 for (int i = 0; i < statsEventList.data.size(); i++) {
99 size_t size;
Tej Singha8fd39d2020-01-14 13:46:27 -0800100 uint8_t* buffer = AStatsEvent_getBuffer(statsEventList.data[i], &size);
Ruchir Rastogi9ecc9862019-12-06 12:42:27 -0800101
102 android::util::StatsEventParcel p;
103 // vector.assign() creates a copy, but this is inevitable unless
104 // stats_event.h/c uses a vector as opposed to a buffer.
105 p.buffer.assign(buffer, buffer + size);
106 parcels.push_back(std::move(p));
107 }
108
109 resultReceiver->pullFinished(atomTag, success, parcels);
Tej Singhc03d0092019-11-21 12:47:37 -0800110 for (int i = 0; i < statsEventList.data.size(); i++) {
Tej Singha8fd39d2020-01-14 13:46:27 -0800111 AStatsEvent_release(statsEventList.data[i]);
Tej Singhc03d0092019-11-21 12:47:37 -0800112 }
113 return android::binder::Status::ok();
114 }
115
116 const int64_t& getCoolDownNs() const { return mCoolDownNs; }
117 const int64_t& getTimeoutNs() const { return mTimeoutNs; }
118 const std::vector<int32_t>& getAdditiveFields() const { return mAdditiveFields; }
119
120 private:
Tej Singha8fd39d2020-01-14 13:46:27 -0800121 const AStatsManager_PullAtomCallback mCallback;
Tej Singhdab324f2020-01-13 16:03:15 -0800122 void* mCookie;
Tej Singhc03d0092019-11-21 12:47:37 -0800123 const int64_t mCoolDownNs;
124 const int64_t mTimeoutNs;
125 const std::vector<int32_t> mAdditiveFields;
126};
127
128static std::mutex pullAtomMutex;
Jeffrey Huang666510a2019-12-11 14:46:14 -0800129static android::sp<android::os::IStatsd> sStatsd = nullptr;
Tej Singhc03d0092019-11-21 12:47:37 -0800130
131static std::map<int32_t, android::sp<StatsPullAtomCallbackInternal>> mPullers;
Tej Singh518d77d2020-01-13 17:56:58 -0800132static android::sp<android::os::IStatsd> getStatsService();
Tej Singhc03d0092019-11-21 12:47:37 -0800133
134class StatsDeathRecipient : public android::IBinder::DeathRecipient {
135 public:
136 StatsDeathRecipient() = default;
137 ~StatsDeathRecipient() override = default;
138
139 // android::IBinder::DeathRecipient override:
140 void binderDied(const android::wp<android::IBinder>& /* who */) override {
Tej Singh518d77d2020-01-13 17:56:58 -0800141 {
142 std::lock_guard<std::mutex> lock(pullAtomMutex);
Tej Singhc03d0092019-11-21 12:47:37 -0800143 sStatsd = nullptr;
144 }
Tej Singh518d77d2020-01-13 17:56:58 -0800145 android::sp<android::os::IStatsd> statsService = getStatsService();
Tej Singhc03d0092019-11-21 12:47:37 -0800146 if (statsService == nullptr) {
147 return;
148 }
Tej Singh518d77d2020-01-13 17:56:58 -0800149
150 std::map<int32_t, android::sp<StatsPullAtomCallbackInternal>> pullersCopy;
151 {
152 std::lock_guard<std::mutex> lock(pullAtomMutex);
153 pullersCopy = mPullers;
154 }
155 for (auto it : pullersCopy) {
Tej Singhc03d0092019-11-21 12:47:37 -0800156 statsService->registerNativePullAtomCallback(it.first, it.second->getCoolDownNs(),
157 it.second->getTimeoutNs(),
158 it.second->getAdditiveFields(), it.second);
159 }
160 }
161};
162
163static android::sp<StatsDeathRecipient> statsDeathRecipient = new StatsDeathRecipient();
164
Tej Singh518d77d2020-01-13 17:56:58 -0800165static android::sp<android::os::IStatsd> getStatsService() {
166 std::lock_guard<std::mutex> lock(pullAtomMutex);
Tej Singhc03d0092019-11-21 12:47:37 -0800167 if (!sStatsd) {
168 // Fetch statsd.
169 const android::sp<android::IBinder> binder =
Tej Singh518d77d2020-01-13 17:56:58 -0800170 android::defaultServiceManager()->getService(android::String16("stats"));
Tej Singhc03d0092019-11-21 12:47:37 -0800171 if (!binder) {
172 return nullptr;
173 }
174 binder->linkToDeath(statsDeathRecipient);
Jeffrey Huang666510a2019-12-11 14:46:14 -0800175 sStatsd = android::interface_cast<android::os::IStatsd>(binder);
Tej Singhc03d0092019-11-21 12:47:37 -0800176 }
177 return sStatsd;
178}
179
Tej Singh518d77d2020-01-13 17:56:58 -0800180void registerStatsPullAtomCallbackBlocking(int32_t atomTag,
181 android::sp<StatsPullAtomCallbackInternal> cb) {
182 const android::sp<android::os::IStatsd> statsService = getStatsService();
183 if (statsService == nullptr) {
184 // Statsd not available
185 return;
186 }
187
188 statsService->registerNativePullAtomCallback(atomTag, cb->getCoolDownNs(), cb->getTimeoutNs(),
189 cb->getAdditiveFields(), cb);
190}
191
192void unregisterStatsPullAtomCallbackBlocking(int32_t atomTag) {
193 const android::sp<android::os::IStatsd> statsService = getStatsService();
194 if (statsService == nullptr) {
195 // Statsd not available
196 return;
197 }
198
199 statsService->unregisterNativePullAtomCallback(atomTag);
200}
201
Tej Singha8fd39d2020-01-14 13:46:27 -0800202void AStatsManager_registerPullAtomCallback(int32_t atom_tag,
203 AStatsManager_PullAtomCallback callback,
204 AStatsManager_PullAtomMetadata* metadata,
205 void* cookie) {
Tej Singhc03d0092019-11-21 12:47:37 -0800206 int64_t coolDownNs = metadata == nullptr ? DEFAULT_COOL_DOWN_NS : metadata->cool_down_ns;
207 int64_t timeoutNs = metadata == nullptr ? DEFAULT_TIMEOUT_NS : metadata->timeout_ns;
208
209 std::vector<int32_t> additiveFields;
Tej Singha8fd39d2020-01-14 13:46:27 -0800210 if (metadata != nullptr) {
211 additiveFields = metadata->additive_fields;
Tej Singhc03d0092019-11-21 12:47:37 -0800212 }
213
Tej Singhc03d0092019-11-21 12:47:37 -0800214 android::sp<StatsPullAtomCallbackInternal> callbackBinder = new StatsPullAtomCallbackInternal(
215 callback, cookie, coolDownNs, timeoutNs, additiveFields);
Tej Singhdab324f2020-01-13 16:03:15 -0800216
Tej Singh518d77d2020-01-13 17:56:58 -0800217 {
218 std::lock_guard<std::mutex> lg(pullAtomMutex);
219 // Always add to the map. If statsd is dead, we will add them when it comes back.
220 mPullers[atom_tag] = callbackBinder;
Tej Singhdab324f2020-01-13 16:03:15 -0800221 }
222
Tej Singh518d77d2020-01-13 17:56:58 -0800223 std::thread registerThread(registerStatsPullAtomCallbackBlocking, atom_tag, callbackBinder);
224 registerThread.detach();
Tej Singhc03d0092019-11-21 12:47:37 -0800225}
Tej Singhdab324f2020-01-13 16:03:15 -0800226
Tej Singha8fd39d2020-01-14 13:46:27 -0800227void AStatsManager_unregisterPullAtomCallback(int32_t atom_tag) {
Tej Singh518d77d2020-01-13 17:56:58 -0800228 {
229 std::lock_guard<std::mutex> lg(pullAtomMutex);
230 // Always remove the puller from our map.
231 // If statsd is down, we will not register it when it comes back.
232 mPullers.erase(atom_tag);
Tej Singhdab324f2020-01-13 16:03:15 -0800233 }
Tej Singh518d77d2020-01-13 17:56:58 -0800234 std::thread unregisterThread(unregisterStatsPullAtomCallbackBlocking, atom_tag);
235 unregisterThread.detach();
Tej Singhdab324f2020-01-13 16:03:15 -0800236}