Files
frameworks_base/cmds/incident/main.cpp
Yi Jin 0f0471623e Implement Pii Stripper Part 3
The incident request args sets privacy spec. Strip action is optimized
to run once for each type of spec and ready for flush multiple times.
Incident command is updated to take -p option to specify privacy spec.

Bug: 64687253
Test: unit tests written, manually run incident command to test as well
Change-Id: I6753df117f76dc1a5f4d2152baa3fbbf56b490e4
2017-09-07 10:53:51 -07:00

284 lines
7.8 KiB
C++

/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "incident"
#include "incident_sections.h"
#include <android/os/BnIncidentReportStatusListener.h>
#include <android/os/IIncidentManager.h>
#include <android/os/IncidentReportArgs.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <utils/Looper.h>
#include <cstring>
#include <fcntl.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
using namespace android;
using namespace android::base;
using namespace android::binder;
using namespace android::os;
// ================================================================================
class StatusListener : public BnIncidentReportStatusListener {
public:
StatusListener();
virtual ~StatusListener();
virtual Status onReportStarted();
virtual Status onReportSectionStatus(int32_t section, int32_t status);
virtual Status onReportServiceStatus(const String16& service, int32_t status);
virtual Status onReportFinished();
virtual Status onReportFailed();
};
StatusListener::StatusListener()
{
}
StatusListener::~StatusListener()
{
}
Status
StatusListener::onReportStarted()
{
return Status::ok();
}
Status
StatusListener::onReportSectionStatus(int32_t section, int32_t status)
{
fprintf(stderr, "section %d status %d\n", section, status);
return Status::ok();
}
Status
StatusListener::onReportServiceStatus(const String16& service, int32_t status)
{
fprintf(stderr, "service '%s' status %d\n", String8(service).string(), status);
return Status::ok();
}
Status
StatusListener::onReportFinished()
{
fprintf(stderr, "done\n");
exit(0);
return Status::ok();
}
Status
StatusListener::onReportFailed()
{
fprintf(stderr, "failed\n");
exit(1);
return Status::ok();
}
// ================================================================================
static void section_list(FILE* out) {
IncidentSection sections[INCIDENT_SECTION_COUNT];
int i = 0;
int j = 0;
// sort the sections based on id
while (i < INCIDENT_SECTION_COUNT) {
IncidentSection curr = INCIDENT_SECTIONS[i];
for (int k = 0; k < j; k++) {
if (curr.id > sections[k].id) {
continue;
}
IncidentSection tmp = curr;
curr = sections[k];
sections[k] = tmp;
}
sections[j] = curr;
i++;
j++;
}
fprintf(out, "available sections:\n");
for (int i = 0; i < INCIDENT_SECTION_COUNT; ++i) {
fprintf(out, "id: %4d, name: %s\n", sections[i].id, sections[i].name);
}
}
// ================================================================================
static IncidentSection const*
find_section(const char* name)
{
size_t low = 0;
size_t high = INCIDENT_SECTION_COUNT - 1;
while (low <= high) {
size_t mid = (low + high) >> 1;
IncidentSection const* section = INCIDENT_SECTIONS + mid;
int cmp = strcmp(section->name, name);
if (cmp < 0) {
low = mid + 1;
} else if (cmp > 0) {
high = mid - 1;
} else {
return section;
}
}
return NULL;
}
// ================================================================================
static int
get_dest(const char* arg)
{
if (strcmp(arg, "LOCAL") == 0) return 0;
if (strcmp(arg, "EXPLICIT") == 0) return 1;
if (strcmp(arg, "AUTOMATIC") == 0) return 2;
return -1; // return the default value
}
// ================================================================================
static void
usage(FILE* out)
{
fprintf(out, "usage: incident OPTIONS [SECTION...]\n");
fprintf(out, "\n");
fprintf(out, "Takes an incident report.\n");
fprintf(out, "\n");
fprintf(out, "OPTIONS\n");
fprintf(out, " -b (default) print the report to stdout (in proto format)\n");
fprintf(out, " -d send the report into dropbox\n");
fprintf(out, " -l list available sections\n");
fprintf(out, " -p privacy spec, LOCAL, EXPLICIT or AUTOMATIC\n");
fprintf(out, "\n");
fprintf(out, " SECTION the field numbers of the incident report fields to include\n");
fprintf(out, "\n");
}
int
main(int argc, char** argv)
{
Status status;
IncidentReportArgs args;
enum { DEST_DROPBOX, DEST_STDOUT } destination = DEST_STDOUT;
int dest = -1; // default
// Parse the args
int opt;
while ((opt = getopt(argc, argv, "bhdlp:")) != -1) {
switch (opt) {
case 'h':
usage(stdout);
return 0;
case 'l':
section_list(stdout);
return 0;
case 'b':
destination = DEST_STDOUT;
break;
case 'd':
destination = DEST_DROPBOX;
break;
case 'p':
dest = get_dest(optarg);
break;
default:
usage(stderr);
return 1;
}
}
if (optind == argc) {
args.setAll(true);
} else {
for (int i=optind; i<argc; i++) {
const char* arg = argv[i];
char* end;
if (arg[0] != '\0') {
int section = strtol(arg, &end, 0);
if (*end == '\0') {
args.addSection(section);
} else {
IncidentSection const* ic = find_section(arg);
if (ic == NULL) {
fprintf(stderr, "Invalid section: %s\n", arg);
return 1;
}
args.addSection(ic->id);
}
}
}
}
args.setDest(dest);
// Start the thread pool.
sp<ProcessState> ps(ProcessState::self());
ps->startThreadPool();
ps->giveThreadPoolName();
// Look up the service
sp<IIncidentManager> service = interface_cast<IIncidentManager>(
defaultServiceManager()->getService(android::String16("incident")));
if (service == NULL) {
fprintf(stderr, "Couldn't look up the incident service\n");
return 1;
}
// Construct the stream
int fds[2];
pipe(fds);
unique_fd readEnd(fds[0]);
unique_fd writeEnd(fds[1]);
if (destination == DEST_STDOUT) {
// Call into the service
sp<StatusListener> listener(new StatusListener());
status = service->reportIncidentToStream(args, listener, writeEnd);
if (!status.isOk()) {
fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
return 1;
}
// Wait for the result and print out the data they send.
//IPCThreadState::self()->joinThreadPool();
while (true) {
int amt = splice(fds[0], NULL, STDOUT_FILENO, NULL, 4096, 0);
fprintf(stderr, "spliced %d bytes\n", amt);
if (amt < 0) {
return errno;
} else if (amt == 0) {
return 0;
}
}
} else {
status = service->reportIncident(args);
if (!status.isOk()) {
fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
return 1;
} else {
return 0;
}
}
}