android 6.0 healthd vold接收uevent
16lz
2021-01-26
之前我们分析过了ueventd处理uevent事件,这篇博客我们看下healthd和vold是如何接受相关的uevent事件的。
一、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\n", optopt); exit(1); } } } ret = healthd_init();//初始化 if (ret) { KLOG_ERROR("Initialization failed, exiting\n"); exit(2); } healthd_mainloop();//进入epoll循环 KLOG_ERROR("Main loop terminated, exiting\n"); 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\n", 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\n"); 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\n");}
将ueventd的fd加入到epoll中,当有数据过来就调用uevent_event处理函数
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\n", errno); return -1; } eventct++; return 0;}
uevent_event函数处理uevent事件
#define UEVENT_MSG_LEN 2048static 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\n"); 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,但是它自己调用的socket原始函数,而没有使用uevent_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 }}
更多相关文章
- android ndk windows 环境配置
- android中事件的处理
- 【Android游戏开发十五】关于Android(安卓)游戏开发中 OnTouchEv
- android:使用WebView, WebChromeClient和WebViewClient加载网页
- Android(安卓)Rect类的构造函数参数说明
- Android事件分发机制的探索与发现之View篇
- Android系统启动流程 -3
- Android设置中的Preferencescreen用法介绍与分析
- Android通话默认打开扬声器