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