1#ifndef ANDROID_PDX_CLIENT_H_
2#define ANDROID_PDX_CLIENT_H_
3
4#include <errno.h>
5#include <sys/types.h>
6
7#include <memory>
8#include <string>
9#include <type_traits>
10
11#include <pdx/channel_handle.h>
12#include <pdx/client_channel.h>
13#include <pdx/client_channel_factory.h>
14#include <pdx/file_handle.h>
15#include <pdx/message_reader.h>
16#include <pdx/message_writer.h>
17#include <pdx/rpc/remote_method_type.h>
18#include <pdx/status.h>
19
20namespace android {
21namespace pdx {
22
23class Transaction;
24
25/*
26 * Base class of client-side service API classes.
27 */
28class Client {
29 public:
30  static const int64_t kInfiniteTimeout = -1;
31
32  virtual ~Client() = default;
33
34  /*
35   * Returns true if the Client instance successfully initialized, false
36   * otherwise. Subclasses that can fail to initialize must override this and
37   * AND their initialization result with this base class method's result.
38   *
39   * This method is not intended to perform initialization, only to report
40   * the status of the initialization.
41   */
42  virtual bool IsInitialized() const;
43
44  /*
45   * Returns the error code describing the Client initialization failure, or 0
46   * if there was no failure.
47   */
48  int error() const;
49
50  // Returns a reference to IPC channel handle.
51  LocalChannelHandle& GetChannelHandle();
52  const LocalChannelHandle& GetChannelHandle() const;
53
54 protected:
55  friend Transaction;
56  explicit Client(std::unique_ptr<ClientChannel> channel);
57  explicit Client(std::unique_ptr<ClientChannelFactory> channel_factory,
58                  int64_t timeout_ms = kInfiniteTimeout);
59
60  /*
61   * Called by Client::Connect() after successfully connecting to the service
62   * endpoint. Subclasses may override this method to perform additional setup,
63   * including sending messages to complete the connection process.
64   *
65   * Subclasses may call Client::Close() within this method to terminate the
66   * connection; Client::Connect() returns the negated error passed to
67   * Client::Close() when this happens.
68   */
69  virtual void OnConnect();
70
71  enum : size_t { MAX_IMPULSE_LENGTH = sizeof(uint64_t) * 4 };
72
73  Status<void> SendImpulse(int opcode);
74  Status<void> SendImpulse(int opcode, const void* buffer, size_t length);
75
76  /*
77   * Remote method call API using pdx::rpc serialization.
78   * Include pdx/rpc/remote_method.h to use these methods.
79   */
80  template <typename RemoteMethodType, typename... Args>
81  Status<typename RemoteMethodType::Return> InvokeRemoteMethod(Args&&... args);
82
83  template <typename RemoteMethodType, typename ReturnType, typename... Args>
84  Status<void> InvokeRemoteMethodInPlace(ReturnType* return_value,
85                                         Args&&... args);
86
87  /*
88   * Close the endpoint file descriptor and optionally indicate an error, which
89   * may be retrieved through error(). Subclasses may use this in their
90   * constructor to signal failure during initialization or at other times
91   * during operation.
92   */
93  void Close(int error);
94
95  /*
96   * Returns true if the client is connected to the service, false otherwise.
97   */
98  bool IsConnected() const;
99
100  /*
101   * Enables auto-reconnect with the given timeout. Use kInfiniteTimeout (-1)
102   * for no timeout. Auto-reconnect can only be enabled if the Client class
103   * was constructed with a ClientChannelFactory.
104   */
105  void EnableAutoReconnect(int64_t reconnect_timeout_ms);
106
107  /*
108   * Disables auto-reconnect.
109   */
110  void DisableAutoReconnect();
111
112  /*
113   * Returns an fd that the client may use to check/wait for asynchronous
114   * notifications to the channel. It is implementation dependent how the
115   * transport backend handles this feature, however all implementations must
116   * support at least POLLIN/EPOLLIN/readable.
117   *
118   * For uses that require more than one type of event, use
119   * ClientChannel::GetEventMask() to distinguish between events.
120   */
121  int event_fd() const;
122
123  /*
124   * Returns the underlying ClientChannel object.
125   */
126  ClientChannel* GetChannel() const { return channel_.get(); }
127  std::unique_ptr<ClientChannel>&& TakeChannel() { return std::move(channel_); }
128
129 private:
130  Client(const Client&) = delete;
131  void operator=(const Client&) = delete;
132
133  Status<void> CheckReconnect();
134  bool NeedToDisconnectChannel(int error) const;
135  void CheckDisconnect(int error);
136
137  template <typename T>
138  inline void CheckDisconnect(const Status<T>& status) {
139    if (!status)
140      CheckDisconnect(status.error());
141  }
142
143  std::unique_ptr<ClientChannel> channel_;
144  int error_{0};
145
146  // Reconnection state.
147  std::unique_ptr<ClientChannelFactory> channel_factory_;
148  int64_t reconnect_timeout_ms_{0};
149  bool auto_reconnect_enabled_{false};
150};
151
152/*
153 * Utility template base class for client-side service API classes. Handles
154 * initialization checks during allocation and automatically cleans up on
155 * failure.
156 *
157 * @tparam T Type of the class extending this one.
158 * @tparam C Client class to wrap. Defaults to the Client class.
159 */
160template <typename T, typename ParentClient = Client>
161class ClientBase : public ParentClient {
162 public:
163  // Type of the client this class wraps.
164  using ClientType = ParentClient;
165
166  static_assert(std::is_base_of<Client, ParentClient>::value,
167                "The provided parent client is not a Client subclass.");
168
169  /*
170   * Allocates a new instance of the superclass and checks for successful
171   * initialization.
172   *
173   * The variadic arguments must expand to match one of type T's constructors
174   * and are passed through unchanged. If a timeout is desired, subclasses are
175   * responsible for passing this through to the appropriate ClientBase
176   * constructor.
177   *
178   * Returns a unique_ptr to the new instance on success, or an empty unique_ptr
179   * otherwise.
180   */
181  template <typename... Args>
182  static inline std::unique_ptr<T> Create(Args&&... args) {
183    std::unique_ptr<T> client(new T(std::forward<Args>(args)...));
184    if (client->IsInitialized())
185      return client;
186    else
187      return nullptr;
188  }
189
190 protected:
191  /*
192   * Type of the base class. Useful for referencing the base class type and
193   * constructor in subclasses. Subclasses with non-public constructors
194   * must declare BASE a friend.
195   */
196  using BASE = ClientBase<T, ParentClient>;
197
198  /*
199   * Type of the unique_ptr deleter. Useful for friend declarations.
200   */
201  using deleter_type = typename std::unique_ptr<T>::deleter_type;
202
203  using ParentClient::ParentClient;
204};
205
206class Transaction final : public OutputResourceMapper,
207                          public InputResourceMapper {
208 public:
209  Transaction(Client& client);
210  ~Transaction();
211
212  template <typename T>
213  Status<T> Send(int opcode) {
214    return SendVector<T>(opcode, nullptr, 0, nullptr, 0);
215  }
216
217  template <typename T>
218  Status<T> Send(int opcode, const void* send_buffer, size_t send_length,
219                 void* receive_buffer, size_t receive_length) {
220    const bool send = (send_buffer && send_length);
221    const bool receive = (receive_buffer && receive_length);
222    const iovec send_vector = {const_cast<void*>(send_buffer), send_length};
223    const iovec receive_vector = {receive_buffer, receive_length};
224    return SendVector<T>(opcode, send ? &send_vector : nullptr, send ? 1 : 0,
225                         receive ? &receive_vector : nullptr, receive ? 1 : 0);
226  }
227
228  template <typename T>
229  Status<T> SendVector(int opcode, const iovec* send_vector, size_t send_count,
230                       const iovec* receive_vector, size_t receive_count) {
231    Status<T> ret;
232    SendTransaction(opcode, &ret, send_vector, send_count, receive_vector,
233                    receive_count);
234    return ret;
235  }
236
237  template <typename T, size_t send_count, size_t receive_count>
238  Status<T> SendVector(int opcode, const iovec (&send_vector)[send_count],
239                       const iovec (&receive_vector)[receive_count]) {
240    return SendVector<T>(opcode, send_vector, send_count, receive_vector,
241                         receive_count);
242  }
243
244  template <typename T, size_t send_count>
245  Status<T> SendVector(int opcode, const iovec (&send_vector)[send_count],
246                       std::nullptr_t) {
247    return SendVector<T>(opcode, send_vector, send_count, nullptr, 0);
248  }
249
250  template <typename T, size_t receive_count>
251  Status<T> SendVector(int opcode, std::nullptr_t,
252                       const iovec (&receive_vector)[receive_count]) {
253    return SendVector<T>(opcode, nullptr, 0, receive_vector, receive_count);
254  }
255
256  // OutputResourceMapper
257  Status<FileReference> PushFileHandle(const LocalHandle& handle) override;
258  Status<FileReference> PushFileHandle(const BorrowedHandle& handle) override;
259  Status<FileReference> PushFileHandle(const RemoteHandle& handle) override;
260  Status<ChannelReference> PushChannelHandle(
261      const LocalChannelHandle& handle) override;
262  Status<ChannelReference> PushChannelHandle(
263      const BorrowedChannelHandle& handle) override;
264  Status<ChannelReference> PushChannelHandle(
265      const RemoteChannelHandle& handle) override;
266
267  // InputResourceMapper
268  bool GetFileHandle(FileReference ref, LocalHandle* handle) override;
269  bool GetChannelHandle(ChannelReference ref,
270                        LocalChannelHandle* handle) override;
271
272 private:
273  bool EnsureStateAllocated();
274  void SendTransaction(int opcode, Status<void>* ret, const iovec* send_vector,
275                       size_t send_count, const iovec* receive_vector,
276                       size_t receive_count);
277  void SendTransaction(int opcode, Status<int>* ret, const iovec* send_vector,
278                       size_t send_count, const iovec* receive_vector,
279                       size_t receive_count);
280  void SendTransaction(int opcode, Status<LocalHandle>* ret,
281                       const iovec* send_vector, size_t send_count,
282                       const iovec* receive_vector, size_t receive_count);
283  void SendTransaction(int opcode, Status<LocalChannelHandle>* ret,
284                       const iovec* send_vector, size_t send_count,
285                       const iovec* receive_vector, size_t receive_count);
286  void CheckDisconnect(int error);
287
288  template <typename T>
289  inline void CheckDisconnect(const Status<T>& status) {
290    if (!status)
291      CheckDisconnect(status.error());
292  }
293
294  Client& client_;
295  void* state_{nullptr};
296  bool state_allocated_{false};
297};
298
299}  // namespace pdx
300}  // namespace android
301
302#endif  // ANDROID_PDX_CLIENT_H_
303