You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
676 lines
20 KiB
676 lines
20 KiB
#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) noexcept { *this = std::move(other); }
|
|
|
|
Message& Message::operator=(Message&& other) noexcept {
|
|
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 = 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
|