属性服务端的启动以及通信架构
- init进程与属性服务线程之间通过本地套接字socket进行通信。
- 客户端进程与属性服务线程(init属性服务进程)之间通信:
/dev/socket/property_service。
- 属性服务线程位于init进程中。
- 如要修改持久化的属性,在属性服务线程中还会通过调用属性的持久化线程服务的接口,以队列的方式发送请求。
源码分析
- StartPropertyService
c
复制代码
void StartPropertyService(int* epoll_socket) {
InitPropertySet("ro.property_service.version", "2");
int sockets[2];
// 创建双向通信的unix 套接字,用于propety_service 和 init 进程之间的通信
if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets) != 0) {
PLOG(FATAL) << "Failed to socketpair() between property_service and init";
}
*epoll_socket = from_init_socket = sockets[0]; // 一个给 init 进程
init_socket = sockets[1]; // 一个给 service
StartSendingMessages();
// 创建监听socket, /dev/socket/property_service 这个节点
if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
/*passcred=*/false, /*should_listen=*/false, 0666, /*uid=*/0,
/*gid=*/0, /*socketcon=*/{});
result.ok()) {
property_set_fd = *result;
} else {
LOG(FATAL) << "start_property_service socket creation failed: " << result.error();
}
// 最多允许8个客户端连接到 property_service
listen(property_set_fd, 8);
// 创建服务线程
auto new_thread = std::thread{PropertyServiceThread};
property_service_thread.swap(new_thread);
auto async_persist_writes =
android::base::GetBoolProperty("ro.property_service.async_persist_writes", false);
// 如果支持异步写入
if (async_persist_writes) {
persist_write_thread = std::make_unique<PersistWriteThread>();
}
}
- PropertyServiceThread
c
复制代码
static void PropertyServiceThread() {
Epoll epoll;
if (auto result = epoll.Open(); !result.ok()) {
LOG(FATAL) << result.error();
}
// 接收来自系统的属性设置处理
if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd);
!result.ok()) {
LOG(FATAL) << result.error();
}
// 接收来自init 进程的消息
if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result.ok()) {
LOG(FATAL) << result.error();
}
while (true) {
auto epoll_result = epoll.Wait(std::nullopt);
if (!epoll_result.ok()) {
LOG(ERROR) << epoll_result.error();
}
}
}
- handle_property_set_fd、PROP_MSG_SETPROP 和 PROP_MSG_SETPROP2
c
复制代码
static void handle_property_set_fd() {
static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */
// 接收一个来自客户端的连接
int s = accept4(property_set_fd, nullptr, nullptr, SOCK_CLOEXEC);
if (s == -1) {
return;
}
ucred cr;
socklen_t cr_size = sizeof(cr);
if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
close(s);
PLOG(ERROR) << "sys_prop: unable to get SO_PEERCRED";
return;
}
SocketConnection socket(s, cr);
uint32_t timeout_ms = kDefaultSocketTimeout;
uint32_t cmd = 0;
// 接收cmd
if (!socket.RecvUint32(&cmd, &timeout_ms)) {
PLOG(ERROR) << "sys_prop: error while reading command from the socket";
socket.SendUint32(PROP_ERROR_READ_CMD);
return;
}
// 处理cmd 类型
switch (cmd) {
case PROP_MSG_SETPROP: {
char prop_name[PROP_NAME_MAX];
char prop_value[PROP_VALUE_MAX];
// 接收name 及value
if (!socket.RecvChars(prop_name, PROP_NAME_MAX, &timeout_ms) ||
!socket.RecvChars(prop_value, PROP_VALUE_MAX, &timeout_ms)) {
PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP): error while reading name/value from the socket";
return;
}
prop_name[PROP_NAME_MAX-1] = 0;
prop_value[PROP_VALUE_MAX-1] = 0;
// 获取上下文
std::string source_context;
if (!socket.GetSourceContext(&source_context)) {
PLOG(ERROR) << "Unable to set property '" << prop_name << "': getpeercon() failed";
return;
}
const auto& cr = socket.cred();
std::string error;
// 调用 handler 处理
auto result = HandlePropertySetNoSocket(prop_name, prop_value, source_context, cr, &error);
if (result != PROP_SUCCESS) {
LOG(ERROR) << "Unable to set property '" << prop_name << "' from uid:" << cr.uid
<< " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
}
break;
}
case PROP_MSG_SETPROP2: {
std::string name;
std::string value;
if (!socket.RecvString(&name, &timeout_ms) ||
!socket.RecvString(&value, &timeout_ms)) {
PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP2): error while reading name/value from the socket";
socket.SendUint32(PROP_ERROR_READ_DATA);
return;
}
std::string source_context;
if (!socket.GetSourceContext(&source_context)) {
PLOG(ERROR) << "Unable to set property '" << name << "': getpeercon() failed";
socket.SendUint32(PROP_ERROR_PERMISSION_DENIED);
return;
}
// HandlePropertySet takes ownership of the socket if the set is handled asynchronously.
const auto& cr = socket.cred();
std::string error;
auto result = HandlePropertySet(name, value, source_context, cr, &socket, &error);
if (!result) {
// Result will be sent after completion.
return;
}
if (*result != PROP_SUCCESS) {
LOG(ERROR) << "Unable to set property '" << name << "' from uid:" << cr.uid
<< " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
}
socket.SendUint32(*result);
break;
}
default:
LOG(ERROR) << "sys_prop: invalid command " << cmd;
socket.SendUint32(PROP_ERROR_INVALID_CMD);
break;
}
}
- persist_write_thread
c
复制代码
static std::optional<uint32_t> PropertySet(const std::string& name, const std::string& value,
SocketConnection* socket, std::string* error) {
size_t valuelen = value.size();
if (!IsLegalPropertyName(name)) {
*error = "Illegal property name";
return {PROP_ERROR_INVALID_NAME};
}
if (auto result = IsLegalPropertyValue(name, value); !result.ok()) {
*error = result.error().message();
return {PROP_ERROR_INVALID_VALUE};
}
prop_info* pi = (prop_info*)__system_property_find(name.c_str());
if (pi != nullptr) {
// ro.* properties are actually "write-once".
if (StartsWith(name, "ro.")) {
*error = "Read-only property was already set";
return {PROP_ERROR_READ_ONLY_PROPERTY};
}
__system_property_update(pi, value.c_str(), valuelen);
} else {
int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen);
if (rc < 0) {
*error = "__system_property_add failed";
return {PROP_ERROR_SET_FAILED};
}
}
// Don't write properties to disk until after we have read all default
// properties to prevent them from being overwritten by default values.
if (socket && persistent_properties_loaded && StartsWith(name, "persist.")) {
if (persist_write_thread) {
// 如果有异步persist 线程,调用线程发消息
persist_write_thread->Write(name, value, std::move(*socket));
return {};
}
// 同步操作
WritePersistentProperty(name, value);
}
// 通知属性发生变化
NotifyPropertyChange(name, value);
return {PROP_SUCCESS};
}
c
复制代码
void PersistWriteThread::Write(std::string name, std::string value, SocketConnection socket) {
{
std::unique_lock<std::mutex> lock(mutex_);
// std::deque<std::tuple<std::string, std::string, SocketConnection>> work_;
// 从队列中取出一个work_对象
work_.emplace_back(std::move(name), std::move(value), std::move(socket));
}
cv_.notify_all();
}
总结