M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions

View File

@@ -0,0 +1,451 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <cutils/properties.h>
#include <utils/RefBase.h>
#include <utils/Log.h>
#include <ui/PixelFormat.h>
#include <ui/FramebufferNativeWindow.h>
#include <ui/EGLUtils.h>
#include <GLES/gl.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <pixelflinger/pixelflinger.h>
#include "DisplayHardware/DisplayHardware.h"
#include <hardware/copybit.h>
#include <hardware/overlay.h>
#include <hardware/gralloc.h>
#include "GLExtensions.h"
using namespace android;
static __attribute__((noinline))
void checkGLErrors()
{
do {
// there could be more than one error flag
GLenum error = glGetError();
if (error == GL_NO_ERROR)
break;
LOGE("GL error 0x%04x", int(error));
} while(true);
}
static __attribute__((noinline))
void checkEGLErrors(const char* token)
{
EGLint error = eglGetError();
if (error && error != EGL_SUCCESS) {
LOGE("%s: EGL error 0x%04x (%s)",
token, int(error), EGLUtils::strerror(error));
}
}
/*
* Initialize the display to the specified values.
*
*/
DisplayHardware::DisplayHardware(
const sp<SurfaceFlinger>& flinger,
uint32_t dpy)
: DisplayHardwareBase(flinger, dpy),
mFlags(0)
{
init(dpy);
}
DisplayHardware::~DisplayHardware()
{
fini();
}
unsigned int DisplayHardware::getDumpframe() const { return mDumpFrame; }
float DisplayHardware::getDpiX() const { return mDpiX; }
float DisplayHardware::getDpiY() const { return mDpiY; }
float DisplayHardware::getDensity() const { return mDensity; }
float DisplayHardware::getRefreshRate() const { return mRefreshRate; }
int DisplayHardware::getWidth() const { return mWidth; }
int DisplayHardware::getHeight() const { return mHeight; }
PixelFormat DisplayHardware::getFormat() const { return mFormat; }
uint32_t DisplayHardware::getMaxTextureSize() const { return mMaxTextureSize; }
uint32_t DisplayHardware::getMaxViewportDims() const { return mMaxViewportDims; }
void DisplayHardware::init(uint32_t dpy)
{
mNativeWindow = new FramebufferNativeWindow();
framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
mDpiX = mNativeWindow->xdpi;
mDpiY = mNativeWindow->ydpi;
mRefreshRate = fbDev->fps;
mOverlayEngine = NULL;
hw_module_t const* module;
if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
overlay_control_open(module, &mOverlayEngine);
}
char property[PROPERTY_VALUE_MAX];
// enable/disable frames dump
mDumpFrame=0;
if (property_get("debug.dumpframe.enable", property, "0")) {
mDumpFrame = atoi(property);
}
EGLint w, h, dummy;
EGLint numConfigs=0;
EGLSurface surface;
EGLContext context;
// initialize EGL
EGLint attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_NONE, 0,
EGL_NONE
};
// debug: disable h/w rendering
if (property_get("debug.sf.hw", property, NULL) > 0) {
if (atoi(property) == 0) {
LOGW("H/W composition disabled");
attribs[2] = EGL_CONFIG_CAVEAT;
attribs[3] = EGL_SLOW_CONFIG;
mFlags |= CPU_COMPOSITION;
} else {
// We have hardware composition enabled. Check the composition type
if (property_get("debug.composition.type", property, NULL) > 0) {
if(((strncmp(property, "c2d", 3)) == 0) ||
((strncmp(property, "mdp", 3)) == 0)) {
// We wish to use c2d or mdp composition. Try opening copybit
if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
copybit_device_t* copybit;
copybit_open(module, &copybit);
if(copybit) {
LOGW("C2D or MDP composition");
mFlags |= (((strncmp(property, "c2d", 3)) == 0)) ? C2D_COMPOSITION:0;
attribs[2] = EGL_CONFIG_CAVEAT;
attribs[3] = EGL_SLOW_CONFIG;
copybit_close(copybit);
}
}
}
}
}
}
// TODO: all the extensions below should be queried through
// eglGetProcAddress().
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, NULL, NULL);
eglGetConfigs(display, NULL, 0, &numConfigs);
EGLConfig config;
status_t err = EGLUtils::selectConfigForNativeWindow(
display, attribs, mNativeWindow.get(), &config);
LOGE_IF(err, "couldn't find an EGLConfig matching the screen format");
EGLint r,g,b,a;
eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r);
eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b);
eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
if (mNativeWindow->isUpdateOnDemand()) {
mFlags |= PARTIAL_UPDATES;
}
if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) {
if (dummy == EGL_SLOW_CONFIG)
mFlags |= SLOW_CONFIG;
}
/*
* Create our main surface
*/
surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL);
eglQuerySurface(display, surface, EGL_WIDTH, &mWidth);
eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight);
#if defined(TARGET_USES_OVERLAY)
mOverlayLibObject = new overlay::Overlay();
if(overlay::initOverlay() == -1)
LOGE("overlay::initOverlay() ERROR!!");
mOverlayUIEnable = false;
mOverlayUIEnablePropVal = false;
#if defined(SF_BYPASS)
property_get("debug.overlayui.enable", property, "0");
if (atoi(property)) {
mOverlayUIEnable = true;
mOverlayUIEnablePropVal= true;
}
#endif
#endif
if (mFlags & PARTIAL_UPDATES) {
// if we have partial updates, we definitely don't need to
// preserve the backbuffer, which may be costly.
eglSurfaceAttrib(display, surface,
EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED);
}
if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) {
if (dummy == EGL_BUFFER_PRESERVED) {
mFlags |= BUFFER_PRESERVED;
}
}
/* Read density from build-specific ro.sf.lcd_density property
* except if it is overridden by qemu.sf.lcd_density.
*/
if (property_get("qemu.sf.lcd_density", property, NULL) <= 0) {
if (property_get("ro.sf.lcd_density", property, NULL) <= 0) {
LOGW("ro.sf.lcd_density not defined, using 160 dpi by default.");
strcpy(property, "160");
}
} else {
/* for the emulator case, reset the dpi values too */
mDpiX = mDpiY = atoi(property);
}
mDensity = atoi(property) * (1.0f/160.0f);
/*
* Create our OpenGL ES context
*/
EGLint contextAttributes[] = {
#ifdef EGL_IMG_context_priority
#ifdef HAS_CONTEXT_PRIORITY
#warning "using EGL_IMG_context_priority"
EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG,
#endif
#endif
EGL_NONE, EGL_NONE
};
context = eglCreateContext(display, config, NULL, contextAttributes);
mDisplay = display;
mConfig = config;
mSurface = surface;
mContext = context;
mFormat = fbDev->format;
mPageFlipCount = 0;
/*
* Gather OpenGL ES extensions
*/
eglMakeCurrent(display, surface, surface, context);
GLExtensions& extensions(GLExtensions::getInstance());
extensions.initWithGLStrings(
glGetString(GL_VENDOR),
glGetString(GL_RENDERER),
glGetString(GL_VERSION),
glGetString(GL_EXTENSIONS),
eglQueryString(display, EGL_VENDOR),
eglQueryString(display, EGL_VERSION),
eglQueryString(display, EGL_EXTENSIONS));
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, &mMaxViewportDims);
#ifdef EGL_ANDROID_swap_rectangle
if (extensions.hasExtension("EGL_ANDROID_swap_rectangle")) {
if (eglSetSwapRectangleANDROID(display, surface,
0, 0, mWidth, mHeight) == EGL_TRUE) {
// This could fail if this extension is not supported by this
// specific surface (of config)
mFlags |= SWAP_RECTANGLE;
}
}
// when we have the choice between PARTIAL_UPDATES and SWAP_RECTANGLE
// choose PARTIAL_UPDATES, which should be more efficient
if (mFlags & PARTIAL_UPDATES)
mFlags &= ~SWAP_RECTANGLE;
#endif
LOGI("EGL informations:");
LOGI("# of configs : %d", numConfigs);
LOGI("vendor : %s", extensions.getEglVendor());
LOGI("version : %s", extensions.getEglVersion());
LOGI("extensions: %s", extensions.getEglExtension());
LOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
LOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
LOGI("OpenGL informations:");
LOGI("vendor : %s", extensions.getVendor());
LOGI("renderer : %s", extensions.getRenderer());
LOGI("version : %s", extensions.getVersion());
LOGI("extensions: %s", extensions.getExtension());
LOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize);
LOGI("GL_MAX_VIEWPORT_DIMS = %d", mMaxViewportDims);
LOGI("flags = %08x", mFlags);
// Unbind the context from this thread
eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
/*
* Clean up. Throw out our local state.
*
* (It's entirely possible we'll never get here, since this is meant
* for real hardware, which doesn't restart.)
*/
void DisplayHardware::fini()
{
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglTerminate(mDisplay);
overlay_control_close(mOverlayEngine);
}
void DisplayHardware::releaseScreen() const
{
DisplayHardwareBase::releaseScreen();
}
void DisplayHardware::acquireScreen() const
{
DisplayHardwareBase::acquireScreen();
}
uint32_t DisplayHardware::getPageFlipCount() const {
return mPageFlipCount;
}
status_t DisplayHardware::compositionComplete() const {
return mNativeWindow->compositionComplete();
}
int DisplayHardware::getCurrentBufferIndex() const {
return mNativeWindow->getCurrentBufferIndex();
}
native_handle_t* DisplayHardware::getCurrentFBHandle() const{
return (native_handle_t*)mNativeWindow->getCurrentBufferHandle(mNativeWindow.get());
}
void DisplayHardware::flip(const Region& dirty) const
{
checkGLErrors();
EGLDisplay dpy = mDisplay;
EGLSurface surface = mSurface;
#ifdef EGL_ANDROID_swap_rectangle
if (mFlags & SWAP_RECTANGLE) {
const Region newDirty(dirty.intersect(bounds()));
const Rect b(newDirty.getBounds());
eglSetSwapRectangleANDROID(dpy, surface,
b.left, b.top, b.width(), b.height());
}
#endif
if (mFlags & PARTIAL_UPDATES) {
mNativeWindow->setUpdateRectangle(dirty.getBounds());
}
mPageFlipCount++;
eglSwapBuffers(dpy, surface);
checkEGLErrors("eglSwapBuffers");
// for debugging
//glClearColor(1,0,0,0);
//glClear(GL_COLOR_BUFFER_BIT);
}
status_t DisplayHardware::postBypassBuffer(const native_handle_t* handle, int w,
int h, int format, int orientation,
int isHPDON) const
{
framebuffer_device_t *fbDev = (framebuffer_device_t *)mNativeWindow->getDevice();
return fbDev->postBypassBuffer(fbDev, handle, w, h, format, orientation, isHPDON);
}
status_t DisplayHardware::closeBypass() const
{
framebuffer_device_t *fbDev = (framebuffer_device_t *)mNativeWindow->getDevice();
return fbDev->closeBypass(fbDev);
}
status_t DisplayHardware::postOrigResBuffer(const native_handle_t* handle, int w,
int h, int format, int orientation
) const
{
framebuffer_device_t *fbDev = (framebuffer_device_t *)mNativeWindow->getDevice();
return fbDev->postOrigResBuffer(fbDev, handle, w, h, format, orientation);
}
status_t DisplayHardware::startOrigResDisplay() const {
framebuffer_device_t *fbDev = (framebuffer_device_t *)mNativeWindow->getDevice();
return fbDev->startOrigResDisplay(fbDev);
}
status_t DisplayHardware::stopOrigResDisplay() const {
framebuffer_device_t *fbDev = (framebuffer_device_t *)mNativeWindow->getDevice();
return fbDev->stopOrigResDisplay(fbDev);
}
status_t DisplayHardware::copyBypassBuffer() const
{
framebuffer_device_t *fbDev = (framebuffer_device_t *)mNativeWindow->getDevice();
return fbDev->copyBypassBuffer(fbDev);
}
uint32_t DisplayHardware::getFlags() const
{
return mFlags;
}
void DisplayHardware::makeCurrent() const
{
eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
}
void DisplayHardware::orientationChanged(int orientation) const
{
mNativeWindow->orientationChanged(orientation);
}
void DisplayHardware::videoOverlayStarted(bool started) const
{
mNativeWindow->videoOverlayStarted(started);
}
void DisplayHardware::enableHDMIOutput(int enable) const
{
mNativeWindow->enableHDMIOutput(enable);
}

