You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
291 lines
8.0 KiB
291 lines
8.0 KiB
#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
|