• 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   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    */
GetChannel()126   ClientChannel* GetChannel() const { return channel_.get(); }
TakeChannel()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>
CheckDisconnect(const Status<T> & status)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  */
160 template <typename T, typename ParentClient = Client>
161 class 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>
Create(Args &&...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 
206 class Transaction final : public OutputResourceMapper,
207                           public InputResourceMapper {
208  public:
209   explicit Transaction(Client& client);
210   ~Transaction();
211 
212   template <typename T>
Send(int opcode)213   Status<T> Send(int opcode) {
214     return SendVector<T>(opcode, nullptr, 0, nullptr, 0);
215   }
216 
217   template <typename T>
Send(int opcode,const void * send_buffer,size_t send_length,void * receive_buffer,size_t receive_length)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>
SendVector(int opcode,const iovec * send_vector,size_t send_count,const iovec * receive_vector,size_t receive_count)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>
SendVector(int opcode,const iovec (& send_vector)[send_count],const iovec (& receive_vector)[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>
SendVector(int opcode,const iovec (& send_vector)[send_count],std::nullptr_t)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>
SendVector(int opcode,std::nullptr_t,const iovec (& receive_vector)[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>
CheckDisconnect(const Status<T> & status)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