| /* |
| * Copyright (C) 2023 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef SRC_TRACED_RELAY_RELAY_SERVICE_H_ |
| #define SRC_TRACED_RELAY_RELAY_SERVICE_H_ |
| |
| #include <memory> |
| #include <vector> |
| |
| #include "perfetto/ext/base/unix_socket.h" |
| #include "perfetto/ext/tracing/core/tracing_service.h" |
| #include "src/traced_relay/socket_relay_handler.h" |
| #include "src/tracing/ipc/producer/relay_ipc_client.h" |
| |
| namespace perfetto { |
| |
| namespace base { |
| class TaskRunner; |
| } // namespace base. |
| |
| // RelayClient provides a service that is independent of the relayed producers |
| // and is global in the machine. This class implements time synchronization with |
| // the host machine: |
| // 1. Connects to the host machine using the client socket name (e.g. |
| // vsock://2:10001) to port 10001 of VMADDR_CID_HOST. |
| // 2. After the socket is connected, send the SetPeerIdentity message to let the |
| // tracing service know the identity (machine ID) of this RelayClient. |
| // 3. Then hand over the socket to RelayIPCClient, which is the client |
| // implementation of the RelayPort RPC service. |
| // 4. On any socket error, the RelayClient notifies its user using |
| // OnErrorCallback so the user (class RelayService) may retry the connection. |
| class RelayClient : private base::UnixSocket::EventListener, |
| private RelayIPCClient::EventListener { |
| public: |
| using OnErrorCallback = std::function<void()>; |
| RelayClient(const std::string& client_sock_name, |
| const std::string& machine_id_hint, |
| base::TaskRunner* task_runner, |
| OnErrorCallback on_destroy_callback); |
| ~RelayClient() override; |
| |
| bool ipc_client_connected() const { return phase_ != Phase::CONNECTING; } |
| bool clock_synced_with_service_for_testing() const { |
| return clock_synced_with_service_for_testing_; |
| } |
| |
| private: |
| // UnixSocket::EventListener implementation for connecting to the client |
| // socket. |
| void OnNewIncomingConnection(base::UnixSocket*, |
| std::unique_ptr<base::UnixSocket>) override { |
| // This class doesn't open a socket in listening mode. |
| PERFETTO_DFATAL("Should be unreachable."); |
| } |
| void OnConnect(base::UnixSocket* self, bool connected) override; |
| void OnDisconnect(base::UnixSocket*) override { NotifyError(); } |
| void OnDataAvailable(base::UnixSocket*) override { |
| // Should be handled in the IPC client. |
| PERFETTO_DFATAL("Should be unreachable."); |
| } |
| |
| void NotifyError(); |
| void Connect(); |
| void SendSyncClockRequest(); |
| |
| // RelayIPCClient::EventListener implementation. |
| void OnServiceConnected() override; |
| void OnServiceDisconnected() override; |
| void OnSyncClockResponse(const protos::gen::SyncClockResponse& resp) override; |
| |
| enum class Phase : uint32_t { CONNECTING = 1, PING, UPDATE }; |
| Phase phase_ = Phase::CONNECTING; |
| bool clock_synced_with_service_for_testing_ = false; |
| |
| base::TaskRunner* task_runner_; |
| OnErrorCallback on_error_callback_; |
| |
| std::string client_sock_name_; |
| // A hint to the host traced for inferring the identifier of this machine. |
| std::string machine_id_hint_; |
| std::unique_ptr<base::UnixSocket> client_sock_; |
| std::unique_ptr<RelayIPCClient> relay_ipc_client_; |
| |
| base::WeakPtrFactory<RelayIPCClient::EventListener> |
| weak_factory_for_ipc_client{this}; |
| base::WeakPtrFactory<RelayClient> weak_factory_{this}; |
| }; |
| |
| // A class for relaying the producer data between the local producers and the |
| // remote tracing service. |
| class RelayService : public base::UnixSocket::EventListener { |
| public: |
| explicit RelayService(base::TaskRunner* task_runner); |
| ~RelayService() override = default; |
| |
| // Starts the service relay that forwards messages between the |
| // |server_socket_name| and |client_socket_name| ports. |
| void Start(const char* server_socket_name, const char* client_socket_name); |
| |
| static std::string GetMachineIdHint( |
| bool use_pseudo_boot_id_for_testing = false); |
| |
| void SetRelayClientDisabledForTesting(bool disabled) { |
| relay_client_disabled_for_testing_ = disabled; |
| } |
| void SetMachineIdHintForTesting(std::string machine_id_hint) { |
| machine_id_hint_ = machine_id_hint; |
| } |
| RelayClient* relay_client_for_testing() { return relay_client_.get(); } |
| |
| private: |
| struct PendingConnection { |
| // This keeps a connected UnixSocketRaw server socket in its first element. |
| std::unique_ptr<SocketPair> socket_pair; |
| // This keeps the connecting client connection. |
| std::unique_ptr<base::UnixSocket> connecting_client_conn; |
| }; |
| |
| RelayService(const RelayService&) = delete; |
| RelayService& operator=(const RelayService&) = delete; |
| |
| // UnixSocket::EventListener implementation. |
| void OnNewIncomingConnection(base::UnixSocket*, |
| std::unique_ptr<base::UnixSocket>) override; |
| void OnConnect(base::UnixSocket* self, bool connected) override; |
| void OnDisconnect(base::UnixSocket* self) override; |
| void OnDataAvailable(base::UnixSocket* self) override; |
| |
| void ReconnectRelayClient(); |
| void ConnectRelayClient(); |
| |
| base::TaskRunner* const task_runner_ = nullptr; |
| |
| // A hint to the host traced for inferring the identifier of this machine. |
| std::string machine_id_hint_; |
| |
| std::unique_ptr<base::UnixSocket> listening_socket_; |
| std::string client_socket_name_; |
| |
| // Keeps the socket pairs while waiting for relay connections to be |
| // established. |
| std::vector<PendingConnection> pending_connections_; |
| |
| SocketRelayHandler socket_relay_handler_; |
| |
| std::unique_ptr<RelayClient> relay_client_; |
| // On RelayClient connection error, how long should we wait before retrying. |
| static constexpr uint32_t kDefaultRelayClientRetryDelayMs = 1000; |
| uint32_t relay_client_retry_delay_ms_ = kDefaultRelayClientRetryDelayMs; |
| bool relay_client_disabled_for_testing_ = false; |
| }; |
| |
| } // namespace perfetto |
| |
| #endif // SRC_TRACED_RELAY_RELAY_SERVICE_H_ |