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