现在的位置: 首页 > 综合 > 正文

android下实现framebuffer独占的原理

2013年10月08日 ⁄ 综合 ⁄ 共 4758字 ⁄ 字号 评论关闭

1.android下独占framebuffer的代码(tslib)

int open_framebuffer(void)
{
struct vt_stat vts;
char vtname[128];
int fd, nr;
unsigned y, addr;
struct vt_mode vm;

if ((fbdevice = getenv ("TSLIB_FBDEVICE")) == NULL)
fbdevice = defaultfbdevice;

if ((consoledevice = getenv ("TSLIB_CONSOLEDEVICE")) == NULL)
consoledevice = defaultconsoledevice;

if (strcmp (consoledevice, "none") != 0) {
sprintf (vtname,"%s%d", consoledevice, 1);
        fd = open (vtname, O_WRONLY);
        if (fd < 0) {
               perror("open consoledevice");
               return -1;
        }

if (ioctl(fd, VT_OPENQRY, &nr) < 0) {
               perror("ioctl VT_OPENQRY");
               return -1;
        }
        close(fd);
printf("We get tty num:%d\n", nr);

        sprintf(vtname, "%s%d", consoledevice, nr);

        con_fd = open(vtname, O_RDWR | O_NDELAY);
        if (con_fd < 0) {
               perror("open tty");
               return -1;
        }

        if (ioctl(con_fd, VT_GETSTATE, &vts) == 0)
               last_vt = vts.v_active;

        if (ioctl(con_fd, VT_ACTIVATE, nr) < 0) {
               perror("VT_ACTIVATE");
               close(con_fd);
               return -1;
        }

        if (ioctl(con_fd, VT_WAITACTIVE, nr) < 0) {
               perror("VT_WAITACTIVE");
               close(con_fd);
               return -1;
        }

        if (ioctl(con_fd, KDSETMODE, KD_GRAPHICS) < 0) {
               perror("KDSETMODE");
               close(con_fd);
               return -1;
        }

}

fb_fd = open(fbdevice, O_RDWR);
if (fb_fd == -1) {
perror("open fbdevice");
return -1;
}

if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &fix) < 0) {
perror("ioctl FBIOGET_FSCREENINFO");
close(fb_fd);
return -1;
}

if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &var) < 0) {
perror("ioctl FBIOGET_VSCREENINFO");
close(fb_fd);
return -1;
}
xres = var.xres;
yres = var.yres;

fbuffer = mmap(NULL, fix.smem_len, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fb_fd, 0);
if (fbuffer == (unsigned char *)-1) {
perror("mmap framebuffer");
close(fb_fd);
return -1;
}
memset(fbuffer,0,fix.smem_len);
ioctl(fb_fd, FBIOBLANK, 0);
bytes_per_pixel = (var.bits_per_pixel + 7) / 8;
line_addr = malloc (sizeof (__u32) * var.yres_virtual);
addr = 0;
for (y = 0; y < var.yres_virtual; y++, addr += fix.line_length)
line_addr [y] = fbuffer + addr;

return 0;
}


2. android下的console管理

DisplayHardwareBase::ConsoleManagerThread::ConsoleManagerThread(
        const sp<SurfaceFlinger>& flinger)
    : DisplayEventThreadBase(flinger), consoleFd(-1)
{   
  
   。。。
    // set up signals so we're notified when the console changes
    // we can't use SIGUSR1 because it's used by the java-vm
    vm.mode = VT_PROCESS;  //设置为VT_PROCESS模式,可以console切换
    vm.waitv = 0;
    vm.relsig = SIGUSR2;
    vm.acqsig = SIGUNUSED;
    vm.frsig = 0;

    struct sigaction act;
    sigemptyset(&act.sa_mask);
    act.sa_handler = sigHandler;
    act.sa_flags = 0;
    sigaction(vm.relsig, &act, NULL);

    sigemptyset(&act.sa_mask);
    act.sa_handler = sigHandler;
    act.sa_flags = 0;
    sigaction(vm.acqsig, &act, NULL);

    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, vm.relsig);
    sigaddset(&mask, vm.acqsig);
    sigprocmask(SIG_BLOCK, &mask, NULL);

    // switch to graphic mode
    res = ioctl(fd, KDSETMODE, (void*)KD_GRAPHICS);
    LOGW_IF(res<0,
            "ioctl(%d, KDSETMODE, KD_GRAPHICS) failed, res %d", fd, res);

    this->prev_vt_num = vs.v_active;
    this->vt_num = vtnum;
    this->consoleFd = fd;
}


bool DisplayHardwareBase::ConsoleManagerThread::threadLoop()
{
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, vm.relsig);
    sigaddset(&mask, vm.acqsig);
    int sig = 0;
    sigwait(&mask, &sig);

    if (sig == vm.relsig) {   //收到relsig信号
        sp<SurfaceFlinger> flinger = mFlinger.promote();
        LOGD("About to give-up screen, flinger = %p", flinger.get());
        if (flinger != 0)
            flinger->screenReleased(0);
    } else if (sig == vm.acqsig) {  //收到acqsig信号
        sp<SurfaceFlinger> flinger = mFlinger.promote();
        LOGD("Screen about to return, flinger = %p", flinger.get());
        if (flinger != 0) 
            flinger->screenAcquired(0);
    }
    
    return true;
}


总结:

bool SurfaceFlinger::threadLoop()利用handleConsoleEvents()判断当前进程是否有console的控制权。

当除了surfaceFlinger之外的进程使用VT_ACTIVATE激活了console后,surfaceFlinger失去了console的控制权

mCanDraw返回false,因而不再向framebuffer更新数据。


3.kernel(2.6.29)中的代码调用:

(1). driver/char/vt_ioctl.c +821

case VT_ACTIVATE:
if (!perm)
goto eperm;
if (arg == 0 || arg > MAX_NR_CONSOLES)
ret =  -ENXIO;
else {
arg--;
acquire_console_sem();
ret = vc_allocate(arg);
release_console_sem();
printk("We want active tty%d\n", arg);
if (ret)
break;
set_console(arg); //设置该tty成为当前的console
}


(2). driver/char/vt.c +2406

int set_console(int nr)
{
struct vc_data *vc = vc_cons[fg_console].d;

if (!vc_cons_allocated(nr) || vt_dont_switch ||
(vc->vt_mode.mode == VT_AUTO && vc->vc_mode == KD_GRAPHICS)) { 

//android设置当前console为VT_PROCESS KD_GRAPHICS模式,因而可以切换console

。。。
}


(3).切换新的console

void change_console(struct vc_data *new_vc)
{
struct vc_data *vc;

if (!new_vc || new_vc->vc_num == fg_console || vt_dont_switch)
return;

vc = vc_cons[fg_console].d;
if (vc->vt_mode.mode == VT_PROCESS) {

vc->vt_newvt = new_vc->vc_num;
if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) {  //发送signal给surfaceflinger

return;
}

。。。

}


(4).恢复老的console

static void complete_change_console(struct vc_data *vc)
{

。。。

if (vc->vt_mode.mode == VT_PROCESS) {
/*
* Send the signal as privileged - kill_pid() will
* tell us if the process has gone or something else
* is awry
*/
if (kill_pid(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) {  //发送acqsig信号

。。。

}


---

南京


抱歉!评论已关闭.