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 #define DEBUG false
     17 #include "Log.h"
     18 
     19 #include "FieldValue.h"
     20 #include "IncidentdReporter.h"
     21 #include "packages/UidMap.h"
     22 #include "stats_log_util.h"
     23 
     24 #include <android/os/IIncidentManager.h>
     25 #include <android/os/IncidentReportArgs.h>
     26 #include <android/util/ProtoOutputStream.h>
     27 #include <binder/IBinder.h>
     28 #include <binder/IServiceManager.h>
     29 
     30 #include <vector>
     31 
     32 namespace android {
     33 namespace os {
     34 namespace statsd {
     35 
     36 using android::util::ProtoOutputStream;
     37 using std::vector;
     38 
     39 using util::FIELD_TYPE_INT32;
     40 using util::FIELD_TYPE_INT64;
     41 using util::FIELD_TYPE_MESSAGE;
     42 using util::FIELD_TYPE_STRING;
     43 
     44 // field ids in IncidentHeaderProto
     45 const int FIELD_ID_ALERT_ID = 1;
     46 const int FIELD_ID_REASON = 2;
     47 const int FIELD_ID_CONFIG_KEY = 3;
     48 const int FIELD_ID_CONFIG_KEY_UID = 1;
     49 const int FIELD_ID_CONFIG_KEY_ID = 2;
     50 
     51 const int FIELD_ID_TRIGGER_DETAILS = 4;
     52 const int FIELD_ID_TRIGGER_DETAILS_TRIGGER_METRIC = 1;
     53 const int FIELD_ID_METRIC_VALUE_METRIC_ID = 1;
     54 const int FIELD_ID_METRIC_VALUE_DIMENSION_IN_WHAT = 2;
     55 const int FIELD_ID_METRIC_VALUE_DIMENSION_IN_CONDITION = 3;
     56 const int FIELD_ID_METRIC_VALUE_VALUE = 4;
     57 
     58 const int FIELD_ID_PACKAGE_INFO = 3;
     59 
     60 namespace {
     61 void getProtoData(const int64_t& rule_id, int64_t metricId, const MetricDimensionKey& dimensionKey,
     62                   int64_t metricValue, const ConfigKey& configKey, const string& reason,
     63                   vector<uint8_t>* protoData) {
     64     ProtoOutputStream headerProto;
     65     headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_ALERT_ID, (long long)rule_id);
     66     headerProto.write(FIELD_TYPE_STRING | FIELD_ID_REASON, reason);
     67     uint64_t token =
     68             headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_CONFIG_KEY);
     69     headerProto.write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_KEY_UID, configKey.GetUid());
     70     headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_CONFIG_KEY_ID, (long long)configKey.GetId());
     71     headerProto.end(token);
     72 
     73     token = headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_TRIGGER_DETAILS);
     74 
     75     // MetricValue trigger_metric = 1;
     76     uint64_t metricToken =
     77             headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_TRIGGER_DETAILS_TRIGGER_METRIC);
     78     // message MetricValue {
     79     // optional int64 metric_id = 1;
     80     headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_VALUE_METRIC_ID, (long long)metricId);
     81     // optional DimensionsValue dimension_in_what = 2;
     82     uint64_t dimToken =
     83             headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_METRIC_VALUE_DIMENSION_IN_WHAT);
     84     writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), nullptr, &headerProto);
     85     headerProto.end(dimToken);
     86 
     87     // optional DimensionsValue dimension_in_condition = 3;
     88     dimToken = headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_METRIC_VALUE_DIMENSION_IN_CONDITION);
     89     writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), nullptr, &headerProto);
     90     headerProto.end(dimToken);
     91 
     92     // optional int64 value = 4;
     93     headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_VALUE_VALUE, (long long)metricValue);
     94 
     95     // }
     96     headerProto.end(metricToken);
     97 
     98     // write relevant uid package info
     99     std::set<int32_t> uids;
    100 
    101     for (const auto& dim : dimensionKey.getDimensionKeyInWhat().getValues()) {
    102         int uid = getUidIfExists(dim);
    103         // any uid <= 2000 are predefined AID_*
    104         if (uid > 2000) {
    105             uids.insert(uid);
    106         }
    107     }
    108 
    109     for (const auto& dim : dimensionKey.getDimensionKeyInCondition().getValues()) {
    110         int uid = getUidIfExists(dim);
    111         if (uid > 2000) {
    112             uids.insert(uid);
    113         }
    114     }
    115 
    116     if (!uids.empty()) {
    117         uint64_t token = headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_PACKAGE_INFO);
    118         UidMap::getInstance()->writeUidMapSnapshot(getElapsedRealtimeNs(), true, true, uids,
    119                                                    nullptr /*string set*/, &headerProto);
    120         headerProto.end(token);
    121     }
    122 
    123     headerProto.end(token);
    124 
    125     protoData->resize(headerProto.size());
    126     size_t pos = 0;
    127     sp<android::util::ProtoReader> reader = headerProto.data();
    128     while (reader->readBuffer() != NULL) {
    129         size_t toRead = reader->currentToRead();
    130         std::memcpy(&((*protoData)[pos]), reader->readBuffer(), toRead);
    131         pos += toRead;
    132         reader->move(toRead);
    133     }
    134 }
    135 }  // namespace
    136 
    137 bool GenerateIncidentReport(const IncidentdDetails& config, int64_t rule_id, int64_t metricId,
    138                             const MetricDimensionKey& dimensionKey, int64_t metricValue,
    139                             const ConfigKey& configKey) {
    140     if (config.section_size() == 0) {
    141         VLOG("The alert %lld contains zero section in config(%d,%lld)", (unsigned long long)rule_id,
    142              configKey.GetUid(), (long long)configKey.GetId());
    143         return false;
    144     }
    145 
    146     IncidentReportArgs incidentReport;
    147 
    148     vector<uint8_t> protoData;
    149     getProtoData(rule_id, metricId, dimensionKey, metricValue, configKey,
    150                  config.alert_description(), &protoData);
    151     incidentReport.addHeader(protoData);
    152 
    153     for (int i = 0; i < config.section_size(); i++) {
    154         incidentReport.addSection(config.section(i));
    155     }
    156 
    157     uint8_t dest;
    158     switch (config.dest()) {
    159         case IncidentdDetails_Destination_AUTOMATIC:
    160             dest = android::os::PRIVACY_POLICY_AUTOMATIC;
    161             break;
    162         case IncidentdDetails_Destination_EXPLICIT:
    163             dest = android::os::PRIVACY_POLICY_EXPLICIT;
    164             break;
    165         default:
    166             dest = android::os::PRIVACY_POLICY_AUTOMATIC;
    167     }
    168     incidentReport.setPrivacyPolicy(dest);
    169 
    170     incidentReport.setReceiverPkg(config.receiver_pkg());
    171 
    172     incidentReport.setReceiverCls(config.receiver_cls());
    173 
    174     sp<IIncidentManager> service = interface_cast<IIncidentManager>(
    175             defaultServiceManager()->getService(android::String16("incident")));
    176     if (service == nullptr) {
    177         ALOGW("Failed to fetch incident service.");
    178         return false;
    179     }
    180     VLOG("Calling incidentd %p", service.get());
    181     binder::Status s = service->reportIncident(incidentReport);
    182     VLOG("Report incident status: %s", s.toString8().string());
    183     return s.isOk();
    184 }
    185 
    186 }  // namespace statsd
    187 }  // namespace os
    188 }  // namespace android
    189