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