From c47e2c6a99ddad9497bc3b390c47e363f38e11a4 Mon Sep 17 00:00:00 2001 From: Robert Quattlebaum Date: Wed, 22 Nov 2017 17:24:33 -0800 Subject: lowpan_hdlc_adapter: Wait for Event::OPENED before calling sendFrame() Part of the LoWPAN HAL contract is that the user of the device interface will wait until it receives LowpanEvent::OPENED before calling sending frames using the interface. The LoWPAN HDLC Adapter was breaking that contract, calling sendFrame pretty much immediately after calling open. This change makes sure that we wait for the OPENED event before calling sendFrame(). If we receive an ERROR event first, then we terminate. Bug: b/69687483 Change-Id: I6e0574dbda00775eab6fe8a8c617521e4c48c8cc --- lowpan_hdlc_adapter/lowpan_hdlc_adapter.cpp | 50 ++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/lowpan_hdlc_adapter/lowpan_hdlc_adapter.cpp b/lowpan_hdlc_adapter/lowpan_hdlc_adapter.cpp index c47094b..6986b2f 100644 --- a/lowpan_hdlc_adapter/lowpan_hdlc_adapter.cpp +++ b/lowpan_hdlc_adapter/lowpan_hdlc_adapter.cpp @@ -20,6 +20,9 @@ #include +#include +#include + #include #include #include @@ -54,11 +57,22 @@ struct LowpanDeathRecipient : hidl_death_recipient { struct LowpanDeviceCallback : public ILowpanDeviceCallback { int mFd; + std::mutex mMutex; + std::condition_variable mConditionVariable; + int mOpenError; static const uint32_t kMaxFrameSize = LOWPAN_HDLC_ADAPTER_MAX_FRAME_SIZE; public: - LowpanDeviceCallback(int fd): mFd(fd) { } + LowpanDeviceCallback(int fd): mFd(fd), mOpenError(-1) {} virtual ~LowpanDeviceCallback() = default; + int waitForOpenStatus() { + std::unique_lock lock(mMutex); + if (mOpenError == -1) { + mConditionVariable.wait(lock); + } + return mOpenError; + } + Return onReceiveFrame(const hidl_vec& data) override { if (data.size() > kMaxFrameSize) { ALOGE("TOOBIG: Frame received from device is too big"); @@ -84,6 +98,8 @@ public: buffer[bufferIndex++] = HDLC_BYTE_FLAG; + std::unique_lock lock(mMutex); + if (write(mFd, buffer, bufferIndex) != bufferIndex) { ALOGE("IOFAIL: write: %s (%d)", strerror(errno), errno); exit(EXIT_FAILURE); @@ -93,13 +109,20 @@ public: } Return onEvent(LowpanEvent event, LowpanStatus status) override { + std::unique_lock lock(mMutex); + switch (event) { case LowpanEvent::OPENED: + if (mOpenError == -1) { + mOpenError = 0; + mConditionVariable.notify_all(); + } ALOGI("Device opened"); break; case LowpanEvent::CLOSED: ALOGI("Device closed"); + exit(EXIT_SUCCESS); break; case LowpanEvent::RESET: @@ -107,6 +130,10 @@ public: break; case LowpanEvent::ERROR: + if (mOpenError == -1) { + mOpenError = int(status); + mConditionVariable.notify_all(); + } switch (status) { case LowpanStatus::IOFAIL: ALOGE("IOFAIL: Input/Output error from device. Terminating."); @@ -137,10 +164,18 @@ class ReadThread : public Thread { int mBufferIndex; bool mUnescapeNextByte; uint16_t mFcs; + sp mCallback; public: - ReadThread(sp service, int fd): - Thread(false /*canCallJava*/), kReadThreadBufferSize(service->getMaxFrameSize()), mService(service), mFd(fd), mBufferIndex(0), mUnescapeNextByte(false),mFcs(kHdlcCrcResetValue) { + ReadThread(sp service, int fd, sp callback): + Thread(false /*canCallJava*/), + kReadThreadBufferSize(service->getMaxFrameSize()), + mService(service), + mFd(fd), + mBufferIndex(0), + mUnescapeNextByte(false), + mFcs(kHdlcCrcResetValue), + mCallback(callback) { if (kReadThreadBufferSize < 16) { ALOGE("Device returned bad max frame size: %d bytes", kReadThreadBufferSize); exit(EXIT_FAILURE); @@ -157,6 +192,11 @@ private: bool threadLoop() override { uint8_t buffer[LOWPAN_HDLC_ADAPTER_MAX_FRAME_SIZE]; + if (int error = mCallback->waitForOpenStatus()) { + ALOGE("Call to `open()` failed: %d", error); + exit(EXIT_FAILURE); + } + while (!exitPending()) { ssize_t bytesRead = read(mFd, buffer, sizeof(buffer)); if (exitPending()) { @@ -250,7 +290,7 @@ int main(int argc, char* argv []) { configureRpcThreadpool(1, true /* callerWillJoin */); - sp callback = new LowpanDeviceCallback(STDOUT_FILENO); + sp callback = new LowpanDeviceCallback(STDOUT_FILENO); { auto status = service->open(callback); @@ -267,7 +307,7 @@ int main(int argc, char* argv []) { } } - sp readThread = new ReadThread(service, STDIN_FILENO); + sp readThread = new ReadThread(service, STDIN_FILENO, callback); readThread->run("ReadThread"); -- cgit v1.2.3