Home | History | Annotate | Download | only in src
      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 #define DEBUG false
     17 #include "Log.h"
     18 
     19 #include "IncidentService.h"
     20 
     21 #include "FdBuffer.h"
     22 #include "PrivacyFilter.h"
     23 #include "Reporter.h"
     24 #include "incidentd_util.h"
     25 #include "section_list.h"
     26 
     27 #include <android/os/IncidentReportArgs.h>
     28 #include <binder/IPCThreadState.h>
     29 #include <binder/IResultReceiver.h>
     30 #include <binder/IServiceManager.h>
     31 #include <binder/IShellCallback.h>
     32 #include <log/log.h>
     33 #include <private/android_filesystem_config.h>
     34 #include <utils/Looper.h>
     35 #include <thread>
     36 
     37 #include <unistd.h>
     38 
     39 enum {
     40     WHAT_TAKE_REPORT = 1,
     41     WHAT_SEND_BROADCASTS = 2
     42 };
     43 
     44 #define DEFAULT_DELAY_NS (1000000000LL)
     45 
     46 #define DEFAULT_BYTES_SIZE_LIMIT (96 * 1024 * 1024)        // 96MB
     47 #define DEFAULT_REFACTORY_PERIOD_MS (24 * 60 * 60 * 1000)  // 1 Day
     48 
     49 // Skip these sections for dumpstate only. Dumpstate allows 10s max for each service to dump.
     50 // Skip logs (1100 - 1108) and traces (1200 - 1202) because they are already in the bug report.
     51 // Skip 3018 because it takes too long.
     52 #define SKIPPED_SECTIONS { 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, /* Logs */ \
     53                            1200, 1201, 1202, /* Native, hal, java traces */ \
     54                            3018  /* "meminfo -a --proto" */ }
     55 
     56 namespace android {
     57 namespace os {
     58 namespace incidentd {
     59 
     60 String16 const APPROVE_INCIDENT_REPORTS("android.permission.APPROVE_INCIDENT_REPORTS");
     61 String16 const DUMP_PERMISSION("android.permission.DUMP");
     62 String16 const USAGE_STATS_PERMISSION("android.permission.PACKAGE_USAGE_STATS");
     63 
     64 static Status checkIncidentPermissions(const IncidentReportArgs& args) {
     65     uid_t callingUid = IPCThreadState::self()->getCallingUid();
     66     pid_t callingPid = IPCThreadState::self()->getCallingPid();
     67     if (callingUid == AID_ROOT || callingUid == AID_SHELL) {
     68         // Root and shell are ok.
     69         return Status::ok();
     70     }
     71 
     72     if (checkCallingPermission(APPROVE_INCIDENT_REPORTS)) {
     73         // Permission controller (this is a singleton permission that is always granted
     74         // exactly for PermissionController) is allowed to access incident reports
     75         // so it can show the user info about what they are approving.
     76         return Status::ok();
     77     }
     78 
     79     // checking calling permission.
     80     if (!checkCallingPermission(DUMP_PERMISSION)) {
     81         ALOGW("Calling pid %d and uid %d does not have permission: android.permission.DUMP",
     82               callingPid, callingUid);
     83         return Status::fromExceptionCode(
     84                 Status::EX_SECURITY,
     85                 "Calling process does not have permission: android.permission.DUMP");
     86     }
     87     if (!checkCallingPermission(USAGE_STATS_PERMISSION)) {
     88         ALOGW("Calling pid %d and uid %d does not have permission: android.permission.USAGE_STATS",
     89               callingPid, callingUid);
     90         return Status::fromExceptionCode(
     91                 Status::EX_SECURITY,
     92                 "Calling process does not have permission: android.permission.USAGE_STATS");
     93     }
     94 
     95     // checking calling request uid permission.
     96     switch (args.getPrivacyPolicy()) {
     97         case PRIVACY_POLICY_LOCAL:
     98             if (callingUid != AID_SHELL && callingUid != AID_ROOT) {
     99                 ALOGW("Calling pid %d and uid %d does not have permission to get local data.",
    100                       callingPid, callingUid);
    101                 return Status::fromExceptionCode(
    102                         Status::EX_SECURITY,
    103                         "Calling process does not have permission to get local data.");
    104             }
    105             break;
    106         case PRIVACY_POLICY_EXPLICIT:
    107             if (callingUid != AID_SHELL && callingUid != AID_ROOT && callingUid != AID_STATSD &&
    108                     callingUid != AID_SYSTEM) {
    109                 ALOGW("Calling pid %d and uid %d does not have permission to get explicit data.",
    110                       callingPid, callingUid);
    111                 return Status::fromExceptionCode(
    112                         Status::EX_SECURITY,
    113                         "Calling process does not have permission to get explicit data.");
    114             }
    115             break;
    116     }
    117     return Status::ok();
    118 }
    119 
    120 static string build_uri(const string& pkg, const string& cls, const string& id) {
    121     return "content://android.os.IncidentManager/pending?pkg="
    122         + pkg + "&receiver=" + cls + "&r=" + id;
    123 }
    124 
    125 // ================================================================================
    126 ReportHandler::ReportHandler(const sp<WorkDirectory>& workDirectory,
    127             const sp<Broadcaster>& broadcaster, const sp<Looper>& handlerLooper,
    128             const sp<Throttler>& throttler)
    129         :mLock(),
    130          mWorkDirectory(workDirectory),
    131          mBroadcaster(broadcaster),
    132          mHandlerLooper(handlerLooper),
    133          mBacklogDelay(DEFAULT_DELAY_NS),
    134          mThrottler(throttler),
    135          mBatch(new ReportBatch()) {
    136 }
    137 
    138 ReportHandler::~ReportHandler() {
    139 }
    140 
    141 void ReportHandler::handleMessage(const Message& message) {
    142     switch (message.what) {
    143         case WHAT_TAKE_REPORT:
    144             take_report();
    145             break;
    146         case WHAT_SEND_BROADCASTS:
    147             send_broadcasts();
    148             break;
    149     }
    150 }
    151 
    152 void ReportHandler::schedulePersistedReport(const IncidentReportArgs& args) {
    153     mBatch->addPersistedReport(args);
    154     mHandlerLooper->removeMessages(this, WHAT_TAKE_REPORT);
    155     mHandlerLooper->sendMessage(this, Message(WHAT_TAKE_REPORT));
    156 }
    157 
    158 void ReportHandler::scheduleStreamingReport(const IncidentReportArgs& args,
    159         const sp<IIncidentReportStatusListener>& listener, int streamFd) {
    160     mBatch->addStreamingReport(args, listener, streamFd);
    161     mHandlerLooper->removeMessages(this, WHAT_TAKE_REPORT);
    162     mHandlerLooper->sendMessage(this, Message(WHAT_TAKE_REPORT));
    163 }
    164 
    165 void ReportHandler::scheduleSendBacklog() {
    166     unique_lock<mutex> lock(mLock);
    167     mBacklogDelay = DEFAULT_DELAY_NS;
    168     schedule_send_broadcasts_locked();
    169 }
    170 
    171 void ReportHandler::schedule_send_broadcasts_locked() {
    172     mHandlerLooper->removeMessages(this, WHAT_SEND_BROADCASTS);
    173     mHandlerLooper->sendMessageDelayed(mBacklogDelay, this, Message(WHAT_SEND_BROADCASTS));
    174 }
    175 
    176 void ReportHandler::take_report() {
    177     // Cycle the batch and throttle.
    178     sp<ReportBatch> batch;
    179     {
    180         unique_lock<mutex> lock(mLock);
    181         batch = mThrottler->filterBatch(mBatch);
    182     }
    183 
    184     if (batch->empty()) {
    185         // Nothing to do.
    186         return;
    187     }
    188 
    189     sp<Reporter> reporter = new Reporter(mWorkDirectory, batch);
    190 
    191     // Take the report, which might take a while. More requests might queue
    192     // up while we're doing this, and we'll handle them in their next batch.
    193     // TODO: We should further rate-limit the reports to no more than N per time-period.
    194     // TODO: Move this inside reporter.
    195     size_t reportByteSize = 0;
    196     reporter->runReport(&reportByteSize);
    197 
    198     // Tell the throttler how big it was, for the next throttling.
    199     // TODO: This still isn't ideal. The throttler really should just track the
    200     // persisted reqeusts, but changing Reporter::runReport() to track that individually
    201     // will be a big change.
    202     if (batch->hasPersistedReports()) {
    203         mThrottler->addReportSize(reportByteSize);
    204     }
    205 
    206     // Kick off the next steps, one of which is to send any new or otherwise remaining
    207     // approvals, and one of which is to send any new or remaining broadcasts.
    208     {
    209         unique_lock<mutex> lock(mLock);
    210         schedule_send_broadcasts_locked();
    211     }
    212 }
    213 
    214 void ReportHandler::send_broadcasts() {
    215     Broadcaster::broadcast_status_t result = mBroadcaster->sendBroadcasts();
    216     if (result == Broadcaster::BROADCASTS_FINISHED) {
    217         // We're done.
    218         unique_lock<mutex> lock(mLock);
    219         mBacklogDelay = DEFAULT_DELAY_NS;
    220     } else if (result == Broadcaster::BROADCASTS_REPEAT) {
    221         // It worked, but there are more.
    222         unique_lock<mutex> lock(mLock);
    223         mBacklogDelay = DEFAULT_DELAY_NS;
    224         schedule_send_broadcasts_locked();
    225     } else if (result == Broadcaster::BROADCASTS_BACKOFF) {
    226         // There was a failure. Exponential backoff.
    227         unique_lock<mutex> lock(mLock);
    228         mBacklogDelay *= 2;
    229         ALOGI("Error sending to dropbox. Trying again in %lld minutes",
    230               (mBacklogDelay / (1000000000LL * 60)));
    231         schedule_send_broadcasts_locked();
    232     }
    233 }
    234 
    235 // ================================================================================
    236 IncidentService::IncidentService(const sp<Looper>& handlerLooper) {
    237     mThrottler = new Throttler(DEFAULT_BYTES_SIZE_LIMIT, DEFAULT_REFACTORY_PERIOD_MS);
    238     mWorkDirectory = new WorkDirectory();
    239     mBroadcaster = new Broadcaster(mWorkDirectory);
    240     mHandler = new ReportHandler(mWorkDirectory, mBroadcaster, handlerLooper,
    241             mThrottler);
    242     mBroadcaster->setHandler(mHandler);
    243 }
    244 
    245 IncidentService::~IncidentService() {}
    246 
    247 Status IncidentService::reportIncident(const IncidentReportArgs& args) {
    248     IncidentReportArgs argsCopy(args);
    249 
    250     // Validate that the privacy policy is one of the real ones.
    251     // If it isn't, clamp it to the next more restrictive real one.
    252     argsCopy.setPrivacyPolicy(cleanup_privacy_policy(args.getPrivacyPolicy()));
    253 
    254     // TODO: Check that the broadcast recevier has the proper permissions
    255     // TODO: Maybe we should consider relaxing the permissions if it's going to
    256     // dropbox, but definitely not if it's going to the broadcaster.
    257     Status status = checkIncidentPermissions(args);
    258     if (!status.isOk()) {
    259         return status;
    260     }
    261 
    262     // If they asked for the LOCAL privacy policy, give them EXPLICT.  LOCAL has to
    263     // be streamed. (This only applies to shell/root, because everyone else would have
    264     // been rejected by checkIncidentPermissions()).
    265     if (argsCopy.getPrivacyPolicy() < PRIVACY_POLICY_EXPLICIT) {
    266         ALOGI("Demoting privacy policy to EXPLICT for persisted report.");
    267         argsCopy.setPrivacyPolicy(PRIVACY_POLICY_EXPLICIT);
    268     }
    269 
    270     // If they didn't specify a component, use dropbox.
    271     if (argsCopy.receiverPkg().length() == 0 && argsCopy.receiverCls().length() == 0) {
    272         argsCopy.setReceiverPkg(DROPBOX_SENTINEL.getPackageName());
    273         argsCopy.setReceiverCls(DROPBOX_SENTINEL.getClassName());
    274     }
    275 
    276     mHandler->schedulePersistedReport(argsCopy);
    277 
    278     return Status::ok();
    279 }
    280 
    281 Status IncidentService::reportIncidentToStream(const IncidentReportArgs& args,
    282                                                const sp<IIncidentReportStatusListener>& listener,
    283                                                const unique_fd& stream) {
    284     IncidentReportArgs argsCopy(args);
    285 
    286     // Streaming reports can not also be broadcast.
    287     argsCopy.setReceiverPkg("");
    288     argsCopy.setReceiverCls("");
    289 
    290     // Validate that the privacy policy is one of the real ones.
    291     // If it isn't, clamp it to the next more restrictive real one.
    292     argsCopy.setPrivacyPolicy(cleanup_privacy_policy(args.getPrivacyPolicy()));
    293 
    294     Status status = checkIncidentPermissions(argsCopy);
    295     if (!status.isOk()) {
    296         return status;
    297     }
    298 
    299     // The ReportRequest takes ownership of the fd, so we need to dup it.
    300     int fd = dup(stream.get());
    301     if (fd < 0) {
    302         return Status::fromStatusT(-errno);
    303     }
    304 
    305     mHandler->scheduleStreamingReport(argsCopy, listener, fd);
    306 
    307     return Status::ok();
    308 }
    309 
    310 Status IncidentService::systemRunning() {
    311     if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
    312         return Status::fromExceptionCode(Status::EX_SECURITY,
    313                                          "Only system uid can call systemRunning");
    314     }
    315 
    316     // When system_server is up and running, schedule the dropbox task to run.
    317     mBroadcaster->reset();
    318     mHandler->scheduleSendBacklog();
    319 
    320     return Status::ok();
    321 }
    322 
    323 Status IncidentService::getIncidentReportList(const String16& pkg16, const String16& cls16,
    324             vector<String16>* result) {
    325     status_t err;
    326     const string pkg(String8(pkg16).string());
    327     const string cls(String8(cls16).string());
    328 
    329     // List the reports
    330     vector<sp<ReportFile>> all;
    331     err = mWorkDirectory->getReports(&all, 0);
    332     if (err != NO_ERROR) {
    333         return Status::fromStatusT(err);
    334     }
    335 
    336     // Find the ones that match pkg and cls.
    337     for (sp<ReportFile>& file: all) {
    338         err = file->loadEnvelope();
    339         if (err != NO_ERROR) {
    340             continue;
    341         }
    342         const ReportFileProto& envelope = file->getEnvelope();
    343         size_t reportCount = envelope.report_size();
    344         for (int reportIndex = 0; reportIndex < reportCount; reportIndex++) {
    345             const ReportFileProto_Report& report = envelope.report(reportIndex);
    346             if (pkg == report.pkg() && cls == report.cls()) {
    347                 result->push_back(String16(build_uri(pkg, cls, file->getId()).c_str()));
    348                 break;
    349             }
    350         }
    351     }
    352 
    353     return Status::ok();
    354 }
    355 
    356 Status IncidentService::getIncidentReport(const String16& pkg16, const String16& cls16,
    357             const String16& id16, IncidentManager::IncidentReport* result) {
    358     status_t err;
    359 
    360     const string pkg(String8(pkg16).string());
    361     const string cls(String8(cls16).string());
    362     const string id(String8(id16).string());
    363 
    364     IncidentReportArgs args;
    365     sp<ReportFile> file = mWorkDirectory->getReport(pkg, cls, id, &args);
    366     if (file != nullptr) {
    367         // Create pipe
    368         int fds[2];
    369         if (pipe(fds) != 0) {
    370             ALOGW("Error opening pipe to filter incident report: %s",
    371                   file->getDataFileName().c_str());
    372             return Status::ok();
    373         }
    374         result->setTimestampNs(file->getTimestampNs());
    375         result->setPrivacyPolicy(file->getEnvelope().privacy_policy());
    376         result->takeFileDescriptor(fds[0]);
    377         int writeFd = fds[1];
    378         // spawn a thread to write the data. Release the writeFd ownership to the thread.
    379         thread th([file, writeFd, args]() { file->startFilteringData(writeFd, args); });
    380 
    381         th.detach();
    382     }
    383 
    384     return Status::ok();
    385 }
    386 
    387 Status IncidentService::deleteIncidentReports(const String16& pkg16, const String16& cls16,
    388             const String16& id16) {
    389     const string pkg(String8(pkg16).string());
    390     const string cls(String8(cls16).string());
    391     const string id(String8(id16).string());
    392 
    393     sp<ReportFile> file = mWorkDirectory->getReport(pkg, cls, id, nullptr);
    394     if (file != nullptr) {
    395         mWorkDirectory->commit(file, pkg, cls);
    396     }
    397     mBroadcaster->clearBroadcasts(pkg, cls, id);
    398 
    399     return Status::ok();
    400 }
    401 
    402 Status IncidentService::deleteAllIncidentReports(const String16& pkg16) {
    403     const string pkg(String8(pkg16).string());
    404 
    405     mWorkDirectory->commitAll(pkg);
    406     mBroadcaster->clearPackageBroadcasts(pkg);
    407 
    408     return Status::ok();
    409 }
    410 
    411 /**
    412  * Implement our own because the default binder implementation isn't
    413  * properly handling SHELL_COMMAND_TRANSACTION.
    414  */
    415 status_t IncidentService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
    416                                      uint32_t flags) {
    417     status_t err;
    418 
    419     switch (code) {
    420         case SHELL_COMMAND_TRANSACTION: {
    421             int in = data.readFileDescriptor();
    422             int out = data.readFileDescriptor();
    423             int err = data.readFileDescriptor();
    424             int argc = data.readInt32();
    425             Vector<String8> args;
    426             for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
    427                 args.add(String8(data.readString16()));
    428             }
    429             sp<IShellCallback> shellCallback = IShellCallback::asInterface(data.readStrongBinder());
    430             sp<IResultReceiver> resultReceiver =
    431                     IResultReceiver::asInterface(data.readStrongBinder());
    432 
    433             FILE* fin = fdopen(in, "r");
    434             FILE* fout = fdopen(out, "w");
    435             FILE* ferr = fdopen(err, "w");
    436 
    437             if (fin == NULL || fout == NULL || ferr == NULL) {
    438                 resultReceiver->send(NO_MEMORY);
    439             } else {
    440                 err = command(fin, fout, ferr, args);
    441                 resultReceiver->send(err);
    442             }
    443 
    444             if (fin != NULL) {
    445                 fflush(fin);
    446                 fclose(fin);
    447             }
    448             if (fout != NULL) {
    449                 fflush(fout);
    450                 fclose(fout);
    451             }
    452             if (fout != NULL) {
    453                 fflush(ferr);
    454                 fclose(ferr);
    455             }
    456 
    457             return NO_ERROR;
    458         } break;
    459         default: { return BnIncidentManager::onTransact(code, data, reply, flags); }
    460     }
    461 }
    462 
    463 status_t IncidentService::command(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
    464     const int argCount = args.size();
    465 
    466     if (argCount >= 1) {
    467         if (!args[0].compare(String8("privacy"))) {
    468             return cmd_privacy(in, out, err, args);
    469         }
    470         if (!args[0].compare(String8("throttler"))) {
    471             mThrottler->dump(out);
    472             return NO_ERROR;
    473         }
    474         if (!args[0].compare(String8("section"))) {
    475             int id = atoi(args[1]);
    476             int idx = 0;
    477             while (SECTION_LIST[idx] != NULL) {
    478                 const Section* section = SECTION_LIST[idx];
    479                 if (section->id == id) {
    480                     fprintf(out, "Section[%d] %s\n", id, section->name.string());
    481                     break;
    482                 }
    483                 idx++;
    484             }
    485             return NO_ERROR;
    486         }
    487     }
    488     return cmd_help(out);
    489 }
    490 
    491 status_t IncidentService::cmd_help(FILE* out) {
    492     fprintf(out, "usage: adb shell cmd incident privacy print <section_id>\n");
    493     fprintf(out, "usage: adb shell cmd incident privacy parse <section_id> < proto.txt\n");
    494     fprintf(out, "    Prints/parses for the section id.\n\n");
    495     fprintf(out, "usage: adb shell cmd incident section <section_id>\n");
    496     fprintf(out, "    Prints section id and its name.\n\n");
    497     fprintf(out, "usage: adb shell cmd incident throttler\n");
    498     fprintf(out, "    Prints the current throttler state\n");
    499     return NO_ERROR;
    500 }
    501 
    502 static void printPrivacy(const Privacy* p, FILE* out, String8 indent) {
    503     if (p == NULL) return;
    504     fprintf(out, "%sid:%d, type:%d, dest:%d\n", indent.string(), p->field_id, p->type, p->policy);
    505     if (p->children == NULL) return;
    506     for (int i = 0; p->children[i] != NULL; i++) {  // NULL-terminated.
    507         printPrivacy(p->children[i], out, indent + "  ");
    508     }
    509 }
    510 
    511 status_t IncidentService::cmd_privacy(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
    512     (void)in;
    513 
    514     const int argCount = args.size();
    515     if (argCount >= 3) {
    516         String8 opt = args[1];
    517         int sectionId = atoi(args[2].string());
    518 
    519         const Privacy* p = get_privacy_of_section(sectionId);
    520         if (p == NULL) {
    521             fprintf(err, "Can't find section id %d\n", sectionId);
    522             return NO_ERROR;
    523         }
    524         fprintf(err, "Get privacy for %d\n", sectionId);
    525         if (opt == "print") {
    526             printPrivacy(p, out, String8(""));
    527         } else if (opt == "parse") {
    528             /*
    529             FdBuffer buf;
    530             status_t error = buf.read(fileno(in), 60000);
    531             if (error != NO_ERROR) {
    532                 fprintf(err, "Error reading from stdin\n");
    533                 return error;
    534             }
    535             fprintf(err, "Read %zu bytes\n", buf.size());
    536             PrivacyFilter pBuf(p, buf.data());
    537 
    538             PrivacySpec spec = PrivacySpec::new_spec(argCount > 3 ? atoi(args[3]) : -1);
    539             error = pBuf.strip(spec);
    540             if (error != NO_ERROR) {
    541                 fprintf(err, "Error strip pii fields with spec %d\n", spec.policy);
    542                 return error;
    543             }
    544             return pBuf.flush(fileno(out));
    545             */
    546             return -1;
    547         }
    548     } else {
    549         return cmd_help(out);
    550     }
    551     return NO_ERROR;
    552 }
    553 
    554 status_t IncidentService::dump(int fd, const Vector<String16>& args) {
    555     if (std::find(args.begin(), args.end(), String16("--proto")) == args.end()) {
    556         ALOGD("Skip dumping incident. Only proto format is supported.");
    557         dprintf(fd, "Incident dump only supports proto version.\n");
    558         return NO_ERROR;
    559     }
    560 
    561     ALOGD("Dump incident proto");
    562     IncidentReportArgs incidentArgs;
    563     incidentArgs.setPrivacyPolicy(PRIVACY_POLICY_EXPLICIT);
    564     int skipped[] = SKIPPED_SECTIONS;
    565     for (const Section** section = SECTION_LIST; *section; section++) {
    566         const int id = (*section)->id;
    567         if (std::find(std::begin(skipped), std::end(skipped), id) == std::end(skipped)
    568                 && !section_requires_specific_mention(id)) {
    569             incidentArgs.addSection(id);
    570         }
    571     }
    572 
    573     if (!checkIncidentPermissions(incidentArgs).isOk()) {
    574         return PERMISSION_DENIED;
    575     }
    576 
    577     // The ReportRequest takes ownership of the fd, so we need to dup it.
    578     int fd1 = dup(fd);
    579     if (fd1 < 0) {
    580         return -errno;
    581     }
    582 
    583     // TODO: Remove this.  Someone even dumpstate, wanting to get an incident report
    584     // should use the API.  That will take making dumpstated call the API, which is a
    585     // good thing.  It also means it won't be subject to the timeout.
    586     mHandler->scheduleStreamingReport(incidentArgs, NULL, fd1);
    587 
    588     return NO_ERROR;
    589 }
    590 
    591 }  // namespace incidentd
    592 }  // namespace os
    593 }  // namespace android
    594