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/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 writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), nullptr, &headerProto);
81 headerProto.end(dimToken);
82
83 // deprecated field
84 // optional DimensionsValue dimension_in_condition = 3;
85
86 // optional int64 value = 4;
87 headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_VALUE_VALUE, (long long)metricValue);
88
89 // }
90 headerProto.end(metricToken);
91
92 // write relevant uid package info
93 std::set<int32_t> uids;
94
95 for (const auto& dim : dimensionKey.getDimensionKeyInWhat().getValues()) {
96 int uid = getUidIfExists(dim);
97 // any uid <= 2000 are predefined AID_*
98 if (uid > 2000) {
99 uids.insert(uid);
100 }
101 }
102
103 if (!uids.empty()) {
104 uint64_t token = headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_PACKAGE_INFO);
105 UidMap::getInstance()->writeUidMapSnapshot(getElapsedRealtimeNs(), true, true, uids,
106 nullptr /*string set*/, &headerProto);
107 headerProto.end(token);
108 }
109
110 headerProto.end(token);
111
112 protoData->resize(headerProto.size());
113 size_t pos = 0;
114 sp<android::util::ProtoReader> reader = headerProto.data();
115 while (reader->readBuffer() != NULL) {
116 size_t toRead = reader->currentToRead();
117 std::memcpy(&((*protoData)[pos]), reader->readBuffer(), toRead);
118 pos += toRead;
119 reader->move(toRead);
120 }
121 }
122 } // namespace
123
GenerateIncidentReport(const IncidentdDetails & config,int64_t rule_id,int64_t metricId,const MetricDimensionKey & dimensionKey,int64_t metricValue,const ConfigKey & configKey)124 bool GenerateIncidentReport(const IncidentdDetails& config, int64_t rule_id, int64_t metricId,
125 const MetricDimensionKey& dimensionKey, int64_t metricValue,
126 const ConfigKey& configKey) {
127 if (config.section_size() == 0) {
128 VLOG("The alert %lld contains zero section in config(%d,%lld)", (unsigned long long)rule_id,
129 configKey.GetUid(), (long long)configKey.GetId());
130 return false;
131 }
132
133 AIncidentReportArgs* args = AIncidentReportArgs_init();
134
135 vector<uint8_t> protoData;
136 getProtoData(rule_id, metricId, dimensionKey, metricValue, configKey,
137 config.alert_description(), &protoData);
138 AIncidentReportArgs_addHeader(args, protoData.data(), protoData.size());
139
140 for (int i = 0; i < config.section_size(); i++) {
141 AIncidentReportArgs_addSection(args, config.section(i));
142 }
143
144 uint8_t dest;
145 switch (config.dest()) {
146 case IncidentdDetails_Destination_AUTOMATIC:
147 dest = INCIDENT_REPORT_PRIVACY_POLICY_AUTOMATIC;
148 break;
149 case IncidentdDetails_Destination_EXPLICIT:
150 dest = INCIDENT_REPORT_PRIVACY_POLICY_EXPLICIT;
151 break;
152 default:
153 dest = INCIDENT_REPORT_PRIVACY_POLICY_AUTOMATIC;
154 }
155 AIncidentReportArgs_setPrivacyPolicy(args, dest);
156
157 AIncidentReportArgs_setReceiverPackage(args, config.receiver_pkg().c_str());
158
159 AIncidentReportArgs_setReceiverClass(args, config.receiver_cls().c_str());
160
161 int err = AIncidentReportArgs_takeReport(args);
162 AIncidentReportArgs_delete(args);
163
164 return err == NO_ERROR;
165 }
166
167 } // namespace statsd
168 } // namespace os
169 } // namespace android
170