• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
broadcastSubscriberDied(void * rawPir)30 void SubscriberReporter::broadcastSubscriberDied(void* rawPir) {
31     SubscriberReporter& thiz = getInstance();
32 
33     // Erase the mapping from a (config_key, subscriberId) to a pir if the
34     // mapping exists. This requires iterating over the map, but this operation
35     // should be rare and the map is expected to be small.
36     lock_guard<mutex> lock(thiz.mLock);
37     for (auto subscriberMapIt = thiz.mIntentMap.begin(); subscriberMapIt != thiz.mIntentMap.end();
38          subscriberMapIt++) {
39         unordered_map<int64_t, shared_ptr<IPendingIntentRef>>& subscriberMap =
40                 subscriberMapIt->second;
41         for (auto pirIt = subscriberMap.begin(); pirIt != subscriberMap.end(); pirIt++) {
42             if (pirIt->second.get() == rawPir) {
43                 subscriberMap.erase(pirIt);
44                 if (subscriberMap.empty()) {
45                     thiz.mIntentMap.erase(subscriberMapIt);
46                 }
47                 // pirIt and subscriberMapIt are now invalid.
48                 return;
49             }
50         }
51     }
52 }
53 
SubscriberReporter()54 SubscriberReporter::SubscriberReporter() :
55     mBroadcastSubscriberDeathRecipient(AIBinder_DeathRecipient_new(broadcastSubscriberDied)) {
56 }
57 
setBroadcastSubscriber(const ConfigKey & configKey,int64_t subscriberId,const shared_ptr<IPendingIntentRef> & pir)58 void SubscriberReporter::setBroadcastSubscriber(const ConfigKey& configKey,
59                                                 int64_t subscriberId,
60                                                 const shared_ptr<IPendingIntentRef>& pir) {
61     VLOG("SubscriberReporter::setBroadcastSubscriber called with configKey %s and subscriberId "
62          "%lld.",
63          configKey.ToString().c_str(), (long long)subscriberId);
64     {
65         lock_guard<mutex> lock(mLock);
66         mIntentMap[configKey][subscriberId] = pir;
67     }
68     // Pass the raw binder pointer address to be the cookie of the death recipient. While the death
69     // notification is fired, the cookie is used for identifying which binder was died. Because
70     // the NDK binder doesn't pass dead binder pointer to binder death handler, the binder death
71     // handler can't know who died.
72     // If a dedicated cookie is used to store metadata (config key, subscriber id) for direct
73     // lookup, a data structure is needed manage the cookies.
74     AIBinder_linkToDeath(pir->asBinder().get(), mBroadcastSubscriberDeathRecipient.get(),
75                          pir.get());
76 }
77 
unsetBroadcastSubscriber(const ConfigKey & configKey,int64_t subscriberId)78 void SubscriberReporter::unsetBroadcastSubscriber(const ConfigKey& configKey,
79                                                   int64_t subscriberId) {
80     VLOG("SubscriberReporter::unsetBroadcastSubscriber called.");
81     lock_guard<mutex> lock(mLock);
82     auto subscriberMapIt = mIntentMap.find(configKey);
83     if (subscriberMapIt != mIntentMap.end()) {
84         subscriberMapIt->second.erase(subscriberId);
85         if (subscriberMapIt->second.empty()) {
86             mIntentMap.erase(configKey);
87         }
88     }
89 }
90 
alertBroadcastSubscriber(const ConfigKey & configKey,const Subscription & subscription,const MetricDimensionKey & dimKey) const91 void SubscriberReporter::alertBroadcastSubscriber(const ConfigKey& configKey,
92                                                   const Subscription& subscription,
93                                                   const MetricDimensionKey& dimKey) const {
94     // Reminder about ids:
95     //  subscription id - name of the Subscription (that ties the Alert to the broadcast)
96     //  subscription rule_id - the name of the Alert (that triggers the broadcast)
97     //  subscriber_id - name of the PendingIntent to use to send the broadcast
98     //  config uid - the uid that uploaded the config (and therefore gave the PendingIntent,
99     //                 although the intent may be to broadcast to a different uid)
100     //  config id - the name of this config (for this particular uid)
101 
102     VLOG("SubscriberReporter::alertBroadcastSubscriber called.");
103     lock_guard<mutex> lock(mLock);
104 
105     if (!subscription.has_broadcast_subscriber_details()
106             || !subscription.broadcast_subscriber_details().has_subscriber_id()) {
107         ALOGE("Broadcast subscriber does not have an id.");
108         return;
109     }
110     int64_t subscriberId = subscription.broadcast_subscriber_details().subscriber_id();
111 
112     vector<string> cookies;
113     cookies.reserve(subscription.broadcast_subscriber_details().cookie_size());
114     for (auto& cookie : subscription.broadcast_subscriber_details().cookie()) {
115         cookies.push_back(cookie);
116     }
117 
118     auto it1 = mIntentMap.find(configKey);
119     if (it1 == mIntentMap.end()) {
120         ALOGW("Cannot inform subscriber for missing config key %s ", configKey.ToString().c_str());
121         return;
122     }
123     auto it2 = it1->second.find(subscriberId);
124     if (it2 == it1->second.end()) {
125         ALOGW("Cannot inform subscriber of config %s for missing subscriberId %lld ",
126                 configKey.ToString().c_str(), (long long)subscriberId);
127         return;
128     }
129     sendBroadcastLocked(it2->second, configKey, subscription, cookies, dimKey);
130 }
131 
sendBroadcastLocked(const shared_ptr<IPendingIntentRef> & pir,const ConfigKey & configKey,const Subscription & subscription,const vector<string> & cookies,const MetricDimensionKey & dimKey) const132 void SubscriberReporter::sendBroadcastLocked(const shared_ptr<IPendingIntentRef>& pir,
133                                              const ConfigKey& configKey,
134                                              const Subscription& subscription,
135                                              const vector<string>& cookies,
136                                              const MetricDimensionKey& dimKey) const {
137     VLOG("SubscriberReporter::sendBroadcastLocked called.");
138     pir->sendSubscriberBroadcast(
139             configKey.GetUid(),
140             configKey.GetId(),
141             subscription.id(),
142             subscription.rule_id(),
143             cookies,
144             dimKey.getDimensionKeyInWhat().toStatsDimensionsValueParcel());
145 }
146 
147 }  // namespace statsd
148 }  // namespace os
149 }  // namespace android
150