#include "pdx/service.h" #include #include #include #include #include #include namespace android { namespace pdx { std::shared_ptr Channel::GetFromMessageInfo(const MessageInfo& info) { return info.channel ? info.channel->shared_from_this() : std::shared_ptr(); } 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) noexcept { *this = std::move(other); } Message& Message::operator=(Message&& other) noexcept { Destroy(); auto base = reinterpret_cast(&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(info_.impulse); } const std::uint8_t* Message::ImpulseEnd() const { return ImpulseBegin() + (IsImpulse() ? GetSendLength() : 0); } Status 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 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 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 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 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 Message::Write(const void* buffer, size_t length) { PDX_TRACE_NAME("Message::Write"); if (auto svc = service_.lock()) { const struct iovec vector = {const_cast(buffer), length}; return svc->endpoint()->WriteMessageData(this, &vector, 1); } else { return ErrorStatus{ESHUTDOWN}; } } Status 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 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 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 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 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 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 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 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 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(error)); replied_ = ret.ok(); return ret; } else { return ErrorStatus{EINVAL}; } } Status Message::Reply(const LocalHandle& handle) { PDX_TRACE_NAME("Message::ReplyFileHandle"); auto svc = service_.lock(); if (!replied_ && svc) { Status 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 Message::Reply(const BorrowedHandle& handle) { PDX_TRACE_NAME("Message::ReplyFileHandle"); auto svc = service_.lock(); if (!replied_ && svc) { Status 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 Message::Reply(const RemoteHandle& handle) { PDX_TRACE_NAME("Message::ReplyFileHandle"); auto svc = service_.lock(); if (!replied_ && svc) { Status ret = svc->endpoint()->MessageReply(this, handle.Get()); replied_ = ret.ok(); return ret; } else { return ErrorStatus{EINVAL}; } } Status 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 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 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 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 Message::PushChannel( int flags, const std::shared_ptr& 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 Message::PushChannel( Service* service, int flags, const std::shared_ptr& channel, int* channel_id) { PDX_TRACE_NAME("Message::PushChannel"); return service->PushChannel(this, flags, channel, channel_id); } Status Message::CheckChannel(ChannelReference ref, std::shared_ptr* channel) const { PDX_TRACE_NAME("Message::CheckChannel"); if (auto svc = service_.lock()) { return svc->CheckChannel(this, ref, channel); } else { return ErrorStatus(ESHUTDOWN); } } Status Message::CheckChannel(const Service* service, ChannelReference ref, std::shared_ptr* 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 Message::GetChannel() const { return channel_.lock(); } Status Message::SetChannel(const std::shared_ptr& chan) { channel_ = chan; Status status; if (auto svc = service_.lock()) status = svc->SetChannel(info_.cid, chan); return status; } std::shared_ptr Message::GetService() const { return service_.lock(); } const MessageInfo& Message::GetInfo() const { return info_; } Service::Service(const std::string& name, std::unique_ptr 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::GetFromMessageInfo(const MessageInfo& info) { return info.service ? info.service->shared_from_this() : std::shared_ptr(); } bool Service::IsInitialized() const { return endpoint_.get() != nullptr; } std::shared_ptr Service::OnChannelOpen(Message& /*message*/) { return nullptr; } void Service::OnChannelClose(Message& /*message*/, const std::shared_ptr& /*channel*/) {} Status Service::SetChannel(int channel_id, const std::shared_ptr& channel) { PDX_TRACE_NAME("Service::SetChannel"); std::lock_guard 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 Service::GetChannel(int channel_id) const { PDX_TRACE_NAME("Service::GetChannel"); std::lock_guard autolock(channels_mutex_); auto search = channels_.find(channel_id); if (search != channels_.end()) return search->second; else return nullptr; } Status Service::CloseChannel(int channel_id) { PDX_TRACE_NAME("Service::CloseChannel"); std::lock_guard 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 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 Service::PushChannel( Message* message, int flags, const std::shared_ptr& channel, int* channel_id) { PDX_TRACE_NAME("Service::PushChannel"); std::lock_guard autolock(channels_mutex_); int channel_id_temp = -1; Status 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 Service::CheckChannel(const Message* message, ChannelReference ref, std::shared_ptr* 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 autolock(channels_mutex_); Channel* channel_context = nullptr; Status 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 Service::HandleMessage(Message& message) { return DefaultHandleMessage(message); } void Service::HandleImpulse(Message& /*impulse*/) {} Status 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 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 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 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 = 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 Service::Cancel() { return endpoint_->Cancel(); } } // namespace pdx } // namespace android