diff options
author | Robert Quattlebaum <rquattle@google.com> | 2017-11-22 17:24:33 -0800 |
---|---|---|
committer | Robert Quattlebaum <rquattle@google.com> | 2017-11-22 17:25:37 -0800 |
commit | c47e2c6a99ddad9497bc3b390c47e363f38e11a4 (patch) | |
tree | 72c7da3071bdc87b651a7f5d91b6c9ee54b4e6c9 | |
parent | 1ed605b98876dc15df2f3a946f61a07ca161b392 (diff) | |
download | lowpan-c47e2c6a99ddad9497bc3b390c47e363f38e11a4.tar.gz |
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
-rw-r--r-- | lowpan_hdlc_adapter/lowpan_hdlc_adapter.cpp | 50 |
1 files 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 <unistd.h> +#include <mutex> +#include <condition_variable> + #include <hidl/HidlTransportSupport.h> #include <hidl/ServiceManagement.h> #include <hidl/Status.h> @@ -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<std::mutex> lock(mMutex); + if (mOpenError == -1) { + mConditionVariable.wait(lock); + } + return mOpenError; + } + Return<void> onReceiveFrame(const hidl_vec<uint8_t>& 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<std::mutex> 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<void> onEvent(LowpanEvent event, LowpanStatus status) override { + std::unique_lock<std::mutex> 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<LowpanDeviceCallback> mCallback; public: - ReadThread(sp<ILowpanDevice> service, int fd): - Thread(false /*canCallJava*/), kReadThreadBufferSize(service->getMaxFrameSize()), mService(service), mFd(fd), mBufferIndex(0), mUnescapeNextByte(false),mFcs(kHdlcCrcResetValue) { + ReadThread(sp<ILowpanDevice> service, int fd, sp<LowpanDeviceCallback> 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<ILowpanDeviceCallback> callback = new LowpanDeviceCallback(STDOUT_FILENO); + sp<LowpanDeviceCallback> callback = new LowpanDeviceCallback(STDOUT_FILENO); { auto status = service->open(callback); @@ -267,7 +307,7 @@ int main(int argc, char* argv []) { } } - sp<Thread> readThread = new ReadThread(service, STDIN_FILENO); + sp<Thread> readThread = new ReadThread(service, STDIN_FILENO, callback); readThread->run("ReadThread"); |