|  | #include "pdx/service.h" | 
|  |  | 
|  | #include <fcntl.h> | 
|  | #include <log/log.h> | 
|  | #include <utils/misc.h> | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <cstdint> | 
|  |  | 
|  | #include <pdx/trace.h> | 
|  |  | 
|  | namespace android { | 
|  | namespace pdx { | 
|  |  | 
|  | std::shared_ptr<Channel> Channel::GetFromMessageInfo(const MessageInfo& info) { | 
|  | return info.channel ? info.channel->shared_from_this() | 
|  | : std::shared_ptr<Channel>(); | 
|  | } | 
|  |  | 
|  | Message::Message() : replied_(true) {} | 
|  |  | 
|  | Message::Message(const MessageInfo& info) | 
|  | : service_{Service::GetFromMessageInfo(info)}, | 
|  | channel_{Channel::GetFromMessageInfo(info)}, | 
|  | info_{info}, | 
|  | replied_{IsImpulse()} { | 
|  | auto svc = service_.lock(); | 
|  | if (svc) | 
|  | state_ = svc->endpoint()->AllocateMessageState(); | 
|  | } | 
|  |  | 
|  | // C++11 specifies the move semantics for shared_ptr but not weak_ptr. This | 
|  | // means we have to manually implement the desired move semantics for Message. | 
|  | Message::Message(Message&& other) { *this = std::move(other); } | 
|  |  | 
|  | Message& Message::operator=(Message&& other) { | 
|  | Destroy(); | 
|  | auto base = reinterpret_cast<std::uint8_t*>(&info_); | 
|  | std::fill(&base[0], &base[sizeof(info_)], 0); | 
|  | replied_ = true; | 
|  | std::swap(service_, other.service_); | 
|  | std::swap(channel_, other.channel_); | 
|  | std::swap(info_, other.info_); | 
|  | std::swap(state_, other.state_); | 
|  | std::swap(replied_, other.replied_); | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | Message::~Message() { Destroy(); } | 
|  |  | 
|  | void Message::Destroy() { | 
|  | auto svc = service_.lock(); | 
|  | if (svc) { | 
|  | if (!replied_) { | 
|  | ALOGE( | 
|  | "ERROR: Service \"%s\" failed to reply to message: op=%d pid=%d " | 
|  | "cid=%d\n", | 
|  | svc->name_.c_str(), info_.op, info_.pid, info_.cid); | 
|  | svc->DefaultHandleMessage(*this); | 
|  | } | 
|  | svc->endpoint()->FreeMessageState(state_); | 
|  | } | 
|  | state_ = nullptr; | 
|  | service_.reset(); | 
|  | channel_.reset(); | 
|  | } | 
|  |  | 
|  | const std::uint8_t* Message::ImpulseBegin() const { | 
|  | return reinterpret_cast<const std::uint8_t*>(info_.impulse); | 
|  | } | 
|  |  | 
|  | const std::uint8_t* Message::ImpulseEnd() const { | 
|  | return ImpulseBegin() + (IsImpulse() ? GetSendLength() : 0); | 
|  | } | 
|  |  | 
|  | Status<size_t> Message::ReadVector(const struct iovec* vector, | 
|  | size_t vector_length) { | 
|  | PDX_TRACE_NAME("Message::ReadVector"); | 
|  | if (auto svc = service_.lock()) { | 
|  | return svc->endpoint()->ReadMessageData(this, vector, vector_length); | 
|  | } else { | 
|  | return ErrorStatus{ESHUTDOWN}; | 
|  | } | 
|  | } | 
|  |  | 
|  | Status<void> Message::ReadVectorAll(const struct iovec* vector, | 
|  | size_t vector_length) { | 
|  | PDX_TRACE_NAME("Message::ReadVectorAll"); | 
|  | if (auto svc = service_.lock()) { | 
|  | const auto status = | 
|  | svc->endpoint()->ReadMessageData(this, vector, vector_length); | 
|  | if (!status) | 
|  | return status.error_status(); | 
|  | size_t size_to_read = 0; | 
|  | for (size_t i = 0; i < vector_length; i++) | 
|  | size_to_read += vector[i].iov_len; | 
|  | if (status.get() < size_to_read) | 
|  | return ErrorStatus{EIO}; | 
|  | return {}; | 
|  | } else { | 
|  | return ErrorStatus{ESHUTDOWN}; | 
|  | } | 
|  | } | 
|  |  | 
|  | Status<size_t> Message::Read(void* buffer, size_t length) { | 
|  | PDX_TRACE_NAME("Message::Read"); | 
|  | if (auto svc = service_.lock()) { | 
|  | const struct iovec vector = {buffer, length}; | 
|  | return svc->endpoint()->ReadMessageData(this, &vector, 1); | 
|  | } else { | 
|  | return ErrorStatus{ESHUTDOWN}; | 
|  | } | 
|  | } | 
|  |  | 
|  | Status<size_t> Message::WriteVector(const struct iovec* vector, | 
|  | size_t vector_length) { | 
|  | PDX_TRACE_NAME("Message::WriteVector"); | 
|  | if (auto svc = service_.lock()) { | 
|  | return svc->endpoint()->WriteMessageData(this, vector, vector_length); | 
|  | } else { | 
|  | return ErrorStatus{ESHUTDOWN}; | 
|  | } | 
|  | } | 
|  |  | 
|  | Status<void> Message::WriteVectorAll(const struct iovec* vector, | 
|  | size_t vector_length) { | 
|  | PDX_TRACE_NAME("Message::WriteVector"); | 
|  | if (auto svc = service_.lock()) { | 
|  | const auto status = | 
|  | svc->endpoint()->WriteMessageData(this, vector, vector_length); | 
|  | if (!status) | 
|  | return status.error_status(); | 
|  | size_t size_to_write = 0; | 
|  | for (size_t i = 0; i < vector_length; i++) | 
|  | size_to_write += vector[i].iov_len; | 
|  | if (status.get() < size_to_write) | 
|  | return ErrorStatus{EIO}; | 
|  | return {}; | 
|  | } else { | 
|  | return ErrorStatus{ESHUTDOWN}; | 
|  | } | 
|  | } | 
|  |  | 
|  | Status<size_t> Message::Write(const void* buffer, size_t length) { | 
|  | PDX_TRACE_NAME("Message::Write"); | 
|  | if (auto svc = service_.lock()) { | 
|  | const struct iovec vector = {const_cast<void*>(buffer), length}; | 
|  | return svc->endpoint()->WriteMessageData(this, &vector, 1); | 
|  | } else { | 
|  | return ErrorStatus{ESHUTDOWN}; | 
|  | } | 
|  | } | 
|  |  | 
|  | Status<FileReference> Message::PushFileHandle(const LocalHandle& handle) { | 
|  | PDX_TRACE_NAME("Message::PushFileHandle"); | 
|  | if (auto svc = service_.lock()) { | 
|  | return svc->endpoint()->PushFileHandle(this, handle); | 
|  | } else { | 
|  | return ErrorStatus{ESHUTDOWN}; | 
|  | } | 
|  | } | 
|  |  | 
|  | Status<FileReference> Message::PushFileHandle(const BorrowedHandle& handle) { | 
|  | PDX_TRACE_NAME("Message::PushFileHandle"); | 
|  | if (auto svc = service_.lock()) { | 
|  | return svc->endpoint()->PushFileHandle(this, handle); | 
|  | } else { | 
|  | return ErrorStatus{ESHUTDOWN}; | 
|  | } | 
|  | } | 
|  |  | 
|  | Status<FileReference> Message::PushFileHandle(const RemoteHandle& handle) { | 
|  | PDX_TRACE_NAME("Message::PushFileHandle"); | 
|  | if (auto svc = service_.lock()) { | 
|  | return svc->endpoint()->PushFileHandle(this, handle); | 
|  | } else { | 
|  | return ErrorStatus{ESHUTDOWN}; | 
|  | } | 
|  | } | 
|  |  | 
|  | Status<ChannelReference> Message::PushChannelHandle( | 
|  | const LocalChannelHandle& handle) { | 
|  | PDX_TRACE_NAME("Message::PushChannelHandle"); | 
|  | if (auto svc = service_.lock()) { | 
|  | return svc->endpoint()->PushChannelHandle(this, handle); | 
|  | } else { | 
|  | return ErrorStatus{ESHUTDOWN}; | 
|  | } | 
|  | } | 
|  |  | 
|  | Status<ChannelReference> Message::PushChannelHandle( | 
|  | const BorrowedChannelHandle& handle) { | 
|  | PDX_TRACE_NAME("Message::PushChannelHandle"); | 
|  | if (auto svc = service_.lock()) { | 
|  | return svc->endpoint()->PushChannelHandle(this, handle); | 
|  | } else { | 
|  | return ErrorStatus{ESHUTDOWN}; | 
|  | } | 
|  | } | 
|  |  | 
|  | Status<ChannelReference> Message::PushChannelHandle( | 
|  | const RemoteChannelHandle& handle) { | 
|  | PDX_TRACE_NAME("Message::PushChannelHandle"); | 
|  | if (auto svc = service_.lock()) { | 
|  | return svc->endpoint()->PushChannelHandle(this, handle); | 
|  | } else { | 
|  | return ErrorStatus{ESHUTDOWN}; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool Message::GetFileHandle(FileReference ref, LocalHandle* handle) { | 
|  | PDX_TRACE_NAME("Message::GetFileHandle"); | 
|  | auto svc = service_.lock(); | 
|  | if (!svc) | 
|  | return false; | 
|  |  | 
|  | if (ref >= 0) { | 
|  | *handle = svc->endpoint()->GetFileHandle(this, ref); | 
|  | if (!handle->IsValid()) | 
|  | return false; | 
|  | } else { | 
|  | *handle = LocalHandle{ref}; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool Message::GetChannelHandle(ChannelReference ref, | 
|  | LocalChannelHandle* handle) { | 
|  | PDX_TRACE_NAME("Message::GetChannelHandle"); | 
|  | auto svc = service_.lock(); | 
|  | if (!svc) | 
|  | return false; | 
|  |  | 
|  | if (ref >= 0) { | 
|  | *handle = svc->endpoint()->GetChannelHandle(this, ref); | 
|  | if (!handle->valid()) | 
|  | return false; | 
|  | } else { | 
|  | *handle = LocalChannelHandle{nullptr, ref}; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | Status<void> Message::Reply(int return_code) { | 
|  | PDX_TRACE_NAME("Message::Reply"); | 
|  | auto svc = service_.lock(); | 
|  | if (!replied_ && svc) { | 
|  | const auto ret = svc->endpoint()->MessageReply(this, return_code); | 
|  | replied_ = ret.ok(); | 
|  | return ret; | 
|  | } else { | 
|  | return ErrorStatus{EINVAL}; | 
|  | } | 
|  | } | 
|  |  | 
|  | Status<void> Message::ReplyFileDescriptor(unsigned int fd) { | 
|  | PDX_TRACE_NAME("Message::ReplyFileDescriptor"); | 
|  | auto svc = service_.lock(); | 
|  | if (!replied_ && svc) { | 
|  | const auto ret = svc->endpoint()->MessageReplyFd(this, fd); | 
|  | replied_ = ret.ok(); | 
|  | return ret; | 
|  | } else { | 
|  | return ErrorStatus{EINVAL}; | 
|  | } | 
|  | } | 
|  |  | 
|  | Status<void> Message::ReplyError(unsigned int error) { | 
|  | PDX_TRACE_NAME("Message::ReplyError"); | 
|  | auto svc = service_.lock(); | 
|  | if (!replied_ && svc) { | 
|  | const auto ret = | 
|  | svc->endpoint()->MessageReply(this, -static_cast<int>(error)); | 
|  | replied_ = ret.ok(); | 
|  | return ret; | 
|  | } else { | 
|  | return ErrorStatus{EINVAL}; | 
|  | } | 
|  | } | 
|  |  | 
|  | Status<void> Message::Reply(const LocalHandle& handle) { | 
|  | PDX_TRACE_NAME("Message::ReplyFileHandle"); | 
|  | auto svc = service_.lock(); | 
|  | if (!replied_ && svc) { | 
|  | Status<void> ret; | 
|  |  | 
|  | if (handle) | 
|  | ret = svc->endpoint()->MessageReplyFd(this, handle.Get()); | 
|  | else | 
|  | ret = svc->endpoint()->MessageReply(this, handle.Get()); | 
|  |  | 
|  | replied_ = ret.ok(); | 
|  | return ret; | 
|  | } else { | 
|  | return ErrorStatus{EINVAL}; | 
|  | } | 
|  | } | 
|  |  | 
|  | Status<void> Message::Reply(const BorrowedHandle& handle) { | 
|  | PDX_TRACE_NAME("Message::ReplyFileHandle"); | 
|  | auto svc = service_.lock(); | 
|  | if (!replied_ && svc) { | 
|  | Status<void> ret; | 
|  |  | 
|  | if (handle) | 
|  | ret = svc->endpoint()->MessageReplyFd(this, handle.Get()); | 
|  | else | 
|  | ret = svc->endpoint()->MessageReply(this, handle.Get()); | 
|  |  | 
|  | replied_ = ret.ok(); | 
|  | return ret; | 
|  | } else { | 
|  | return ErrorStatus{EINVAL}; | 
|  | } | 
|  | } | 
|  |  | 
|  | Status<void> Message::Reply(const RemoteHandle& handle) { | 
|  | PDX_TRACE_NAME("Message::ReplyFileHandle"); | 
|  | auto svc = service_.lock(); | 
|  | if (!replied_ && svc) { | 
|  | Status<void> ret; | 
|  |  | 
|  | if (handle) | 
|  | ret = svc->endpoint()->MessageReply(this, handle.Get()); | 
|  | else | 
|  | ret = svc->endpoint()->MessageReply(this, handle.Get()); | 
|  |  | 
|  | replied_ = ret.ok(); | 
|  | return ret; | 
|  | } else { | 
|  | return ErrorStatus{EINVAL}; | 
|  | } | 
|  | } | 
|  |  | 
|  | Status<void> Message::Reply(const LocalChannelHandle& handle) { | 
|  | auto svc = service_.lock(); | 
|  | if (!replied_ && svc) { | 
|  | const auto ret = svc->endpoint()->MessageReplyChannelHandle(this, handle); | 
|  | replied_ = ret.ok(); | 
|  | return ret; | 
|  | } else { | 
|  | return ErrorStatus{EINVAL}; | 
|  | } | 
|  | } | 
|  |  | 
|  | Status<void> Message::Reply(const BorrowedChannelHandle& handle) { | 
|  | auto svc = service_.lock(); | 
|  | if (!replied_ && svc) { | 
|  | const auto ret = svc->endpoint()->MessageReplyChannelHandle(this, handle); | 
|  | replied_ = ret.ok(); | 
|  | return ret; | 
|  | } else { | 
|  | return ErrorStatus{EINVAL}; | 
|  | } | 
|  | } | 
|  |  | 
|  | Status<void> Message::Reply(const RemoteChannelHandle& handle) { | 
|  | auto svc = service_.lock(); | 
|  | if (!replied_ && svc) { | 
|  | const auto ret = svc->endpoint()->MessageReplyChannelHandle(this, handle); | 
|  | replied_ = ret.ok(); | 
|  | return ret; | 
|  | } else { | 
|  | return ErrorStatus{EINVAL}; | 
|  | } | 
|  | } | 
|  |  | 
|  | Status<void> Message::ModifyChannelEvents(int clear_mask, int set_mask) { | 
|  | PDX_TRACE_NAME("Message::ModifyChannelEvents"); | 
|  | if (auto svc = service_.lock()) { | 
|  | return svc->endpoint()->ModifyChannelEvents(info_.cid, clear_mask, | 
|  | set_mask); | 
|  | } else { | 
|  | return ErrorStatus{ESHUTDOWN}; | 
|  | } | 
|  | } | 
|  |  | 
|  | Status<RemoteChannelHandle> Message::PushChannel( | 
|  | int flags, const std::shared_ptr<Channel>& channel, int* channel_id) { | 
|  | PDX_TRACE_NAME("Message::PushChannel"); | 
|  | if (auto svc = service_.lock()) { | 
|  | return svc->PushChannel(this, flags, channel, channel_id); | 
|  | } else { | 
|  | return ErrorStatus(ESHUTDOWN); | 
|  | } | 
|  | } | 
|  |  | 
|  | Status<RemoteChannelHandle> Message::PushChannel( | 
|  | Service* service, int flags, const std::shared_ptr<Channel>& channel, | 
|  | int* channel_id) { | 
|  | PDX_TRACE_NAME("Message::PushChannel"); | 
|  | return service->PushChannel(this, flags, channel, channel_id); | 
|  | } | 
|  |  | 
|  | Status<int> Message::CheckChannel(ChannelReference ref, | 
|  | std::shared_ptr<Channel>* channel) const { | 
|  | PDX_TRACE_NAME("Message::CheckChannel"); | 
|  | if (auto svc = service_.lock()) { | 
|  | return svc->CheckChannel(this, ref, channel); | 
|  | } else { | 
|  | return ErrorStatus(ESHUTDOWN); | 
|  | } | 
|  | } | 
|  |  | 
|  | Status<int> Message::CheckChannel(const Service* service, ChannelReference ref, | 
|  | std::shared_ptr<Channel>* channel) const { | 
|  | PDX_TRACE_NAME("Message::CheckChannel"); | 
|  | return service->CheckChannel(this, ref, channel); | 
|  | } | 
|  |  | 
|  | pid_t Message::GetProcessId() const { return info_.pid; } | 
|  |  | 
|  | pid_t Message::GetThreadId() const { return info_.tid; } | 
|  |  | 
|  | uid_t Message::GetEffectiveUserId() const { return info_.euid; } | 
|  |  | 
|  | gid_t Message::GetEffectiveGroupId() const { return info_.egid; } | 
|  |  | 
|  | int Message::GetChannelId() const { return info_.cid; } | 
|  |  | 
|  | int Message::GetMessageId() const { return info_.mid; } | 
|  |  | 
|  | int Message::GetOp() const { return info_.op; } | 
|  |  | 
|  | int Message::GetFlags() const { return info_.flags; } | 
|  |  | 
|  | size_t Message::GetSendLength() const { return info_.send_len; } | 
|  |  | 
|  | size_t Message::GetReceiveLength() const { return info_.recv_len; } | 
|  |  | 
|  | size_t Message::GetFileDescriptorCount() const { return info_.fd_count; } | 
|  |  | 
|  | std::shared_ptr<Channel> Message::GetChannel() const { return channel_.lock(); } | 
|  |  | 
|  | Status<void> Message::SetChannel(const std::shared_ptr<Channel>& chan) { | 
|  | channel_ = chan; | 
|  | Status<void> status; | 
|  | if (auto svc = service_.lock()) | 
|  | status = svc->SetChannel(info_.cid, chan); | 
|  | return status; | 
|  | } | 
|  |  | 
|  | std::shared_ptr<Service> Message::GetService() const { return service_.lock(); } | 
|  |  | 
|  | const MessageInfo& Message::GetInfo() const { return info_; } | 
|  |  | 
|  | Service::Service(const std::string& name, std::unique_ptr<Endpoint> endpoint) | 
|  | : name_(name), endpoint_{std::move(endpoint)} { | 
|  | if (!endpoint_) | 
|  | return; | 
|  |  | 
|  | const auto status = endpoint_->SetService(this); | 
|  | ALOGE_IF(!status, "Failed to set service context because: %s", | 
|  | status.GetErrorMessage().c_str()); | 
|  | } | 
|  |  | 
|  | Service::~Service() { | 
|  | if (endpoint_) { | 
|  | const auto status = endpoint_->SetService(nullptr); | 
|  | ALOGE_IF(!status, "Failed to clear service context because: %s", | 
|  | status.GetErrorMessage().c_str()); | 
|  | } | 
|  | } | 
|  |  | 
|  | std::shared_ptr<Service> Service::GetFromMessageInfo(const MessageInfo& info) { | 
|  | return info.service ? info.service->shared_from_this() | 
|  | : std::shared_ptr<Service>(); | 
|  | } | 
|  |  | 
|  | bool Service::IsInitialized() const { return endpoint_.get() != nullptr; } | 
|  |  | 
|  | std::shared_ptr<Channel> Service::OnChannelOpen(Message& /*message*/) { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | void Service::OnChannelClose(Message& /*message*/, | 
|  | const std::shared_ptr<Channel>& /*channel*/) {} | 
|  |  | 
|  | Status<void> Service::SetChannel(int channel_id, | 
|  | const std::shared_ptr<Channel>& channel) { | 
|  | PDX_TRACE_NAME("Service::SetChannel"); | 
|  | std::lock_guard<std::mutex> autolock(channels_mutex_); | 
|  |  | 
|  | const auto status = endpoint_->SetChannel(channel_id, channel.get()); | 
|  | if (!status) { | 
|  | ALOGE("%s::SetChannel: Failed to set channel context: %s\n", name_.c_str(), | 
|  | status.GetErrorMessage().c_str()); | 
|  |  | 
|  | // It's possible someone mucked with things behind our back by calling the C | 
|  | // API directly. Since we know the channel id isn't valid, make sure we | 
|  | // don't have it in the channels map. | 
|  | if (status.error() == ENOENT) | 
|  | channels_.erase(channel_id); | 
|  | } else { | 
|  | if (channel != nullptr) | 
|  | channels_[channel_id] = channel; | 
|  | else | 
|  | channels_.erase(channel_id); | 
|  | } | 
|  | return status; | 
|  | } | 
|  |  | 
|  | std::shared_ptr<Channel> Service::GetChannel(int channel_id) const { | 
|  | PDX_TRACE_NAME("Service::GetChannel"); | 
|  | std::lock_guard<std::mutex> autolock(channels_mutex_); | 
|  |  | 
|  | auto search = channels_.find(channel_id); | 
|  | if (search != channels_.end()) | 
|  | return search->second; | 
|  | else | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | Status<void> Service::CloseChannel(int channel_id) { | 
|  | PDX_TRACE_NAME("Service::CloseChannel"); | 
|  | std::lock_guard<std::mutex> autolock(channels_mutex_); | 
|  |  | 
|  | const auto status = endpoint_->CloseChannel(channel_id); | 
|  |  | 
|  | // Always erase the map entry, in case someone mucked with things behind our | 
|  | // back using the C API directly. | 
|  | channels_.erase(channel_id); | 
|  |  | 
|  | return status; | 
|  | } | 
|  |  | 
|  | Status<void> Service::ModifyChannelEvents(int channel_id, int clear_mask, | 
|  | int set_mask) { | 
|  | PDX_TRACE_NAME("Service::ModifyChannelEvents"); | 
|  | return endpoint_->ModifyChannelEvents(channel_id, clear_mask, set_mask); | 
|  | } | 
|  |  | 
|  | Status<RemoteChannelHandle> Service::PushChannel( | 
|  | Message* message, int flags, const std::shared_ptr<Channel>& channel, | 
|  | int* channel_id) { | 
|  | PDX_TRACE_NAME("Service::PushChannel"); | 
|  |  | 
|  | std::lock_guard<std::mutex> autolock(channels_mutex_); | 
|  |  | 
|  | int channel_id_temp = -1; | 
|  | Status<RemoteChannelHandle> ret = | 
|  | endpoint_->PushChannel(message, flags, channel.get(), &channel_id_temp); | 
|  | ALOGE_IF(!ret.ok(), "%s::PushChannel: Failed to push channel: %s", | 
|  | name_.c_str(), strerror(ret.error())); | 
|  |  | 
|  | if (channel && channel_id_temp != -1) | 
|  | channels_[channel_id_temp] = channel; | 
|  | if (channel_id) | 
|  | *channel_id = channel_id_temp; | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | Status<int> Service::CheckChannel(const Message* message, ChannelReference ref, | 
|  | std::shared_ptr<Channel>* channel) const { | 
|  | PDX_TRACE_NAME("Service::CheckChannel"); | 
|  |  | 
|  | // Synchronization to maintain consistency between the kernel's channel | 
|  | // context pointer and the userspace channels_ map. Other threads may attempt | 
|  | // to modify the map at the same time, which could cause the channel context | 
|  | // pointer returned by the kernel to be invalid. | 
|  | std::lock_guard<std::mutex> autolock(channels_mutex_); | 
|  |  | 
|  | Channel* channel_context = nullptr; | 
|  | Status<int> ret = endpoint_->CheckChannel( | 
|  | message, ref, channel ? &channel_context : nullptr); | 
|  | if (ret && channel) { | 
|  | if (channel_context) | 
|  | *channel = channel_context->shared_from_this(); | 
|  | else | 
|  | *channel = nullptr; | 
|  | } | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | std::string Service::DumpState(size_t /*max_length*/) { return ""; } | 
|  |  | 
|  | Status<void> Service::HandleMessage(Message& message) { | 
|  | return DefaultHandleMessage(message); | 
|  | } | 
|  |  | 
|  | void Service::HandleImpulse(Message& /*impulse*/) {} | 
|  |  | 
|  | Status<void> Service::HandleSystemMessage(Message& message) { | 
|  | const MessageInfo& info = message.GetInfo(); | 
|  |  | 
|  | switch (info.op) { | 
|  | case opcodes::CHANNEL_OPEN: { | 
|  | ALOGD("%s::OnChannelOpen: pid=%d cid=%d\n", name_.c_str(), info.pid, | 
|  | info.cid); | 
|  | message.SetChannel(OnChannelOpen(message)); | 
|  | return message.Reply(0); | 
|  | } | 
|  |  | 
|  | case opcodes::CHANNEL_CLOSE: { | 
|  | ALOGD("%s::OnChannelClose: pid=%d cid=%d\n", name_.c_str(), info.pid, | 
|  | info.cid); | 
|  | OnChannelClose(message, Channel::GetFromMessageInfo(info)); | 
|  | message.SetChannel(nullptr); | 
|  | return message.Reply(0); | 
|  | } | 
|  |  | 
|  | case opcodes::REPORT_SYSPROP_CHANGE: | 
|  | ALOGD("%s:REPORT_SYSPROP_CHANGE: pid=%d cid=%d\n", name_.c_str(), | 
|  | info.pid, info.cid); | 
|  | OnSysPropChange(); | 
|  | android::report_sysprop_change(); | 
|  | return message.Reply(0); | 
|  |  | 
|  | case opcodes::DUMP_STATE: { | 
|  | ALOGD("%s:DUMP_STATE: pid=%d cid=%d\n", name_.c_str(), info.pid, | 
|  | info.cid); | 
|  | auto response = DumpState(message.GetReceiveLength()); | 
|  | const size_t response_size = response.size() < message.GetReceiveLength() | 
|  | ? response.size() | 
|  | : message.GetReceiveLength(); | 
|  | const Status<size_t> status = | 
|  | message.Write(response.data(), response_size); | 
|  | if (status && status.get() < response_size) | 
|  | return message.ReplyError(EIO); | 
|  | else | 
|  | return message.Reply(status); | 
|  | } | 
|  |  | 
|  | default: | 
|  | return ErrorStatus{EOPNOTSUPP}; | 
|  | } | 
|  | } | 
|  |  | 
|  | Status<void> Service::DefaultHandleMessage(Message& message) { | 
|  | const MessageInfo& info = message.GetInfo(); | 
|  |  | 
|  | ALOGD_IF(TRACE, "Service::DefaultHandleMessage: pid=%d cid=%d op=%d\n", | 
|  | info.pid, info.cid, info.op); | 
|  |  | 
|  | switch (info.op) { | 
|  | case opcodes::CHANNEL_OPEN: | 
|  | case opcodes::CHANNEL_CLOSE: | 
|  | case opcodes::REPORT_SYSPROP_CHANGE: | 
|  | case opcodes::DUMP_STATE: | 
|  | return HandleSystemMessage(message); | 
|  |  | 
|  | default: | 
|  | return message.ReplyError(EOPNOTSUPP); | 
|  | } | 
|  | } | 
|  |  | 
|  | void Service::OnSysPropChange() {} | 
|  |  | 
|  | Status<void> Service::ReceiveAndDispatch() { | 
|  | Message message; | 
|  | const auto status = endpoint_->MessageReceive(&message); | 
|  | if (!status) { | 
|  | ALOGE("Failed to receive message: %s\n", status.GetErrorMessage().c_str()); | 
|  | return status; | 
|  | } | 
|  |  | 
|  | std::shared_ptr<Service> service = message.GetService(); | 
|  |  | 
|  | if (!service) { | 
|  | ALOGE("Service::ReceiveAndDispatch: service context is NULL!!!\n"); | 
|  | // Don't block the sender indefinitely in this error case. | 
|  | endpoint_->MessageReply(&message, -EINVAL); | 
|  | return ErrorStatus{EINVAL}; | 
|  | } | 
|  |  | 
|  | if (message.IsImpulse()) { | 
|  | service->HandleImpulse(message); | 
|  | return {}; | 
|  | } else if (service->HandleSystemMessage(message)) { | 
|  | return {}; | 
|  | } else { | 
|  | return service->HandleMessage(message); | 
|  | } | 
|  | } | 
|  |  | 
|  | Status<void> Service::Cancel() { return endpoint_->Cancel(); } | 
|  |  | 
|  | }  // namespace pdx | 
|  | }  // namespace android |