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 
GetChannelHandle() const122 const LocalChannelHandle& Client::GetChannelHandle() const {
123   return channel_->GetChannelHandle();
124 }
125 
126 ///////////////////////////// Transaction implementation //////////////////////
127 
Transaction(Client & client)128 Transaction::Transaction(Client& client) : client_{client} {}
129 
~Transaction()130 Transaction::~Transaction() {
131   if (state_allocated_ && client_.GetChannel())
132     client_.GetChannel()->FreeTransactionState(state_);
133 }
134 
EnsureStateAllocated()135 bool Transaction::EnsureStateAllocated() {
136   if (!state_allocated_ && client_.GetChannel()) {
137     state_ = client_.GetChannel()->AllocateTransactionState();
138     state_allocated_ = true;
139   }
140   return state_allocated_;
141 }
142 
SendTransaction(int opcode,Status<void> * ret,const iovec * send_vector,size_t send_count,const iovec * receive_vector,size_t receive_count)143 void 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 
SendTransaction(int opcode,Status<int> * ret,const iovec * send_vector,size_t send_count,const iovec * receive_vector,size_t receive_count)167 void 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 
SendTransaction(int opcode,Status<LocalHandle> * ret,const iovec * send_vector,size_t send_count,const iovec * receive_vector,size_t receive_count)188 void 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 
SendTransaction(int opcode,Status<LocalChannelHandle> * ret,const iovec * send_vector,size_t send_count,const iovec * receive_vector,size_t receive_count)209 void 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 
PushFileHandle(const LocalHandle & handle)230 Status<FileReference> Transaction::PushFileHandle(const LocalHandle& handle) {
231   if (client_.CheckReconnect() && EnsureStateAllocated())
232     return client_.GetChannel()->PushFileHandle(state_, handle);
233   return ErrorStatus{ESHUTDOWN};
234 }
235 
PushFileHandle(const BorrowedHandle & handle)236 Status<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 
PushFileHandle(const RemoteHandle & handle)243 Status<FileReference> Transaction::PushFileHandle(const RemoteHandle& handle) {
244   return handle.Get();
245 }
246 
PushChannelHandle(const LocalChannelHandle & handle)247 Status<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 
PushChannelHandle(const BorrowedChannelHandle & handle)254 Status<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 
PushChannelHandle(const RemoteChannelHandle & handle)261 Status<ChannelReference> Transaction::PushChannelHandle(
262     const RemoteChannelHandle& handle) {
263   return handle.value();
264 }
265 
GetFileHandle(FileReference ref,LocalHandle * handle)266 bool Transaction::GetFileHandle(FileReference ref, LocalHandle* handle) {
267   return client_.CheckReconnect() && EnsureStateAllocated() &&
268          client_.GetChannel()->GetFileHandle(state_, ref, handle);
269 }
270 
GetChannelHandle(ChannelReference ref,LocalChannelHandle * handle)271 bool Transaction::GetChannelHandle(ChannelReference ref,
272                                    LocalChannelHandle* handle) {
273   return client_.CheckReconnect() && EnsureStateAllocated() &&
274          client_.GetChannel()->GetChannelHandle(state_, ref, handle);
275 }
276 
CheckDisconnect(int error)277 void 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