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 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 54 SubscriberReporter::SubscriberReporter() : 55 mBroadcastSubscriberDeathRecipient(AIBinder_DeathRecipient_new(broadcastSubscriberDied)) { 56 } 57 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 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 91 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 132 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