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 STATSD_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/util/ProtoOutputStream.h>
25 #include <incident/incident_report.h>
26 
27 #include <vector>
28 
29 namespace android {
30 namespace os {
31 namespace statsd {
32 
33 using android::util::ProtoOutputStream;
34 using std::vector;
35 
36 using util::FIELD_TYPE_INT32;
37 using util::FIELD_TYPE_INT64;
38 using util::FIELD_TYPE_MESSAGE;
39 using util::FIELD_TYPE_STRING;
40 
41 // field ids in IncidentHeaderProto
42 const int FIELD_ID_ALERT_ID = 1;
43 const int FIELD_ID_REASON = 2;
44 const int FIELD_ID_CONFIG_KEY = 3;
45 const int FIELD_ID_CONFIG_KEY_UID = 1;
46 const int FIELD_ID_CONFIG_KEY_ID = 2;
47 
48 const int FIELD_ID_TRIGGER_DETAILS = 4;
49 const int FIELD_ID_TRIGGER_DETAILS_TRIGGER_METRIC = 1;
50 const int FIELD_ID_METRIC_VALUE_METRIC_ID = 1;
51 const int FIELD_ID_METRIC_VALUE_DIMENSION_IN_WHAT = 2;
52 const int FIELD_ID_METRIC_VALUE_VALUE = 4;
53 
54 const int FIELD_ID_PACKAGE_INFO = 3;
55 
56 namespace {
getProtoData(const int64_t & rule_id,int64_t metricId,const MetricDimensionKey & dimensionKey,int64_t metricValue,const ConfigKey & configKey,const string & reason,vector<uint8_t> * protoData)57 void getProtoData(const int64_t& rule_id, int64_t metricId, const MetricDimensionKey& dimensionKey,
58                   int64_t metricValue, const ConfigKey& configKey, const string& reason,
59                   vector<uint8_t>* protoData) {
60     ProtoOutputStream headerProto;
61     headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_ALERT_ID, (long long)rule_id);
62     headerProto.write(FIELD_TYPE_STRING | FIELD_ID_REASON, reason);
63     uint64_t token =
64             headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_CONFIG_KEY);
65     headerProto.write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_KEY_UID, configKey.GetUid());
66     headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_CONFIG_KEY_ID, (long long)configKey.GetId());
67     headerProto.end(token);
68 
69     token = headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_TRIGGER_DETAILS);
70 
71     // MetricValue trigger_metric = 1;
72     uint64_t metricToken =
73             headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_TRIGGER_DETAILS_TRIGGER_METRIC);
74     // message MetricValue {
75     // optional int64 metric_id = 1;
76     headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_VALUE_METRIC_ID, (long long)metricId);
77     // optional DimensionsValue dimension_in_what = 2;
78     uint64_t dimToken =
79             headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_METRIC_VALUE_DIMENSION_IN_WHAT);
80     set<int32_t> usedUids;
81     writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), {}, nullptr, usedUids,
82                           &headerProto);
83     headerProto.end(dimToken);
84 
85     // deprecated field
86     // optional DimensionsValue dimension_in_condition = 3;
87 
88     // optional int64 value = 4;
89     headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_VALUE_VALUE, (long long)metricValue);
90 
91     // }
92     headerProto.end(metricToken);
93 
94     // write relevant uid package info
95     std::set<int32_t> uids;
96 
97     for (const auto& dim : dimensionKey.getDimensionKeyInWhat().getValues()) {
98         int uid = getUidIfExists(dim);
99         // any uid <= 2000 are predefined AID_*
100         if (uid > 2000) {
101             uids.insert(uid);
102         }
103     }
104 
105     if (!uids.empty()) {
106         uint64_t token = headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_PACKAGE_INFO);
107         UidMap::getInstance()->writeUidMapSnapshot(
108                 getElapsedRealtimeNs(),
109                 {true, true,
110                  /*truncatedCertificateHashSize*/ 0, /*omitSystemUids*/ false},
111                 uids, nullptr /*installerIndices*/, nullptr /*string set*/, &headerProto);
112         headerProto.end(token);
113     }
114 
115     headerProto.end(token);
116 
117     protoData->resize(headerProto.size());
118     size_t pos = 0;
119     sp<android::util::ProtoReader> reader = headerProto.data();
120     while (reader->readBuffer() != NULL) {
121         size_t toRead = reader->currentToRead();
122         std::memcpy(&((*protoData)[pos]), reader->readBuffer(), toRead);
123         pos += toRead;
124         reader->move(toRead);
125     }
126 }
127 }  // namespace
128 
GenerateIncidentReport(const IncidentdDetails & config,int64_t rule_id,int64_t metricId,const MetricDimensionKey & dimensionKey,int64_t metricValue,const ConfigKey & configKey)129 bool GenerateIncidentReport(const IncidentdDetails& config, int64_t rule_id, int64_t metricId,
130                             const MetricDimensionKey& dimensionKey, int64_t metricValue,
131                             const ConfigKey& configKey) {
132     if (config.section_size() == 0) {
133         VLOG("The alert %lld contains zero section in config(%d,%lld)", (unsigned long long)rule_id,
134              configKey.GetUid(), (long long)configKey.GetId());
135         return false;
136     }
137 
138     AIncidentReportArgs* args = AIncidentReportArgs_init();
139 
140     vector<uint8_t> protoData;
141     getProtoData(rule_id, metricId, dimensionKey, metricValue, configKey,
142                  config.alert_description(), &protoData);
143     AIncidentReportArgs_addHeader(args, protoData.data(), protoData.size());
144 
145     for (int i = 0; i < config.section_size(); i++) {
146         AIncidentReportArgs_addSection(args, config.section(i));
147     }
148 
149     uint8_t dest;
150     switch (config.dest()) {
151         case IncidentdDetails_Destination_AUTOMATIC:
152             dest = INCIDENT_REPORT_PRIVACY_POLICY_AUTOMATIC;
153             break;
154         case IncidentdDetails_Destination_EXPLICIT:
155             dest = INCIDENT_REPORT_PRIVACY_POLICY_EXPLICIT;
156             break;
157         default:
158             dest = INCIDENT_REPORT_PRIVACY_POLICY_AUTOMATIC;
159     }
160     AIncidentReportArgs_setPrivacyPolicy(args, dest);
161 
162     AIncidentReportArgs_setReceiverPackage(args, config.receiver_pkg().c_str());
163 
164     AIncidentReportArgs_setReceiverClass(args, config.receiver_cls().c_str());
165 
166     int err = AIncidentReportArgs_takeReport(args);
167     AIncidentReportArgs_delete(args);
168 
169     return err == NO_ERROR;
170 }
171 
172 }  // namespace statsd
173 }  // namespace os
174 }  // namespace android
175