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