之前我们分析过了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    }}



更多相关文章

  1. android ndk windows 环境配置
  2. android中事件的处理
  3. 【Android游戏开发十五】关于Android(安卓)游戏开发中 OnTouchEv
  4. android:使用WebView, WebChromeClient和WebViewClient加载网页
  5. Android(安卓)Rect类的构造函数参数说明
  6. Android事件分发机制的探索与发现之View篇
  7. Android系统启动流程 -3
  8. Android设置中的Preferencescreen用法介绍与分析
  9. Android通话默认打开扬声器

随机推荐

  1. Android学习笔记——设置EditText只输入
  2. 常用的android studio插件
  3. Android手动显示和隐藏软键盘方法总结
  4. Android(安卓)Studio更新SDK后出现的问题
  5. Android(安卓)获取Inflate得到的view的宽
  6. Android(安卓)启动分析 --- init.c (syst
  7. Android(安卓)3D模型展示
  8. 【Android之OkHttp介绍】
  9. USB 相关笔记
  10. Unity 打包 Android(安卓)API 26