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