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

Commit 5fa662db authored by Gavin Corkery's avatar Gavin Corkery Committed by Android (Google) Code Review
Browse files

Merge "Add retrieveBugreport dumpstate implementation"

parents 63f8a793 a44686c4
Loading
Loading
Loading
Loading
+42 −0
Original line number Original line Diff line number Diff line
@@ -58,6 +58,13 @@ static binder::Status exception(uint32_t code, const std::string& msg,
    exit(0);
    exit(0);
}
}


[[noreturn]] static void* dumpstate_thread_retrieve(void* data) {
    std::unique_ptr<DumpstateInfo> ds_info(static_cast<DumpstateInfo*>(data));
    ds_info->ds->Retrieve(ds_info->calling_uid, ds_info->calling_package);
    MYLOGD("Finished retrieving a bugreport. Exiting.\n");
    exit(0);
}

[[noreturn]] static void signalErrorAndExit(sp<IDumpstateListener> listener, int error_code) {
[[noreturn]] static void signalErrorAndExit(sp<IDumpstateListener> listener, int error_code) {
    listener->onError(error_code);
    listener->onError(error_code);
    exit(0);
    exit(0);
@@ -192,6 +199,41 @@ binder::Status DumpstateService::cancelBugreport(int32_t calling_uid,
    return binder::Status::ok();
    return binder::Status::ok();
}
}


binder::Status DumpstateService::retrieveBugreport(
    int32_t calling_uid, const std::string& calling_package,
    android::base::unique_fd bugreport_fd,
    const std::string& bugreport_file,
    const sp<IDumpstateListener>& listener) {

    ds_ = &(Dumpstate::GetInstance());
    DumpstateInfo* ds_info = new DumpstateInfo();
    ds_info->ds = ds_;
    ds_info->calling_uid = calling_uid;
    ds_info->calling_package = calling_package;
    ds_->listener_ = listener;
    std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
    // Use a /dev/null FD when initializing options since none is provided.
    android::base::unique_fd devnull_fd(
        TEMP_FAILURE_RETRY(open("/dev/null", O_WRONLY | O_CLOEXEC)));

    options->Initialize(Dumpstate::BugreportMode::BUGREPORT_DEFAULT,
                        0, bugreport_fd, devnull_fd, false);

    if (bugreport_fd.get() == -1) {
        MYLOGE("Invalid filedescriptor");
        signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
    }
    ds_->SetOptions(std::move(options));
    ds_->path_ = bugreport_file;
    pthread_t thread;
    status_t err = pthread_create(&thread, nullptr, dumpstate_thread_retrieve, ds_info);
    if (err != 0) {
        MYLOGE("Could not create a thread");
        signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
    }
    return binder::Status::ok();
}

status_t DumpstateService::dump(int fd, const Vector<String16>&) {
status_t DumpstateService::dump(int fd, const Vector<String16>&) {
    std::lock_guard<std::mutex> lock(lock_);
    std::lock_guard<std::mutex> lock(lock_);
    if (ds_ == nullptr) {
    if (ds_ == nullptr) {
+7 −0
Original line number Original line Diff line number Diff line
@@ -46,6 +46,13 @@ class DumpstateService : public BinderService<DumpstateService>, public BnDumpst
                                  int bugreport_flags, const sp<IDumpstateListener>& listener,
                                  int bugreport_flags, const sp<IDumpstateListener>& listener,
                                  bool is_screenshot_requested) override;
                                  bool is_screenshot_requested) override;


    binder::Status retrieveBugreport(int32_t calling_uid,
                                     const std::string& calling_package,
                                     android::base::unique_fd bugreport_fd,
                                     const std::string& bugreport_file,
                                     const sp<IDumpstateListener>& listener)
                                     override;

    binder::Status cancelBugreport(int32_t calling_uid,
    binder::Status cancelBugreport(int32_t calling_uid,
                                   const std::string& calling_package) override;
                                   const std::string& calling_package) override;


+22 −1
Original line number Original line Diff line number Diff line
@@ -50,7 +50,10 @@ interface IDumpstate {
    const int BUGREPORT_MODE_DEFAULT = 6;
    const int BUGREPORT_MODE_DEFAULT = 6;


    // Use pre-dumped data.
    // Use pre-dumped data.
    const int BUGREPORT_FLAG_USE_PREDUMPED_UI_DATA = 1;
    const int BUGREPORT_FLAG_USE_PREDUMPED_UI_DATA = 0x1;

    // Defer user consent.
    const int BUGREPORT_FLAG_DEFER_CONSENT = 0x2;


    /**
    /**
     * Speculatively pre-dumps UI data for a bugreport request that might come later.
     * Speculatively pre-dumps UI data for a bugreport request that might come later.
@@ -100,4 +103,22 @@ interface IDumpstate {
     * @param callingPackage package of the original application that requested the cancellation.
     * @param callingPackage package of the original application that requested the cancellation.
     */
     */
    void cancelBugreport(int callingUid, @utf8InCpp String callingPackage);
    void cancelBugreport(int callingUid, @utf8InCpp String callingPackage);

    /**
     * Retrieves a previously generated bugreport.
     *
     * <p>The caller must have previously generated a bugreport using
     * {@link #startBugreport} with the {@link BUGREPORT_FLAG_DEFER_CONSENT}
     * flag set.
     *
     * @param callingUid UID of the original application that requested the report.
     * @param callingPackage package of the original application that requested the report.
     * @param bugreportFd the file to which the zipped bugreport should be written
     * @param bugreportFile the path of the bugreport file
     * @param listener callback for updates; optional
     */
    void retrieveBugreport(int callingUid, @utf8InCpp String callingPackage,
                           FileDescriptor bugreportFd,
                           @utf8InCpp String bugreportFile,
                           IDumpstateListener listener);
}
}
+6 −1
Original line number Original line Diff line number Diff line
@@ -50,6 +50,9 @@ interface IDumpstateListener {
    /* There is currently a bugreport running. The caller should try again later. */
    /* There is currently a bugreport running. The caller should try again later. */
    const int BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS = 5;
    const int BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS = 5;


    /* There is no bugreport to retrieve for the given caller. */
    const int BUGREPORT_ERROR_NO_BUGREPORT_TO_RETRIEVE = 6;

    /**
    /**
     * Called on an error condition with one of the error codes listed above.
     * Called on an error condition with one of the error codes listed above.
     */
     */
@@ -57,8 +60,10 @@ interface IDumpstateListener {


    /**
    /**
     * Called when taking bugreport finishes successfully.
     * Called when taking bugreport finishes successfully.
     *
     * @param bugreportFile The location of the bugreport file
     */
     */
    oneway void onFinished();
    oneway void onFinished(@utf8InCpp String bugreportFile);


    /**
    /**
     * Called when screenshot is taken.
     * Called when screenshot is taken.
+63 −8
Original line number Original line Diff line number Diff line
@@ -2825,6 +2825,7 @@ void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
                                        const android::base::unique_fd& screenshot_fd_in,
                                        const android::base::unique_fd& screenshot_fd_in,
                                        bool is_screenshot_requested) {
                                        bool is_screenshot_requested) {
    this->use_predumped_ui_data = bugreport_flags & BugreportFlag::BUGREPORT_USE_PREDUMPED_UI_DATA;
    this->use_predumped_ui_data = bugreport_flags & BugreportFlag::BUGREPORT_USE_PREDUMPED_UI_DATA;
    this->is_consent_deferred = bugreport_flags & BugreportFlag::BUGREPORT_FLAG_DEFER_CONSENT;
    // Duplicate the fds because the passed in fds don't outlive the binder transaction.
    // Duplicate the fds because the passed in fds don't outlive the binder transaction.
    bugreport_fd.reset(fcntl(bugreport_fd_in.get(), F_DUPFD_CLOEXEC, 0));
    bugreport_fd.reset(fcntl(bugreport_fd_in.get(), F_DUPFD_CLOEXEC, 0));
    screenshot_fd.reset(fcntl(screenshot_fd_in.get(), F_DUPFD_CLOEXEC, 0));
    screenshot_fd.reset(fcntl(screenshot_fd_in.get(), F_DUPFD_CLOEXEC, 0));
@@ -2907,10 +2908,64 @@ void Dumpstate::Initialize() {


Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& calling_package) {
Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& calling_package) {
    Dumpstate::RunStatus status = RunInternal(calling_uid, calling_package);
    Dumpstate::RunStatus status = RunInternal(calling_uid, calling_package);
    HandleRunStatus(status);
    return status;
}

Dumpstate::RunStatus Dumpstate::Retrieve(int32_t calling_uid, const std::string& calling_package) {
    Dumpstate::RunStatus status = RetrieveInternal(calling_uid, calling_package);
    HandleRunStatus(status);
    return status;
}

Dumpstate::RunStatus  Dumpstate::RetrieveInternal(int32_t calling_uid,
                                                  const std::string& calling_package) {
  consent_callback_ = new ConsentCallback();
  const String16 incidentcompanion("incidentcompanion");
  sp<android::IBinder> ics(
      defaultServiceManager()->checkService(incidentcompanion));
  android::String16 package(calling_package.c_str());
  if (ics != nullptr) {
    MYLOGD("Checking user consent via incidentcompanion service\n");
    android::interface_cast<android::os::IIncidentCompanion>(ics)->authorizeReport(
        calling_uid, package, String16(), String16(),
        0x1 /* FLAG_CONFIRMATION_DIALOG */, consent_callback_.get());
  } else {
    MYLOGD(
        "Unable to check user consent; incidentcompanion service unavailable\n");
    return RunStatus::USER_CONSENT_TIMED_OUT;
  }
  UserConsentResult consent_result = consent_callback_->getResult();
  int timeout_ms = 30 * 1000;
  while (consent_result == UserConsentResult::UNAVAILABLE &&
      consent_callback_->getElapsedTimeMs() < timeout_ms) {
    sleep(1);
    consent_result = consent_callback_->getResult();
  }
  if (consent_result == UserConsentResult::DENIED) {
    return RunStatus::USER_CONSENT_DENIED;
  }
  if (consent_result == UserConsentResult::UNAVAILABLE) {
    MYLOGD("Canceling user consent request via incidentcompanion service\n");
    android::interface_cast<android::os::IIncidentCompanion>(ics)->cancelAuthorization(
        consent_callback_.get());
    return RunStatus::USER_CONSENT_TIMED_OUT;
  }

  bool copy_succeeded =
      android::os::CopyFileToFd(path_, options_->bugreport_fd.get());
  if (copy_succeeded) {
    android::os::UnlinkAndLogOnError(path_);
  }
  return copy_succeeded ? Dumpstate::RunStatus::OK
                        : Dumpstate::RunStatus::ERROR;
}

void Dumpstate::HandleRunStatus(Dumpstate::RunStatus status) {
      if (listener_ != nullptr) {
      if (listener_ != nullptr) {
        switch (status) {
        switch (status) {
            case Dumpstate::RunStatus::OK:
            case Dumpstate::RunStatus::OK:
                listener_->onFinished();
                listener_->onFinished(path_.c_str());
                break;
                break;
            case Dumpstate::RunStatus::HELP:
            case Dumpstate::RunStatus::HELP:
                break;
                break;
@@ -2928,9 +2983,7 @@ Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& call
                break;
                break;
        }
        }
    }
    }
    return status;
}
}

