summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Alex Vakulenko <avakulenko@google.com> 2017-03-23 17:44:58 -0700
committer Alex Vakulenko <avakulenko@google.com> 2017-03-31 10:45:52 -0700
commit4782814b340bb55a0fbff9f7b6cfd4d27cffd85a (patch)
tree7392a5948d9d8c62c0245485ac52c70d0e7977f0
parent4ab4aa40eb7ecf9ad38307fa56cd1c059c1c2e20 (diff)
libpdx_uds: Improve client connection logic
Handle the case where the service created a socket file but not bound the socket to it, or not listening for incoming requests yet. Also, if the service has crashed and left the socket file behind, need to make sure we reconnect once the service is restarted. Bug: None Test: `m -j32` succeeds, device boots and CubeSea app works on Sailfish Change-Id: I2039cfca6faccd5d1d4b725e454075669484b880 (cherry picked from commit d074fc416a7a90e76a0b28a870080c1dd30079a1)
-rw-r--r--libs/vr/libpdx_uds/client_channel_factory.cpp69
1 files changed, 56 insertions, 13 deletions
diff --git a/libs/vr/libpdx_uds/client_channel_factory.cpp b/libs/vr/libpdx_uds/client_channel_factory.cpp
index 18791276a1..f059453ce0 100644
--- a/libs/vr/libpdx_uds/client_channel_factory.cpp
+++ b/libs/vr/libpdx_uds/client_channel_factory.cpp
@@ -6,10 +6,16 @@
#include <sys/un.h>
#include <unistd.h>
+#include <chrono>
+#include <thread>
+
#include <uds/channel_manager.h>
#include <uds/client_channel.h>
#include <uds/ipc_helper.h>
+using std::chrono::duration_cast;
+using std::chrono::steady_clock;
+
namespace android {
namespace pdx {
namespace uds {
@@ -41,13 +47,11 @@ std::unique_ptr<pdx::ClientChannelFactory> ClientChannelFactory::Create(
Status<std::unique_ptr<pdx::ClientChannel>> ClientChannelFactory::Connect(
int64_t timeout_ms) const {
- auto status = WaitForEndpoint(endpoint_path_, timeout_ms);
- if (!status)
- return ErrorStatus(status.error());
+ Status<void> status;
LocalHandle socket_fd{socket(AF_UNIX, SOCK_STREAM, 0)};
if (!socket_fd) {
- ALOGE("ClientChannelFactory::Connect: socket error %s", strerror(errno));
+ ALOGE("ClientChannelFactory::Connect: socket error: %s", strerror(errno));
return ErrorStatus(errno);
}
@@ -56,16 +60,55 @@ Status<std::unique_ptr<pdx::ClientChannel>> ClientChannelFactory::Connect(
strncpy(remote.sun_path, endpoint_path_.c_str(), sizeof(remote.sun_path));
remote.sun_path[sizeof(remote.sun_path) - 1] = '\0';
- int ret = RETRY_EINTR(connect(
- socket_fd.Get(), reinterpret_cast<sockaddr*>(&remote), sizeof(remote)));
- if (ret == -1) {
- ALOGE(
- "ClientChannelFactory::Connect: Failed to initialize connection when "
- "connecting %s",
- strerror(errno));
- return ErrorStatus(errno);
- }
+ bool use_timeout = (timeout_ms >= 0);
+ auto now = steady_clock::now();
+ auto time_end = now + std::chrono::milliseconds{timeout_ms};
+
+ bool connected = false;
+ while (!connected) {
+ int64_t timeout = -1;
+ if (use_timeout) {
+ auto remaining = time_end - now;
+ timeout = duration_cast<std::chrono::milliseconds>(remaining).count();
+ if (timeout < 0)
+ return ErrorStatus(ETIMEDOUT);
+ }
+ ALOGD("ClientChannelFactory: Waiting for endpoint at %s", remote.sun_path);
+ status = WaitForEndpoint(endpoint_path_, timeout);
+ if (!status)
+ return ErrorStatus(status.error());
+
+ ALOGD("ClientChannelFactory: Connecting to %s", remote.sun_path);
+ int ret = RETRY_EINTR(connect(
+ socket_fd.Get(), reinterpret_cast<sockaddr*>(&remote), sizeof(remote)));
+ if (ret == -1) {
+ ALOGD("ClientChannelFactory: Connect error %d: %s", errno,
+ strerror(errno));
+ if (errno == ECONNREFUSED) {
+ // Connection refused can be the result of connecting too early (the
+ // service socket is created but not being listened to yet).
+ ALOGD("ClientChannelFactory: Connection refused, waiting...");
+ using namespace std::literals::chrono_literals;
+ std::this_thread::sleep_for(100ms);
+ } else if (errno != ENOENT && errno != ENOTDIR) {
+ // ENOENT/ENOTDIR might mean that the socket file/directory containing
+ // it has been just deleted. Try to wait for its creation and do not
+ // return an error immediately.
+ ALOGE(
+ "ClientChannelFactory::Connect: Failed to initialize connection "
+ "when connecting: %s",
+ strerror(errno));
+ return ErrorStatus(errno);
+ }
+ } else {
+ connected = true;
+ }
+ if (use_timeout)
+ now = steady_clock::now();
+ } // while (!connected)
+ ALOGD("ClientChannelFactory: Connected successfully to %s...",
+ remote.sun_path);
RequestHeader<BorrowedHandle> request;
InitRequest(&request, opcodes::CHANNEL_OPEN, 0, 0, false);
status = SendData(socket_fd.Get(), request);