Tej Singh | c03d009 | 2019-11-21 12:47:37 -0800 | [diff] [blame] | 1 | /* |
| 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 Rastogi | 223dadb | 2020-01-24 18:21:36 -0800 | [diff] [blame] | 18 | #include <thread> |
Tej Singh | c03d009 | 2019-11-21 12:47:37 -0800 | [diff] [blame] | 19 | #include <vector> |
| 20 | |
| 21 | #include <stats_event.h> |
| 22 | #include <stats_pull_atom_callback.h> |
| 23 | |
Ruchir Rastogi | 223dadb | 2020-01-24 18:21:36 -0800 | [diff] [blame] | 24 | #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 Singh | 518d77d | 2020-01-13 17:56:58 -0800 | [diff] [blame] | 31 | |
Ruchir Rastogi | 223dadb | 2020-01-24 18:21:36 -0800 | [diff] [blame] | 32 | using Status = ::ndk::ScopedAStatus; |
| 33 | using aidl::android::os::BnPullAtomCallback; |
| 34 | using aidl::android::os::IPullAtomResultReceiver; |
| 35 | using aidl::android::os::IStatsd; |
| 36 | using aidl::android::util::StatsEventParcel; |
| 37 | using ::ndk::SharedRefBase; |
Tej Singh | c03d009 | 2019-11-21 12:47:37 -0800 | [diff] [blame] | 38 | |
Tej Singh | a8fd39d | 2020-01-14 13:46:27 -0800 | [diff] [blame] | 39 | struct AStatsEventList { |
| 40 | std::vector<AStatsEvent*> data; |
Tej Singh | c03d009 | 2019-11-21 12:47:37 -0800 | [diff] [blame] | 41 | }; |
| 42 | |
Tej Singh | a8fd39d | 2020-01-14 13:46:27 -0800 | [diff] [blame] | 43 | AStatsEvent* AStatsEventList_addStatsEvent(AStatsEventList* pull_data) { |
| 44 | AStatsEvent* event = AStatsEvent_obtain(); |
Tej Singh | c03d009 | 2019-11-21 12:47:37 -0800 | [diff] [blame] | 45 | pull_data->data.push_back(event); |
| 46 | return event; |
| 47 | } |
| 48 | |
Tej Singh | c06f147 | 2020-03-13 19:14:05 -0700 | [diff] [blame] | 49 | static const int64_t DEFAULT_COOL_DOWN_MILLIS = 1000LL; // 1 second. |
Tej Singh | 00ffb6c | 2020-05-21 19:34:09 -0700 | [diff] [blame^] | 50 | static const int64_t DEFAULT_TIMEOUT_MILLIS = 2000LL; // 2 seconds. |
Tej Singh | c03d009 | 2019-11-21 12:47:37 -0800 | [diff] [blame] | 51 | |
Tej Singh | a8fd39d | 2020-01-14 13:46:27 -0800 | [diff] [blame] | 52 | struct AStatsManager_PullAtomMetadata { |
Tej Singh | c06f147 | 2020-03-13 19:14:05 -0700 | [diff] [blame] | 53 | int64_t cool_down_millis; |
| 54 | int64_t timeout_millis; |
Tej Singh | a8fd39d | 2020-01-14 13:46:27 -0800 | [diff] [blame] | 55 | std::vector<int32_t> additive_fields; |
| 56 | }; |
| 57 | |
| 58 | AStatsManager_PullAtomMetadata* AStatsManager_PullAtomMetadata_obtain() { |
| 59 | AStatsManager_PullAtomMetadata* metadata = new AStatsManager_PullAtomMetadata(); |
Tej Singh | c06f147 | 2020-03-13 19:14:05 -0700 | [diff] [blame] | 60 | metadata->cool_down_millis = DEFAULT_COOL_DOWN_MILLIS; |
| 61 | metadata->timeout_millis = DEFAULT_TIMEOUT_MILLIS; |
Tej Singh | a8fd39d | 2020-01-14 13:46:27 -0800 | [diff] [blame] | 62 | metadata->additive_fields = std::vector<int32_t>(); |
| 63 | return metadata; |
| 64 | } |
| 65 | |
| 66 | void AStatsManager_PullAtomMetadata_release(AStatsManager_PullAtomMetadata* metadata) { |
| 67 | delete metadata; |
| 68 | } |
| 69 | |
Tej Singh | c06f147 | 2020-03-13 19:14:05 -0700 | [diff] [blame] | 70 | void AStatsManager_PullAtomMetadata_setCoolDownMillis(AStatsManager_PullAtomMetadata* metadata, |
| 71 | int64_t cool_down_millis) { |
| 72 | metadata->cool_down_millis = cool_down_millis; |
Tej Singh | a8fd39d | 2020-01-14 13:46:27 -0800 | [diff] [blame] | 73 | } |
| 74 | |
Tej Singh | c06f147 | 2020-03-13 19:14:05 -0700 | [diff] [blame] | 75 | int64_t AStatsManager_PullAtomMetadata_getCoolDownMillis(AStatsManager_PullAtomMetadata* metadata) { |
| 76 | return metadata->cool_down_millis; |
| 77 | } |
| 78 | |
| 79 | void AStatsManager_PullAtomMetadata_setTimeoutMillis(AStatsManager_PullAtomMetadata* metadata, |
| 80 | int64_t timeout_millis) { |
| 81 | metadata->timeout_millis = timeout_millis; |
| 82 | } |
| 83 | |
| 84 | int64_t AStatsManager_PullAtomMetadata_getTimeoutMillis(AStatsManager_PullAtomMetadata* metadata) { |
| 85 | return metadata->timeout_millis; |
Tej Singh | a8fd39d | 2020-01-14 13:46:27 -0800 | [diff] [blame] | 86 | } |
| 87 | |
| 88 | void AStatsManager_PullAtomMetadata_setAdditiveFields(AStatsManager_PullAtomMetadata* metadata, |
Tej Singh | c06f147 | 2020-03-13 19:14:05 -0700 | [diff] [blame] | 89 | int32_t* additive_fields, |
| 90 | int32_t num_fields) { |
Tej Singh | a8fd39d | 2020-01-14 13:46:27 -0800 | [diff] [blame] | 91 | metadata->additive_fields.assign(additive_fields, additive_fields + num_fields); |
| 92 | } |
| 93 | |
Tej Singh | c06f147 | 2020-03-13 19:14:05 -0700 | [diff] [blame] | 94 | int32_t AStatsManager_PullAtomMetadata_getNumAdditiveFields( |
| 95 | AStatsManager_PullAtomMetadata* metadata) { |
| 96 | return metadata->additive_fields.size(); |
| 97 | } |
| 98 | |
| 99 | void AStatsManager_PullAtomMetadata_getAdditiveFields(AStatsManager_PullAtomMetadata* metadata, |
| 100 | int32_t* fields) { |
| 101 | std::copy(metadata->additive_fields.begin(), metadata->additive_fields.end(), fields); |
Tej Singh | c06f147 | 2020-03-13 19:14:05 -0700 | [diff] [blame] | 102 | } |
| 103 | |
Ruchir Rastogi | 223dadb | 2020-01-24 18:21:36 -0800 | [diff] [blame] | 104 | class StatsPullAtomCallbackInternal : public BnPullAtomCallback { |
Tej Singh | c03d009 | 2019-11-21 12:47:37 -0800 | [diff] [blame] | 105 | public: |
Tej Singh | a8fd39d | 2020-01-14 13:46:27 -0800 | [diff] [blame] | 106 | StatsPullAtomCallbackInternal(const AStatsManager_PullAtomCallback callback, void* cookie, |
Tej Singh | c06f147 | 2020-03-13 19:14:05 -0700 | [diff] [blame] | 107 | const int64_t coolDownMillis, const int64_t timeoutMillis, |
Tej Singh | c03d009 | 2019-11-21 12:47:37 -0800 | [diff] [blame] | 108 | const std::vector<int32_t> additiveFields) |
| 109 | : mCallback(callback), |
| 110 | mCookie(cookie), |
Tej Singh | c06f147 | 2020-03-13 19:14:05 -0700 | [diff] [blame] | 111 | mCoolDownMillis(coolDownMillis), |
| 112 | mTimeoutMillis(timeoutMillis), |
Tej Singh | c03d009 | 2019-11-21 12:47:37 -0800 | [diff] [blame] | 113 | mAdditiveFields(additiveFields) {} |
| 114 | |
Ruchir Rastogi | 223dadb | 2020-01-24 18:21:36 -0800 | [diff] [blame] | 115 | Status onPullAtom(int32_t atomTag, |
| 116 | const std::shared_ptr<IPullAtomResultReceiver>& resultReceiver) override { |
Tej Singh | a8fd39d | 2020-01-14 13:46:27 -0800 | [diff] [blame] | 117 | AStatsEventList statsEventList; |
Tej Singh | dab324f | 2020-01-13 16:03:15 -0800 | [diff] [blame] | 118 | int successInt = mCallback(atomTag, &statsEventList, mCookie); |
Tej Singh | a8fd39d | 2020-01-14 13:46:27 -0800 | [diff] [blame] | 119 | bool success = successInt == AStatsManager_PULL_SUCCESS; |
Ruchir Rastogi | 9ecc986 | 2019-12-06 12:42:27 -0800 | [diff] [blame] | 120 | |
| 121 | // Convert stats_events into StatsEventParcels. |
Ruchir Rastogi | 223dadb | 2020-01-24 18:21:36 -0800 | [diff] [blame] | 122 | std::vector<StatsEventParcel> parcels; |
Ruchir Rastogi | 9ecc986 | 2019-12-06 12:42:27 -0800 | [diff] [blame] | 123 | for (int i = 0; i < statsEventList.data.size(); i++) { |
| 124 | size_t size; |
Tej Singh | a8fd39d | 2020-01-14 13:46:27 -0800 | [diff] [blame] | 125 | uint8_t* buffer = AStatsEvent_getBuffer(statsEventList.data[i], &size); |
Ruchir Rastogi | 9ecc986 | 2019-12-06 12:42:27 -0800 | [diff] [blame] | 126 | |
Ruchir Rastogi | 223dadb | 2020-01-24 18:21:36 -0800 | [diff] [blame] | 127 | StatsEventParcel p; |
Ruchir Rastogi | 9ecc986 | 2019-12-06 12:42:27 -0800 | [diff] [blame] | 128 | // 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 Singh | c03d009 | 2019-11-21 12:47:37 -0800 | [diff] [blame] | 135 | for (int i = 0; i < statsEventList.data.size(); i++) { |
Tej Singh | a8fd39d | 2020-01-14 13:46:27 -0800 | [diff] [blame] | 136 | AStatsEvent_release(statsEventList.data[i]); |
Tej Singh | c03d009 | 2019-11-21 12:47:37 -0800 | [diff] [blame] | 137 | } |
Ruchir Rastogi | 223dadb | 2020-01-24 18:21:36 -0800 | [diff] [blame] | 138 | return Status::ok(); |
Tej Singh | c03d009 | 2019-11-21 12:47:37 -0800 | [diff] [blame] | 139 | } |
| 140 | |
Tej Singh | c06f147 | 2020-03-13 19:14:05 -0700 | [diff] [blame] | 141 | int64_t getCoolDownMillis() const { return mCoolDownMillis; } |
| 142 | int64_t getTimeoutMillis() const { return mTimeoutMillis; } |
Tej Singh | c03d009 | 2019-11-21 12:47:37 -0800 | [diff] [blame] | 143 | const std::vector<int32_t>& getAdditiveFields() const { return mAdditiveFields; } |
| 144 | |
| 145 | private: |
Tej Singh | a8fd39d | 2020-01-14 13:46:27 -0800 | [diff] [blame] | 146 | const AStatsManager_PullAtomCallback mCallback; |
Tej Singh | dab324f | 2020-01-13 16:03:15 -0800 | [diff] [blame] | 147 | void* mCookie; |
Tej Singh | c06f147 | 2020-03-13 19:14:05 -0700 | [diff] [blame] | 148 | const int64_t mCoolDownMillis; |
| 149 | const int64_t mTimeoutMillis; |
Tej Singh | c03d009 | 2019-11-21 12:47:37 -0800 | [diff] [blame] | 150 | const std::vector<int32_t> mAdditiveFields; |
| 151 | }; |
| 152 | |
| 153 | static std::mutex pullAtomMutex; |
Ruchir Rastogi | 223dadb | 2020-01-24 18:21:36 -0800 | [diff] [blame] | 154 | static std::shared_ptr<IStatsd> sStatsd = nullptr; |
Tej Singh | c03d009 | 2019-11-21 12:47:37 -0800 | [diff] [blame] | 155 | |
Ruchir Rastogi | 223dadb | 2020-01-24 18:21:36 -0800 | [diff] [blame] | 156 | static std::map<int32_t, std::shared_ptr<StatsPullAtomCallbackInternal>> mPullers; |
| 157 | static std::shared_ptr<IStatsd> getStatsService(); |
Tej Singh | c03d009 | 2019-11-21 12:47:37 -0800 | [diff] [blame] | 158 | |
Ruchir Rastogi | 223dadb | 2020-01-24 18:21:36 -0800 | [diff] [blame] | 159 | static void binderDied(void* /*cookie*/) { |
| 160 | { |
| 161 | std::lock_guard<std::mutex> lock(pullAtomMutex); |
| 162 | sStatsd = nullptr; |
Tej Singh | c03d009 | 2019-11-21 12:47:37 -0800 | [diff] [blame] | 163 | } |
Tej Singh | c03d009 | 2019-11-21 12:47:37 -0800 | [diff] [blame] | 164 | |
Ruchir Rastogi | 223dadb | 2020-01-24 18:21:36 -0800 | [diff] [blame] | 165 | std::shared_ptr<IStatsd> statsService = getStatsService(); |
| 166 | if (statsService == nullptr) { |
| 167 | return; |
| 168 | } |
Tej Singh | c03d009 | 2019-11-21 12:47:37 -0800 | [diff] [blame] | 169 | |
Ruchir Rastogi | 223dadb | 2020-01-24 18:21:36 -0800 | [diff] [blame] | 170 | // 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 Singh | c06f147 | 2020-03-13 19:14:05 -0700 | [diff] [blame] | 178 | statsService->registerNativePullAtomCallback(it.first, it.second->getCoolDownMillis(), |
| 179 | it.second->getTimeoutMillis(), |
Ruchir Rastogi | 223dadb | 2020-01-24 18:21:36 -0800 | [diff] [blame] | 180 | it.second->getAdditiveFields(), it.second); |
| 181 | } |
| 182 | } |
| 183 | |
| 184 | static ::ndk::ScopedAIBinder_DeathRecipient sDeathRecipient( |
| 185 | AIBinder_DeathRecipient_new(binderDied)); |
| 186 | |
| 187 | static std::shared_ptr<IStatsd> getStatsService() { |
Tej Singh | 518d77d | 2020-01-13 17:56:58 -0800 | [diff] [blame] | 188 | std::lock_guard<std::mutex> lock(pullAtomMutex); |
Tej Singh | c03d009 | 2019-11-21 12:47:37 -0800 | [diff] [blame] | 189 | if (!sStatsd) { |
Ruchir Rastogi | 223dadb | 2020-01-24 18:21:36 -0800 | [diff] [blame] | 190 | // 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 Singh | c03d009 | 2019-11-21 12:47:37 -0800 | [diff] [blame] | 195 | } |
Tej Singh | c03d009 | 2019-11-21 12:47:37 -0800 | [diff] [blame] | 196 | } |
| 197 | return sStatsd; |
| 198 | } |
| 199 | |
Tej Singh | 518d77d | 2020-01-13 17:56:58 -0800 | [diff] [blame] | 200 | void registerStatsPullAtomCallbackBlocking(int32_t atomTag, |
Ruchir Rastogi | 223dadb | 2020-01-24 18:21:36 -0800 | [diff] [blame] | 201 | std::shared_ptr<StatsPullAtomCallbackInternal> cb) { |
| 202 | const std::shared_ptr<IStatsd> statsService = getStatsService(); |
Tej Singh | 518d77d | 2020-01-13 17:56:58 -0800 | [diff] [blame] | 203 | if (statsService == nullptr) { |
| 204 | // Statsd not available |
| 205 | return; |
| 206 | } |
| 207 | |
Tej Singh | c06f147 | 2020-03-13 19:14:05 -0700 | [diff] [blame] | 208 | statsService->registerNativePullAtomCallback( |
| 209 | atomTag, cb->getCoolDownMillis(), cb->getTimeoutMillis(), cb->getAdditiveFields(), cb); |
Tej Singh | 518d77d | 2020-01-13 17:56:58 -0800 | [diff] [blame] | 210 | } |
| 211 | |
| 212 | void unregisterStatsPullAtomCallbackBlocking(int32_t atomTag) { |
Ruchir Rastogi | 223dadb | 2020-01-24 18:21:36 -0800 | [diff] [blame] | 213 | const std::shared_ptr<IStatsd> statsService = getStatsService(); |
Tej Singh | 518d77d | 2020-01-13 17:56:58 -0800 | [diff] [blame] | 214 | if (statsService == nullptr) { |
| 215 | // Statsd not available |
| 216 | return; |
| 217 | } |
| 218 | |
| 219 | statsService->unregisterNativePullAtomCallback(atomTag); |
| 220 | } |
| 221 | |
Tej Singh | c06f147 | 2020-03-13 19:14:05 -0700 | [diff] [blame] | 222 | void 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 Singh | c03d009 | 2019-11-21 12:47:37 -0800 | [diff] [blame] | 227 | |
| 228 | std::vector<int32_t> additiveFields; |
Tej Singh | a8fd39d | 2020-01-14 13:46:27 -0800 | [diff] [blame] | 229 | if (metadata != nullptr) { |
| 230 | additiveFields = metadata->additive_fields; |
Tej Singh | c03d009 | 2019-11-21 12:47:37 -0800 | [diff] [blame] | 231 | } |
| 232 | |
Ruchir Rastogi | 223dadb | 2020-01-24 18:21:36 -0800 | [diff] [blame] | 233 | std::shared_ptr<StatsPullAtomCallbackInternal> callbackBinder = |
Tej Singh | c06f147 | 2020-03-13 19:14:05 -0700 | [diff] [blame] | 234 | SharedRefBase::make<StatsPullAtomCallbackInternal>(callback, cookie, coolDownMillis, |
| 235 | timeoutMillis, additiveFields); |
Tej Singh | dab324f | 2020-01-13 16:03:15 -0800 | [diff] [blame] | 236 | |
Tej Singh | 518d77d | 2020-01-13 17:56:58 -0800 | [diff] [blame] | 237 | { |
| 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 Singh | dab324f | 2020-01-13 16:03:15 -0800 | [diff] [blame] | 241 | } |
| 242 | |
Tej Singh | 518d77d | 2020-01-13 17:56:58 -0800 | [diff] [blame] | 243 | std::thread registerThread(registerStatsPullAtomCallbackBlocking, atom_tag, callbackBinder); |
| 244 | registerThread.detach(); |
Tej Singh | c03d009 | 2019-11-21 12:47:37 -0800 | [diff] [blame] | 245 | } |
Tej Singh | dab324f | 2020-01-13 16:03:15 -0800 | [diff] [blame] | 246 | |
Tej Singh | c06f147 | 2020-03-13 19:14:05 -0700 | [diff] [blame] | 247 | void AStatsManager_clearPullAtomCallback(int32_t atom_tag) { |
Tej Singh | 518d77d | 2020-01-13 17:56:58 -0800 | [diff] [blame] | 248 | { |
| 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 Singh | dab324f | 2020-01-13 16:03:15 -0800 | [diff] [blame] | 253 | } |
Tej Singh | 518d77d | 2020-01-13 17:56:58 -0800 | [diff] [blame] | 254 | std::thread unregisterThread(unregisterStatsPullAtomCallbackBlocking, atom_tag); |
| 255 | unregisterThread.detach(); |
Tej Singh | dab324f | 2020-01-13 16:03:15 -0800 | [diff] [blame] | 256 | } |