Home | History | Annotate | Download | only in subscriber
      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