| #include "pdx/client.h" | |
| #include <log/log.h> | |
| #include <pdx/trace.h> | |
| namespace android { | |
| namespace pdx { | |
| void Client::EnableAutoReconnect(int64_t reconnect_timeout_ms) { | |
| if (channel_factory_) { | |
| reconnect_timeout_ms_ = reconnect_timeout_ms; | |
| auto_reconnect_enabled_ = true; | |
| } | |
| } | |
| void Client::DisableAutoReconnect() { auto_reconnect_enabled_ = false; } | |
| bool Client::IsConnected() const { return channel_.get() != nullptr; } | |
| Status<void> Client::CheckReconnect() { | |
| Status<void> ret; | |
| bool was_disconnected = !IsConnected(); | |
| if (auto_reconnect_enabled_ && was_disconnected && channel_factory_) { | |
| auto status = channel_factory_->Connect(reconnect_timeout_ms_); | |
| if (!status) { | |
| error_ = -status.error(); | |
| ret.SetError(status.error()); | |
| return ret; | |
| } | |
| channel_ = status.take(); | |
| } | |
| if (!IsConnected()) { | |
| ret.SetError(ESHUTDOWN); | |
| } else { | |
| // Call the subclass OnConnect handler. The subclass may choose to close the | |
| // connection in the handler, in which case error_ will be non-zero. | |
| if (was_disconnected) | |
| OnConnect(); | |
| if (!IsConnected()) | |
| ret.SetError(-error_); | |
| else | |
| ret.SetValue(); | |
| } | |
| return ret; | |
| } | |
| bool Client::NeedToDisconnectChannel(int error) const { | |
| return error == ESHUTDOWN && auto_reconnect_enabled_; | |
| } | |
| void Client::CheckDisconnect(int error) { | |
| if (NeedToDisconnectChannel(error)) | |
| Close(error); | |
| } | |
| Client::Client(std::unique_ptr<ClientChannel> channel) | |
| : channel_{std::move(channel)} {} | |
| Client::Client(std::unique_ptr<ClientChannelFactory> channel_factory, | |
| int64_t timeout_ms) | |
| : channel_factory_{std::move(channel_factory)} { | |
| auto status = channel_factory_->Connect(timeout_ms); | |
| if (!status) { | |
| ALOGE("Client::Client: Failed to connect to service because: %s", | |
| status.GetErrorMessage().c_str()); | |
| error_ = -status.error(); | |
| } else { | |
| channel_ = status.take(); | |
| } | |
| } | |
| bool Client::IsInitialized() const { | |
| return IsConnected() || (channel_factory_ && auto_reconnect_enabled_); | |
| } | |
| void Client::OnConnect() {} | |
| int Client::error() const { return error_; } | |
| Status<void> Client::SendImpulse(int opcode) { | |
| PDX_TRACE_NAME("Client::SendImpulse"); | |
| auto status = CheckReconnect(); | |
| if (!status) | |
| return status; | |
| status = channel_->SendImpulse(opcode, nullptr, 0); | |
| CheckDisconnect(status); | |
| return status; | |
| } | |
| Status<void> Client::SendImpulse(int opcode, const void* buffer, | |
| size_t length) { | |
| PDX_TRACE_NAME("Client::SendImpulse"); | |
| auto status = CheckReconnect(); | |
| if (!status) | |
| return status; | |
| status = channel_->SendImpulse(opcode, buffer, length); | |
| CheckDisconnect(status); | |
| return status; | |
| } | |
| void Client::Close(int error) { | |
| channel_.reset(); | |
| // Normalize error codes to negative integer space. | |
| error_ = error <= 0 ? error : -error; | |
| } | |
| int Client::event_fd() const { | |
| return IsConnected() ? channel_->event_fd() : -1; | |
| } | |
| LocalChannelHandle& Client::GetChannelHandle() { | |
| return channel_->GetChannelHandle(); | |
| } | |
| const LocalChannelHandle& Client::GetChannelHandle() const { | |
| return channel_->GetChannelHandle(); | |
| } | |
| ///////////////////////////// Transaction implementation ////////////////////// | |
| Transaction::Transaction(Client& client) : client_{client} {} | |
| Transaction::~Transaction() { | |
| if (state_allocated_ && client_.GetChannel()) | |
| client_.GetChannel()->FreeTransactionState(state_); | |
| } | |
| bool Transaction::EnsureStateAllocated() { | |
| if (!state_allocated_ && client_.GetChannel()) { | |
| state_ = client_.GetChannel()->AllocateTransactionState(); | |
| state_allocated_ = true; | |
| } | |
| return state_allocated_; | |
| } | |
| void Transaction::SendTransaction(int opcode, Status<void>* ret, | |
| const iovec* send_vector, size_t send_count, | |
| const iovec* receive_vector, | |
| size_t receive_count) { | |
| *ret = client_.CheckReconnect(); | |
| if (!*ret) | |
| return; | |
| if (!EnsureStateAllocated()) { | |
| ret->SetError(ESHUTDOWN); | |
| return; | |
| } | |
| auto status = client_.GetChannel()->SendWithInt( | |
| state_, opcode, send_vector, send_count, receive_vector, receive_count); | |
| if (status) { | |
| ret->SetValue(); | |
| } else { | |
| ret->SetError(status.error()); | |
| } | |
| CheckDisconnect(status); | |
| } | |
| void Transaction::SendTransaction(int opcode, Status<int>* ret, | |
| const iovec* send_vector, size_t send_count, | |
| const iovec* receive_vector, | |
| size_t receive_count) { | |
| auto status = client_.CheckReconnect(); | |
| if (!status) { | |
| ret->SetError(status.error()); | |
| return; | |
| } | |
| if (!EnsureStateAllocated()) { | |
| ret->SetError(ESHUTDOWN); | |
| return; | |
| } | |
| *ret = client_.GetChannel()->SendWithInt( | |
| state_, opcode, send_vector, send_count, receive_vector, receive_count); | |
| CheckDisconnect(*ret); | |
| } | |
| void Transaction::SendTransaction(int opcode, Status<LocalHandle>* ret, | |
| const iovec* send_vector, size_t send_count, | |
| const iovec* receive_vector, | |
| size_t receive_count) { | |
| auto status = client_.CheckReconnect(); | |
| if (!status) { | |
| ret->SetError(status.error()); | |
| return; | |
| } | |
| if (!EnsureStateAllocated()) { | |
| ret->SetError(ESHUTDOWN); | |
| return; | |
| } | |
| *ret = client_.GetChannel()->SendWithFileHandle( | |
| state_, opcode, send_vector, send_count, receive_vector, receive_count); | |
| CheckDisconnect(*ret); | |
| } | |
| void Transaction::SendTransaction(int opcode, Status<LocalChannelHandle>* ret, | |
| const iovec* send_vector, size_t send_count, | |
| const iovec* receive_vector, | |
| size_t receive_count) { | |
| auto status = client_.CheckReconnect(); | |
| if (!status) { | |
| ret->SetError(status.error()); | |
| return; | |
| } | |
| if (!EnsureStateAllocated()) { | |
| ret->SetError(ESHUTDOWN); | |
| return; | |
| } | |
| *ret = client_.GetChannel()->SendWithChannelHandle( | |
| state_, opcode, send_vector, send_count, receive_vector, receive_count); | |
| CheckDisconnect(*ret); | |
| } | |
| Status<FileReference> Transaction::PushFileHandle(const LocalHandle& handle) { | |
| if (client_.CheckReconnect() && EnsureStateAllocated()) | |
| return client_.GetChannel()->PushFileHandle(state_, handle); | |
| return ErrorStatus{ESHUTDOWN}; | |
| } | |
| Status<FileReference> Transaction::PushFileHandle( | |
| const BorrowedHandle& handle) { | |
| if (client_.CheckReconnect() && EnsureStateAllocated()) | |
| return client_.GetChannel()->PushFileHandle(state_, handle); | |
| return ErrorStatus{ESHUTDOWN}; | |
| } | |
| Status<FileReference> Transaction::PushFileHandle(const RemoteHandle& handle) { | |
| return handle.Get(); | |
| } | |
| Status<ChannelReference> Transaction::PushChannelHandle( | |
| const LocalChannelHandle& handle) { | |
| if (client_.CheckReconnect() && EnsureStateAllocated()) | |
| return client_.GetChannel()->PushChannelHandle(state_, handle); | |
| return ErrorStatus{ESHUTDOWN}; | |
| } | |
| Status<ChannelReference> Transaction::PushChannelHandle( | |
| const BorrowedChannelHandle& handle) { | |
| if (client_.CheckReconnect() && EnsureStateAllocated()) | |
| return client_.GetChannel()->PushChannelHandle(state_, handle); | |
| return ErrorStatus{ESHUTDOWN}; | |
| } | |
| Status<ChannelReference> Transaction::PushChannelHandle( | |
| const RemoteChannelHandle& handle) { | |
| return handle.value(); | |
| } | |
| bool Transaction::GetFileHandle(FileReference ref, LocalHandle* handle) { | |
| return client_.CheckReconnect() && EnsureStateAllocated() && | |
| client_.GetChannel()->GetFileHandle(state_, ref, handle); | |
| } | |
| bool Transaction::GetChannelHandle(ChannelReference ref, | |
| LocalChannelHandle* handle) { | |
| return client_.CheckReconnect() && EnsureStateAllocated() && | |
| client_.GetChannel()->GetChannelHandle(state_, ref, handle); | |
| } | |
| void Transaction::CheckDisconnect(int error) { | |
| if (client_.NeedToDisconnectChannel(error)) { | |
| if (state_allocated_) { | |
| if (client_.GetChannel()) | |
| client_.GetChannel()->FreeTransactionState(state_); | |
| state_ = nullptr; | |
| state_allocated_ = false; | |
| } | |
| client_.Close(error); | |
| } | |
| } | |
| } // namespace pdx | |
| } // namespace android |