blob: 63464f2d58c56f0bdb5b3a83e9afc3c2a94a1362 [file] [log] [blame]
Joe Onorato99598ee2019-02-11 15:55:13 +00001/*
2 * Copyright (C) 2016 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
17#include "Log.h"
18
19#include "Broadcaster.h"
20
21#include "IncidentService.h"
22
23#include <android/os/DropBoxManager.h>
24#include <binder/IServiceManager.h>
Yao Chencbafce92019-04-01 15:56:44 -070025#include <thread>
Joe Onorato99598ee2019-02-11 15:55:13 +000026
27namespace android {
28namespace os {
29namespace incidentd {
30
31using android::os::IIncidentCompanion;
32using binder::Status;
33
34// ============================================================
35Broadcaster::ConsentListener::ConsentListener(const sp<Broadcaster>& broadcaster,
36 const ReportId& reportId)
37 :mBroadcaster(broadcaster),
38 mId(reportId) {
39}
40
41Broadcaster::ConsentListener::~ConsentListener() {
42}
43
44Status Broadcaster::ConsentListener::onReportApproved() {
45 mBroadcaster->report_approved(mId);
46 return Status::ok();
47}
48
49Status Broadcaster::ConsentListener::onReportDenied() {
50 mBroadcaster->report_denied(mId);
51 return Status::ok();
52}
53
54// ============================================================
55Broadcaster::ReportId::ReportId()
56 :id(),
57 pkg(),
58 cls() {
59}
60
61Broadcaster::ReportId::ReportId(const ReportId& that)
62 :id(that.id),
63 pkg(that.pkg),
64 cls(that.cls) {
65}
66
67Broadcaster::ReportId::ReportId(const string& i, const string& p, const string& c)
68 :id(i),
69 pkg(p),
70 cls(c) {
71}
72
73Broadcaster::ReportId::~ReportId() {
74}
75
76bool Broadcaster::ReportId::operator<(const ReportId& that) const {
77 if (id < that.id) {
78 return true;
79 }
80 if (id > that.id) {
81 return false;
82 }
83 if (pkg < that.pkg) {
84 return true;
85 }
86 if (pkg > that.pkg) {
87 return false;
88 }
89 if (cls < that.cls) {
90 return true;
91 }
92 return false;
93}
94
95// ============================================================
96Broadcaster::ReportStatus::ReportStatus()
97 :approval_sent(false),
98 ready_sent(false),
99 listener(nullptr) {
100}
101
102Broadcaster::ReportStatus::ReportStatus(const ReportStatus& that)
103 :approval_sent(that.approval_sent),
104 ready_sent(that.ready_sent),
105 listener(that.listener) {
106}
107
108Broadcaster::ReportStatus::~ReportStatus() {
109}
110
111// ============================================================
112Broadcaster::Broadcaster(const sp<WorkDirectory>& workDirectory)
113 :mReportHandler(),
114 mWorkDirectory(workDirectory) {
115}
116
117void Broadcaster::setHandler(const sp<ReportHandler>& handler) {
118 mReportHandler = handler;
119}
120
121void Broadcaster::reset() {
122 unique_lock<mutex> lock(mLock);
123 mLastSent = 0;
124 mHistory.clear();
125 // Could cancel the listeners, but this happens when
126 // the system process crashes, so don't bother.
127}
128
129void Broadcaster::clearBroadcasts(const string& pkg, const string& cls, const string& id) {
130 unique_lock<mutex> lock(mLock);
131
132 map<ReportId,ReportStatus>::const_iterator found = mHistory.find(ReportId(id, pkg, cls));
133 if (found != mHistory.end()) {
134 if (found->second.listener != nullptr) {
135 sp<IIncidentCompanion> ics = get_incident_companion();
136 if (ics != nullptr) {
137 ics->cancelAuthorization(found->second.listener);
138 }
139 }
140 mHistory.erase(found);
141 }
142}
143
144void Broadcaster::clearPackageBroadcasts(const string& pkg) {
145 unique_lock<mutex> lock(mLock);
146
147 map<ReportId,ReportStatus>::iterator it = mHistory.begin();
148 while (it != mHistory.end()) {
149 if (it->first.pkg == pkg) {
150 if (it->second.listener != nullptr) {
151 sp<IIncidentCompanion> ics = get_incident_companion();
152 if (ics != nullptr) {
153 ics->cancelAuthorization(it->second.listener);
154 }
155 }
156 it = mHistory.erase(it);
157 } else {
158 it++;
159 }
160 }
161}
162
163Broadcaster::broadcast_status_t Broadcaster::sendBroadcasts() {
164 int err;
165 int64_t lastSent = get_last_sent();
166
167 vector<sp<ReportFile>> files;
168 mWorkDirectory->getReports(&files, 0); //lastSent);
169
170 // Don't send multiple broadcasts to the same receiver.
171 set<ReportId> reportReadyBroadcasts;
172
173 for (const sp<ReportFile>& file: files) {
174 err = file->loadEnvelope();
175 if (err != NO_ERROR) {
176 ALOGW("Error (%s) loading envelope from %s", strerror(-err),
177 file->getEnvelopeFileName().c_str());
178 continue;
179 }
180
181 const ReportFileProto& envelope = file->getEnvelope();
182
183 if (!envelope.completed()) {
184 ALOGI("Incident report not completed skipping it: %s",
185 file->getEnvelopeFileName().c_str());
186 continue;
187 }
188
189 // When one of the broadcast functions in this loop fails, it's almost
190 // certainly because the system process is crashing or has crashed. Rather
191 // than continuing to pound on the system process and potentially make things
192 // worse, we bail right away, return BROADCASTS_BACKOFF, and we will try
193 // again later. In the meantime, if the system process did crash, it might
194 // clear out mHistory, which means we'll be back here again to send the
195 // backlog.
196 size_t reportCount = envelope.report_size();
197 bool hasApprovalPending = false;
198 for (int reportIndex = 0; reportIndex < reportCount; reportIndex++) {
199
200 const ReportFileProto_Report& report = envelope.report(reportIndex);
201 status_t err;
202 if (report.privacy_policy() == PRIVACY_POLICY_AUTOMATIC || report.share_approved()) {
203 // It's privacy policy is AUTO, or it's been approved,
204 // so send the actual broadcast.
205 if (!was_ready_sent(file->getId(), report.pkg(), report.cls())) {
206 if (report.pkg() == DROPBOX_SENTINEL.getPackageName()
207 && report.cls() == DROPBOX_SENTINEL.getClassName()) {
208 IncidentReportArgs args;
209 get_args_from_report(&args, report);
210 err = send_to_dropbox(file, args);
211 if (err != NO_ERROR) {
212 return BROADCASTS_BACKOFF;
213 }
214 } else {
215 reportReadyBroadcasts.insert(ReportId(file->getId(), report.pkg(),
216 report.cls()));
217 }
218 }
219 } else {
220 // It's not approved yet, so send the approval.
221 if (!was_approval_sent(file->getId(), report.pkg(), report.cls())) {
222 err = send_approval_broadcasts(file->getId(), report.pkg(), report.cls());
223 if (err != NO_ERROR) {
224 return BROADCASTS_BACKOFF;
225 }
226 hasApprovalPending = true;
227 }
228 }
229 }
230
231 lastSent = file->getTimestampNs();
232 if (!hasApprovalPending) {
233 set_last_sent(lastSent);
234 }
235 }
236
237 for (const ReportId& report: reportReadyBroadcasts) {
238 err = send_report_ready_broadcasts(report.id, report.pkg, report.cls);
239 if (err != NO_ERROR) {
240 return BROADCASTS_BACKOFF;
241 }
242 }
243
244 return mWorkDirectory->hasMore(lastSent) ? BROADCASTS_REPEAT : BROADCASTS_FINISHED;
245}
246
247void Broadcaster::set_last_sent(int64_t timestamp) {
248 unique_lock<mutex> lock(mLock);
249 mLastSent = timestamp;
250}
251
252int64_t Broadcaster::get_last_sent() {
253 unique_lock<mutex> lock(mLock);
254 return mLastSent;
255}
256
257/*
258void Broadcaster::printReportStatuses() const {
259 ALOGD("mHistory {");
260 for (map<ReportId,ReportStatus>::const_iterator it = mHistory.begin();
261 it != mHistory.end(); it++) {
262 ALOGD(" [%s %s] --> [%d %d]", it->first.id.c_str(), it->first.pkg.c_str(),
263 it->second.approval_sent, it->second.ready_sent);
264 }
265 ALOGD("}");
266}
267*/
268
269bool Broadcaster::was_approval_sent(const string& id, const string& pkg, const string& cls) {
270 unique_lock<mutex> lock(mLock);
271 map<ReportId,ReportStatus>::const_iterator found = mHistory.find(ReportId(id, pkg, cls));
272 if (found != mHistory.end()) {
273 return found->second.approval_sent;
274 }
275 return false;
276}
277
278void Broadcaster::set_approval_sent(const string& id, const string& pkg, const string& cls,
279 const sp<ConsentListener>& listener) {
280 unique_lock<mutex> lock(mLock);
281 ReportStatus& reportStatus = mHistory[ReportId(id, pkg, cls)];
282 reportStatus.approval_sent = true;
283 reportStatus.listener = listener;
284}
285
286bool Broadcaster::was_ready_sent(const string& id, const string& pkg, const string& cls) {
287 unique_lock<mutex> lock(mLock);
288 map<ReportId,ReportStatus>::const_iterator found = mHistory.find(ReportId(id, pkg, cls));
289 if (found != mHistory.end()) {
290 return found->second.ready_sent;
291 }
292 return false;
293}
294
295void Broadcaster::set_ready_sent(const string& id, const string& pkg, const string& cls) {
296 unique_lock<mutex> lock(mLock);
297 mHistory[ReportId(id, pkg, cls)].ready_sent = true;
298}
299
300status_t Broadcaster::send_approval_broadcasts(const string& id, const string& pkg,
301 const string& cls) {
302 sp<IIncidentCompanion> ics = get_incident_companion();
303 if (ics == nullptr) {
304 return NAME_NOT_FOUND;
305 }
306
307 sp<ConsentListener> listener = new ConsentListener(this, ReportId(id, pkg, cls));
308
309 ALOGI("send_approval_broadcasts for %s %s/%s", id.c_str(), pkg.c_str(), cls.c_str());
310
311 Status status = ics->authorizeReport(0, String16(pkg.c_str()),
312 String16(cls.c_str()), String16(id.c_str()), 0, listener);
313
314 if (!status.isOk()) {
315 // authorizeReport is oneway, so any error is a transaction error.
316 return status.transactionError();
317 }
318
319 set_approval_sent(id, pkg, cls, listener);
320
321 return NO_ERROR;
322}
323
324void Broadcaster::report_approved(const ReportId& reportId) {
325 status_t err;
326
327 // Kick off broadcaster to do send the ready broadcasts.
328 ALOGI("The user approved the report, so kicking off another broadcast pass. %s %s/%s",
329 reportId.id.c_str(), reportId.pkg.c_str(), reportId.cls.c_str());
330 sp<ReportFile> file = mWorkDirectory->getReport(reportId.pkg, reportId.cls, reportId.id,
331 nullptr);
332 if (file != nullptr) {
333 err = file->loadEnvelope();
334 if (err != NO_ERROR) {
335 return;
336 }
337
338 err = file->markApproved(reportId.pkg, reportId.cls);
339 if (err != NO_ERROR) {
340 ALOGI("Couldn't find report that was just approved: %s %s/%s",
341 reportId.id.c_str(), reportId.pkg.c_str(), reportId.cls.c_str());
342 return;
343 }
344
345 file->saveEnvelope();
346 if (err != NO_ERROR) {
347 return;
348 }
349 }
350 mReportHandler->scheduleSendBacklog();
351}
352
353void Broadcaster::report_denied(const ReportId& reportId) {
354 // The user didn't approve the report, so remove it from the WorkDirectory.
355 ALOGI("The user denied the report, so deleting it. %s %s/%s",
356 reportId.id.c_str(), reportId.pkg.c_str(), reportId.cls.c_str());
357 sp<ReportFile> file = mWorkDirectory->getReport(reportId.pkg, reportId.cls, reportId.id,
358 nullptr);
359 if (file != nullptr) {
360 mWorkDirectory->commit(file, reportId.pkg, reportId.cls);
361 }
362}
363
364status_t Broadcaster::send_report_ready_broadcasts(const string& id, const string& pkg,
365 const string& cls) {
366 sp<IIncidentCompanion> ics = get_incident_companion();
367 if (ics == nullptr) {
368 return NAME_NOT_FOUND;
369 }
370
371 ALOGI("send_report_ready_broadcasts for %s %s/%s", id.c_str(), pkg.c_str(), cls.c_str());
372
373 Status status = ics->sendReportReadyBroadcast(String16(pkg.c_str()), String16(cls.c_str()));
374
375 if (!status.isOk()) {
376 // sendReportReadyBroadcast is oneway, so any error is a transaction error.
377 return status.transactionError();
378 }
379
380 set_ready_sent(id, pkg, cls);
381
382 return NO_ERROR;
383}
384
385status_t Broadcaster::send_to_dropbox(const sp<ReportFile>& file,
386 const IncidentReportArgs& args) {
387 status_t err;
388
389 sp<DropBoxManager> dropbox = new DropBoxManager();
390 if (dropbox == nullptr) {
391 ALOGW("Can't reach dropbox now, so we won't be able to write the incident report to there");
392 return NO_ERROR;
393 }
394
Yao Chencbafce92019-04-01 15:56:44 -0700395 int fds[2];
396 if (pipe(fds) != 0) {
397 ALOGW("Error opening pipe to filter incident report: %s", file->getDataFileName().c_str());
398 return NO_ERROR;
Joe Onorato99598ee2019-02-11 15:55:13 +0000399 }
400
Yao Chencbafce92019-04-01 15:56:44 -0700401 int readFd = fds[0];
402 int writeFd = fds[1];
403
404 // spawn a thread to write the data. Release the writeFd ownership to the thread.
405 thread th([file, writeFd, args]() { file->startFilteringData(writeFd, args); });
406
407 th.detach();
408
Joe Onorato99598ee2019-02-11 15:55:13 +0000409 // Takes ownership of readFd.
410 Status status = dropbox->addFile(String16("incident"), readFd, 0);
411 if (!status.isOk()) {
412 // TODO: This may or may not leak the readFd, depending on where it failed.
413 // Not sure how to fix this given the dropbox API.
414 ALOGW("Error sending incident report to dropbox.");
415 return -errno;
416 }
417
418 // On successful write, tell the working directory that this file is done.
419 mWorkDirectory->commit(file, DROPBOX_SENTINEL.getPackageName(),
420 DROPBOX_SENTINEL.getClassName());
421
422 // Don't need to call set_ready_sent, because we just removed it from the ReportFile,
423 // so we'll never hear about it again.
424
425 return NO_ERROR;
426}
427
428sp<IIncidentCompanion> Broadcaster::get_incident_companion() {
429 sp<IBinder> binder = defaultServiceManager()->getService(String16("incidentcompanion"));
430 if (binder == nullptr) {
431 ALOGI("Can not find IIncidentCompanion service to send broadcast. Will try again later.");
432 return nullptr;
433 }
434
435 sp<IIncidentCompanion> ics = interface_cast<IIncidentCompanion>(binder);
436 if (ics == nullptr) {
437 ALOGI("The incidentcompanion service is not an IIncidentCompanion. Will try again later.");
438 return nullptr;
439 }
440
441 return ics;
442}
443
444} // namespace incidentd
445} // namespace os
446} // namespace android
447
448