connection.cc 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. // Copyright 2022 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "chromeos/components/mojo_service_manager/connection.h"
  5. #include <errno.h>
  6. #include <sys/socket.h>
  7. #include <sys/un.h>
  8. #include <cstdlib>
  9. #include <string>
  10. #include <utility>
  11. #include "base/bind.h"
  12. #include "base/check_op.h"
  13. #include "base/metrics/histogram_functions.h"
  14. #include "base/no_destructor.h"
  15. #include "base/posix/eintr_wrapper.h"
  16. #include "base/threading/platform_thread.h"
  17. #include "base/time/time.h"
  18. #include "base/timer/elapsed_timer.h"
  19. #include "mojo/public/cpp/bindings/pending_receiver.h"
  20. #include "mojo/public/cpp/bindings/pending_remote.h"
  21. #include "mojo/public/cpp/bindings/remote.h"
  22. #include "mojo/public/cpp/platform/platform_channel.h"
  23. #include "mojo/public/cpp/system/invitation.h"
  24. namespace chromeos::mojo_service_manager {
  25. namespace {
  26. // The socket path to connect to the service manager.
  27. constexpr char kServiceManagerSocketPath[] = "/run/mojo/service_manager.sock";
  28. // The default mojo pipe name for bootstrap the mojo.
  29. constexpr int kDefaultMojoInvitationPipeName = 0;
  30. // The connection may fail if the socket is not exist or the permission is not
  31. // set to the right permission. This could happen if the ChromeOS mojo service
  32. // manager is starting. We may need to wait for a while and retry.
  33. //
  34. // TODO(b/234318452): Clean up this retry logic after we collect enough UMA
  35. // data.
  36. //
  37. // The retry interval of connecting to the service manager. It is expected that
  38. // normally the first retry should be able to perform the bootstrap on all
  39. // devices.
  40. constexpr base::TimeDelta kRetryInterval = base::Milliseconds(1);
  41. // The retry timeout of connecting to the service manager.
  42. constexpr base::TimeDelta kRetryTimeout = base::Seconds(5);
  43. base::ScopedFD ConnectToServiceManagerUnixSocket() {
  44. base::ScopedFD sock{socket(AF_UNIX, SOCK_STREAM, 0)};
  45. if (!sock.is_valid()) {
  46. PLOG(ERROR) << "Failed to create socket.";
  47. return base::ScopedFD{};
  48. }
  49. struct sockaddr_un unix_addr {
  50. .sun_family = AF_UNIX,
  51. };
  52. static_assert(sizeof(kServiceManagerSocketPath) <=
  53. sizeof(unix_addr.sun_path));
  54. strncpy(unix_addr.sun_path, kServiceManagerSocketPath,
  55. sizeof(kServiceManagerSocketPath));
  56. int rc = HANDLE_EINTR(connect(sock.get(),
  57. reinterpret_cast<const sockaddr*>(&unix_addr),
  58. sizeof(unix_addr)));
  59. if (rc == -1 && errno != EISCONN) {
  60. PLOG(ERROR) << "Failed to connect to service manager unix socket.";
  61. return base::ScopedFD{};
  62. }
  63. return sock;
  64. }
  65. mojo::PendingRemote<mojom::ServiceManager> ConnectToMojoServiceManager() {
  66. base::ScopedFD sock = ConnectToServiceManagerUnixSocket();
  67. if (!sock.is_valid())
  68. return mojo::PendingRemote<mojom::ServiceManager>{};
  69. auto invitation = mojo::IncomingInvitation::Accept(
  70. mojo::PlatformChannelEndpoint(mojo::PlatformHandle(std::move(sock))));
  71. mojo::ScopedMessagePipeHandle pipe =
  72. invitation.ExtractMessagePipe(kDefaultMojoInvitationPipeName);
  73. return mojo::PendingRemote<mojom::ServiceManager>(std::move(pipe), 0u);
  74. }
  75. mojo::Remote<mojom::ServiceManager>& GetRemote() {
  76. static base::NoDestructor<mojo::Remote<mojom::ServiceManager>> instance;
  77. return *instance;
  78. }
  79. // Sends the histogram to record the retry times of bootstrap.
  80. void SendBootsrapRetryTimesHistogram(int retry_times) {
  81. // Note that sample will be 0 if didn't retry, and it will be in the underflow
  82. // bucket.
  83. base::UmaHistogramCustomCounts("Ash.MojoServiceManager.BootstrapRetryTimes",
  84. retry_times, 1, 5000, 50);
  85. }
  86. // Sends the histogram to record whether the connection is lost during ash
  87. // running.
  88. void SendIsConnectionLostHistogram(bool is_connection_lost) {
  89. base::UmaHistogramBoolean("Ash.MojoServiceManager.IsConnectionLost",
  90. is_connection_lost);
  91. }
  92. void OnDisconnect(uint32_t reason, const std::string& message) {
  93. SendIsConnectionLostHistogram(true);
  94. LOG(FATAL) << "Disconnecting from ChromeOS mojo service manager is "
  95. "unexpected. Reason: "
  96. << reason << ", message: " << message;
  97. }
  98. } // namespace
  99. bool BootstrapServiceManagerConnection() {
  100. CHECK(!GetRemote().is_bound()) << "remote_ has already bound.";
  101. // We block and sleep here because we assume that it doesn't need to retry at
  102. // all.
  103. int retry_times = 0;
  104. for (base::ElapsedTimer timer; timer.Elapsed() < kRetryTimeout;
  105. base::PlatformThread::Sleep(kRetryInterval), ++retry_times) {
  106. mojo::PendingRemote<mojom::ServiceManager> remote =
  107. ConnectToMojoServiceManager();
  108. if (!remote.is_valid())
  109. continue;
  110. SendBootsrapRetryTimesHistogram(retry_times);
  111. GetRemote().Bind(std::move(remote));
  112. GetRemote().set_disconnect_with_reason_handler(
  113. base::BindOnce(&OnDisconnect));
  114. return true;
  115. }
  116. SendBootsrapRetryTimesHistogram(retry_times);
  117. return false;
  118. }
  119. bool IsServiceManagerBound() {
  120. return GetRemote().is_bound();
  121. }
  122. void ResetServiceManagerConnection() {
  123. SendIsConnectionLostHistogram(false);
  124. GetRemote().reset();
  125. }
  126. mojom::ServiceManagerProxy* GetServiceManagerProxy() {
  127. return GetRemote().get();
  128. }
  129. void SetServiceManagerRemoteForTesting( // IN-TEST
  130. mojo::PendingRemote<mojom::ServiceManager> remote) {
  131. CHECK(remote.is_valid());
  132. GetRemote().Bind(std::move(remote));
  133. GetRemote().set_disconnect_with_reason_handler(base::BindOnce(&OnDisconnect));
  134. }
  135. } // namespace chromeos::mojo_service_manager