service.cpp revision f0a7bd033941e26e380232a0515e903cf8e678e5
1#define LOG_TAG "ServiceFramework"
2#include "pdx/service.h"
3
4#include <fcntl.h>
5#include <log/log.h>
6#include <utils/misc.h>
7
8#include <algorithm>
9#include <cstdint>
10
11#include <pdx/trace.h>
12
13#define TRACE 0
14
15namespace android {
16namespace pdx {
17
18std::shared_ptr<Channel> Channel::GetFromMessageInfo(const MessageInfo& info) {
19  return info.channel ? info.channel->shared_from_this()
20                      : std::shared_ptr<Channel>();
21}
22
23Message::Message() : replied_(true) {}
24
25Message::Message(const MessageInfo& info)
26    : service_{Service::GetFromMessageInfo(info)},
27      channel_{Channel::GetFromMessageInfo(info)},
28      info_{info},
29      replied_{IsImpulse()} {
30  auto svc = service_.lock();
31  if (svc)
32    state_ = svc->endpoint()->AllocateMessageState();
33}
34
35// C++11 specifies the move semantics for shared_ptr but not weak_ptr. This
36// means we have to manually implement the desired move semantics for Message.
37Message::Message(Message&& other) { *this = std::move(other); }
38
39Message& Message::operator=(Message&& other) {
40  Destroy();
41  auto base = reinterpret_cast<std::uint8_t*>(&info_);
42  std::fill(&base[0], &base[sizeof(info_)], 0);
43  replied_ = true;
44  std::swap(service_, other.service_);
45  std::swap(channel_, other.channel_);
46  std::swap(info_, other.info_);
47  std::swap(state_, other.state_);
48  std::swap(replied_, other.replied_);
49  return *this;
50}
51
52Message::~Message() { Destroy(); }
53
54void Message::Destroy() {
55  auto svc = service_.lock();
56  if (svc) {
57    if (!replied_) {
58      ALOGE(
59          "ERROR: Service \"%s\" failed to reply to message: op=%d pid=%d "
60          "cid=%d\n",
61          svc->name_.c_str(), info_.op, info_.pid, info_.cid);
62      svc->DefaultHandleMessage(*this);
63    }
64    svc->endpoint()->FreeMessageState(state_);
65  }
66  state_ = nullptr;
67  service_.reset();
68  channel_.reset();
69}
70
71const std::uint8_t* Message::ImpulseBegin() const {
72  return reinterpret_cast<const std::uint8_t*>(info_.impulse);
73}
74
75const std::uint8_t* Message::ImpulseEnd() const {
76  return ImpulseBegin() + (IsImpulse() ? GetSendLength() : 0);
77}
78
79Status<size_t> Message::ReadVector(const struct iovec* vector,
80                                   size_t vector_length) {
81  PDX_TRACE_NAME("Message::ReadVector");
82  if (auto svc = service_.lock()) {
83    return svc->endpoint()->ReadMessageData(this, vector, vector_length);
84  } else {
85    return ErrorStatus{ESHUTDOWN};
86  }
87}
88
89Status<void> Message::ReadVectorAll(const struct iovec* vector,
90                                    size_t vector_length) {
91  PDX_TRACE_NAME("Message::ReadVectorAll");
92  if (auto svc = service_.lock()) {
93    const auto status =
94        svc->endpoint()->ReadMessageData(this, vector, vector_length);
95    if (!status)
96      return status.error_status();
97    size_t size_to_read = 0;
98    for (size_t i = 0; i < vector_length; i++)
99      size_to_read += vector[i].iov_len;
100    if (status.get() < size_to_read)
101      return ErrorStatus{EIO};
102    return {};
103  } else {
104    return ErrorStatus{ESHUTDOWN};
105  }
106}
107
108Status<size_t> Message::Read(void* buffer, size_t length) {
109  PDX_TRACE_NAME("Message::Read");
110  if (auto svc = service_.lock()) {
111    const struct iovec vector = {buffer, length};
112    return svc->endpoint()->ReadMessageData(this, &vector, 1);
113  } else {
114    return ErrorStatus{ESHUTDOWN};
115  }
116}
117
118Status<size_t> Message::WriteVector(const struct iovec* vector,
119                                    size_t vector_length) {
120  PDX_TRACE_NAME("Message::WriteVector");
121  if (auto svc = service_.lock()) {
122    return svc->endpoint()->WriteMessageData(this, vector, vector_length);
123  } else {
124    return ErrorStatus{ESHUTDOWN};
125  }
126}
127
128Status<void> Message::WriteVectorAll(const struct iovec* vector,
129                                     size_t vector_length) {
130  PDX_TRACE_NAME("Message::WriteVector");
131  if (auto svc = service_.lock()) {
132    const auto status =
133        svc->endpoint()->WriteMessageData(this, vector, vector_length);
134    if (!status)
135      return status.error_status();
136    size_t size_to_write = 0;
137    for (size_t i = 0; i < vector_length; i++)
138      size_to_write += vector[i].iov_len;
139    if (status.get() < size_to_write)
140      return ErrorStatus{EIO};
141    return {};
142  } else {
143    return ErrorStatus{ESHUTDOWN};
144  }
145}
146
147Status<size_t> Message::Write(const void* buffer, size_t length) {
148  PDX_TRACE_NAME("Message::Write");
149  if (auto svc = service_.lock()) {
150    const struct iovec vector = {const_cast<void*>(buffer), length};
151    return svc->endpoint()->WriteMessageData(this, &vector, 1);
152  } else {
153    return ErrorStatus{ESHUTDOWN};
154  }
155}
156
157Status<FileReference> Message::PushFileHandle(const LocalHandle& handle) {
158  PDX_TRACE_NAME("Message::PushFileHandle");
159  if (auto svc = service_.lock()) {
160    return svc->endpoint()->PushFileHandle(this, handle);
161  } else {
162    return ErrorStatus{ESHUTDOWN};
163  }
164}
165
166Status<FileReference> Message::PushFileHandle(const BorrowedHandle& handle) {
167  PDX_TRACE_NAME("Message::PushFileHandle");
168  if (auto svc = service_.lock()) {
169    return svc->endpoint()->PushFileHandle(this, handle);
170  } else {
171    return ErrorStatus{ESHUTDOWN};
172  }
173}
174
175Status<FileReference> Message::PushFileHandle(const RemoteHandle& handle) {
176  PDX_TRACE_NAME("Message::PushFileHandle");
177  if (auto svc = service_.lock()) {
178    return svc->endpoint()->PushFileHandle(this, handle);
179  } else {
180    return ErrorStatus{ESHUTDOWN};
181  }
182}
183
184Status<ChannelReference> Message::PushChannelHandle(
185    const LocalChannelHandle& handle) {
186  PDX_TRACE_NAME("Message::PushChannelHandle");
187  if (auto svc = service_.lock()) {
188    return svc->endpoint()->PushChannelHandle(this, handle);
189  } else {
190    return ErrorStatus{ESHUTDOWN};
191  }
192}
193
194Status<ChannelReference> Message::PushChannelHandle(
195    const BorrowedChannelHandle& handle) {
196  PDX_TRACE_NAME("Message::PushChannelHandle");
197  if (auto svc = service_.lock()) {
198    return svc->endpoint()->PushChannelHandle(this, handle);
199  } else {
200    return ErrorStatus{ESHUTDOWN};
201  }
202}
203
204Status<ChannelReference> Message::PushChannelHandle(
205    const RemoteChannelHandle& handle) {
206  PDX_TRACE_NAME("Message::PushChannelHandle");
207  if (auto svc = service_.lock()) {
208    return svc->endpoint()->PushChannelHandle(this, handle);
209  } else {
210    return ErrorStatus{ESHUTDOWN};
211  }
212}
213
214bool Message::GetFileHandle(FileReference ref, LocalHandle* handle) {
215  PDX_TRACE_NAME("Message::GetFileHandle");
216  auto svc = service_.lock();
217  if (!svc)
218    return false;
219
220  if (ref >= 0) {
221    *handle = svc->endpoint()->GetFileHandle(this, ref);
222    if (!handle->IsValid())
223      return false;
224  } else {
225    *handle = LocalHandle{ref};
226  }
227  return true;
228}
229
230bool Message::GetChannelHandle(ChannelReference ref,
231                               LocalChannelHandle* handle) {
232  PDX_TRACE_NAME("Message::GetChannelHandle");
233  auto svc = service_.lock();
234  if (!svc)
235    return false;
236
237  if (ref >= 0) {
238    *handle = svc->endpoint()->GetChannelHandle(this, ref);
239    if (!handle->valid())
240      return false;
241  } else {
242    *handle = LocalChannelHandle{nullptr, ref};
243  }
244  return true;
245}
246
247Status<void> Message::Reply(int return_code) {
248  PDX_TRACE_NAME("Message::Reply");
249  auto svc = service_.lock();
250  if (!replied_ && svc) {
251    const auto ret = svc->endpoint()->MessageReply(this, return_code);
252    replied_ = ret.ok();
253    return ret;
254  } else {
255    return ErrorStatus{EINVAL};
256  }
257}
258
259Status<void> Message::ReplyFileDescriptor(unsigned int fd) {
260  PDX_TRACE_NAME("Message::ReplyFileDescriptor");
261  auto svc = service_.lock();
262  if (!replied_ && svc) {
263    const auto ret = svc->endpoint()->MessageReplyFd(this, fd);
264    replied_ = ret.ok();
265    return ret;
266  } else {
267    return ErrorStatus{EINVAL};
268  }
269}
270
271Status<void> Message::ReplyError(unsigned int error) {
272  PDX_TRACE_NAME("Message::ReplyError");
273  auto svc = service_.lock();
274  if (!replied_ && svc) {
275    const auto ret =
276        svc->endpoint()->MessageReply(this, -static_cast<int>(error));
277    replied_ = ret.ok();
278    return ret;
279  } else {
280    return ErrorStatus{EINVAL};
281  }
282}
283
284Status<void> Message::Reply(const LocalHandle& handle) {
285  PDX_TRACE_NAME("Message::ReplyFileHandle");
286  auto svc = service_.lock();
287  if (!replied_ && svc) {
288    Status<void> ret;
289
290    if (handle)
291      ret = svc->endpoint()->MessageReplyFd(this, handle.Get());
292    else
293      ret = svc->endpoint()->MessageReply(this, handle.Get());
294
295    replied_ = ret.ok();
296    return ret;
297  } else {
298    return ErrorStatus{EINVAL};
299  }
300}
301
302Status<void> Message::Reply(const BorrowedHandle& handle) {
303  PDX_TRACE_NAME("Message::ReplyFileHandle");
304  auto svc = service_.lock();
305  if (!replied_ && svc) {
306    Status<void> ret;
307
308    if (handle)
309      ret = svc->endpoint()->MessageReplyFd(this, handle.Get());
310    else
311      ret = svc->endpoint()->MessageReply(this, handle.Get());
312
313    replied_ = ret.ok();
314    return ret;
315  } else {
316    return ErrorStatus{EINVAL};
317  }
318}
319
320Status<void> Message::Reply(const RemoteHandle& handle) {
321  PDX_TRACE_NAME("Message::ReplyFileHandle");
322  auto svc = service_.lock();
323  if (!replied_ && svc) {
324    Status<void> ret;
325
326    if (handle)
327      ret = svc->endpoint()->MessageReply(this, handle.Get());
328    else
329      ret = svc->endpoint()->MessageReply(this, handle.Get());
330
331    replied_ = ret.ok();
332    return ret;
333  } else {
334    return ErrorStatus{EINVAL};
335  }
336}
337
338Status<void> Message::Reply(const LocalChannelHandle& handle) {
339  auto svc = service_.lock();
340  if (!replied_ && svc) {
341    const auto ret = svc->endpoint()->MessageReplyChannelHandle(this, handle);
342    replied_ = ret.ok();
343    return ret;
344  } else {
345    return ErrorStatus{EINVAL};
346  }
347}
348
349Status<void> Message::Reply(const BorrowedChannelHandle& handle) {
350  auto svc = service_.lock();
351  if (!replied_ && svc) {
352    const auto ret = svc->endpoint()->MessageReplyChannelHandle(this, handle);
353    replied_ = ret.ok();
354    return ret;
355  } else {
356    return ErrorStatus{EINVAL};
357  }
358}
359
360Status<void> Message::Reply(const RemoteChannelHandle& handle) {
361  auto svc = service_.lock();
362  if (!replied_ && svc) {
363    const auto ret = svc->endpoint()->MessageReplyChannelHandle(this, handle);
364    replied_ = ret.ok();
365    return ret;
366  } else {
367    return ErrorStatus{EINVAL};
368  }
369}
370
371Status<void> Message::ModifyChannelEvents(int clear_mask, int set_mask) {
372  PDX_TRACE_NAME("Message::ModifyChannelEvents");
373  if (auto svc = service_.lock()) {
374    return svc->endpoint()->ModifyChannelEvents(info_.cid, clear_mask,
375                                                set_mask);
376  } else {
377    return ErrorStatus{ESHUTDOWN};
378  }
379}
380
381Status<RemoteChannelHandle> Message::PushChannel(
382    int flags, const std::shared_ptr<Channel>& channel, int* channel_id) {
383  PDX_TRACE_NAME("Message::PushChannel");
384  if (auto svc = service_.lock()) {
385    return svc->PushChannel(this, flags, channel, channel_id);
386  } else {
387    return ErrorStatus(ESHUTDOWN);
388  }
389}
390
391Status<RemoteChannelHandle> Message::PushChannel(
392    Service* service, int flags, const std::shared_ptr<Channel>& channel,
393    int* channel_id) {
394  PDX_TRACE_NAME("Message::PushChannel");
395  return service->PushChannel(this, flags, channel, channel_id);
396}
397
398Status<int> Message::CheckChannel(ChannelReference ref,
399                                  std::shared_ptr<Channel>* channel) const {
400  PDX_TRACE_NAME("Message::CheckChannel");
401  if (auto svc = service_.lock()) {
402    return svc->CheckChannel(this, ref, channel);
403  } else {
404    return ErrorStatus(ESHUTDOWN);
405  }
406}
407
408Status<int> Message::CheckChannel(const Service* service, ChannelReference ref,
409                                  std::shared_ptr<Channel>* channel) const {
410  PDX_TRACE_NAME("Message::CheckChannel");
411  return service->CheckChannel(this, ref, channel);
412}
413
414pid_t Message::GetProcessId() const { return info_.pid; }
415
416pid_t Message::GetThreadId() const { return info_.tid; }
417
418uid_t Message::GetEffectiveUserId() const { return info_.euid; }
419
420gid_t Message::GetEffectiveGroupId() const { return info_.egid; }
421
422int Message::GetChannelId() const { return info_.cid; }
423
424int Message::GetMessageId() const { return info_.mid; }
425
426int Message::GetOp() const { return info_.op; }
427
428int Message::GetFlags() const { return info_.flags; }
429
430size_t Message::GetSendLength() const { return info_.send_len; }
431
432size_t Message::GetReceiveLength() const { return info_.recv_len; }
433
434size_t Message::GetFileDescriptorCount() const { return info_.fd_count; }
435
436std::shared_ptr<Channel> Message::GetChannel() const { return channel_.lock(); }
437
438Status<void> Message::SetChannel(const std::shared_ptr<Channel>& chan) {
439  channel_ = chan;
440  Status<void> status;
441  if (auto svc = service_.lock())
442    status = svc->SetChannel(info_.cid, chan);
443  return status;
444}
445
446std::shared_ptr<Service> Message::GetService() const { return service_.lock(); }
447
448const MessageInfo& Message::GetInfo() const { return info_; }
449
450Service::Service(const std::string& name, std::unique_ptr<Endpoint> endpoint)
451    : name_(name), endpoint_{std::move(endpoint)} {
452  if (!endpoint_)
453    return;
454
455  const auto status = endpoint_->SetService(this);
456  ALOGE_IF(!status, "Failed to set service context because: %s",
457           status.GetErrorMessage().c_str());
458}
459
460Service::~Service() {
461  if (endpoint_) {
462    const auto status = endpoint_->SetService(nullptr);
463    ALOGE_IF(!status, "Failed to clear service context because: %s",
464             status.GetErrorMessage().c_str());
465  }
466}
467
468std::shared_ptr<Service> Service::GetFromMessageInfo(const MessageInfo& info) {
469  return info.service ? info.service->shared_from_this()
470                      : std::shared_ptr<Service>();
471}
472
473bool Service::IsInitialized() const { return endpoint_.get() != nullptr; }
474
475std::shared_ptr<Channel> Service::OnChannelOpen(Message& /*message*/) {
476  return nullptr;
477}
478
479void Service::OnChannelClose(Message& /*message*/,
480                             const std::shared_ptr<Channel>& /*channel*/) {}
481
482Status<void> Service::SetChannel(int channel_id,
483                                 const std::shared_ptr<Channel>& channel) {
484  PDX_TRACE_NAME("Service::SetChannel");
485  std::lock_guard<std::mutex> autolock(channels_mutex_);
486
487  const auto status = endpoint_->SetChannel(channel_id, channel.get());
488  if (!status) {
489    ALOGE("%s::SetChannel: Failed to set channel context: %s\n", name_.c_str(),
490          status.GetErrorMessage().c_str());
491
492    // It's possible someone mucked with things behind our back by calling the C
493    // API directly. Since we know the channel id isn't valid, make sure we
494    // don't have it in the channels map.
495    if (status.error() == ENOENT)
496      channels_.erase(channel_id);
497  } else {
498    if (channel != nullptr)
499      channels_[channel_id] = channel;
500    else
501      channels_.erase(channel_id);
502  }
503  return status;
504}
505
506std::shared_ptr<Channel> Service::GetChannel(int channel_id) const {
507  PDX_TRACE_NAME("Service::GetChannel");
508  std::lock_guard<std::mutex> autolock(channels_mutex_);
509
510  auto search = channels_.find(channel_id);
511  if (search != channels_.end())
512    return search->second;
513  else
514    return nullptr;
515}
516
517Status<void> Service::CloseChannel(int channel_id) {
518  PDX_TRACE_NAME("Service::CloseChannel");
519  std::lock_guard<std::mutex> autolock(channels_mutex_);
520
521  const auto status = endpoint_->CloseChannel(channel_id);
522
523  // Always erase the map entry, in case someone mucked with things behind our
524  // back using the C API directly.
525  channels_.erase(channel_id);
526
527  return status;
528}
529
530Status<void> Service::ModifyChannelEvents(int channel_id, int clear_mask,
531                                          int set_mask) {
532  PDX_TRACE_NAME("Service::ModifyChannelEvents");
533  return endpoint_->ModifyChannelEvents(channel_id, clear_mask, set_mask);
534}
535
536Status<RemoteChannelHandle> Service::PushChannel(
537    Message* message, int flags, const std::shared_ptr<Channel>& channel,
538    int* channel_id) {
539  PDX_TRACE_NAME("Service::PushChannel");
540
541  std::lock_guard<std::mutex> autolock(channels_mutex_);
542
543  int channel_id_temp = -1;
544  Status<RemoteChannelHandle> ret =
545      endpoint_->PushChannel(message, flags, channel.get(), &channel_id_temp);
546  ALOGE_IF(!ret.ok(), "%s::PushChannel: Failed to push channel: %s",
547           name_.c_str(), strerror(ret.error()));
548
549  if (channel && channel_id_temp != -1)
550    channels_[channel_id_temp] = channel;
551  if (channel_id)
552    *channel_id = channel_id_temp;
553
554  return ret;
555}
556
557Status<int> Service::CheckChannel(const Message* message, ChannelReference ref,
558                                  std::shared_ptr<Channel>* channel) const {
559  PDX_TRACE_NAME("Service::CheckChannel");
560
561  // Synchronization to maintain consistency between the kernel's channel
562  // context pointer and the userspace channels_ map. Other threads may attempt
563  // to modify the map at the same time, which could cause the channel context
564  // pointer returned by the kernel to be invalid.
565  std::lock_guard<std::mutex> autolock(channels_mutex_);
566
567  Channel* channel_context = nullptr;
568  Status<int> ret = endpoint_->CheckChannel(
569      message, ref, channel ? &channel_context : nullptr);
570  if (ret && channel) {
571    if (channel_context)
572      *channel = channel_context->shared_from_this();
573    else
574      *channel = nullptr;
575  }
576
577  return ret;
578}
579
580std::string Service::DumpState(size_t /*max_length*/) { return ""; }
581
582Status<void> Service::HandleMessage(Message& message) {
583  return DefaultHandleMessage(message);
584}
585
586void Service::HandleImpulse(Message& /*impulse*/) {}
587
588Status<void> Service::HandleSystemMessage(Message& message) {
589  const MessageInfo& info = message.GetInfo();
590
591  switch (info.op) {
592    case opcodes::CHANNEL_OPEN: {
593      ALOGD("%s::OnChannelOpen: pid=%d cid=%d\n", name_.c_str(), info.pid,
594            info.cid);
595      message.SetChannel(OnChannelOpen(message));
596      return message.Reply(0);
597    }
598
599    case opcodes::CHANNEL_CLOSE: {
600      ALOGD("%s::OnChannelClose: pid=%d cid=%d\n", name_.c_str(), info.pid,
601            info.cid);
602      OnChannelClose(message, Channel::GetFromMessageInfo(info));
603      message.SetChannel(nullptr);
604      return message.Reply(0);
605    }
606
607    case opcodes::REPORT_SYSPROP_CHANGE:
608      ALOGD("%s:REPORT_SYSPROP_CHANGE: pid=%d cid=%d\n", name_.c_str(),
609            info.pid, info.cid);
610      OnSysPropChange();
611      android::report_sysprop_change();
612      return message.Reply(0);
613
614    case opcodes::DUMP_STATE: {
615      ALOGD("%s:DUMP_STATE: pid=%d cid=%d\n", name_.c_str(), info.pid,
616            info.cid);
617      auto response = DumpState(message.GetReceiveLength());
618      const size_t response_size = response.size() < message.GetReceiveLength()
619                                       ? response.size()
620                                       : message.GetReceiveLength();
621      const Status<size_t> status =
622          message.Write(response.data(), response_size);
623      if (status && status.get() < response_size)
624        return message.ReplyError(EIO);
625      else
626        return message.Reply(status);
627    }
628
629    default:
630      return ErrorStatus{EOPNOTSUPP};
631  }
632}
633
634Status<void> Service::DefaultHandleMessage(Message& message) {
635  const MessageInfo& info = message.GetInfo();
636
637  ALOGD_IF(TRACE, "Service::DefaultHandleMessage: pid=%d cid=%d op=%d\n",
638           info.pid, info.cid, info.op);
639
640  switch (info.op) {
641    case opcodes::CHANNEL_OPEN:
642    case opcodes::CHANNEL_CLOSE:
643    case opcodes::REPORT_SYSPROP_CHANGE:
644    case opcodes::DUMP_STATE:
645      return HandleSystemMessage(message);
646
647    default:
648      return message.ReplyError(EOPNOTSUPP);
649  }
650}
651
652void Service::OnSysPropChange() {}
653
654Status<void> Service::ReceiveAndDispatch() {
655  Message message;
656  const auto status = endpoint_->MessageReceive(&message);
657  if (!status) {
658    ALOGE("Failed to receive message: %s\n", status.GetErrorMessage().c_str());
659    return status;
660  }
661
662  std::shared_ptr<Service> service = message.GetService();
663
664  if (!service) {
665    ALOGE("Service::ReceiveAndDispatch: service context is NULL!!!\n");
666    // Don't block the sender indefinitely in this error case.
667    endpoint_->MessageReply(&message, -EINVAL);
668    return ErrorStatus{EINVAL};
669  }
670
671  if (message.IsImpulse()) {
672    service->HandleImpulse(message);
673    return {};
674  } else if (service->HandleSystemMessage(message)) {
675    return {};
676  } else {
677    return service->HandleMessage(message);
678  }
679}
680
681Status<void> Service::Cancel() { return endpoint_->Cancel(); }
682
683}  // namespace pdx
684}  // namespace android
685