blob: 177bbba4431bc19a08bf45eb6cbb1c4e1d7b88ad [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>
28#include "include/stats_pull_atom_callback.h"
29
30struct pulled_stats_event_list {
31 std::vector<stats_event*> data;
32};
33
34struct stats_event* add_stats_event_to_pull_data(pulled_stats_event_list* pull_data) {
35 struct stats_event* event = stats_event_obtain();
36 pull_data->data.push_back(event);
37 return event;
38}
39
40static const int64_t DEFAULT_COOL_DOWN_NS = 1000000000LL; // 1 second.
41static const int64_t DEFAULT_TIMEOUT_NS = 10000000000LL; // 10 seconds.
42
43class StatsPullAtomCallbackInternal : public android::os::BnPullAtomCallback {
44 public:
45 StatsPullAtomCallbackInternal(const stats_pull_atom_callback_t* callback, const void* cookie,
46 const int64_t coolDownNs, const int64_t timeoutNs,
47 const std::vector<int32_t> additiveFields)
48 : mCallback(callback),
49 mCookie(cookie),
50 mCoolDownNs(coolDownNs),
51 mTimeoutNs(timeoutNs),
52 mAdditiveFields(additiveFields) {}
53
54 ::android::binder::Status onPullAtom(
55 int32_t atomTag,
56 const ::android::sp<::android::os::IPullAtomResultReceiver>& resultReceiver) override {
57 pulled_stats_event_list statsEventList;
58 bool success = (*mCallback)(atomTag, &statsEventList, mCookie);
Ruchir Rastogi9ecc9862019-12-06 12:42:27 -080059
60 // Convert stats_events into StatsEventParcels.
61 std::vector<android::util::StatsEventParcel> parcels;
62 for (int i = 0; i < statsEventList.data.size(); i++) {
63 size_t size;
64 uint8_t* buffer = stats_event_get_buffer(statsEventList.data[i], &size);
65
66 android::util::StatsEventParcel p;
67 // vector.assign() creates a copy, but this is inevitable unless
68 // stats_event.h/c uses a vector as opposed to a buffer.
69 p.buffer.assign(buffer, buffer + size);
70 parcels.push_back(std::move(p));
71 }
72
73 resultReceiver->pullFinished(atomTag, success, parcels);
Tej Singhc03d0092019-11-21 12:47:37 -080074 for (int i = 0; i < statsEventList.data.size(); i++) {
75 stats_event_release(statsEventList.data[i]);
76 }
77 return android::binder::Status::ok();
78 }
79
80 const int64_t& getCoolDownNs() const { return mCoolDownNs; }
81 const int64_t& getTimeoutNs() const { return mTimeoutNs; }
82 const std::vector<int32_t>& getAdditiveFields() const { return mAdditiveFields; }
83
84 private:
85 const stats_pull_atom_callback_t* mCallback;
86 const void* mCookie;
87 const int64_t mCoolDownNs;
88 const int64_t mTimeoutNs;
89 const std::vector<int32_t> mAdditiveFields;
90};
91
92static std::mutex pullAtomMutex;
Jeffrey Huang666510a2019-12-11 14:46:14 -080093static android::sp<android::os::IStatsd> sStatsd = nullptr;
Tej Singhc03d0092019-11-21 12:47:37 -080094
95static std::map<int32_t, android::sp<StatsPullAtomCallbackInternal>> mPullers;
Jeffrey Huang666510a2019-12-11 14:46:14 -080096static android::sp<android::os::IStatsd> getStatsServiceLocked();
Tej Singhc03d0092019-11-21 12:47:37 -080097
98class StatsDeathRecipient : public android::IBinder::DeathRecipient {
99 public:
100 StatsDeathRecipient() = default;
101 ~StatsDeathRecipient() override = default;
102
103 // android::IBinder::DeathRecipient override:
104 void binderDied(const android::wp<android::IBinder>& /* who */) override {
105 std::lock_guard<std::mutex> lock(pullAtomMutex);
106 if (sStatsd) {
107 sStatsd = nullptr;
108 }
Jeffrey Huang666510a2019-12-11 14:46:14 -0800109 android::sp<android::os::IStatsd> statsService = getStatsServiceLocked();
Tej Singhc03d0092019-11-21 12:47:37 -0800110 if (statsService == nullptr) {
111 return;
112 }
113 for (auto it : mPullers) {
114 statsService->registerNativePullAtomCallback(it.first, it.second->getCoolDownNs(),
115 it.second->getTimeoutNs(),
116 it.second->getAdditiveFields(), it.second);
117 }
118 }
119};
120
121static android::sp<StatsDeathRecipient> statsDeathRecipient = new StatsDeathRecipient();
122
Jeffrey Huang666510a2019-12-11 14:46:14 -0800123static android::sp<android::os::IStatsd> getStatsServiceLocked() {
Tej Singhc03d0092019-11-21 12:47:37 -0800124 if (!sStatsd) {
125 // Fetch statsd.
126 const android::sp<android::IBinder> binder =
127 android::defaultServiceManager()->checkService(android::String16("stats"));
128 if (!binder) {
129 return nullptr;
130 }
131 binder->linkToDeath(statsDeathRecipient);
Jeffrey Huang666510a2019-12-11 14:46:14 -0800132 sStatsd = android::interface_cast<android::os::IStatsd>(binder);
Tej Singhc03d0092019-11-21 12:47:37 -0800133 }
134 return sStatsd;
135}
136
137void register_stats_pull_atom_callback(int32_t atom_tag, stats_pull_atom_callback_t* callback,
138 pull_atom_metadata* metadata, void* cookie) {
139 int64_t coolDownNs = metadata == nullptr ? DEFAULT_COOL_DOWN_NS : metadata->cool_down_ns;
140 int64_t timeoutNs = metadata == nullptr ? DEFAULT_TIMEOUT_NS : metadata->timeout_ns;
141
142 std::vector<int32_t> additiveFields;
143 if (metadata != nullptr && metadata->additive_fields != nullptr) {
144 additiveFields.assign(metadata->additive_fields,
145 metadata->additive_fields + metadata->additive_fields_size);
146 }
147
148 std::lock_guard<std::mutex> lg(pullAtomMutex);
Jeffrey Huang666510a2019-12-11 14:46:14 -0800149 const android::sp<android::os::IStatsd> statsService = getStatsServiceLocked();
Tej Singhc03d0092019-11-21 12:47:37 -0800150 if (statsService == nullptr) {
151 // Error - statsd not available
152 return;
153 }
154
155 android::sp<StatsPullAtomCallbackInternal> callbackBinder = new StatsPullAtomCallbackInternal(
156 callback, cookie, coolDownNs, timeoutNs, additiveFields);
157 mPullers[atom_tag] = callbackBinder;
158 statsService->registerNativePullAtomCallback(atom_tag, coolDownNs, timeoutNs, additiveFields,
159 callbackBinder);
160}