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

Commit b1db390e authored by Yifan Hong's avatar Yifan Hong
Browse files

lshal: Allow read to timeout in debug()

Start timing when debug() has returned. When the specific
timeout has reached (currently 1s) and the relay thread
has not finish, tell the relay thread to stop.

Test: while true; do date; lshal debug android.hardware.health.storage@1.0::IStorage/default; done
Test: lshal_test

Bug: 111997867
Change-Id: Ib9235d3bd2fc3a54eb316da8d8b59d987988b134
parent a5ae7868
Loading
Loading
Loading
Loading
+51 −4
Original line number Diff line number Diff line
@@ -16,33 +16,75 @@

#include "PipeRelay.h"

#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

#include <atomic>

#include <android-base/logging.h>
#include <utils/Thread.h>

namespace android {
namespace lshal {

static constexpr struct timeval READ_TIMEOUT { .tv_sec = 1, .tv_usec = 0 };

struct PipeRelay::RelayThread : public Thread {
    explicit RelayThread(int fd, std::ostream &os);

    bool threadLoop() override;
    void setFinished();

private:
    int mFd;
    std::ostream &mOutStream;

    // If we were to use requestExit() and exitPending() instead, threadLoop()
    // may not run at all by the time ~PipeRelay is called (i.e. debug() has
    // returned from HAL). By using our own flag, we ensure that select() and
    // read() are executed until data are drained.
    std::atomic_bool mFinished;

    DISALLOW_COPY_AND_ASSIGN(RelayThread);
};

////////////////////////////////////////////////////////////////////////////////

PipeRelay::RelayThread::RelayThread(int fd, std::ostream &os)
    : mFd(fd),
      mOutStream(os) {
}
      : mFd(fd), mOutStream(os), mFinished(false) {}

bool PipeRelay::RelayThread::threadLoop() {
    char buffer[1024];
    ssize_t n = read(mFd, buffer, sizeof(buffer));

    fd_set set;
    FD_ZERO(&set);
    FD_SET(mFd, &set);

    struct timeval timeout = READ_TIMEOUT;

    int res = TEMP_FAILURE_RETRY(select(mFd + 1, &set, nullptr, nullptr, &timeout));
    if (res < 0) {
        PLOG(INFO) << "select() failed";
        return false;
    }

    if (res == 0 || !FD_ISSET(mFd, &set)) {
        if (mFinished) {
            LOG(WARNING) << "debug: timeout reading from pipe, output may be truncated.";
            return false;
        }
        // timeout, but debug() has not returned, so wait for HAL to finish.
        return true;
    }

    // FD_ISSET(mFd, &set) == true. Data available, start reading
    ssize_t n = TEMP_FAILURE_RETRY(read(mFd, buffer, sizeof(buffer)));

    if (n < 0) {
        PLOG(ERROR) << "read() failed";
    }

    if (n <= 0) {
        return false;
@@ -53,6 +95,10 @@ bool PipeRelay::RelayThread::threadLoop() {
    return true;
}

void PipeRelay::RelayThread::setFinished() {
    mFinished = true;
}

////////////////////////////////////////////////////////////////////////////////

PipeRelay::PipeRelay(std::ostream &os)
@@ -79,6 +125,7 @@ PipeRelay::~PipeRelay() {
    CloseFd(&mFds[1]);

    if (mThread != nullptr) {
        mThread->setFinished();
        mThread->join();
        mThread.clear();
    }