Home | History | Annotate | Download | only in libpdx
      1 #include "pdx/client.h"
      2 
      3 #define LOG_TAG "ServiceFramework"
      4 #include <log/log.h>
      5 
      6 #include <pdx/trace.h>
      7 
      8 namespace android {
      9 namespace pdx {
     10 
     11 void Client::EnableAutoReconnect(int64_t reconnect_timeout_ms) {
     12   if (channel_factory_) {
     13     reconnect_timeout_ms_ = reconnect_timeout_ms;
     14     auto_reconnect_enabled_ = true;
     15   }
     16 }
     17 
     18 void Client::DisableAutoReconnect() { auto_reconnect_enabled_ = false; }
     19 
     20 bool Client::IsConnected() const { return channel_.get() != nullptr; }
     21 
     22 Status<void> Client::CheckReconnect() {
     23   Status<void> ret;
     24   bool was_disconnected = !IsConnected();
     25   if (auto_reconnect_enabled_ && was_disconnected && channel_factory_) {
     26     auto status = channel_factory_->Connect(reconnect_timeout_ms_);
     27     if (!status) {
     28       error_ = -status.error();
     29       ret.SetError(status.error());
     30       return ret;
     31     }
     32     channel_ = status.take();
     33   }
     34 
     35   if (!IsConnected()) {
     36     ret.SetError(ESHUTDOWN);
     37   } else {
     38     // Call the subclass OnConnect handler. The subclass may choose to close the
     39     // connection in the handler, in which case error_ will be non-zero.
     40     if (was_disconnected)
     41       OnConnect();
     42     if (!IsConnected())
     43       ret.SetError(-error_);
     44     else
     45       ret.SetValue();
     46   }
     47 
     48   return ret;
     49 }
     50 
     51 bool Client::NeedToDisconnectChannel(int error) const {
     52   return error == ESHUTDOWN && auto_reconnect_enabled_;
     53 }
     54 
     55 void Client::CheckDisconnect(int error) {
     56   if (NeedToDisconnectChannel(error))
     57     Close(error);
     58 }
     59 
     60 Client::Client(std::unique_ptr<ClientChannel> channel)
     61     : channel_{std::move(channel)} {}
     62 
     63 Client::Client(std::unique_ptr<ClientChannelFactory> channel_factory,
     64                int64_t timeout_ms)
     65     : channel_factory_{std::move(channel_factory)} {
     66   auto status = channel_factory_->Connect(timeout_ms);
     67   if (!status) {
     68     ALOGE("Client::Client: Failed to connect to service because: %s",
     69           status.GetErrorMessage().c_str());
     70     error_ = -status.error();
     71   } else {
     72     channel_ = status.take();
     73   }
     74 }
     75 
     76 bool Client::IsInitialized() const {
     77   return IsConnected() || (channel_factory_ && auto_reconnect_enabled_);
     78 }
     79 
     80 void Client::OnConnect() {}
     81 
     82 int Client::error() const { return error_; }
     83 
     84 Status<void> Client::SendImpulse(int opcode) {
     85   PDX_TRACE_NAME("Client::SendImpulse");
     86 
     87   auto status = CheckReconnect();
     88   if (!status)
     89     return status;
     90 
     91   status = channel_->SendImpulse(opcode, nullptr, 0);
     92   CheckDisconnect(status);
     93   return status;
     94 }
     95 
     96 Status<void> Client::SendImpulse(int opcode, const void* buffer,
     97                                  size_t length) {
     98   PDX_TRACE_NAME("Client::SendImpulse");
     99 
    100   auto status = CheckReconnect();
    101   if (!status)
    102     return status;
    103 
    104   status = channel_->SendImpulse(opcode, buffer, length);
    105   CheckDisconnect(status);
    106   return status;
    107 }
    108 
    109 void Client::Close(int error) {
    110   channel_.reset();
    111   // Normalize error codes to negative integer space.
    112   error_ = error <= 0 ? error : -error;
    113 }
    114 
    115 int Client::event_fd() const {
    116   return IsConnected() ? channel_->event_fd() : -1;
    117 }
    118 
    119 LocalChannelHandle& Client::GetChannelHandle() {
    120   return channel_->GetChannelHandle();
    121 }
    122 
    123 ///////////////////////////// Transaction implementation //////////////////////
    124 
    125 Transaction::Transaction(Client& client) : client_{client} {}
    126 
    127 Transaction::~Transaction() {
    128   if (state_allocated_ && client_.GetChannel())
    129     client_.GetChannel()->FreeTransactionState(state_);
    130 }
    131 
    132 bool Transaction::EnsureStateAllocated() {
    133   if (!state_allocated_ && client_.GetChannel()) {
    134     state_ = client_.GetChannel()->AllocateTransactionState();
    135     state_allocated_ = true;
    136   }
    137   return state_allocated_;
    138 }
    139 
    140 void Transaction::SendTransaction(int opcode, Status<void>* ret,
    141                                   const iovec* send_vector, size_t send_count,
    142                                   const iovec* receive_vector,
    143                                   size_t receive_count) {
    144   *ret = client_.CheckReconnect();
    145   if (!*ret)
    146     return;
    147 
    148   if (!EnsureStateAllocated()) {
    149     ret->SetError(ESHUTDOWN);
    150     return;
    151   }
    152 
    153   auto status = client_.GetChannel()->SendWithInt(
    154       state_, opcode, send_vector, send_count, receive_vector, receive_count);
    155 
    156   if (status) {
    157     ret->SetValue();
    158   } else {
    159     ret->SetError(status.error());
    160   }
    161   CheckDisconnect(status);
    162 }
    163 
    164 void Transaction::SendTransaction(int opcode, Status<int>* ret,
    165                                   const iovec* send_vector, size_t send_count,
    166                                   const iovec* receive_vector,
    167                                   size_t receive_count) {
    168   auto status = client_.CheckReconnect();
    169   if (!status) {
    170     ret->SetError(status.error());
    171     return;
    172   }
    173 
    174   if (!EnsureStateAllocated()) {
    175     ret->SetError(ESHUTDOWN);
    176     return;
    177   }
    178 
    179   *ret = client_.GetChannel()->SendWithInt(
    180       state_, opcode, send_vector, send_count, receive_vector, receive_count);
    181 
    182   CheckDisconnect(*ret);
    183 }
    184 
    185 void Transaction::SendTransaction(int opcode, Status<LocalHandle>* ret,
    186                                   const iovec* send_vector, size_t send_count,
    187                                   const iovec* receive_vector,
    188                                   size_t receive_count) {
    189   auto status = client_.CheckReconnect();
    190   if (!status) {
    191     ret->SetError(status.error());
    192     return;
    193   }
    194 
    195   if (!EnsureStateAllocated()) {
    196     ret->SetError(ESHUTDOWN);
    197     return;
    198   }
    199 
    200   *ret = client_.GetChannel()->SendWithFileHandle(
    201       state_, opcode, send_vector, send_count, receive_vector, receive_count);
    202 
    203   CheckDisconnect(*ret);
    204 }
    205 
    206 void Transaction::SendTransaction(int opcode, Status<LocalChannelHandle>* ret,
    207                                   const iovec* send_vector, size_t send_count,
    208                                   const iovec* receive_vector,
    209                                   size_t receive_count) {
    210   auto status = client_.CheckReconnect();
    211   if (!status) {
    212     ret->SetError(status.error());
    213     return;
    214   }
    215 
    216   if (!EnsureStateAllocated()) {
    217     ret->SetError(ESHUTDOWN);
    218     return;
    219   }
    220 
    221   *ret = client_.GetChannel()->SendWithChannelHandle(
    222       state_, opcode, send_vector, send_count, receive_vector, receive_count);
    223 
    224   CheckDisconnect(*ret);
    225 }
    226 
    227 Status<FileReference> Transaction::PushFileHandle(const LocalHandle& handle) {
    228   if (client_.CheckReconnect() && EnsureStateAllocated())
    229     return client_.GetChannel()->PushFileHandle(state_, handle);
    230   return ErrorStatus{ESHUTDOWN};
    231 }
    232 
    233 Status<FileReference> Transaction::PushFileHandle(
    234     const BorrowedHandle& handle) {
    235   if (client_.CheckReconnect() && EnsureStateAllocated())
    236     return client_.GetChannel()->PushFileHandle(state_, handle);
    237   return ErrorStatus{ESHUTDOWN};
    238 }
    239 
    240 Status<FileReference> Transaction::PushFileHandle(const RemoteHandle& handle) {
    241   return handle.Get();
    242 }
    243 
    244 Status<ChannelReference> Transaction::PushChannelHandle(
    245     const LocalChannelHandle& handle) {
    246   if (client_.CheckReconnect() && EnsureStateAllocated())
    247     return client_.GetChannel()->PushChannelHandle(state_, handle);
    248   return ErrorStatus{ESHUTDOWN};
    249 }
    250 
    251 Status<ChannelReference> Transaction::PushChannelHandle(
    252     const BorrowedChannelHandle& handle) {
    253   if (client_.CheckReconnect() && EnsureStateAllocated())
    254     return client_.GetChannel()->PushChannelHandle(state_, handle);
    255   return ErrorStatus{ESHUTDOWN};
    256 }
    257 
    258 Status<ChannelReference> Transaction::PushChannelHandle(
    259     const RemoteChannelHandle& handle) {
    260   return handle.value();
    261 }
    262 
    263 bool Transaction::GetFileHandle(FileReference ref, LocalHandle* handle) {
    264   return client_.CheckReconnect() && EnsureStateAllocated() &&
    265          client_.GetChannel()->GetFileHandle(state_, ref, handle);
    266 }
    267 
    268 bool Transaction::GetChannelHandle(ChannelReference ref,
    269                                    LocalChannelHandle* handle) {
    270   return client_.CheckReconnect() && EnsureStateAllocated() &&
    271          client_.GetChannel()->GetChannelHandle(state_, ref, handle);
    272 }
    273 
    274 void Transaction::CheckDisconnect(int error) {
    275   if (client_.NeedToDisconnectChannel(error)) {
    276     if (state_allocated_) {
    277       if (client_.GetChannel())
    278         client_.GetChannel()->FreeTransactionState(state_);
    279       state_ = nullptr;
    280       state_allocated_ = false;
    281     }
    282     client_.Close(error);
    283   }
    284 }
    285 
    286 }  // namespace pdx
    287 }  // namespace android
    288