1 /*
2 * Copyright (C) 2018 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 #define DEBUG false // STOPSHIP if true
18 #include "Log.h"
19
20 #include "SubscriberReporter.h"
21
22 using std::lock_guard;
23
24 namespace android {
25 namespace os {
26 namespace statsd {
27
28 using std::vector;
29
30 struct BroadcastSubscriberDeathCookie {
BroadcastSubscriberDeathCookieandroid::os::statsd::BroadcastSubscriberDeathCookie31 BroadcastSubscriberDeathCookie(const ConfigKey& configKey, int64_t subscriberId,
32 const shared_ptr<IPendingIntentRef>& pir):
33 mConfigKey(configKey),
34 mSubscriberId(subscriberId),
35 mPir(pir) {}
36
37 ConfigKey mConfigKey;
38 int64_t mSubscriberId;
39 shared_ptr<IPendingIntentRef> mPir;
40 };
41
broadcastSubscriberDied(void * cookie)42 void SubscriberReporter::broadcastSubscriberDied(void* cookie) {
43 auto cookie_ = static_cast<BroadcastSubscriberDeathCookie*>(cookie);
44 ConfigKey& configKey = cookie_->mConfigKey;
45 int64_t subscriberId = cookie_->mSubscriberId;
46 shared_ptr<IPendingIntentRef>& pir = cookie_->mPir;
47
48 SubscriberReporter& thiz = getInstance();
49
50 // Erase the mapping from a (config_key, subscriberId) to a pir if the
51 // mapping exists.
52 lock_guard<mutex> lock(thiz.mLock);
53 auto subscriberMapIt = thiz.mIntentMap.find(configKey);
54 if (subscriberMapIt != thiz.mIntentMap.end()) {
55 auto subscriberMap = subscriberMapIt->second;
56 auto pirIt = subscriberMap.find(subscriberId);
57 if (pirIt != subscriberMap.end() && pirIt->second == pir) {
58 subscriberMap.erase(subscriberId);
59 if (subscriberMap.empty()) {
60 thiz.mIntentMap.erase(configKey);
61 }
62 }
63 }
64
65 // The death recipient corresponding to this specific pir can never be
66 // triggered again, so free up resources.
67 delete cookie_;
68 }
69
SubscriberReporter()70 SubscriberReporter::SubscriberReporter() :
71 mBroadcastSubscriberDeathRecipient(AIBinder_DeathRecipient_new(broadcastSubscriberDied)) {
72 }
73
setBroadcastSubscriber(const ConfigKey & configKey,int64_t subscriberId,const shared_ptr<IPendingIntentRef> & pir)74 void SubscriberReporter::setBroadcastSubscriber(const ConfigKey& configKey,
75 int64_t subscriberId,
76 const shared_ptr<IPendingIntentRef>& pir) {
77 VLOG("SubscriberReporter::setBroadcastSubscriber called.");
78 {
79 lock_guard<mutex> lock(mLock);
80 mIntentMap[configKey][subscriberId] = pir;
81 }
82 AIBinder_linkToDeath(pir->asBinder().get(), mBroadcastSubscriberDeathRecipient.get(),
83 new BroadcastSubscriberDeathCookie(configKey, subscriberId, pir));
84 }
85
unsetBroadcastSubscriber(const ConfigKey & configKey,int64_t subscriberId)86 void SubscriberReporter::unsetBroadcastSubscriber(const ConfigKey& configKey,
87 int64_t subscriberId) {
88 VLOG("SubscriberReporter::unsetBroadcastSubscriber called.");
89 lock_guard<mutex> lock(mLock);
90 auto subscriberMapIt = mIntentMap.find(configKey);
91 if (subscriberMapIt != mIntentMap.end()) {
92 subscriberMapIt->second.erase(subscriberId);
93 if (subscriberMapIt->second.empty()) {
94 mIntentMap.erase(configKey);
95 }
96 }
97 }
98
alertBroadcastSubscriber(const ConfigKey & configKey,const Subscription & subscription,const MetricDimensionKey & dimKey) const99 void SubscriberReporter::alertBroadcastSubscriber(const ConfigKey& configKey,
100 const Subscription& subscription,
101 const MetricDimensionKey& dimKey) const {
102 // Reminder about ids:
103 // subscription id - name of the Subscription (that ties the Alert to the broadcast)
104 // subscription rule_id - the name of the Alert (that triggers the broadcast)
105 // subscriber_id - name of the PendingIntent to use to send the broadcast
106 // config uid - the uid that uploaded the config (and therefore gave the PendingIntent,
107 // although the intent may be to broadcast to a different uid)
108 // config id - the name of this config (for this particular uid)
109
110 VLOG("SubscriberReporter::alertBroadcastSubscriber called.");
111 lock_guard<mutex> lock(mLock);
112
113 if (!subscription.has_broadcast_subscriber_details()
114 || !subscription.broadcast_subscriber_details().has_subscriber_id()) {
115 ALOGE("Broadcast subscriber does not have an id.");
116 return;
117 }
118 int64_t subscriberId = subscription.broadcast_subscriber_details().subscriber_id();
119
120 vector<string> cookies;
121 cookies.reserve(subscription.broadcast_subscriber_details().cookie_size());
122 for (auto& cookie : subscription.broadcast_subscriber_details().cookie()) {
123 cookies.push_back(cookie);
124 }
125
126 auto it1 = mIntentMap.find(configKey);
127 if (it1 == mIntentMap.end()) {
128 ALOGW("Cannot inform subscriber for missing config key %s ", configKey.ToString().c_str());
129 return;
130 }
131 auto it2 = it1->second.find(subscriberId);
132 if (it2 == it1->second.end()) {
133 ALOGW("Cannot inform subscriber of config %s for missing subscriberId %lld ",
134 configKey.ToString().c_str(), (long long)subscriberId);
135 return;
136 }
137 sendBroadcastLocked(it2->second, configKey, subscription, cookies, dimKey);
138 }
139
sendBroadcastLocked(const shared_ptr<IPendingIntentRef> & pir,const ConfigKey & configKey,const Subscription & subscription,const vector<string> & cookies,const MetricDimensionKey & dimKey) const140 void SubscriberReporter::sendBroadcastLocked(const shared_ptr<IPendingIntentRef>& pir,
141 const ConfigKey& configKey,
142 const Subscription& subscription,
143 const vector<string>& cookies,
144 const MetricDimensionKey& dimKey) const {
145 VLOG("SubscriberReporter::sendBroadcastLocked called.");
146 pir->sendSubscriberBroadcast(
147 configKey.GetUid(),
148 configKey.GetId(),
149 subscription.id(),
150 subscription.rule_id(),
151 cookies,
152 dimKey.getDimensionKeyInWhat().toStatsDimensionsValueParcel());
153 }
154
getBroadcastSubscriber(const ConfigKey & configKey,int64_t subscriberId)155 shared_ptr<IPendingIntentRef> SubscriberReporter::getBroadcastSubscriber(const ConfigKey& configKey,
156 int64_t subscriberId) {
157 lock_guard<mutex> lock(mLock);
158 auto subscriberMapIt = mIntentMap.find(configKey);
159 if (subscriberMapIt == mIntentMap.end()) {
160 return nullptr;
161 }
162 auto pirMapIt = subscriberMapIt->second.find(subscriberId);
163 if (pirMapIt == subscriberMapIt->second.end()) {
164 return nullptr;
165 }
166 return pirMapIt->second;
167 }
168
169 } // namespace statsd
170 } // namespace os
171 } // namespace android
172