Android 模擬器的上使用GPS的bug

由於最近研究Android 模擬器的GPS模塊的實現,發現瞭模擬器GPS的bug。

啟動模擬器,通過DDMS發送經緯度,通過應用可以抓到數據,進入設置,安全與位置,關閉GPS,再打開,再次打開GPS測試軟件,再次發送經緯度,怎麼也收不到。

查看瞭代碼發現Android模擬器中完成GPS模塊的功能主要是一個HAL層代碼,通過socket接收發送過來的經緯度信息,其中代碼是有問題的,GPS模塊的工作主要是一個線程,當關閉GPS模塊的時候這個線程結束瞭,再次打開的時候不會去啟動這個線程,所以GPS模塊就不工作瞭,具體看如下代碼:

[cpp]
static void 
gps_state_thread( void*  arg ) 

    GpsState*   state = (GpsState*) arg; 
    NmeaReader  reader[1]; 
    int         epoll_fd   = epoll_create(2); 
    int         started    = 0; 
    int         gps_fd     = state->fd; 
    int         control_fd = state->control[1]; 
 
    nmea_reader_init( reader ); 
 
    // register control file descriptors for polling  
    epoll_register( epoll_fd, control_fd ); 
    epoll_register( epoll_fd, gps_fd ); 
 
    D("gps thread running"); 
 
    // now loop  
    for (;;) { 
        struct epoll_event   events[2]; 
        int                  ne, nevents; 
 
        nevents = epoll_wait( epoll_fd, events, 2, -1 ); 
        if (nevents < 0) { 
            if (errno != EINTR) 
                LOGE("epoll_wait() unexpected error: %s", strerror(errno)); 
            continue; 
        } 
        D("gps thread received %d events", nevents); 
        for (ne = 0; ne < nevents; ne++) { 
            if ((events[ne].events & (EPOLLERR|EPOLLHUP)) != 0) { 
                LOGE("EPOLLERR or EPOLLHUP after epoll_wait() !?"); 
                return; 
            } 
            if ((events[ne].events & EPOLLIN) != 0) { 
                int  fd = events[ne].data.fd; 
 
                if (fd == control_fd) 
                { 
                    char  cmd = 255; 
                    int   ret; 
                    D("gps control fd event"); 
                    do { 
                        ret = read( fd, &cmd, 1 ); 
                    } while (ret < 0 && errno == EINTR); 
 
                    if (cmd == CMD_QUIT) { 
                        D("gps thread quitting on demand"); 
                        return; 
                    } 
                    else if (cmd == CMD_START) { 
                        if (!started) { 
                            D("gps thread starting  location_cb=%p", state->callbacks.location_cb); 
                            started = 1; 
                            nmea_reader_set_callback( reader, state->callbacks.location_cb ); 
                        } 
                    } 
                    else if (cmd == CMD_STOP) { 
                        if (started) { 
                            D("gps thread stopping"); 
                            started = 0; 
                            nmea_reader_set_callback( reader, NULL ); 
                        } 
                    } 
                } 
                else if (fd == gps_fd) 
                { 
                    char  buff[32]; 
                    D("gps fd event"); 
                    for (;;) { 
                        int  nn, ret; 
 
                        ret = read( fd, buff, sizeof(buff) ); 
                        if (ret < 0) { 
                            if (errno == EINTR) 
                                continue; 
                            if (errno != EWOULDBLOCK) 
                                LOGE("error while reading from gps daemon socket: %s:", strerror(errno)); 
                            break; 
                        } 
                        D("received %d bytes: %.*s", ret, ret, buff); 
                        for (nn = 0; nn < ret; nn++) 
                            nmea_reader_addc( reader, buff[nn] ); 
                    } 
                    D("gps fd event end"); 
                } 
                else 
                { 
                    LOGE("epoll_wait() returned unkown fd %d ?", fd); 
                } 
            } 
        } 
    } 

static void
gps_state_thread( void*  arg )
{
    GpsState*   state = (GpsState*) arg;
    NmeaReader  reader[1];
    int         epoll_fd   = epoll_create(2);
    int         started    = 0;
    int         gps_fd     = state->fd;
    int         control_fd = state->control[1];

    nmea_reader_init( reader );

    // register control file descriptors for polling
    epoll_register( epoll_fd, control_fd );
    epoll_register( epoll_fd, gps_fd );

    D("gps thread running");

    // now loop
    for (;;) {
        struct epoll_event   events[2];
        int                  ne, nevents;

        nevents = epoll_wait( epoll_fd, events, 2, -1 );
        if (nevents < 0) {
            if (errno != EINTR)
                LOGE("epoll_wait() unexpected error: %s", strerror(errno));
            continue;
        }
        D("gps thread received %d events", nevents);
        for (ne = 0; ne < nevents; ne++) {
            if ((events[ne].events & (EPOLLERR|EPOLLHUP)) != 0) {
                LOGE("EPOLLERR or EPOLLHUP after epoll_wait() !?");
                return;
            }
            if ((events[ne].events & EPOLLIN) != 0) {
                int  fd = events[ne].data.fd;

                if (fd == control_fd)
                {
                    char  cmd = 255;
                    int   ret;
                    D("gps control fd event");
                    do {
                        ret = read( fd, &cmd, 1 );
                    } while (ret < 0 && errno == EINTR);

                    if (cmd == CMD_QUIT) {
                        D("gps thread quitting on demand");
                        return;
                    }
                    else if (cmd == CMD_START) {
                        if (!started) {
                            D("gps thread starting  location_cb=%p", state->callbacks.location_cb);
                            started = 1;
                            nmea_reader_set_callback( reader, state->callbacks.location_cb );
                        }
                    }
                    else if (cmd == CMD_STOP) {
                        if (started) {
                            D("gps thread stopping");
                            started = 0;
                            nmea_reader_set_callback( reader, NULL );
                        }
                    }
                }
                else if (fd == gps_fd)
                {
                    char  buff[32];
                    D("gps fd event");
                    for (;;) {
                        int  nn, ret;

                        ret = read( fd, buff, sizeof(buff) );
                        if (ret < 0) {
                            if (errno == EINTR)
                                continue;
                            if (errno != EWOULDBLOCK)
                                LOGE("error while reading from gps daemon socket: %s:", strerror(errno));
                            break;
                        }
                        D("received %d bytes: %.*s", ret, ret, buff);
                        for (nn = 0; nn < ret; nn++)
                            nmea_reader_addc( reader, buff[nn] );
                    }
                    D("gps fd event end");
                }
                else
                {
                    LOGE("epoll_wait() returned unkown fd %d ?", fd);
                }
            }
        }
    }
}

若要修改的話,就是在setting中開始追代碼嘍,在再次開啟GPS模塊的時候再調用init回調函數,再次開啟線程。

以上隻是我的拙見。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *