• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
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)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 
GenerateIncidentReport(const IncidentdDetails & config,int64_t rule_id,int64_t metricId,const MetricDimensionKey & dimensionKey,int64_t metricValue,const ConfigKey & configKey)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