您的位置:首页 > 移动开发 > Android开发

android下实现framebuffer独占的原理

2011-08-03 19:08 363 查看
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信号

。。。

}

---

南京
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: