Home | History | Annotate | Download | only in pdx
      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    */
    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  */
    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>
    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   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