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