blob: bfa2d879b505101cbe1d6e23a23146fcde98e470 [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>
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08007
8namespace android {
9namespace pdx {
10
11void 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
18void Client::DisableAutoReconnect() { auto_reconnect_enabled_ = false; }
19
20bool Client::IsConnected() const { return channel_.get() != nullptr; }
21
22Status<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
51bool Client::NeedToDisconnectChannel(int error) const {
52 return error == ESHUTDOWN && auto_reconnect_enabled_;
53}
54
55void Client::CheckDisconnect(int error) {
56 if (NeedToDisconnectChannel(error))
57 Close(error);
58}
59
60Client::Client(std::unique_ptr<ClientChannel> channel)
61 : channel_{std::move(channel)} {}
62
63Client::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
76bool Client::IsInitialized() const {
77 return IsConnected() || (channel_factory_ && auto_reconnect_enabled_);
78}
79
80void Client::OnConnect() {}
81
82int Client::error() const { return error_; }
83
84Status<void> Client::SendImpulse(int opcode) {
85 PDX_TRACE_NAME("Client::SendImpulse");
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080086
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
96Status<void> Client::SendImpulse(int opcode, const void* buffer,
97 size_t length) {
98 PDX_TRACE_NAME("Client::SendImpulse");
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080099
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
109void Client::Close(int error) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800110 channel_.reset();
111 // Normalize error codes to negative integer space.
112 error_ = error <= 0 ? error : -error;
113}
114
115int Client::event_fd() const {
116 return IsConnected() ? channel_->event_fd() : -1;
117}
118
119LocalChannelHandle& Client::GetChannelHandle() {
120 return channel_->GetChannelHandle();
121}
122
123///////////////////////////// Transaction implementation //////////////////////
124
125Transaction::Transaction(Client& client) : client_{client} {}
126
127Transaction::~Transaction() {
128 if (state_allocated_ && client_.GetChannel())
129 client_.GetChannel()->FreeTransactionState(state_);
130}
131
132bool Transaction::EnsureStateAllocated() {
133 if (!state_allocated_ && client_.GetChannel()) {
134 state_ = client_.GetChannel()->AllocateTransactionState();
135 state_allocated_ = true;
136 }
137 return state_allocated_;
138}
139
140void 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
164void 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
185void 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
206void 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
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700227Status<FileReference> Transaction::PushFileHandle(const LocalHandle& handle) {
228 if (client_.CheckReconnect() && EnsureStateAllocated())
229 return client_.GetChannel()->PushFileHandle(state_, handle);
230 return ErrorStatus{ESHUTDOWN};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800231}
232
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700233Status<FileReference> Transaction::PushFileHandle(
234 const BorrowedHandle& handle) {
235 if (client_.CheckReconnect() && EnsureStateAllocated())
236 return client_.GetChannel()->PushFileHandle(state_, handle);
237 return ErrorStatus{ESHUTDOWN};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800238}
239
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700240Status<FileReference> Transaction::PushFileHandle(const RemoteHandle& handle) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800241 return handle.Get();
242}
243
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700244Status<ChannelReference> Transaction::PushChannelHandle(
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800245 const LocalChannelHandle& handle) {
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700246 if (client_.CheckReconnect() && EnsureStateAllocated())
247 return client_.GetChannel()->PushChannelHandle(state_, handle);
248 return ErrorStatus{ESHUTDOWN};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800249}
250
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700251Status<ChannelReference> Transaction::PushChannelHandle(
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800252 const BorrowedChannelHandle& handle) {
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700253 if (client_.CheckReconnect() && EnsureStateAllocated())
254 return client_.GetChannel()->PushChannelHandle(state_, handle);
255 return ErrorStatus{ESHUTDOWN};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800256}
257
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700258Status<ChannelReference> Transaction::PushChannelHandle(
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800259 const RemoteChannelHandle& handle) {
260 return handle.value();
261}
262
263bool Transaction::GetFileHandle(FileReference ref, LocalHandle* handle) {
264 return client_.CheckReconnect() && EnsureStateAllocated() &&
265 client_.GetChannel()->GetFileHandle(state_, ref, handle);
266}
267
268bool Transaction::GetChannelHandle(ChannelReference ref,
269 LocalChannelHandle* handle) {
270 return client_.CheckReconnect() && EnsureStateAllocated() &&
271 client_.GetChannel()->GetChannelHandle(state_, ref, handle);
272}
273
274void 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