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