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 
setBroadcastSubscriber(const ConfigKey & configKey,int64_t subscriberId,const sp<IBinder> & intentSender)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 
unsetBroadcastSubscriber(const ConfigKey & configKey,int64_t subscriberId)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 
removeConfig(const ConfigKey & configKey)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 
alertBroadcastSubscriber(const ConfigKey & configKey,const Subscription & subscription,const MetricDimensionKey & dimKey) const59 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 
sendBroadcastLocked(const sp<IBinder> & intentSender,const ConfigKey & configKey,const Subscription & subscription,const vector<String16> & cookies,const MetricDimensionKey & dimKey) const100 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 
getStatsDimensionsValueHelper(const vector<FieldValue> & dims,size_t * index,int depth,int prefix,vector<StatsDimensionsValue> * output)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 
getStatsDimensionsValue(const HashableDimensionKey & dim)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