Home | History | Annotate | Download | only in incident
      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 "incident"
     18 
     19 #include "incident_sections.h"
     20 
     21 #include <android/os/BnIncidentReportStatusListener.h>
     22 #include <android/os/IIncidentManager.h>
     23 #include <android/os/IncidentReportArgs.h>
     24 #include <android/util/ProtoOutputStream.h>
     25 #include <binder/IPCThreadState.h>
     26 #include <binder/IServiceManager.h>
     27 #include <utils/Looper.h>
     28 
     29 #include <cstring>
     30 #include <fcntl.h>
     31 #include <getopt.h>
     32 #include <stdio.h>
     33 #include <stdlib.h>
     34 #include <unistd.h>
     35 
     36 using namespace android;
     37 using namespace android::base;
     38 using namespace android::binder;
     39 using namespace android::os;
     40 using android::util::FIELD_COUNT_SINGLE;
     41 using android::util::FIELD_TYPE_STRING;
     42 using android::util::ProtoOutputStream;
     43 
     44 // ================================================================================
     45 class StatusListener : public BnIncidentReportStatusListener {
     46 public:
     47     StatusListener();
     48     virtual ~StatusListener();
     49 
     50     virtual Status onReportStarted();
     51     virtual Status onReportSectionStatus(int32_t section, int32_t status);
     52     virtual Status onReportServiceStatus(const String16& service, int32_t status);
     53     virtual Status onReportFinished();
     54     virtual Status onReportFailed();
     55 };
     56 
     57 StatusListener::StatusListener()
     58 {
     59 }
     60 
     61 StatusListener::~StatusListener()
     62 {
     63 }
     64 
     65 Status
     66 StatusListener::onReportStarted()
     67 {
     68     return Status::ok();
     69 }
     70 
     71 Status
     72 StatusListener::onReportSectionStatus(int32_t section, int32_t status)
     73 {
     74     fprintf(stderr, "section %d status %d\n", section, status);
     75     ALOGD("section %d status %d\n", section, status);
     76     return Status::ok();
     77 }
     78 
     79 Status
     80 StatusListener::onReportServiceStatus(const String16& service, int32_t status)
     81 {
     82     fprintf(stderr, "service '%s' status %d\n", String8(service).string(), status);
     83     ALOGD("service '%s' status %d\n", String8(service).string(), status);
     84     return Status::ok();
     85 }
     86 
     87 Status
     88 StatusListener::onReportFinished()
     89 {
     90     fprintf(stderr, "done\n");
     91     ALOGD("done\n");
     92     exit(0);
     93     return Status::ok();
     94 }
     95 
     96 Status
     97 StatusListener::onReportFailed()
     98 {
     99     fprintf(stderr, "failed\n");
    100     ALOGD("failed\n");
    101     exit(1);
    102     return Status::ok();
    103 }
    104 
    105 // ================================================================================
    106 static void section_list(FILE* out) {
    107     IncidentSection sections[INCIDENT_SECTION_COUNT];
    108     int i = 0;
    109     int j = 0;
    110     // sort the sections based on id
    111     while (i < INCIDENT_SECTION_COUNT) {
    112         IncidentSection curr = INCIDENT_SECTIONS[i];
    113         for (int k = 0; k < j; k++) {
    114             if (curr.id > sections[k].id) {
    115                 continue;
    116             }
    117             IncidentSection tmp = curr;
    118             curr = sections[k];
    119             sections[k] = tmp;
    120         }
    121         sections[j] = curr;
    122         i++;
    123         j++;
    124     }
    125 
    126     fprintf(out, "available sections:\n");
    127     for (int i = 0; i < INCIDENT_SECTION_COUNT; ++i) {
    128         fprintf(out, "id: %4d, name: %s\n", sections[i].id, sections[i].name);
    129     }
    130 }
    131 
    132 // ================================================================================
    133 static IncidentSection const*
    134 find_section(const char* name)
    135 {
    136     ssize_t low = 0;
    137     ssize_t high = INCIDENT_SECTION_COUNT - 1;
    138 
    139     while (low <= high) {
    140         ssize_t mid = (low + high) / 2;
    141         IncidentSection const* section = INCIDENT_SECTIONS + mid;
    142 
    143         int cmp = strcmp(section->name, name);
    144         if (cmp < 0) {
    145             low = mid + 1;
    146         } else if (cmp > 0) {
    147             high = mid - 1;
    148         } else {
    149             return section;
    150         }
    151     }
    152     return NULL;
    153 }
    154 
    155 // ================================================================================
    156 static int
    157 get_privacy_policy(const char* arg)
    158 {
    159     if (strcmp(arg, "L") == 0
    160         || strcmp(arg, "LOCAL") == 0) {
    161       return PRIVACY_POLICY_LOCAL;
    162     }
    163     if (strcmp(arg, "E") == 0
    164         || strcmp(arg, "EXPLICIT") == 0) {
    165       return PRIVACY_POLICY_EXPLICIT;
    166     }
    167     if (strcmp(arg, "A") == 0
    168         || strcmp(arg, "AUTO") == 0
    169         || strcmp(arg, "AUTOMATIC") == 0) {
    170       return PRIVACY_POLICY_AUTOMATIC;
    171     }
    172     return -1; // return the default value
    173 }
    174 
    175 // ================================================================================
    176 static bool
    177 parse_receiver_arg(const string& arg, string* pkg, string* cls)
    178 {
    179     if (arg.length() == 0) {
    180         return true;
    181     }
    182     size_t slash = arg.find('/');
    183     if (slash == string::npos) {
    184         return false;
    185     }
    186     if (slash == 0 || slash == arg.length() - 1) {
    187         return false;
    188     }
    189     if (arg.find('/', slash+1) != string::npos) {
    190         return false;
    191     }
    192     pkg->assign(arg, 0, slash);
    193     cls->assign(arg, slash+1);
    194     if ((*cls)[0] == '.') {
    195         *cls = (*pkg) + (*cls);
    196     }
    197     return true;
    198 }
    199 
    200 // ================================================================================
    201 static void
    202 usage(FILE* out)
    203 {
    204     fprintf(out, "usage: incident OPTIONS [SECTION...]\n");
    205     fprintf(out, "\n");
    206     fprintf(out, "Takes an incident report.\n");
    207     fprintf(out, "\n");
    208     fprintf(out, "OPTIONS\n");
    209     fprintf(out, "  -l           list available sections\n");
    210     fprintf(out, "  -p           privacy spec, LOCAL, EXPLICIT or AUTOMATIC. Default AUTOMATIC.\n");
    211     fprintf(out, "\n");
    212     fprintf(out, "and one of these destinations:\n");
    213     fprintf(out, "  -b           (default) print the report to stdout (in proto format)\n");
    214     fprintf(out, "  -d           send the report into dropbox\n");
    215     fprintf(out, "  -r REASON    human readable description of why the report is taken.\n");
    216     fprintf(out, "  -s PKG/CLS   send broadcast to the broadcast receiver.\n");
    217     fprintf(out, "\n");
    218     fprintf(out, "  SECTION     the field numbers of the incident report fields to include\n");
    219     fprintf(out, "\n");
    220 }
    221 
    222 int
    223 main(int argc, char** argv)
    224 {
    225     Status status;
    226     IncidentReportArgs args;
    227     enum { DEST_UNSET, DEST_DROPBOX, DEST_STDOUT, DEST_BROADCAST } destination = DEST_UNSET;
    228     int privacyPolicy = PRIVACY_POLICY_AUTOMATIC;
    229     string reason;
    230     string receiverArg;
    231 
    232     // Parse the args
    233     int opt;
    234     while ((opt = getopt(argc, argv, "bhdlp:r:s:")) != -1) {
    235         switch (opt) {
    236             case 'h':
    237                 usage(stdout);
    238                 return 0;
    239             case 'l':
    240                 section_list(stdout);
    241                 return 0;
    242             case 'b':
    243                 if (!(destination == DEST_UNSET || destination == DEST_STDOUT)) {
    244                     usage(stderr);
    245                     return 1;
    246                 }
    247                 destination = DEST_STDOUT;
    248                 break;
    249             case 'd':
    250                 if (!(destination == DEST_UNSET || destination == DEST_DROPBOX)) {
    251                     usage(stderr);
    252                     return 1;
    253                 }
    254                 destination = DEST_DROPBOX;
    255                 break;
    256             case 'p':
    257                 privacyPolicy = get_privacy_policy(optarg);
    258                 break;
    259             case 'r':
    260                 if (reason.size() > 0) {
    261                     usage(stderr);
    262                     return 1;
    263                 }
    264                 reason = optarg;
    265                 break;
    266             case 's':
    267                 if (destination != DEST_UNSET) {
    268                     usage(stderr);
    269                     return 1;
    270                 }
    271                 destination = DEST_BROADCAST;
    272                 receiverArg = optarg;
    273                 break;
    274             default:
    275                 usage(stderr);
    276                 return 1;
    277         }
    278     }
    279     if (destination == DEST_UNSET) {
    280         destination = DEST_STDOUT;
    281     }
    282 
    283     string pkg;
    284     string cls;
    285     if (parse_receiver_arg(receiverArg, &pkg, &cls)) {
    286         args.setReceiverPkg(pkg);
    287         args.setReceiverCls(cls);
    288     } else {
    289         fprintf(stderr, "badly formatted -s package/class option: %s\n\n", receiverArg.c_str());
    290         usage(stderr);
    291         return 1;
    292     }
    293 
    294     if (optind == argc) {
    295         args.setAll(true);
    296     } else {
    297         for (int i=optind; i<argc; i++) {
    298             const char* arg = argv[i];
    299             char* end;
    300             if (arg[0] != '\0') {
    301                 int section = strtol(arg, &end, 0);
    302                 if (*end == '\0') {
    303                     args.addSection(section);
    304                 } else {
    305                     IncidentSection const* ic = find_section(arg);
    306                     if (ic == NULL) {
    307                         ALOGD("Invalid section: %s\n", arg);
    308                         fprintf(stderr, "Invalid section: %s\n", arg);
    309                         return 1;
    310                     }
    311                     args.addSection(ic->id);
    312                 }
    313             }
    314         }
    315     }
    316     args.setPrivacyPolicy(privacyPolicy);
    317 
    318     if (reason.size() > 0) {
    319         ProtoOutputStream proto;
    320         proto.write(/* reason field id */ 2 | FIELD_TYPE_STRING | FIELD_COUNT_SINGLE, reason);
    321         vector<uint8_t> header;
    322         proto.serializeToVector(&header);
    323         args.addHeader(header);
    324     }
    325 
    326     // Start the thread pool.
    327     sp<ProcessState> ps(ProcessState::self());
    328     ps->startThreadPool();
    329     ps->giveThreadPoolName();
    330 
    331     // Look up the service
    332     sp<IIncidentManager> service = interface_cast<IIncidentManager>(
    333             defaultServiceManager()->getService(android::String16("incident")));
    334     if (service == NULL) {
    335         fprintf(stderr, "Couldn't look up the incident service\n");
    336         return 1;
    337     }
    338 
    339     // Construct the stream
    340     int fds[2];
    341     pipe(fds);
    342 
    343     unique_fd readEnd(fds[0]);
    344     unique_fd writeEnd(fds[1]);
    345 
    346     if (destination == DEST_STDOUT) {
    347         // Call into the service
    348         sp<StatusListener> listener(new StatusListener());
    349         status = service->reportIncidentToStream(args, listener, writeEnd);
    350 
    351         if (!status.isOk()) {
    352             fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
    353             return 1;
    354         }
    355 
    356         // Wait for the result and print out the data they send.
    357         //IPCThreadState::self()->joinThreadPool();
    358 
    359         while (true) {
    360             uint8_t buf[4096];
    361             ssize_t amt = TEMP_FAILURE_RETRY(read(fds[0], buf, sizeof(buf)));
    362             if (amt < 0) {
    363                 break;
    364             } else if (amt == 0) {
    365                 break;
    366             }
    367 
    368             ssize_t wamt = TEMP_FAILURE_RETRY(write(STDOUT_FILENO, buf, amt));
    369             if (wamt != amt) {
    370                 return errno;
    371             }
    372         }
    373     } else {
    374         status = service->reportIncident(args);
    375         if (!status.isOk()) {
    376             fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
    377             return 1;
    378         } else {
    379             return 0;
    380         }
    381     }
    382 
    383 }
    384