View File

@@ -0,0 +1,152 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_DISPLAY_HARDWARE_H
#define ANDROID_DISPLAY_HARDWARE_H
#include <stdlib.h>
#include <ui/PixelFormat.h>
#include <ui/Region.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <pixelflinger/pixelflinger.h>
#if defined(TARGET_USES_OVERLAY)
#include "overlayLib.h"
#endif
#include "GLExtensions.h"
#include "DisplayHardware/DisplayHardwareBase.h"
struct overlay_control_device_t;
struct framebuffer_device_t;
struct copybit_image_t;
namespace android {
class FramebufferNativeWindow;
class DisplayHardware : public DisplayHardwareBase
{
public:
enum {
COPY_BITS_EXTENSION = 0x00000008,
BUFFER_PRESERVED = 0x00010000,
PARTIAL_UPDATES = 0x00020000, // video driver feature
SLOW_CONFIG = 0x00040000, // software
SWAP_RECTANGLE = 0x00080000,
CPU_COMPOSITION = 0x00100000,
C2D_COMPOSITION = 0x00200000 // C2D composition
};
DisplayHardware(
const sp<SurfaceFlinger>& flinger,
uint32_t displayIndex);
~DisplayHardware();
void releaseScreen() const;
void acquireScreen() const;
// Flip the front and back buffers if the back buffer is "dirty". Might
// be instantaneous, might involve copying the frame buffer around.
void flip(const Region& dirty) const;
status_t postBypassBuffer(const native_handle_t* handle, int w = 0, int h = 0,
int format = 0, int orientation = 0, int isHPDON = 0) const;
status_t closeBypass() const;
status_t startOrigResDisplay() const;
status_t postOrigResBuffer(const native_handle_t* handle, int w = 0, int h = 0,
int format = 0, int orientation = 0) const;
status_t stopOrigResDisplay() const;
status_t copyBypassBuffer() const;
unsigned int getDumpframe() const;
float getDpiX() const;
float getDpiY() const;
float getRefreshRate() const;
float getDensity() const;
int getWidth() const;
int getHeight() const;
PixelFormat getFormat() const;
uint32_t getFlags() const;
void makeCurrent() const;
uint32_t getMaxTextureSize() const;
uint32_t getMaxViewportDims() const;
void orientationChanged(int orientation) const;
void videoOverlayStarted(bool started) const;
void enableHDMIOutput(int enable) const;
uint32_t getPageFlipCount() const;
EGLDisplay getEGLDisplay() const { return mDisplay; }
EGLContext getEGLContext() const { return mContext; }
overlay_control_device_t* getOverlayEngine() const { return mOverlayEngine; }
#if defined(TARGET_USES_OVERLAY)
overlay::Overlay* getOverlayObject() const { return mOverlayLibObject; }
bool isOverlayUIEnabled() const { return mOverlayUIEnable; }
void setOverlayUIEnabled(bool enable) const {
if (mOverlayUIEnablePropVal)
mOverlayUIEnable = enable;
}
#endif
status_t compositionComplete() const;
native_handle_t* getCurrentFBHandle() const;
Rect bounds() const {
return Rect(mWidth, mHeight);
}
// only for debugging
int getCurrentBufferIndex() const;
private:
void init(uint32_t displayIndex) __attribute__((noinline));
void fini() __attribute__((noinline));
EGLDisplay mDisplay;
EGLSurface mSurface;
EGLContext mContext;
EGLConfig mConfig;
float mDpiX;
float mDpiY;
float mRefreshRate;
float mDensity;
int mWidth;
int mHeight;
PixelFormat mFormat;
uint32_t mFlags;
unsigned int mDumpFrame;
mutable uint32_t mPageFlipCount;
GLint mMaxViewportDims;
GLint mMaxTextureSize;
sp<FramebufferNativeWindow> mNativeWindow;
overlay_control_device_t* mOverlayEngine;
#if defined(TARGET_USES_OVERLAY)
overlay::Overlay* mOverlayLibObject;
mutable bool mOverlayUIEnable;
bool mOverlayUIEnablePropVal;
#endif
};
}; // namespace android
#endif // ANDROID_DISPLAY_HARDWARE_H

