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