1 #include "pdx/client.h"
2
3 #include <log/log.h>
4
5 #include <pdx/trace.h>
6
7 namespace android {
8 namespace pdx {
9
EnableAutoReconnect(int64_t reconnect_timeout_ms)10 void 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
DisableAutoReconnect()17 void Client::DisableAutoReconnect() { auto_reconnect_enabled_ = false; }
18
IsConnected() const19 bool Client::IsConnected() const { return channel_.get() != nullptr; }
20
CheckReconnect()21 Status<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
NeedToDisconnectChannel(int error) const50 bool Client::NeedToDisconnectChannel(int error) const {
51 return error == ESHUTDOWN && auto_reconnect_enabled_;
52 }
53
CheckDisconnect(int error)54 void Client::CheckDisconnect(int error) {
55 if (NeedToDisconnectChannel(error))
56 Close(error);
57 }
58
Client(std::unique_ptr<ClientChannel> channel)59 Client::Client(std::unique_ptr<ClientChannel> channel)
60 : channel_{std::move(channel)} {}
61
Client(std::unique_ptr<ClientChannelFactory> channel_factory,int64_t timeout_ms)62 Client::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
IsInitialized() const75 bool Client::IsInitialized() const {
76 return IsConnected() || (channel_factory_ && auto_reconnect_enabled_);
77 }
78
OnConnect()79 void Client::OnConnect() {}
80
error() const81 int Client::error() const { return error_; }
82
SendImpulse(int opcode)83 Status<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
SendImpulse(int opcode,const void * buffer,size_t length)95 Status<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
Close(int error)108 void Client::Close(int error) {
109 channel_.reset();
110 // Normalize error codes to negative integer space.
111 error_ = error <= 0 ? error : -error;
112 }
113
event_fd() const114 int Client::event_fd() const {
115 return IsConnected() ? channel_->event_fd() : -1;
116 }
117
GetChannelHandle()118 LocalChannelHandle& Client::GetChannelHandle() {
119 return channel_->GetChannelHandle();
120 }
121
122 ///////////////////////////// Transaction implementation //////////////////////
123
Transaction(Client & client)124 Transaction::Transaction(Client& client) : client_{client} {}
125
~Transaction()126 Transaction::~Transaction() {
127 if (state_allocated_ && client_.GetChannel())
128 client_.GetChannel()->FreeTransactionState(state_);
129 }
130
EnsureStateAllocated()131 bool Transaction::EnsureStateAllocated() {
132 if (!state_allocated_ && client_.GetChannel()) {
133 state_ = client_.GetChannel()->AllocateTransactionState();
134 state_allocated_ = true;
135 }
136 return state_allocated_;
137 }
138
SendTransaction(int opcode,Status<void> * ret,const iovec * send_vector,size_t send_count,const iovec * receive_vector,size_t receive_count)139 void Transaction::SendTransaction(int opcode, Status<void>* ret,
140 const iovec* send_vector, size_t send_count,
141 const iovec* receive_vector,
142 size_t receive_count) {
143 *ret = client_.CheckReconnect();
144 if (!*ret)
145 return;
146
147 if (!EnsureStateAllocated()) {
148 ret->SetError(ESHUTDOWN);
149 return;
150 }
151
152 auto status = client_.GetChannel()->SendWithInt(
153 state_, opcode, send_vector, send_count, receive_vector, receive_count);
154
155 if (status) {
156 ret->SetValue();
157 } else {
158 ret->SetError(status.error());
159 }
160 CheckDisconnect(status);
161 }
162
SendTransaction(int opcode,Status<int> * ret,const iovec * send_vector,size_t send_count,const iovec * receive_vector,size_t receive_count)163 void Transaction::SendTransaction(int opcode, Status<int>* ret,
164 const iovec* send_vector, size_t send_count,
165 const iovec* receive_vector,
166 size_t receive_count) {
167 auto status = client_.CheckReconnect();
168 if (!status) {
169 ret->SetError(status.error());
170 return;
171 }
172
173 if (!EnsureStateAllocated()) {
174 ret->SetError(ESHUTDOWN);
175 return;
176 }
177
178 *ret = client_.GetChannel()->SendWithInt(
179 state_, opcode, send_vector, send_count, receive_vector, receive_count);
180
181 CheckDisconnect(*ret);
182 }
183
SendTransaction(int opcode,Status<LocalHandle> * ret,const iovec * send_vector,size_t send_count,const iovec * receive_vector,size_t receive_count)184 void Transaction::SendTransaction(int opcode, Status<LocalHandle>* ret,
185 const iovec* send_vector, size_t send_count,
186 const iovec* receive_vector,
187 size_t receive_count) {
188 auto status = client_.CheckReconnect();
189 if (!status) {
190 ret->SetError(status.error());
191 return;
192 }
193
194 if (!EnsureStateAllocated()) {
195 ret->SetError(ESHUTDOWN);
196 return;
197 }
198
199 *ret = client_.GetChannel()->SendWithFileHandle(
200 state_, opcode, send_vector, send_count, receive_vector, receive_count);
201
202 CheckDisconnect(*ret);
203 }
204
SendTransaction(int opcode,Status<LocalChannelHandle> * ret,const iovec * send_vector,size_t send_count,const iovec * receive_vector,size_t receive_count)205 void Transaction::SendTransaction(int opcode, Status<LocalChannelHandle>* ret,
206 const iovec* send_vector, size_t send_count,
207 const iovec* receive_vector,
208 size_t receive_count) {
209 auto status = client_.CheckReconnect();
210 if (!status) {
211 ret->SetError(status.error());
212 return;
213 }
214
215 if (!EnsureStateAllocated()) {
216 ret->SetError(ESHUTDOWN);
217 return;
218 }
219
220 *ret = client_.GetChannel()->SendWithChannelHandle(
221 state_, opcode, send_vector, send_count, receive_vector, receive_count);
222
223 CheckDisconnect(*ret);
224 }
225
PushFileHandle(const LocalHandle & handle)226 Status<FileReference> Transaction::PushFileHandle(const LocalHandle& handle) {
227 if (client_.CheckReconnect() && EnsureStateAllocated())
228 return client_.GetChannel()->PushFileHandle(state_, handle);
229 return ErrorStatus{ESHUTDOWN};
230 }
231
PushFileHandle(const BorrowedHandle & handle)232 Status<FileReference> Transaction::PushFileHandle(
233 const BorrowedHandle& handle) {
234 if (client_.CheckReconnect() && EnsureStateAllocated())
235 return client_.GetChannel()->PushFileHandle(state_, handle);
236 return ErrorStatus{ESHUTDOWN};
237 }
238
PushFileHandle(const RemoteHandle & handle)239 Status<FileReference> Transaction::PushFileHandle(const RemoteHandle& handle) {
240 return handle.Get();
241 }
242
PushChannelHandle(const LocalChannelHandle & handle)243 Status<ChannelReference> Transaction::PushChannelHandle(
244 const LocalChannelHandle& handle) {
245 if (client_.CheckReconnect() && EnsureStateAllocated())
246 return client_.GetChannel()->PushChannelHandle(state_, handle);
247 return ErrorStatus{ESHUTDOWN};
248 }
249
PushChannelHandle(const BorrowedChannelHandle & handle)250 Status<ChannelReference> Transaction::PushChannelHandle(
251 const BorrowedChannelHandle& handle) {
252 if (client_.CheckReconnect() && EnsureStateAllocated())
253 return client_.GetChannel()->PushChannelHandle(state_, handle);
254 return ErrorStatus{ESHUTDOWN};
255 }
256
PushChannelHandle(const RemoteChannelHandle & handle)257 Status<ChannelReference> Transaction::PushChannelHandle(
258 const RemoteChannelHandle& handle) {
259 return handle.value();
260 }
261
GetFileHandle(FileReference ref,LocalHandle * handle)262 bool Transaction::GetFileHandle(FileReference ref, LocalHandle* handle) {
263 return client_.CheckReconnect() && EnsureStateAllocated() &&
264 client_.GetChannel()->GetFileHandle(state_, ref, handle);
265 }
266
GetChannelHandle(ChannelReference ref,LocalChannelHandle * handle)267 bool Transaction::GetChannelHandle(ChannelReference ref,
268 LocalChannelHandle* handle) {
269 return client_.CheckReconnect() && EnsureStateAllocated() &&
270 client_.GetChannel()->GetChannelHandle(state_, ref, handle);
271 }
272
CheckDisconnect(int error)273 void Transaction::CheckDisconnect(int error) {
274 if (client_.NeedToDisconnectChannel(error)) {
275 if (state_allocated_) {
276 if (client_.GetChannel())
277 client_.GetChannel()->FreeTransactionState(state_);
278 state_ = nullptr;
279 state_allocated_ = false;
280 }
281 client_.Close(error);
282 }
283 }
284
285 } // namespace pdx
286 } // namespace android
287