android 6.0 healthd vold受信uevent
6697 ワード
以前はueventdがueventイベントを処理することを分析しましたが、このブログではhealthdとvoldが関連するueventイベントをどのように受け入れているかを見てみましょう.
一、healthdはueventを受け入れる
次はheathdのメイン関数です
まずhealthdを見てみましょうinit関数
ueventdのfdをepollに追加し、データが来たらuevent_を呼び出します.イベント処理関数
uevent_event関数によるueventイベントの処理
epollの主関数はhealthd_mainloopで、epoll_waitはイベントが来るのを待っており,イベントが来ると応答の処理関数を呼び出す.
二、vold処理uevent
voldがueventイベントを処理するのを見てみましょう.典型的にはnetlink socketが使用されますが、uevent_を使用せずに独自に呼び出されたsocket元の関数です.open_socketパッケージの関数は、最後にsocketのfdをNetlinkHandlerオブジェクトに転送します.
netlinkHandlerの間でどのようにデータを受け入れるかは詳しくは言わないが、主にSocketListenerでnetlink socketのデータを受け入れ、NetlinkListenerでこれらのデータをNetlinkEventにカプセル化し、呼び出し
NetlinkHandler::onEvent関数:
一、healthdはueventを受け入れる
次はheathdのメイン関数です
int main(int argc, char **argv) {
int ch;
int ret;
klog_set_level(KLOG_LEVEL);
healthd_mode_ops = &android_ops;
if (!strcmp(basename(argv[0]), "charger")) {
healthd_mode_ops = &charger_ops;
} else {
while ((ch = getopt(argc, argv, "cr")) != -1) {
switch (ch) {
case 'c':
healthd_mode_ops = &charger_ops;
break;
case 'r':
healthd_mode_ops = &recovery_ops;
break;
case '?':
default:
KLOG_ERROR(LOG_TAG, "Unrecognized healthd option: %c
",
optopt);
exit(1);
}
}
}
ret = healthd_init();//
if (ret) {
KLOG_ERROR("Initialization failed, exiting
");
exit(2);
}
healthd_mainloop();// epoll
KLOG_ERROR("Main loop terminated, exiting
");
return 3;
}
まずhealthdを見てみましょうinit関数
static int healthd_init() {
epollfd = epoll_create(MAX_EPOLL_EVENTS);// epoll fd
if (epollfd == -1) {
KLOG_ERROR(LOG_TAG,
"epoll_create failed; errno=%d
",
errno);
return -1;
}
healthd_board_init(&healthd_config);
healthd_mode_ops->init(&healthd_config);
wakealarm_init();//alarm
uevent_init();// uevent
gBatteryMonitor = new BatteryMonitor();
gBatteryMonitor->init(&healthd_config);
return 0;
}
uevent_Init関数、主にuevent_を介してopen_socket関数はnetlink socketを作成し、これは前のueventdで説明したように、static void uevent_init(void) {
uevent_fd = uevent_open_socket(64*1024, true);// netlink socket
if (uevent_fd < 0) {
KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed
");
return;
}
fcntl(uevent_fd, F_SETFL, O_NONBLOCK);//
if (healthd_register_event(uevent_fd, uevent_event))// epoll
KLOG_ERROR(LOG_TAG,
"register for uevent events failed
");
}
ueventdのfdをepollに追加し、データが来たらuevent_を呼び出します.イベント処理関数
int healthd_register_event(int fd, void (*handler)(uint32_t)) {
struct epoll_event ev;
ev.events = EPOLLIN | EPOLLWAKEUP;
ev.data.ptr = (void *)handler;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
KLOG_ERROR(LOG_TAG,
"epoll_ctl failed; errno=%d
", errno);
return -1;
}
eventct++;
return 0;
}
uevent_event関数によるueventイベントの処理
#define UEVENT_MSG_LEN 2048
static void uevent_event(uint32_t /*epevents*/) {
char msg[UEVENT_MSG_LEN+2];
char *cp;
int n;
n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);// netlink socket
if (n <= 0)
return;
if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
return;
msg[n] = '\0';
msg[n+1] = '\0';
cp = msg;
while (*cp) {
if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {//
healthd_battery_update();//
break;
}
/* advance to after the next \0 */
while (*cp++)//
;
}
}
epollの主関数はhealthd_mainloopで、epoll_waitはイベントが来るのを待っており,イベントが来ると応答の処理関数を呼び出す.
static void healthd_mainloop(void) {
while (1) {
struct epoll_event events[eventct];
int nevents;
int timeout = awake_poll_interval;
int mode_timeout;
mode_timeout = healthd_mode_ops->preparetowait();
if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout))
timeout = mode_timeout;
nevents = epoll_wait(epollfd, events, eventct, timeout);
if (nevents == -1) {
if (errno == EINTR)
continue;
KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed
");
break;
}
for (int n = 0; n < nevents; ++n) {
if (events[n].data.ptr)
(*(void (*)(int))events[n].data.ptr)(events[n].events);
}
if (!nevents)
periodic_chores();
healthd_mode_ops->heartbeat();
}
return;
}
二、vold処理uevent
voldがueventイベントを処理するのを見てみましょう.典型的にはnetlink socketが使用されますが、uevent_を使用せずに独自に呼び出されたsocket元の関数です.open_socketパッケージの関数は、最後にsocketのfdをNetlinkHandlerオブジェクトに転送します.
int NetlinkManager::start() {
struct sockaddr_nl nladdr;
int sz = 64 * 1024;
int on = 1;
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
nladdr.nl_pid = getpid();
nladdr.nl_groups = 0xffffffff;
if ((mSock = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC,
NETLINK_KOBJECT_UEVENT)) < 0) {
SLOGE("Unable to create uevent socket: %s", strerror(errno));
return -1;
}
if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {
SLOGE("Unable to set uevent socket SO_RCVBUFFORCE option: %s", strerror(errno));
goto out;
}
if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));
goto out;
}
if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
SLOGE("Unable to bind uevent socket: %s", strerror(errno));
goto out;
}
mHandler = new NetlinkHandler(mSock);
if (mHandler->start()) {
SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));
goto out;
}
return 0;
out:
close(mSock);
return -1;
}
netlinkHandlerの間でどのようにデータを受け入れるかは詳しくは言わないが、主にSocketListenerでnetlink socketのデータを受け入れ、NetlinkListenerでこれらのデータをNetlinkEventにカプセル化し、呼び出し
NetlinkHandler::onEvent関数:
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
VolumeManager *vm = VolumeManager::Instance();
const char *subsys = evt->getSubsystem();// Subsystem
if (!subsys) {
SLOGW("No subsystem found in netlink event");
return;
}
if (!strcmp(subsys, "block")) {// block
SLOGW("kangchen handleblockEvent");
vm->handleBlockEvent(evt);// event
}
}