blob: e8fc2ea326e38050e663f5118ca521e827090425 [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
31struct pulled_stats_event_list {
32 std::vector<stats_event*> data;
33};
34
35struct stats_event* add_stats_event_to_pull_data(pulled_stats_event_list* pull_data) {
36 struct stats_event* event = stats_event_obtain();
37 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
44class StatsPullAtomCallbackInternal : public android::os::BnPullAtomCallback {
45 public:
Tej Singhdab324f2020-01-13 16:03:15 -080046 StatsPullAtomCallbackInternal(const stats_pull_atom_callback_t callback, void* cookie,
Tej Singhc03d0092019-11-21 12:47:37 -080047 const int64_t coolDownNs, const int64_t timeoutNs,
48 const std::vector<int32_t> additiveFields)
49 : mCallback(callback),
50 mCookie(cookie),
51 mCoolDownNs(coolDownNs),
52 mTimeoutNs(timeoutNs),
53 mAdditiveFields(additiveFields) {}
54
55 ::android::binder::Status onPullAtom(
56 int32_t atomTag,
57 const ::android::sp<::android::os::IPullAtomResultReceiver>& resultReceiver) override {
58 pulled_stats_event_list statsEventList;
Tej Singhdab324f2020-01-13 16:03:15 -080059 int successInt = mCallback(atomTag, &statsEventList, mCookie);
60 bool success = successInt == STATS_PULL_SUCCESS;
Ruchir Rastogi9ecc9862019-12-06 12:42:27 -080061
62 // Convert stats_events into StatsEventParcels.
63 std::vector<android::util::StatsEventParcel> parcels;
64 for (int i = 0; i < statsEventList.data.size(); i++) {
65 size_t size;
66 uint8_t* buffer = stats_event_get_buffer(statsEventList.data[i], &size);
67
68 android::util::StatsEventParcel p;
69 // vector.assign() creates a copy, but this is inevitable unless
70 // stats_event.h/c uses a vector as opposed to a buffer.
71 p.buffer.assign(buffer, buffer + size);
72 parcels.push_back(std::move(p));
73 }
74
75 resultReceiver->pullFinished(atomTag, success, parcels);
Tej Singhc03d0092019-11-21 12:47:37 -080076 for (int i = 0; i < statsEventList.data.size(); i++) {
77 stats_event_release(statsEventList.data[i]);
78 }
79 return android::binder::Status::ok();
80 }
81
82 const int64_t& getCoolDownNs() const { return mCoolDownNs; }
83 const int64_t& getTimeoutNs() const { return mTimeoutNs; }
84 const std::vector<int32_t>& getAdditiveFields() const { return mAdditiveFields; }
85
86 private:
Tej Singh7e1b1902020-01-09 11:48:36 -080087 const stats_pull_atom_callback_t mCallback;
Tej Singhdab324f2020-01-13 16:03:15 -080088 void* mCookie;
Tej Singhc03d0092019-11-21 12:47:37 -080089 const int64_t mCoolDownNs;
90 const int64_t mTimeoutNs;
91 const std::vector<int32_t> mAdditiveFields;
92};
93
94static std::mutex pullAtomMutex;
Jeffrey Huang666510a2019-12-11 14:46:14 -080095static android::sp<android::os::IStatsd> sStatsd = nullptr;
Tej Singhc03d0092019-11-21 12:47:37 -080096
97static std::map<int32_t, android::sp<StatsPullAtomCallbackInternal>> mPullers;
Tej Singh518d77d2020-01-13 17:56:58 -080098static android::sp<android::os::IStatsd> getStatsService();
Tej Singhc03d0092019-11-21 12:47:37 -080099
100class StatsDeathRecipient : public android::IBinder::DeathRecipient {
101 public:
102 StatsDeathRecipient() = default;
103 ~StatsDeathRecipient() override = default;
104
105 // android::IBinder::DeathRecipient override:
106 void binderDied(const android::wp<android::IBinder>& /* who */) override {
Tej Singh518d77d2020-01-13 17:56:58 -0800107 {
108 std::lock_guard<std::mutex> lock(pullAtomMutex);
Tej Singhc03d0092019-11-21 12:47:37 -0800109 sStatsd = nullptr;
110 }
Tej Singh518d77d2020-01-13 17:56:58 -0800111 android::sp<android::os::IStatsd> statsService = getStatsService();
Tej Singhc03d0092019-11-21 12:47:37 -0800112 if (statsService == nullptr) {
113 return;
114 }
Tej Singh518d77d2020-01-13 17:56:58 -0800115
116 std::map<int32_t, android::sp<StatsPullAtomCallbackInternal>> pullersCopy;
117 {
118 std::lock_guard<std::mutex> lock(pullAtomMutex);
119 pullersCopy = mPullers;
120 }
121 for (auto it : pullersCopy) {
Tej Singhc03d0092019-11-21 12:47:37 -0800122 statsService->registerNativePullAtomCallback(it.first, it.second->getCoolDownNs(),
123 it.second->getTimeoutNs(),
124 it.second->getAdditiveFields(), it.second);
125 }
126 }
127};
128
129static android::sp<StatsDeathRecipient> statsDeathRecipient = new StatsDeathRecipient();
130
Tej Singh518d77d2020-01-13 17:56:58 -0800131static android::sp<android::os::IStatsd> getStatsService() {
132 std::lock_guard<std::mutex> lock(pullAtomMutex);
Tej Singhc03d0092019-11-21 12:47:37 -0800133 if (!sStatsd) {
134 // Fetch statsd.
135 const android::sp<android::IBinder> binder =
Tej Singh518d77d2020-01-13 17:56:58 -0800136 android::defaultServiceManager()->getService(android::String16("stats"));
Tej Singhc03d0092019-11-21 12:47:37 -0800137 if (!binder) {
138 return nullptr;
139 }
140 binder->linkToDeath(statsDeathRecipient);
Jeffrey Huang666510a2019-12-11 14:46:14 -0800141 sStatsd = android::interface_cast<android::os::IStatsd>(binder);
Tej Singhc03d0092019-11-21 12:47:37 -0800142 }
143 return sStatsd;
144}
145
Tej Singh518d77d2020-01-13 17:56:58 -0800146void registerStatsPullAtomCallbackBlocking(int32_t atomTag,
147 android::sp<StatsPullAtomCallbackInternal> cb) {
148 const android::sp<android::os::IStatsd> statsService = getStatsService();
149 if (statsService == nullptr) {
150 // Statsd not available
151 return;
152 }
153
154 statsService->registerNativePullAtomCallback(atomTag, cb->getCoolDownNs(), cb->getTimeoutNs(),
155 cb->getAdditiveFields(), cb);
156}
157
158void unregisterStatsPullAtomCallbackBlocking(int32_t atomTag) {
159 const android::sp<android::os::IStatsd> statsService = getStatsService();
160 if (statsService == nullptr) {
161 // Statsd not available
162 return;
163 }
164
165 statsService->unregisterNativePullAtomCallback(atomTag);
166}
167
Tej Singh7e1b1902020-01-09 11:48:36 -0800168void register_stats_pull_atom_callback(int32_t atom_tag, stats_pull_atom_callback_t callback,
Tej Singhc03d0092019-11-21 12:47:37 -0800169 pull_atom_metadata* metadata, void* cookie) {
170 int64_t coolDownNs = metadata == nullptr ? DEFAULT_COOL_DOWN_NS : metadata->cool_down_ns;
171 int64_t timeoutNs = metadata == nullptr ? DEFAULT_TIMEOUT_NS : metadata->timeout_ns;
172
173 std::vector<int32_t> additiveFields;
174 if (metadata != nullptr && metadata->additive_fields != nullptr) {
175 additiveFields.assign(metadata->additive_fields,
176 metadata->additive_fields + metadata->additive_fields_size);
177 }
178
Tej Singhc03d0092019-11-21 12:47:37 -0800179 android::sp<StatsPullAtomCallbackInternal> callbackBinder = new StatsPullAtomCallbackInternal(
180 callback, cookie, coolDownNs, timeoutNs, additiveFields);
Tej Singhdab324f2020-01-13 16:03:15 -0800181
Tej Singh518d77d2020-01-13 17:56:58 -0800182 {
183 std::lock_guard<std::mutex> lg(pullAtomMutex);
184 // Always add to the map. If statsd is dead, we will add them when it comes back.
185 mPullers[atom_tag] = callbackBinder;
Tej Singhdab324f2020-01-13 16:03:15 -0800186 }
187
Tej Singh518d77d2020-01-13 17:56:58 -0800188 std::thread registerThread(registerStatsPullAtomCallbackBlocking, atom_tag, callbackBinder);
189 registerThread.detach();
Tej Singhc03d0092019-11-21 12:47:37 -0800190}
Tej Singhdab324f2020-01-13 16:03:15 -0800191
192void unregister_stats_pull_atom_callback(int32_t atom_tag) {
Tej Singh518d77d2020-01-13 17:56:58 -0800193 {
194 std::lock_guard<std::mutex> lg(pullAtomMutex);
195 // Always remove the puller from our map.
196 // If statsd is down, we will not register it when it comes back.
197 mPullers.erase(atom_tag);
Tej Singhdab324f2020-01-13 16:03:15 -0800198 }
Tej Singh518d77d2020-01-13 17:56:58 -0800199 std::thread unregisterThread(unregisterStatsPullAtomCallbackBlocking, atom_tag);
200 unregisterThread.detach();
Tej Singhdab324f2020-01-13 16:03:15 -0800201}