zoukankan      html  css  js  c++  java
  • 关机充电 分析 -- charger代码分析(Android4.2)

    http://blog.csdn.net/u010223349/article/details/8822747

    Android charger源代码位于system/core/charger目录下,代码量不大,下面就对charger代码作个简单的分析。

    一、main函数

     

    int main(int argc, char **argv)

    {

    int ret;

     

    struct charger *charger = &charger_state;                                            //charger_state是一个charger结构体对象,详见下文第二部分

    int64_t now = curr_time_ms() - 1;                                                  //保存当前时间

        int fd;                                  

        int i;

     

        list_init(&charger->supplies);                                                     //初始化供电设备双向链表 

     

        klog_init();                                                                                //设置log输出设备,这里指向/dev/_ksmg_

        klog_set_level(CHARGER_KLOG_LEVEL);                          //设备打印等级为6

     

        dump_last_kmsg();                                                                   ///dev/last_kmsg中的信息写到/dev/_kmsg_

     

        LOGI("--------------- STARTING CHARGER MODE --------------- ");

     

        //android提供了一个库minui用于简单的UI输出,源码在bootable/recovery/minui中,

       //gr_init()gr_font_size()minui库提供方法,gr_init()UI输出作准备,gr_font_size()获得字体大小

        gr_init();                                                                          

        gr_font_size(&char_width, &char_height);               

     

        //遍历/dev/input目录下的设备,将EV_RELEV_KEY设备的信息保存到ev_fds[]结构体中

        ev_init(input_callback, charger);                              

     

        fd = uevent_open_socket(64*1024, true);                                           //创建一个socket用于接收kerneluevent

        if (fd >= 0) {

            fcntl(fd, F_SETFL, O_NONBLOCK);

            ev_add_fd(fd, uevent_callback, charger);

        }

        charger->uevent_fd = fd;

        coldboot(charger, "/sys/class/power_supply", "add");                           //kernel重新发送event

     

         //res_create_surface()minui库中提供,用于将一张图片生成一个surface

         //这里是生成了一个用于表示电池错误的surface

        ret = res_create_surface("charger/battery_fail", &charger->surf_unknown); 

        if (ret < 0) {

            LOGE("Cannot load image ");

            charger->surf_unknown = NULL;

        }

     

          //充电画面由几张图片组成,每张图片被称为一帧,charger变量存放的是charger_state

         //变量的指针,charger_state已被初始化过,但是每一个framesurface字段仍没有初始化,

         //下面这个循环就是初始化每个framesurface

        for (i = 0; i < charger->batt_anim->num_frames; i++) {

            struct frame *frame = &charger->batt_anim->frames[i];

     

            ret = res_create_surface(frame->name, &frame->surface);

            if (ret < 0) {

                LOGE("Cannot load image %s ", frame->name);

                /* TODO: free the already allocated surfaces... */

                charger->batt_anim->num_frames = 0;

                charger->batt_anim->num_cycles = 1;

                break;

            }

        }

     

        ev_sync_key_state(set_key_callback, charger);                         //详见下文第三部分

     

    #ifndef CHARGER_DISABLE_INIT_BLANK

        gr_fb_blank(true);

    #endif

     

        charger->next_screen_transition = now - 1;

        charger->next_key_check = -1;

        charger->next_pwr_check = -1;

        reset_animation(charger->batt_anim);

        kick_animation(charger->batt_anim);

     

         //charger的核心,一个大的循环,详见下文第五部分

        event_loop(charger);              

     

        return 0;

    }

     

     

    二、charger结构体

     

    struct charger {

        int64_t next_screen_transition;

        int64_t next_key_check;

        int64_t next_pwr_check;

     

        struct key_state keys[KEY_MAX + 1];                      //保存按键的状态

        int uevent_fd;                                                              //接收kernel uevent的描述符

     

        struct listnode supplies;                                                //这个listnode用于建立charger对象的双向链表

        int num_supplies;                                                         //供电设备的数量

        int num_supplies_online;                                                //正在连接的供电设备的数量

     

        struct animation *batt_anim;

        gr_surface surf_unknown;

     

        struct power_supply *battery;                                   //电池的信息

    };

     

     

     

    三、ev_sync_key_state()函数

     

    int ev_sync_key_state(ev_set_key_callback set_key_cb, void *data)

    {

        unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)];

        unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];

        unsigned i;

        int ret;

     

        for (i = 0; i < ev_dev_count; i++) {

            int code;

     

            memset(key_bits, 0, sizeof(key_bits));

            memset(ev_bits, 0, sizeof(ev_bits));

     

            //测试ev_fds[]中的设备是否有key,如果没有keycontinue

            ret = ioctl(ev_fds[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits);

            if (ret < 0 || !test_bit(EV_KEY, ev_bits))

                continue;

     

            //检测ev_fd[]中的设备key的状态

            ret = ioctl(ev_fds[i].fd, EVIOCGKEY(sizeof(key_bits)), key_bits);

            if (ret < 0)

                continue;

     

            for (code = 0; code <= KEY_MAX; code++) {

               //如果有键被触发,则调用set_key_callback, set_key_callback实现,详见下文第四部分

                if (test_bit(code, key_bits))                   

                     set_key_cb(code, 1, data); 

            }

        }

     

        return 0;

    }

     

     

     

     

    四、set_key_callback()函数

     

    set_key_callback()主要用于记录按键的状态,接受三个参数:codevaluedata, code表示键值,value表示按键的状态,datacharger的指针。

     

    static int set_key_callback(int code, int value, void *data)

    {

        struct charger *charger = data;

        int64_t now = curr_time_ms();

        int down = !!value;

     

        if (code > KEY_MAX)

            return -1;

     

        /* ignore events that don't modify our state */

        if (charger->keys[code].down == down)

            return 0;

     

        /* only record the down even timestamp, as the amount

         * of time the key spent not being pressed is not useful */

        if (down)

            charger->keys[code].timestamp = now;                            //记录按下事件的时间

        charger->keys[code].down = down;                                    //录按键的状态

        charger->keys[code].pending = true;                 

        if (down) {

            LOGV("[%lld] key[%d] down ", now, code);

        } else {

            int64_t duration = now - charger->keys[code].timestamp;

            int64_t secs = duration / 1000;

            int64_t msecs = duration - secs * 1000;

            LOGV("[%lld] key[%d] up (was down for %lld.%lldsec) ", now,

                code, secs, msecs);

        }

     

        return 0;

    }

     

     

    五、event_loop()函数

     

    static void event_loop(struct charger *charger)

    {

        int ret;

     

        while (true) {

            int64_t now = curr_time_ms();

     

            LOGV("[%lld] event_loop() ", now);

            handle_input_state(charger, now);                                             //详见下文第六部分

            handle_power_supply_state(charger, now);                              //详见下文第八部分

     

            /* do screen update last in case any of the above want to start

             * screen transitions (animations, etc)

             */

            update_screen_state(charger, now);                                        //根据上面两个handle_设置的状态进行画面更新

     

             //根据上面操作得到的时间间隔来poll设备,如果有事件,

              //最后会调用set_key_callback()函数来保存按键的事件,供一次循环使用

            wait_next_event(charger, now);      

        }

    }

     

    六、handle_input_state()函数

     

    static void handle_input_state(struct charger *charger, int64_t now)

    {

        process_key(charger, KEY_POWER, now);                                //捕捉POWER键的事件,详见下文第七部分

     

        if (charger->next_key_check != -1 && now > charger->next_key_check)

            charger->next_key_check = -1;

    }

     

     

    七、process_key()函数

     

    static void process_key(struct charger *charger, int code, int64_t now)

    {

        struct key_state *key = &charger->keys[code];

        int64_t next_key_check;

     

    if (code == KEY_POWER) {

               //如果是POWER,并且是按下事件,则判断是否是长按,

               //长按则重启android正常进入系统,否则设置下次检测按键的时间, wait_next_event()//用到

            if (key->down) {

                int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME;

                if (now >= reboot_timeout) {

                          int fd = open("/sys/devices/platform/asoc_spi.1/spi_master/spi1/spi1.0/set_charger_status", O_RDWR);

                          write(fd, "0x1", strlen("0x1"));

                          close(fd);

     

                    LOGI("[%lld] rebooting ", now);

                    android_reboot(ANDROID_RB_RESTART, 0, 0);

                } else {

                    /* if the key is pressed but timeout hasn't expired,

                     * make sure we wake up at the right-ish time to check

                     */

                    set_next_key_check(charger, key, POWER_ON_KEY_TIME);

                }

     

             //如果产生的不是POWER按键的事件,则显示充电动画

            } else {

                /* if the power key got released, force screen state cycle */

                if (key->pending) {

                    request_suspend(false);

                    kick_animation(charger->batt_anim);

                }

            }

    }

     

     

     

    八、handle_power_supply_state()函数

     

    static void handle_power_supply_state(struct charger *charger, int64_t now)

    {

        //如果当前没有连接供电设备,则在一定时间内重启android进入系统

        if (charger->num_supplies_online == 0) {

            request_suspend(false);

            if (charger->next_pwr_check == -1) {

                charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;

                LOGI("[%lld] device unplugged: shutting down in %lld (@ %lld) ",

                     now, UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);

            } else if (now >= charger->next_pwr_check) {

                LOGI("[%lld] shutting down ", now);

                android_reboot(ANDROID_RB_POWEROFF, 0, 0);

            } else {

                /* otherwise we already have a shutdown timer scheduled */

            }

        //如果连接了充电设备,则显示充电画面

        } else {

            /* online supply present, reset shutdown timer if set */

            if (charger->next_pwr_check != -1) {

                LOGI("[%lld] device plugged in: shutdown cancelled ", now);

                kick_animation(charger->batt_anim);

            }

            charger->next_pwr_check = -1;

        }

    }





  • 相关阅读:
    JAVA 多态
    win10 快捷键
    MSTAR SETBOX 常用API
    MSTAR GUI
    APACHE2 服务器配置 (一)
    MSTAR SERVICE结构
    各个国家 不同字符集的unicode 编码范围
    PhpStorm中如何配置SVN,详细操作方法
    PHP/Javascript 数组定义 及JSON中的使用 ---OK
    The "Run One Program Only" Phenomenon
  • 原文地址:https://www.cnblogs.com/liulaolaiu/p/11744549.html
Copyright © 2011-2022 走看看