View File

@@ -0,0 +1,408 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/resource.h>
#include <linux/unistd.h>
#include <utils/Log.h>
#include "DisplayHardware/DisplayHardwareBase.h"
#include "SurfaceFlinger.h"
// ----------------------------------------------------------------------------
// the sim build doesn't have gettid
#ifndef HAVE_GETTID
# define gettid getpid
#endif
// ----------------------------------------------------------------------------
namespace android {
static char const * kSleepFileName = "/sys/power/wait_for_fb_sleep";
static char const * kWakeFileName = "/sys/power/wait_for_fb_wake";
static char const * const kOldSleepFileName = "/sys/android_power/wait_for_fb_sleep";
static char const * const kOldWakeFileName = "/sys/android_power/wait_for_fb_wake";
// This dir exists if the framebuffer console is present, either built into
// the kernel or loaded as a module.
static char const * const kFbconSysDir = "/sys/class/graphics/fbcon";
// ----------------------------------------------------------------------------
DisplayHardwareBase::DisplayEventThreadBase::DisplayEventThreadBase(
const sp<SurfaceFlinger>& flinger)
: Thread(false), mFlinger(flinger) {
}
DisplayHardwareBase::DisplayEventThreadBase::~DisplayEventThreadBase() {
}
// ----------------------------------------------------------------------------
DisplayHardwareBase::DisplayEventThread::DisplayEventThread(
const sp<SurfaceFlinger>& flinger)
: DisplayEventThreadBase(flinger)
{
}
DisplayHardwareBase::DisplayEventThread::~DisplayEventThread()
{
}
bool DisplayHardwareBase::DisplayEventThread::threadLoop()
{
int err = 0;
char buf;
int fd;
fd = open(kSleepFileName, O_RDONLY, 0);
do {
err = read(fd, &buf, 1);
} while (err < 0 && errno == EINTR);
close(fd);
LOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
if (err >= 0) {
sp<SurfaceFlinger> flinger = mFlinger.promote();
LOGD("About to give-up screen, flinger = %p", flinger.get());
if (flinger != 0) {
mBarrier.close();
flinger->screenReleased(0);
mBarrier.wait();
}
}
fd = open(kWakeFileName, O_RDONLY, 0);
do {
err = read(fd, &buf, 1);
} while (err < 0 && errno == EINTR);
close(fd);
LOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
if (err >= 0) {
sp<SurfaceFlinger> flinger = mFlinger.promote();
LOGD("Screen about to return, flinger = %p", flinger.get());
if (flinger != 0)
flinger->screenAcquired(0);
}
return true;
}
status_t DisplayHardwareBase::DisplayEventThread::releaseScreen() const
{
mBarrier.open();
return NO_ERROR;
}
status_t DisplayHardwareBase::DisplayEventThread::readyToRun()
{
if (access(kSleepFileName, R_OK) || access(kWakeFileName, R_OK)) {
if (access(kOldSleepFileName, R_OK) || access(kOldWakeFileName, R_OK)) {
LOGE("Couldn't open %s or %s", kSleepFileName, kWakeFileName);
return NO_INIT;
}
kSleepFileName = kOldSleepFileName;
kWakeFileName = kOldWakeFileName;
}
return NO_ERROR;
}
status_t DisplayHardwareBase::DisplayEventThread::initCheck() const
{
return (((access(kSleepFileName, R_OK) == 0 &&
access(kWakeFileName, R_OK) == 0) ||
(access(kOldSleepFileName, R_OK) == 0 &&
access(kOldWakeFileName, R_OK) == 0)) &&
access(kFbconSysDir, F_OK) != 0) ? NO_ERROR : NO_INIT;
}
// ----------------------------------------------------------------------------
pid_t DisplayHardwareBase::ConsoleManagerThread::sSignalCatcherPid = 0;
DisplayHardwareBase::ConsoleManagerThread::ConsoleManagerThread(
const sp<SurfaceFlinger>& flinger)
: DisplayEventThreadBase(flinger), consoleFd(-1)
{
sSignalCatcherPid = 0;
// create a new console
char const * const ttydev = "/dev/tty0";
int fd = open(ttydev, O_RDWR | O_SYNC);
if (fd<0) {
LOGE("Can't open %s", ttydev);
this->consoleFd = -errno;
return;
}
// to make sure that we are in text mode
int res = ioctl(fd, KDSETMODE, (void*) KD_TEXT);
if (res<0) {
LOGE("ioctl(%d, KDSETMODE, ...) failed, res %d (%s)",
fd, res, strerror(errno));
}
// get the current console
struct vt_stat vs;
res = ioctl(fd, VT_GETSTATE, &vs);
if (res<0) {
LOGE("ioctl(%d, VT_GETSTATE, ...) failed, res %d (%s)",
fd, res, strerror(errno));
this->consoleFd = -errno;
return;
}
// switch to console 7 (which is what X normaly uses)
int vtnum = 7;
do {
res = ioctl(fd, VT_ACTIVATE, (void*)vtnum);
} while(res < 0 && errno == EINTR);
if (res<0) {
LOGE("ioctl(%d, VT_ACTIVATE, ...) failed, %d (%s) for %d",
fd, errno, strerror(errno), vtnum);
this->consoleFd = -errno;
return;
}
do {
res = ioctl(fd, VT_WAITACTIVE, (void*)vtnum);
} while(res < 0 && errno == EINTR);
if (res<0) {
LOGE("ioctl(%d, VT_WAITACTIVE, ...) failed, %d %d %s for %d",
fd, res, errno, strerror(errno), vtnum);
this->consoleFd = -errno;
return;
}
// open the new console
close(fd);
fd = open(ttydev, O_RDWR | O_SYNC);
if (fd<0) {
LOGE("Can't open new console %s", ttydev);
this->consoleFd = -errno;
return;
}
/* disable console line buffer, echo, ... */
struct termios ttyarg;
ioctl(fd, TCGETS , &ttyarg);
ttyarg.c_iflag = 0;
ttyarg.c_lflag = 0;
ioctl(fd, TCSETS , &ttyarg);
// 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;
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;
}
DisplayHardwareBase::ConsoleManagerThread::~ConsoleManagerThread()
{
if (this->consoleFd >= 0) {
int fd = this->consoleFd;
int prev_vt_num = this->prev_vt_num;
int res;
ioctl(fd, KDSETMODE, (void*)KD_TEXT);
do {
res = ioctl(fd, VT_ACTIVATE, (void*)prev_vt_num);
} while(res < 0 && errno == EINTR);
do {
res = ioctl(fd, VT_WAITACTIVE, (void*)prev_vt_num);
} while(res < 0 && errno == EINTR);
close(fd);
char const * const ttydev = "/dev/tty0";
fd = open(ttydev, O_RDWR | O_SYNC);
ioctl(fd, VT_DISALLOCATE, 0);
close(fd);
}
}
status_t DisplayHardwareBase::ConsoleManagerThread::readyToRun()
{
if (this->consoleFd >= 0) {
sSignalCatcherPid = gettid();
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, vm.relsig);
sigaddset(&mask, vm.acqsig);
sigprocmask(SIG_BLOCK, &mask, NULL);
int res = ioctl(this->consoleFd, VT_SETMODE, &vm);
if (res<0) {
LOGE("ioctl(%d, VT_SETMODE, ...) failed, %d (%s)",
this->consoleFd, errno, strerror(errno));
}
return NO_ERROR;
}
return this->consoleFd;
}
void DisplayHardwareBase::ConsoleManagerThread::requestExit()
{
Thread::requestExit();
if (sSignalCatcherPid != 0) {
// wake the thread up
kill(sSignalCatcherPid, SIGINT);
// wait for it...
}
}
void DisplayHardwareBase::ConsoleManagerThread::sigHandler(int sig)
{
// resend the signal to our signal catcher thread
LOGW("received signal %d in thread %d, resending to %d",
sig, gettid(), sSignalCatcherPid);
// we absolutely need the delays below because without them
// our main thread never gets a chance to handle the signal.
usleep(10000);
kill(sSignalCatcherPid, sig);
usleep(10000);
}
status_t DisplayHardwareBase::ConsoleManagerThread::releaseScreen() const
{
int fd = this->consoleFd;
int err = ioctl(fd, VT_RELDISP, (void*)1);
LOGE_IF(err<0, "ioctl(%d, VT_RELDISP, 1) failed %d (%s)",
fd, errno, strerror(errno));
return (err<0) ? (-errno) : status_t(NO_ERROR);
}
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) {
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) {
sp<SurfaceFlinger> flinger = mFlinger.promote();
//LOGD("Screen about to return, flinger = %p", flinger.get());
if (flinger != 0)
flinger->screenAcquired(0);
}
return true;
}
status_t DisplayHardwareBase::ConsoleManagerThread::initCheck() const
{
return consoleFd >= 0 ? NO_ERROR : NO_INIT;
}
// ----------------------------------------------------------------------------
DisplayHardwareBase::DisplayHardwareBase(const sp<SurfaceFlinger>& flinger,
uint32_t displayIndex)
: mCanDraw(true), mScreenAcquired(true)
{
mDisplayEventThread = new DisplayEventThread(flinger);
if (mDisplayEventThread->initCheck() != NO_ERROR) {
// fall-back on the console
mDisplayEventThread = new ConsoleManagerThread(flinger);
}
}
DisplayHardwareBase::~DisplayHardwareBase()
{
// request exit
mDisplayEventThread->requestExitAndWait();
}
void DisplayHardwareBase::setCanDraw(bool canDraw)
{
mCanDraw = canDraw;
}
bool DisplayHardwareBase::canDraw() const
{
return mCanDraw && mScreenAcquired;
}
void DisplayHardwareBase::releaseScreen() const
{
status_t err = mDisplayEventThread->releaseScreen();
if (err >= 0) {
mScreenAcquired = false;
}
}
void DisplayHardwareBase::acquireScreen() const
{
status_t err = mDisplayEventThread->acquireScreen();
if (err >= 0) {
mScreenAcquired = true;
}
}
bool DisplayHardwareBase::isScreenAcquired() const
{
return mScreenAcquired;
}
}; // namespace android