void Dumpstate::Cancel() {
void Dumpstate::Cancel() {
    CleanupTmpFiles();
    CleanupTmpFiles();
    android::os::UnlinkAndLogOnError(log_path_);
    android::os::UnlinkAndLogOnError(log_path_);
@@ -3181,7 +3234,7 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,


    // Share the final file with the caller if the user has consented or Shell is the caller.
    // Share the final file with the caller if the user has consented or Shell is the caller.
    Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
    Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
    if (CalledByApi()) {
    if (CalledByApi() && !options_->is_consent_deferred) {
        status = CopyBugreportIfUserConsented(calling_uid);
        status = CopyBugreportIfUserConsented(calling_uid);
        if (status != Dumpstate::RunStatus::OK &&
        if (status != Dumpstate::RunStatus::OK &&
            status != Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
            status != Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
@@ -3326,9 +3379,11 @@ void Dumpstate::onUiIntensiveBugreportDumpsFinished(int32_t calling_uid) {
}
}


void Dumpstate::MaybeCheckUserConsent(int32_t calling_uid, const std::string& calling_package) {
void Dumpstate::MaybeCheckUserConsent(int32_t calling_uid, const std::string& calling_package) {
    if (multiuser_get_app_id(calling_uid) == AID_SHELL || !CalledByApi()) {
    if (multiuser_get_app_id(calling_uid) == AID_SHELL ||
        // No need to get consent for shell triggered dumpstates, or not through
        !CalledByApi() || options_->is_consent_deferred) {
        // bugreporting API (i.e. no fd to copy back).
        // No need to get consent for shell triggered dumpstates, or not
        // through bugreporting API (i.e. no fd to copy back), or when consent
        // is deferred.
        return;
        return;
    }
    }
    consent_callback_ = new ConsentCallback();
    consent_callback_ = new ConsentCallback();
Loading