MainLoop: improve error handling
am: fd59221459

Change-Id: Ica2fb6ca49c57286c661763192a0f45a23e899c9
diff --git a/main_loop.cpp b/main_loop.cpp
index 62bed31..8ad030a 100644
--- a/main_loop.cpp
+++ b/main_loop.cpp
@@ -30,6 +30,8 @@
 
 namespace {
 constexpr auto kMainBufferSizeBytes = 128 * 1024;
+// TODO(b/32840641): Tune the sleep time.
+constexpr auto kTransientErrorSleepTimeNsec = 100 * 1000;  // 100 usec
 }
 
 MainLoop::MainLoop(const std::string& socket_name)
@@ -53,8 +55,7 @@
   std::tie(datagram_len, err) =
       os_->ReceiveDatagram(sock_fd_, input_buf.data(), input_buf.size());
   if (err) {
-    // TODO(b/32098735): Increment stats counter.
-    // TODO(b/32481888): Improve error handling.
+    ProcessError(err);
     return;
   }
 
@@ -67,5 +68,20 @@
                                      Os::kInvalidFd);
 }
 
+// Private methods below.
+
+void MainLoop::ProcessError(Os::Errno err) {
+  if (err == EINTR || err == ENOMEM) {
+    // TODO(b/32098735): Increment stats counter.
+    os_->Nanosleep(kTransientErrorSleepTimeNsec);
+    return;
+  }
+
+  // Any other error is unexpected, and assumed to be non-recoverable.
+  // (If, e.g., our socket is in a bad state, then we won't be able to receive
+  // any new log messages.)
+  LOG(FATAL) << "Unexpected error: " << std::strerror(err);
+}
+
 }  // namespace wifilogd
 }  // namespace android
diff --git a/main_loop.h b/main_loop.h
index c5a4b48..53c42f8 100644
--- a/main_loop.h
+++ b/main_loop.h
@@ -39,6 +39,8 @@
   void RunOnce();
 
  private:
+  void ProcessError(Os::Errno err);
+
   std::unique_ptr<Os> os_;
   std::unique_ptr<CommandProcessor> command_processor_;
   // We use an int, rather than a unique_fd, because the file
diff --git a/tests/main_loop_unittest.cpp b/tests/main_loop_unittest.cpp
index db04027..b6c1141 100644
--- a/tests/main_loop_unittest.cpp
+++ b/tests/main_loop_unittest.cpp
@@ -109,9 +109,10 @@
   main_loop_->RunOnce();
 }
 
-TEST_F(MainLoopTest, RunOnceDoesNotPassDataToCommandProcessorOnError) {
+TEST_F(MainLoopTest, RunOnceSleepsAndDoesNotPassDataToCommandProcessorOnError) {
   EXPECT_CALL(*os_, ReceiveDatagram(_, _, protocol::kMaxMessageSize))
       .WillOnce(Return(std::tuple<size_t, Os::Errno>{0, EINTR}));
+  EXPECT_CALL(*os_, Nanosleep(_));
   EXPECT_CALL(*command_processor_, ProcessCommand(_, _, _)).Times(0);
   main_loop_->RunOnce();
 }
@@ -131,5 +132,11 @@
       "Failed to get control socket");
 }
 
+TEST_F(MainLoopDeathTest, RunOnceTerminatesOnUnexpectedError) {
+  ON_CALL(*os_, ReceiveDatagram(_, _, protocol::kMaxMessageSize))
+      .WillByDefault(Return(std::tuple<size_t, Os::Errno>{0, EFAULT}));
+  EXPECT_DEATH(main_loop_->RunOnce(), "Unexpected error");
+}
+
 }  // namespace wifilogd
 }  // namespace android