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信号
。。。
}
---
南京