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