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 { 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 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