Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 99598ee6 authored by Joe Onorato's avatar Joe Onorato
Browse files

incidentd can now handle multiple callers asking it for incident reports

Test: bit incident_test:* GtsIncidentManagerTestCases:*
Bug: 123543706
Change-Id: I9f671dd5d8b2ad139f952a23e575c2be16120459
parent 21638cb8
Loading
Loading
Loading
Loading
+42 −5
Original line number Diff line number Diff line
@@ -721,6 +721,7 @@ java_defaults {
            "frameworks/av/camera/aidl",
            "frameworks/av/media/libaudioclient/aidl",
            "frameworks/native/aidl/gui",
            "frameworks/native/libs/incidentcompanion/binder",
            "system/core/storaged/binder",
            "system/vold/binder",
            "system/gsid/aidl",
@@ -968,7 +969,10 @@ java_library {
        output_params: ["store_unknown_fields=true"],
        include_dirs: ["external/protobuf/src"],
    },

    exclude_srcs: [
        "core/proto/android/privacy.proto",
        "core/proto/android/section.proto",
    ],
    sdk_version: "current",
    srcs: [
        "core/proto/**/*.proto",
@@ -988,6 +992,10 @@ java_library {
        "core/proto/**/*.proto",
        "libs/incident/proto/android/os/**/*.proto",
    ],
    exclude_srcs: [
        "core/proto/android/privacy.proto",
        "core/proto/android/section.proto",
    ],
    // Protos have lots of MissingOverride and similar.
    errorprone: {
        javacflags: ["-XepDisableAllChecks"],
@@ -995,9 +1003,9 @@ java_library {
}

// ====  c++ proto device library  ==============================
cc_library {
    name: "libplatformprotos",
    host_supported: true,
cc_defaults {
    name: "libplatformprotos-defaults",

    proto: {
        export_proto_headers: true,
        include_dirs: ["external/protobuf/src"],
@@ -1011,8 +1019,13 @@ cc_library {

    srcs: [
        "core/proto/**/*.proto",
        "libs/incident/**/*.proto",
    ],
}

cc_library {
    name: "libplatformprotos",
    defaults: ["libplatformprotos-defaults"],
    host_supported: true,

    target: {
        host: {
@@ -1024,6 +1037,9 @@ cc_library {
            proto: {
                type: "lite",
            },
            shared_libs: [
                "libprotobuf-cpp-lite",
            ],
            shared: {
                enabled: false,
            },
@@ -1031,6 +1047,26 @@ cc_library {
    },
}

// This is the full proto version of libplatformprotos. It may only
// be used by test code that is not shipped on the device.
cc_library {
    name: "libplatformprotos-test",
    defaults: ["libplatformprotos-defaults"],
    host_supported: false,

    target: {
        android: {
            proto: {
                type: "full",
            },
            shared: {
                enabled: false,
            },
        },
    },
}


gensrcs {
    name: "gen-platform-proto-constants",
    depfile: true,
@@ -1068,6 +1104,7 @@ gensrcs {
    output_extension: "proto.h",
}


subdirs = [
    "cmds/*",
    "core/*",
+4 −0
Original line number Diff line number Diff line
@@ -29,6 +29,10 @@ cc_binary {
        "libincident",
    ],

    static_libs: [
        "libplatformprotos",
    ],

    cflags: [
        "-Wall",
        "-Werror",
+80 −15
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ Status
StatusListener::onReportSectionStatus(int32_t section, int32_t status)
{
    fprintf(stderr, "section %d status %d\n", section, status);
    ALOGD("section %d status %d\n", section, status);
    return Status::ok();
}

@@ -75,6 +76,7 @@ Status
StatusListener::onReportServiceStatus(const String16& service, int32_t status)
{
    fprintf(stderr, "service '%s' status %d\n", String8(service).string(), status);
    ALOGD("service '%s' status %d\n", String8(service).string(), status);
    return Status::ok();
}

@@ -82,6 +84,7 @@ Status
StatusListener::onReportFinished()
{
    fprintf(stderr, "done\n");
    ALOGD("done\n");
    exit(0);
    return Status::ok();
}
@@ -90,6 +93,7 @@ Status
StatusListener::onReportFailed()
{
    fprintf(stderr, "failed\n");
    ALOGD("failed\n");
    exit(1);
    return Status::ok();
}
@@ -146,24 +150,49 @@ find_section(const char* name)

// ================================================================================
static int
get_dest(const char* arg)
get_privacy_policy(const char* arg)
{
    if (strcmp(arg, "L") == 0
        || strcmp(arg, "LOCAL") == 0) {
      return DEST_LOCAL;
      return PRIVACY_POLICY_LOCAL;
    }
    if (strcmp(arg, "E") == 0
        || strcmp(arg, "EXPLICIT") == 0) {
      return DEST_EXPLICIT;
      return PRIVACY_POLICY_EXPLICIT;
    }
    if (strcmp(arg, "A") == 0
        || strcmp(arg, "AUTO") == 0
        || strcmp(arg, "AUTOMATIC") == 0) {
      return DEST_AUTOMATIC;
      return PRIVACY_POLICY_AUTOMATIC;
    }
    return -1; // return the default value
}

// ================================================================================
static bool
parse_receiver_arg(const string& arg, string* pkg, string* cls)
{
    if (arg.length() == 0) {
        return true;
    }
    size_t slash = arg.find('/');
    if (slash == string::npos) {
        return false;
    }
    if (slash == 0 || slash == arg.length() - 1) {
        return false;
    }
    if (arg.find('/', slash+1) != string::npos) {
        return false;
    }
    pkg->assign(arg, 0, slash);
    cls->assign(arg, slash+1);
    if ((*cls)[0] == '.') {
        *cls = (*pkg) + (*cls);
    }
    return true;
}

// ================================================================================
static void
usage(FILE* out)
@@ -173,10 +202,13 @@ usage(FILE* out)
    fprintf(out, "Takes an incident report.\n");
    fprintf(out, "\n");
    fprintf(out, "OPTIONS\n");
    fprintf(out, "  -l           list available sections\n");
    fprintf(out, "  -p           privacy spec, LOCAL, EXPLICIT or AUTOMATIC. Default AUTOMATIC.\n");
    fprintf(out, "\n");
    fprintf(out, "and one of these destinations:\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, "  -s PKG/CLS   send broadcast to the broadcast receiver.\n");
    fprintf(out, "\n");
    fprintf(out, "  SECTION     the field numbers of the incident report fields to include\n");
    fprintf(out, "\n");
@@ -187,12 +219,13 @@ main(int argc, char** argv)
{
    Status status;
    IncidentReportArgs args;
    enum { DEST_DROPBOX, DEST_STDOUT } destination = DEST_STDOUT;
    int dest = -1; // default
    enum { DEST_UNSET, DEST_DROPBOX, DEST_STDOUT, DEST_BROADCAST } destination = DEST_UNSET;
    int privacyPolicy = PRIVACY_POLICY_AUTOMATIC;
    string receiverArg;

    // Parse the args
    int opt;
    while ((opt = getopt(argc, argv, "bhdlp:")) != -1) {
    while ((opt = getopt(argc, argv, "bhdlp:s:")) != -1) {
        switch (opt) {
            case 'h':
                usage(stdout);
@@ -201,13 +234,29 @@ main(int argc, char** argv)
                section_list(stdout);
                return 0;
            case 'b':
                if (!(destination == DEST_UNSET || destination == DEST_STDOUT)) {
                    usage(stderr);
                    return 1;
                }
                destination = DEST_STDOUT;
                break;
            case 'd':
                if (!(destination == DEST_UNSET || destination == DEST_DROPBOX)) {
                    usage(stderr);
                    return 1;
                }
                destination = DEST_DROPBOX;
                break;
            case 'p':
                dest = get_dest(optarg);
                privacyPolicy = get_privacy_policy(optarg);
                break;
            case 's':
                if (destination != DEST_UNSET) {
                    usage(stderr);
                    return 1;
                }
                destination = DEST_BROADCAST;
                receiverArg = optarg;
                break;
            default:
                usage(stderr);
@@ -215,6 +264,17 @@ main(int argc, char** argv)
        }
    }

    string pkg;
    string cls;
    if (parse_receiver_arg(receiverArg, &pkg, &cls)) {
        args.setReceiverPkg(pkg);
        args.setReceiverCls(cls);
    } else {
        fprintf(stderr, "badly formatted -s package/class option: %s\n\n", receiverArg.c_str());
        usage(stderr);
        return 1;
    }

    if (optind == argc) {
        args.setAll(true);
    } else {
@@ -236,7 +296,7 @@ main(int argc, char** argv)
            }
        }
    }
    args.setDest(dest);
    args.setPrivacyPolicy(privacyPolicy);

    // Start the thread pool.
    sp<ProcessState> ps(ProcessState::self());
@@ -272,12 +332,17 @@ main(int argc, char** argv)
        //IPCThreadState::self()->joinThreadPool();

        while (true) {
            int amt = splice(fds[0], NULL, STDOUT_FILENO, NULL, 4096, 0);
            fprintf(stderr, "spliced %d bytes\n", amt);
            uint8_t buf[4096];
            ssize_t amt = TEMP_FAILURE_RETRY(read(fds[0], buf, sizeof(buf)));
            if (amt < 0) {
                return errno;
                break;
            } else if (amt == 0) {
                return 0;
                break;
            }

            ssize_t wamt = TEMP_FAILURE_RETRY(write(STDOUT_FILENO, buf, amt));
            if (wamt != amt) {
                return errno;
            }
        }
    } else {
+27 −3
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ cc_binary {

    srcs: [
        "src/**/*.cpp",
        "src/**/*.proto",
        ":incidentd_section_list",
    ],

@@ -43,6 +44,10 @@ cc_binary {
    local_include_dirs: ["src"],
    generated_headers: ["gen-platform-proto-constants"],

    proto: {
        type: "lite",
    },

    shared_libs: [
        "libbase",
        "libbinder",
@@ -56,6 +61,11 @@ cc_binary {
        "libprotobuf-cpp-lite",
    ],

    static_libs: [
        "libincidentcompanion",
        "libplatformprotos",
    ],

    init_rc: ["incidentd.rc"],
}

@@ -72,6 +82,7 @@ cc_test {
        "-Wall",
        "-Wno-unused-variable",
        "-Wunused-parameter",
        "-g",

        // Allow implicit fallthrough in IncidentService.cpp:85 until it is fixed.
        "-Wno-error=implicit-fallthrough",
@@ -82,21 +93,26 @@ cc_test {

    srcs: [
        "tests/**/*.cpp",
        "src/PrivacyBuffer.cpp",
        "tests/**/*.proto",
        "src/FdBuffer.cpp",
        "src/Privacy.cpp",
        "src/PrivacyFilter.cpp",
        "src/Reporter.cpp",
        "src/Section.cpp",
        "src/Throttler.cpp",
        "src/WorkDirectory.cpp",
        "src/incidentd_util.cpp",
        "src/proto_util.cpp",
        "src/report_directory.cpp",
        "src/**/*.proto",
    ],

    data: ["testdata/**/*"],

    static_libs: [
        "libgmock",
        "libplatformprotos",
        "libincidentcompanion",
        "libplatformprotos-test",
    ],
    shared_libs: [
        "libbase",
@@ -105,11 +121,19 @@ cc_test {
        "libdumputils",
        "libincident",
        "liblog",
        "libprotobuf-cpp-lite",
        "libprotobuf-cpp-full",
        "libprotoutil",
        "libservices",
        "libutils",
    ],

    target: {
        android: {
            proto: {
                type: "full",
            },
        },
    },
}

genrule {
+440 −0
Original line number Diff line number Diff line
/*
 * 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.
 */

#include "Log.h"

#include "Broadcaster.h"

#include "IncidentService.h"

#include <android/os/DropBoxManager.h>
#include <binder/IServiceManager.h>

namespace android {
namespace os {
namespace incidentd {

using android::os::IIncidentCompanion;
using binder::Status;

// ============================================================
Broadcaster::ConsentListener::ConsentListener(const sp<Broadcaster>& broadcaster,
        const ReportId& reportId)
    :mBroadcaster(broadcaster),
     mId(reportId) {
}

Broadcaster::ConsentListener::~ConsentListener() {
}

Status Broadcaster::ConsentListener::onReportApproved() {
    mBroadcaster->report_approved(mId);
    return Status::ok();
}

Status Broadcaster::ConsentListener::onReportDenied() {
    mBroadcaster->report_denied(mId);
    return Status::ok();
}

// ============================================================
Broadcaster::ReportId::ReportId()
    :id(),
     pkg(),
     cls() {
}

Broadcaster::ReportId::ReportId(const ReportId& that)
    :id(that.id),
     pkg(that.pkg),
     cls(that.cls) {
}

Broadcaster::ReportId::ReportId(const string& i, const string& p, const string& c)
    :id(i),
     pkg(p),
     cls(c) {
}

Broadcaster::ReportId::~ReportId() {
}

bool Broadcaster::ReportId::operator<(const ReportId& that) const {
    if (id < that.id) {
        return true;
    }
    if (id > that.id) {
        return false;
    }
    if (pkg < that.pkg) {
        return true;
    }
    if (pkg > that.pkg) {
        return false;
    }
    if (cls < that.cls) {
        return true;
    }
    return false;
}

// ============================================================
Broadcaster::ReportStatus::ReportStatus()
    :approval_sent(false),
     ready_sent(false),
     listener(nullptr) {
}

Broadcaster::ReportStatus::ReportStatus(const ReportStatus& that)
    :approval_sent(that.approval_sent),
     ready_sent(that.ready_sent),
     listener(that.listener) {
}

Broadcaster::ReportStatus::~ReportStatus() {
}

// ============================================================
Broadcaster::Broadcaster(const sp<WorkDirectory>& workDirectory)
        :mReportHandler(),
         mWorkDirectory(workDirectory) {
}

void Broadcaster::setHandler(const sp<ReportHandler>& handler) {
    mReportHandler = handler;
}

void Broadcaster::reset() {
    unique_lock<mutex> lock(mLock);
    mLastSent = 0;
    mHistory.clear();
    // Could cancel the listeners, but this happens when
    // the system process crashes, so don't bother.
}

void Broadcaster::clearBroadcasts(const string& pkg, const string& cls, const string& id) {
    unique_lock<mutex> lock(mLock);

    map<ReportId,ReportStatus>::const_iterator found = mHistory.find(ReportId(id, pkg, cls));
    if (found != mHistory.end()) {
        if (found->second.listener != nullptr) {
            sp<IIncidentCompanion> ics = get_incident_companion();
            if (ics != nullptr) {
                ics->cancelAuthorization(found->second.listener);
            }
        }
        mHistory.erase(found);
    }
}

void Broadcaster::clearPackageBroadcasts(const string& pkg) {
    unique_lock<mutex> lock(mLock);

    map<ReportId,ReportStatus>::iterator it = mHistory.begin();
    while (it != mHistory.end()) {
        if (it->first.pkg == pkg) {
            if (it->second.listener != nullptr) {
                sp<IIncidentCompanion> ics = get_incident_companion();
                if (ics != nullptr) {
                    ics->cancelAuthorization(it->second.listener);
                }
            }
            it = mHistory.erase(it);
        } else {
            it++;
        }
    }
}

Broadcaster::broadcast_status_t Broadcaster::sendBroadcasts() {
    int err;
    int64_t lastSent = get_last_sent();

    vector<sp<ReportFile>> files;
    mWorkDirectory->getReports(&files, 0); //lastSent);

    // Don't send multiple broadcasts to the same receiver.
    set<ReportId> reportReadyBroadcasts;

    for (const sp<ReportFile>& file: files) {
        err = file->loadEnvelope();
        if (err != NO_ERROR) {
            ALOGW("Error (%s) loading envelope from %s", strerror(-err),
                    file->getEnvelopeFileName().c_str());
            continue;
        }

        const ReportFileProto& envelope = file->getEnvelope();

        if (!envelope.completed()) {
            ALOGI("Incident report not completed skipping it: %s",
                    file->getEnvelopeFileName().c_str());
            continue;
        }

        // When one of the broadcast functions in this loop fails, it's almost
        // certainly because the system process is crashing or has crashed.  Rather
        // than continuing to pound on the system process and potentially make things
        // worse, we bail right away, return BROADCASTS_BACKOFF, and we will try
        // again later.  In the meantime, if the system process did crash, it might
        // clear out mHistory, which means we'll be back here again to send the
        // backlog.
        size_t reportCount = envelope.report_size();
        bool hasApprovalPending = false;
        for (int reportIndex = 0; reportIndex < reportCount; reportIndex++) {

            const ReportFileProto_Report& report = envelope.report(reportIndex);
            status_t err;
            if (report.privacy_policy() == PRIVACY_POLICY_AUTOMATIC || report.share_approved()) {
                // It's privacy policy is AUTO, or it's been approved,
                // so send the actual broadcast.
                if (!was_ready_sent(file->getId(), report.pkg(), report.cls())) {
                    if (report.pkg() == DROPBOX_SENTINEL.getPackageName()
                            && report.cls() == DROPBOX_SENTINEL.getClassName()) {
                        IncidentReportArgs args;
                        get_args_from_report(&args, report);
                        err = send_to_dropbox(file, args);
                        if (err != NO_ERROR) {
                            return BROADCASTS_BACKOFF;
                        }
                    } else {
                        reportReadyBroadcasts.insert(ReportId(file->getId(), report.pkg(),
                                    report.cls()));
                    }
                }
            } else {
                // It's not approved yet, so send the approval.
                if (!was_approval_sent(file->getId(), report.pkg(), report.cls())) {
                    err = send_approval_broadcasts(file->getId(), report.pkg(), report.cls());
                    if (err != NO_ERROR) {
                        return BROADCASTS_BACKOFF;
                    }
                    hasApprovalPending = true;
                }
            }
        }

        lastSent = file->getTimestampNs();
        if (!hasApprovalPending) {
            set_last_sent(lastSent);
        }
    }

    for (const ReportId& report: reportReadyBroadcasts) {
        err = send_report_ready_broadcasts(report.id, report.pkg, report.cls);
        if (err != NO_ERROR) {
            return BROADCASTS_BACKOFF;
        }
    }

    return mWorkDirectory->hasMore(lastSent) ? BROADCASTS_REPEAT : BROADCASTS_FINISHED;
}

void Broadcaster::set_last_sent(int64_t timestamp) {
    unique_lock<mutex> lock(mLock);
    mLastSent = timestamp;
}

int64_t Broadcaster::get_last_sent() {
    unique_lock<mutex> lock(mLock);
    return mLastSent;
}

/*
void Broadcaster::printReportStatuses() const {
    ALOGD("mHistory {");
    for (map<ReportId,ReportStatus>::const_iterator it = mHistory.begin();
            it != mHistory.end(); it++) {
        ALOGD("   [%s %s] --> [%d %d]", it->first.id.c_str(), it->first.pkg.c_str(),
                it->second.approval_sent, it->second.ready_sent);
    }
    ALOGD("}");
}
*/

bool Broadcaster::was_approval_sent(const string& id, const string& pkg, const string& cls) {
    unique_lock<mutex> lock(mLock);
    map<ReportId,ReportStatus>::const_iterator found = mHistory.find(ReportId(id, pkg, cls));
    if (found != mHistory.end()) {
        return found->second.approval_sent;
    }
    return false;
}

void Broadcaster::set_approval_sent(const string& id, const string& pkg, const string& cls,
        const sp<ConsentListener>& listener) {
    unique_lock<mutex> lock(mLock);
    ReportStatus& reportStatus = mHistory[ReportId(id, pkg, cls)];
    reportStatus.approval_sent = true;
    reportStatus.listener = listener;
}

bool Broadcaster::was_ready_sent(const string& id, const string& pkg, const string& cls) {
    unique_lock<mutex> lock(mLock);
    map<ReportId,ReportStatus>::const_iterator found = mHistory.find(ReportId(id, pkg, cls));
    if (found != mHistory.end()) {
        return found->second.ready_sent;
    }
    return false;
}

void Broadcaster::set_ready_sent(const string& id, const string& pkg, const string& cls) {
    unique_lock<mutex> lock(mLock);
    mHistory[ReportId(id, pkg, cls)].ready_sent = true;
}

status_t Broadcaster::send_approval_broadcasts(const string& id, const string& pkg,
        const string& cls) {
    sp<IIncidentCompanion> ics = get_incident_companion();
    if (ics == nullptr) {
        return NAME_NOT_FOUND;
    }

    sp<ConsentListener> listener = new ConsentListener(this, ReportId(id, pkg, cls));

    ALOGI("send_approval_broadcasts for %s %s/%s", id.c_str(), pkg.c_str(), cls.c_str());

    Status status = ics->authorizeReport(0, String16(pkg.c_str()),
            String16(cls.c_str()), String16(id.c_str()), 0, listener);

    if (!status.isOk()) {
        // authorizeReport is oneway, so any error is a transaction error.
        return status.transactionError();
    }

    set_approval_sent(id, pkg, cls, listener);

    return NO_ERROR;
}

void Broadcaster::report_approved(const ReportId& reportId) {
    status_t err;

    // Kick off broadcaster to do send the ready broadcasts.
    ALOGI("The user approved the report, so kicking off another broadcast pass. %s %s/%s",
            reportId.id.c_str(), reportId.pkg.c_str(), reportId.cls.c_str());
    sp<ReportFile> file = mWorkDirectory->getReport(reportId.pkg, reportId.cls, reportId.id,
            nullptr);
    if (file != nullptr) {
        err = file->loadEnvelope();
        if (err != NO_ERROR) {
            return;
        }

        err = file->markApproved(reportId.pkg, reportId.cls);
        if (err != NO_ERROR) {
            ALOGI("Couldn't find report that was just approved: %s %s/%s",
                    reportId.id.c_str(), reportId.pkg.c_str(), reportId.cls.c_str());
            return;
        }

        file->saveEnvelope();
        if (err != NO_ERROR) {
            return;
        }
    }
    mReportHandler->scheduleSendBacklog();
}

void Broadcaster::report_denied(const ReportId& reportId) {
    // The user didn't approve the report, so remove it from the WorkDirectory.
    ALOGI("The user denied the report, so deleting it. %s %s/%s",
            reportId.id.c_str(), reportId.pkg.c_str(), reportId.cls.c_str());
    sp<ReportFile> file = mWorkDirectory->getReport(reportId.pkg, reportId.cls, reportId.id,
            nullptr);
    if (file != nullptr) {
        mWorkDirectory->commit(file, reportId.pkg, reportId.cls);
    }
}

status_t Broadcaster::send_report_ready_broadcasts(const string& id, const string& pkg,
        const string& cls) {
    sp<IIncidentCompanion> ics = get_incident_companion();
    if (ics == nullptr) {
        return NAME_NOT_FOUND;
    }

    ALOGI("send_report_ready_broadcasts for %s %s/%s", id.c_str(), pkg.c_str(), cls.c_str());

    Status status = ics->sendReportReadyBroadcast(String16(pkg.c_str()), String16(cls.c_str()));

    if (!status.isOk()) {
        // sendReportReadyBroadcast is oneway, so any error is a transaction error.
        return status.transactionError();
    }

    set_ready_sent(id, pkg, cls);

    return NO_ERROR;
}

status_t Broadcaster::send_to_dropbox(const sp<ReportFile>& file,
        const IncidentReportArgs& args) {
    status_t err;

    sp<DropBoxManager> dropbox = new DropBoxManager();
    if (dropbox == nullptr) {
        ALOGW("Can't reach dropbox now, so we won't be able to write the incident report to there");
        return NO_ERROR;
    }

    // Start a thread to write the data to dropbox.
    int readFd = -1;
    err = file->startFilteringData(&readFd, args);
    if (err != NO_ERROR) {
        return err;
    }

    // Takes ownership of readFd.
    Status status = dropbox->addFile(String16("incident"), readFd, 0);
    if (!status.isOk()) {
        // TODO: This may or may not leak the readFd, depending on where it failed.
        // Not sure how to fix this given the dropbox API.
        ALOGW("Error sending incident report to dropbox.");
        return -errno;
    }

    // On successful write, tell the working directory that this file is done.
    mWorkDirectory->commit(file, DROPBOX_SENTINEL.getPackageName(),
            DROPBOX_SENTINEL.getClassName());

    // Don't need to call set_ready_sent, because we just removed it from the ReportFile,
    // so we'll never hear about it again.

    return NO_ERROR;
}

sp<IIncidentCompanion> Broadcaster::get_incident_companion() {
    sp<IBinder> binder = defaultServiceManager()->getService(String16("incidentcompanion"));
    if (binder == nullptr) {
        ALOGI("Can not find IIncidentCompanion service to send broadcast. Will try again later.");
        return nullptr;
    }

    sp<IIncidentCompanion> ics = interface_cast<IIncidentCompanion>(binder);
    if (ics == nullptr) {
        ALOGI("The incidentcompanion service is not an IIncidentCompanion. Will try again later.");
        return nullptr;
    }

    return ics;
}

}  // namespace incidentd
}  // namespace os
}  // namespace android

Loading