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 android::IBinder; 23 using std::lock_guard; 24 using std::unordered_map; 25 26 namespace android { 27 namespace os { 28 namespace statsd { 29 30 using std::vector; 31 32 void SubscriberReporter::setBroadcastSubscriber(const ConfigKey& configKey, 33 int64_t subscriberId, 34 const sp<IBinder>& intentSender) { 35 VLOG("SubscriberReporter::setBroadcastSubscriber called."); 36 lock_guard<std::mutex> lock(mLock); 37 mIntentMap[configKey][subscriberId] = intentSender; 38 } 39 40 void SubscriberReporter::unsetBroadcastSubscriber(const ConfigKey& configKey, 41 int64_t subscriberId) { 42 VLOG("SubscriberReporter::unsetBroadcastSubscriber called."); 43 lock_guard<std::mutex> lock(mLock); 44 auto subscriberMapIt = mIntentMap.find(configKey); 45 if (subscriberMapIt != mIntentMap.end()) { 46 subscriberMapIt->second.erase(subscriberId); 47 if (subscriberMapIt->second.empty()) { 48 mIntentMap.erase(configKey); 49 } 50 } 51 } 52 53 void SubscriberReporter::removeConfig(const ConfigKey& configKey) { 54 VLOG("SubscriberReporter::removeConfig called."); 55 lock_guard<std::mutex> lock(mLock); 56 mIntentMap.erase(configKey); 57 } 58 59 void SubscriberReporter::alertBroadcastSubscriber(const ConfigKey& configKey, 60 const Subscription& subscription, 61 const MetricDimensionKey& dimKey) const { 62 // Reminder about ids: 63 // subscription id - name of the Subscription (that ties the Alert to the broadcast) 64 // subscription rule_id - the name of the Alert (that triggers the broadcast) 65 // subscriber_id - name of the PendingIntent to use to send the broadcast 66 // config uid - the uid that uploaded the config (and therefore gave the PendingIntent, 67 // although the intent may be to broadcast to a different uid) 68 // config id - the name of this config (for this particular uid) 69 70 VLOG("SubscriberReporter::alertBroadcastSubscriber called."); 71 lock_guard<std::mutex> lock(mLock); 72 73 if (!subscription.has_broadcast_subscriber_details() 74 || !subscription.broadcast_subscriber_details().has_subscriber_id()) { 75 ALOGE("Broadcast subscriber does not have an id."); 76 return; 77 } 78 int64_t subscriberId = subscription.broadcast_subscriber_details().subscriber_id(); 79 80 vector<String16> cookies; 81 cookies.reserve(subscription.broadcast_subscriber_details().cookie_size()); 82 for (auto& cookie : subscription.broadcast_subscriber_details().cookie()) { 83 cookies.push_back(String16(cookie.c_str())); 84 } 85 86 auto it1 = mIntentMap.find(configKey); 87 if (it1 == mIntentMap.end()) { 88 ALOGW("Cannot inform subscriber for missing config key %s ", configKey.ToString().c_str()); 89 return; 90 } 91 auto it2 = it1->second.find(subscriberId); 92 if (it2 == it1->second.end()) { 93 ALOGW("Cannot inform subscriber of config %s for missing subscriberId %lld ", 94 configKey.ToString().c_str(), (long long)subscriberId); 95 return; 96 } 97 sendBroadcastLocked(it2->second, configKey, subscription, cookies, dimKey); 98 } 99 100 void SubscriberReporter::sendBroadcastLocked(const sp<IBinder>& intentSender, 101 const ConfigKey& configKey, 102 const Subscription& subscription, 103 const vector<String16>& cookies, 104 const MetricDimensionKey& dimKey) const { 105 VLOG("SubscriberReporter::sendBroadcastLocked called."); 106 if (mStatsCompanionService == nullptr) { 107 ALOGW("Failed to send subscriber broadcast: could not access StatsCompanionService."); 108 return; 109 } 110 mStatsCompanionService->sendSubscriberBroadcast( 111 intentSender, 112 configKey.GetUid(), 113 configKey.GetId(), 114 subscription.id(), 115 subscription.rule_id(), 116 cookies, 117 getStatsDimensionsValue(dimKey.getDimensionKeyInWhat())); 118 } 119 120 void getStatsDimensionsValueHelper(const vector<FieldValue>& dims, size_t* index, int depth, 121 int prefix, vector<StatsDimensionsValue>* output) { 122 size_t count = dims.size(); 123 while (*index < count) { 124 const auto& dim = dims[*index]; 125 const int valueDepth = dim.mField.getDepth(); 126 const int valuePrefix = dim.mField.getPrefix(depth); 127 if (valueDepth > 2) { 128 ALOGE("Depth > 2 not supported"); 129 return; 130 } 131 if (depth == valueDepth && valuePrefix == prefix) { 132 switch (dim.mValue.getType()) { 133 case INT: 134 output->push_back(StatsDimensionsValue(dim.mField.getPosAtDepth(depth), 135 dim.mValue.int_value)); 136 break; 137 case LONG: 138 output->push_back(StatsDimensionsValue(dim.mField.getPosAtDepth(depth), 139 dim.mValue.long_value)); 140 break; 141 case FLOAT: 142 output->push_back(StatsDimensionsValue(dim.mField.getPosAtDepth(depth), 143 dim.mValue.float_value)); 144 break; 145 case STRING: 146 output->push_back(StatsDimensionsValue(dim.mField.getPosAtDepth(depth), 147 String16(dim.mValue.str_value.c_str()))); 148 break; 149 default: 150 break; 151 } 152 (*index)++; 153 } else if (valueDepth > depth && valuePrefix == prefix) { 154 vector<StatsDimensionsValue> childOutput; 155 getStatsDimensionsValueHelper(dims, index, depth + 1, dim.mField.getPrefix(depth + 1), 156 &childOutput); 157 output->push_back(StatsDimensionsValue(dim.mField.getPosAtDepth(depth), childOutput)); 158 } else { 159 return; 160 } 161 } 162 } 163 164 StatsDimensionsValue SubscriberReporter::getStatsDimensionsValue(const HashableDimensionKey& dim) { 165 if (dim.getValues().size() == 0) { 166 return StatsDimensionsValue(); 167 } 168 169 vector<StatsDimensionsValue> fields; 170 size_t index = 0; 171 getStatsDimensionsValueHelper(dim.getValues(), &index, 0, 0, &fields); 172 return StatsDimensionsValue(dim.getValues()[0].mField.getTag(), fields); 173 } 174 175 } // namespace statsd 176 } // namespace os 177 } // namespace android 178