View File

@@ -0,0 +1,101 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_DISPLAY_HARDWARE_BASE_H
#define ANDROID_DISPLAY_HARDWARE_BASE_H
#include <stdint.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
#include <linux/kd.h>
#include <linux/vt.h>
#include "Barrier.h"
namespace android {
class SurfaceFlinger;
class DisplayHardwareBase
{
public:
DisplayHardwareBase(
const sp<SurfaceFlinger>& flinger,
uint32_t displayIndex);
~DisplayHardwareBase();
// console managment
void releaseScreen() const;
void acquireScreen() const;
bool isScreenAcquired() const;
bool canDraw() const;
void setCanDraw(bool canDraw);
private:
class DisplayEventThreadBase : public Thread {
protected:
wp<SurfaceFlinger> mFlinger;
public:
DisplayEventThreadBase(const sp<SurfaceFlinger>& flinger);
virtual ~DisplayEventThreadBase();
virtual void onFirstRef() {
run("DisplayEventThread", PRIORITY_URGENT_DISPLAY);
}
virtual status_t acquireScreen() const { return NO_ERROR; };
virtual status_t releaseScreen() const { return NO_ERROR; };
virtual status_t initCheck() const = 0;
};
class DisplayEventThread : public DisplayEventThreadBase
{
mutable Barrier mBarrier;
public:
DisplayEventThread(const sp<SurfaceFlinger>& flinger);
virtual ~DisplayEventThread();
virtual bool threadLoop();
virtual status_t readyToRun();
virtual status_t releaseScreen() const;
virtual status_t initCheck() const;
};
class ConsoleManagerThread : public DisplayEventThreadBase
{
int consoleFd;
int vt_num;
int prev_vt_num;
vt_mode vm;
static void sigHandler(int sig);
static pid_t sSignalCatcherPid;
public:
ConsoleManagerThread(const sp<SurfaceFlinger>& flinger);
virtual ~ConsoleManagerThread();
virtual bool threadLoop();
virtual status_t readyToRun();
virtual void requestExit();
virtual status_t releaseScreen() const;
virtual status_t initCheck() const;
};
sp<DisplayEventThreadBase> mDisplayEventThread;
mutable int mCanDraw;
mutable int mScreenAcquired;
};
}; // namespace android
#endif // ANDROID_DISPLAY_HARDWARE_BASE_H