1/*
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#define LOG_TAG "incidentd"
18
19#include "IncidentService.h"
20
21#include "Reporter.h"
22
23#include <binder/IPCThreadState.h>
24#include <binder/IServiceManager.h>
25#include <cutils/log.h>
26#include <private/android_filesystem_config.h>
27#include <utils/Looper.h>
28
29#include <unistd.h>
30
31using namespace android;
32
33enum {
34    WHAT_RUN_REPORT = 1,
35    WHAT_SEND_BACKLOG_TO_DROPBOX = 2
36};
37
38//#define DEFAULT_BACKLOG_DELAY_NS (1000000000LL * 60 * 5)
39#define DEFAULT_BACKLOG_DELAY_NS (1000000000LL)
40
41// ================================================================================
42String16 const DUMP_PERMISSION("android.permission.DUMP");
43String16 const USAGE_STATS_PERMISSION("android.permission.PACKAGE_USAGE_STATS");
44
45static Status
46checkIncidentPermissions()
47{
48    if (!checkCallingPermission(DUMP_PERMISSION)) {
49        ALOGW("Calling pid %d and uid %d does not have permission: android.permission.DUMP",
50                IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid());
51        return Status::fromExceptionCode(Status::EX_SECURITY,
52                "Calling process does not have permission: android.permission.DUMP");
53    }
54    if (!checkCallingPermission(USAGE_STATS_PERMISSION)) {
55        ALOGW("Calling pid %d and uid %d does not have permission: android.permission.USAGE_STATS",
56                IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid());
57        return Status::fromExceptionCode(Status::EX_SECURITY,
58                "Calling process does not have permission: android.permission.USAGE_STATS");
59    }
60    return Status::ok();
61}
62
63
64// ================================================================================
65ReportRequestQueue::ReportRequestQueue()
66{
67}
68
69ReportRequestQueue::~ReportRequestQueue()
70{
71}
72
73void
74ReportRequestQueue::addRequest(const sp<ReportRequest>& request)
75{
76    unique_lock<mutex> lock(mLock);
77    mQueue.push_back(request);
78}
79
80sp<ReportRequest>
81ReportRequestQueue::getNextRequest()
82{
83    unique_lock<mutex> lock(mLock);
84    if (mQueue.empty()) {
85        return NULL;
86    } else {
87        sp<ReportRequest> front(mQueue.front());
88        mQueue.pop_front();
89        return front;
90    }
91}
92
93
94// ================================================================================
95ReportHandler::ReportHandler(const sp<Looper>& handlerLooper, const sp<ReportRequestQueue>& queue)
96    :mBacklogDelay(DEFAULT_BACKLOG_DELAY_NS),
97     mHandlerLooper(handlerLooper),
98     mQueue(queue)
99{
100}
101
102ReportHandler::~ReportHandler()
103{
104}
105
106void
107ReportHandler::handleMessage(const Message& message)
108{
109    switch (message.what) {
110        case WHAT_RUN_REPORT:
111            run_report();
112            break;
113        case WHAT_SEND_BACKLOG_TO_DROPBOX:
114            send_backlog_to_dropbox();
115            break;
116    }
117}
118
119void
120ReportHandler::scheduleRunReport(const sp<ReportRequest>& request)
121{
122    mQueue->addRequest(request);
123    mHandlerLooper->removeMessages(this, WHAT_RUN_REPORT);
124    mHandlerLooper->sendMessage(this, Message(WHAT_RUN_REPORT));
125}
126
127void
128ReportHandler::scheduleSendBacklogToDropbox()
129{
130    unique_lock<mutex> lock(mLock);
131    mBacklogDelay = DEFAULT_BACKLOG_DELAY_NS;
132    schedule_send_backlog_to_dropbox_locked();
133}
134
135void
136ReportHandler::schedule_send_backlog_to_dropbox_locked()
137{
138    mHandlerLooper->removeMessages(this, WHAT_SEND_BACKLOG_TO_DROPBOX);
139    mHandlerLooper->sendMessageDelayed(mBacklogDelay, this,
140            Message(WHAT_SEND_BACKLOG_TO_DROPBOX));
141}
142
143void
144ReportHandler::run_report()
145{
146    sp<Reporter> reporter = new Reporter();
147
148    // Merge all of the requests into one that has all of the
149    // requested fields.
150    while (true) {
151        sp<ReportRequest> request = mQueue->getNextRequest();
152        if (request == NULL) {
153            break;
154        }
155        reporter->batch.add(request);
156        reporter->args.merge(request->args);
157    }
158
159    // Take the report, which might take a while. More requests might queue
160    // up while we're doing this, and we'll handle them in their next batch.
161    // TODO: We should further rate-limit the reports to no more than N per time-period.
162    Reporter::run_report_status_t reportStatus = reporter->runReport();
163    if (reportStatus == Reporter::REPORT_NEEDS_DROPBOX) {
164        unique_lock<mutex> lock(mLock);
165        schedule_send_backlog_to_dropbox_locked();
166    }
167}
168
169void
170ReportHandler::send_backlog_to_dropbox()
171{
172    if (Reporter::upload_backlog() == Reporter::REPORT_NEEDS_DROPBOX) {
173        // There was a failure. Exponential backoff.
174        unique_lock<mutex> lock(mLock);
175        mBacklogDelay *= 2;
176        ALOGI("Error sending to dropbox. Trying again in %lld minutes",
177                (mBacklogDelay / (1000000000LL * 60)));
178        schedule_send_backlog_to_dropbox_locked();
179    } else {
180        mBacklogDelay = DEFAULT_BACKLOG_DELAY_NS;
181    }
182}
183
184// ================================================================================
185IncidentService::IncidentService(const sp<Looper>& handlerLooper)
186    :mQueue(new ReportRequestQueue())
187{
188    mHandler = new ReportHandler(handlerLooper, mQueue);
189}
190
191IncidentService::~IncidentService()
192{
193}
194
195Status
196IncidentService::reportIncident(const IncidentReportArgs& args)
197{
198    ALOGI("reportIncident");
199
200    Status status = checkIncidentPermissions();
201    if (!status.isOk()) {
202        return status;
203    }
204
205    mHandler->scheduleRunReport(new ReportRequest(args, NULL, -1));
206
207    return Status::ok();
208}
209
210Status
211IncidentService::reportIncidentToStream(const IncidentReportArgs& args,
212            const sp<IIncidentReportStatusListener>& listener, const unique_fd& stream)
213{
214    ALOGI("reportIncidentToStream");
215
216    Status status = checkIncidentPermissions();
217    if (!status.isOk()) {
218        return status;
219    }
220
221    int fd = dup(stream.get());
222    if (fd < 0) {
223        return Status::fromStatusT(-errno);
224    }
225
226    mHandler->scheduleRunReport(new ReportRequest(args, listener, fd));
227
228    return Status::ok();
229}
230
231Status
232IncidentService::systemRunning()
233{
234    if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
235        return Status::fromExceptionCode(Status::EX_SECURITY,
236                "Only system uid can call systemRunning");
237    }
238
239    // When system_server is up and running, schedule the dropbox task to run.
240    mHandler->scheduleSendBacklogToDropbox();
241
242    return Status::ok();
243}
244
245