summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChih-Wei Huang <cwhuang@linux.org.tw>2014-10-26 15:38:15 +0800
committerChih-Wei Huang <cwhuang@linux.org.tw>2016-05-06 01:57:08 +0800
commit26be90a0bf2651184fcdbf3b1397edf398a78bfd (patch)
tree6b6c7bddfd1c625e15d07b2afde8521084286635
parent93bfb8724aa5479d1af3e82d6477dc0d5aec321b (diff)
downloadframeworks_native-26be90a0bf2651184fcdbf3b1397edf398a78bfd.zip
frameworks_native-26be90a0bf2651184fcdbf3b1397edf398a78bfd.tar.gz
frameworks_native-26be90a0bf2651184fcdbf3b1397edf398a78bfd.tar.bz2
enable console management
The console management was removed since ICS. But it's useful for debugging. Re-implement it based on the original class ConsoleManagerThread of class DisplayHardwareBase.
-rw-r--r--services/inputflinger/Android.mk3
-rw-r--r--services/inputflinger/EventHub.cpp16
-rw-r--r--services/surfaceflinger/Android.mk6
-rw-r--r--services/surfaceflinger/DisplayDevice.cpp260
-rw-r--r--services/surfaceflinger/DisplayDevice.h4
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp14
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h3
7 files changed, 306 insertions, 0 deletions
diff --git a/services/inputflinger/Android.mk b/services/inputflinger/Android.mk
index ed867d8..773064f 100644
--- a/services/inputflinger/Android.mk
+++ b/services/inputflinger/Android.mk
@@ -39,6 +39,9 @@ LOCAL_SHARED_LIBRARIES := \
#LOCAL_CFLAGS += -fvisibility=hidden
LOCAL_CFLAGS += -Wno-unused-parameter
+ifneq ($(TARGET_BUILD_VARIANT),user)
+ LOCAL_CFLAGS += -DCONSOLE_MANAGER -DANDROID_VT=7
+endif
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index fc8989f..eb6a8fd 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -50,6 +50,8 @@
#include <input/KeyCharacterMap.h>
#include <input/VirtualKeyMap.h>
+#include <linux/vt.h>
+
/* this macro is used to tell if "bit" is set in "array"
* it selects a byte from the array, and does a boolean AND
* operation with a byte that only has the relevant bit set.
@@ -790,6 +792,14 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz
}
}
+#ifdef CONSOLE_MANAGER
+ struct vt_stat vs;
+ int fd_vt = open("/dev/tty0", O_RDWR | O_SYNC);
+ if (fd_vt >= 0) {
+ ioctl(fd_vt, VT_GETSTATE, &vs);
+ close(fd_vt);
+ }
+#endif
// Grab the next input event.
bool deviceChanged = false;
while (mPendingEventIndex < mPendingEventCount) {
@@ -844,6 +854,12 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz
} else if ((readSize % sizeof(struct input_event)) != 0) {
ALOGE("could not get event (wrong size: %d)", readSize);
} else {
+#ifdef CONSOLE_MANAGER
+ if (vs.v_active != ANDROID_VT) {
+ ALOGV("Skip a non Android VT event");
+ continue;
+ }
+#endif
int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
size_t count = size_t(readSize) / sizeof(struct input_event);
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 1eb2361..d77540d 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -40,6 +40,9 @@ LOCAL_SRC_FILES := \
LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+ifneq ($(TARGET_BUILD_VARIANT),user)
+ LOCAL_CFLAGS += -DCONSOLE_MANAGER -DANDROID_VT=7
+endif
ifeq ($(TARGET_BOARD_PLATFORM),omap4)
LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY
endif
@@ -88,6 +91,9 @@ ifneq ($(MAX_VIRTUAL_DISPLAY_DIMENSION),)
else
LOCAL_CFLAGS += -DMAX_VIRTUAL_DISPLAY_DIMENSION=0
endif
+ifneq ($(BOARD_GPU_DRIVERS),)
+ LOCAL_C_INCLUDES := external/drm_gralloc
+endif
LOCAL_CFLAGS += -fvisibility=hidden -Werror=format
LOCAL_CFLAGS += -std=c++11
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 13d44f3..1e42c17 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -19,6 +19,11 @@
#include <string.h>
#include <math.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+
#include <cutils/properties.h>
#include <utils/RefBase.h>
@@ -39,11 +44,249 @@
#include "DisplayDevice.h"
#include "SurfaceFlinger.h"
#include "Layer.h"
+#include "gralloc_drm.h"
// ----------------------------------------------------------------------------
using namespace android;
// ----------------------------------------------------------------------------
+#ifdef CONSOLE_MANAGER
+class ConsoleManagerThread : public Thread {
+public:
+ ConsoleManagerThread(const sp<SurfaceFlinger>&, const wp<IBinder>&);
+ virtual ~ConsoleManagerThread();
+
+ status_t releaseScreen() const;
+
+private:
+ sp<SurfaceFlinger> mFlinger;
+ wp<IBinder> mDisplayToken;
+ int consoleFd;
+ long prev_vt_num;
+ vt_mode vm;
+ virtual void onFirstRef();
+ virtual status_t readyToRun();
+ virtual void requestExit();
+ virtual bool threadLoop();
+ static void sigHandler(int sig);
+ static pid_t sSignalCatcherPid;
+};
+
+ConsoleManagerThread::ConsoleManagerThread(const sp<SurfaceFlinger>& flinger, const wp<IBinder>& token)
+ : Thread(false), mFlinger(flinger), mDisplayToken(token), 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) {
+ ALOGE("Can't open %s, errno=%d (%s)", ttydev, errno, strerror(errno));
+ consoleFd = -errno;
+ return;
+ }
+ ALOGD("Open /dev/tty0 OK");
+
+ // to make sure that we are in text mode
+ int res = ioctl(fd, KDSETMODE, (void*) KD_TEXT);
+ if (res < 0) {
+ ALOGE("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) {
+ ALOGE("ioctl(%d, VT_GETSTATE, ...) failed, res %d (%s)",
+ fd, res, strerror(errno));
+ consoleFd = -errno;
+ return;
+ }
+
+ // switch to console 7 (which is what X normaly uses)
+ do {
+ res = ioctl(fd, VT_ACTIVATE, ANDROID_VT);
+ } while(res < 0 && errno == EINTR);
+ if (res < 0) {
+ ALOGE("ioctl(%d, VT_ACTIVATE, ...) failed, %d (%s) for vt %d",
+ fd, errno, strerror(errno), ANDROID_VT);
+ consoleFd = -errno;
+ return;
+ }
+
+ do {
+ res = ioctl(fd, VT_WAITACTIVE, ANDROID_VT);
+ } while (res < 0 && errno == EINTR);
+ if (res < 0) {
+ ALOGE("ioctl(%d, VT_WAITACTIVE, ...) failed, %d %d %s for vt %d",
+ fd, res, errno, strerror(errno), ANDROID_VT);
+ consoleFd = -errno;
+ return;
+ }
+
+ // open the new console
+ close(fd);
+ fd = open(ttydev, O_RDWR | O_SYNC);
+ if (fd < 0) {
+ ALOGE("Can't open new console %s", ttydev);
+ 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);
+ ALOGW_IF(res < 0,
+ "ioctl(%d, KDSETMODE, KD_GRAPHICS) failed, res %d", fd, res);
+
+ prev_vt_num = vs.v_active;
+ consoleFd = fd;
+}
+
+ConsoleManagerThread::~ConsoleManagerThread()
+{
+ if (consoleFd >= 0) {
+ int fd = consoleFd;
+ int res;
+ ioctl(fd, KDSETMODE, (void*)KD_TEXT);
+ do {
+ res = ioctl(fd, VT_ACTIVATE, prev_vt_num);
+ } while(res < 0 && errno == EINTR);
+ do {
+ res = ioctl(fd, VT_WAITACTIVE, 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 ConsoleManagerThread::releaseScreen() const
+{
+ int err = ioctl(consoleFd, VT_RELDISP, (void*)1);
+ ALOGE_IF(err < 0, "ioctl(%d, VT_RELDISP, 1) failed %d (%s)",
+ consoleFd, errno, strerror(errno));
+ return (err < 0) ? (-errno) : status_t(NO_ERROR);
+}
+
+void ConsoleManagerThread::onFirstRef()
+{
+ run("ConsoleManagerThread", PRIORITY_URGENT_DISPLAY);
+}
+
+status_t ConsoleManagerThread::readyToRun()
+{
+ if (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(consoleFd, VT_SETMODE, &vm);
+ if (res < 0) {
+ ALOGE("ioctl(%d, VT_SETMODE, ...) failed, %d (%s)",
+ consoleFd, errno, strerror(errno));
+ }
+ return NO_ERROR;
+ }
+ return consoleFd;
+}
+
+void ConsoleManagerThread::requestExit()
+{
+ Thread::requestExit();
+ if (sSignalCatcherPid != 0) {
+ // wake the thread up
+ kill(sSignalCatcherPid, SIGINT);
+ // wait for it...
+ }
+}
+
+bool ConsoleManagerThread::threadLoop()
+{
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, vm.relsig);
+ sigaddset(&mask, vm.acqsig);
+
+ int sig = 0;
+ sigwait(&mask, &sig);
+
+ hw_module_t const* mod;
+ gralloc_module_t const* gr = NULL;
+ status_t err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mod);
+ if (!err) {
+ gr = reinterpret_cast<gralloc_module_t const*>(mod);
+ if (!gr->perform)
+ gr = NULL;
+ }
+
+ if (sig == vm.relsig) {
+ if (gr)
+ gr->perform(gr, GRALLOC_MODULE_PERFORM_LEAVE_VT);
+ mFlinger->screenReleased(mDisplayToken.promote());
+ } else if (sig == vm.acqsig) {
+ mFlinger->screenAcquired(mDisplayToken.promote());
+ if (gr)
+ gr->perform(gr, GRALLOC_MODULE_PERFORM_ENTER_VT);
+ }
+
+ return true;
+}
+
+void ConsoleManagerThread::sigHandler(int sig)
+{
+ // resend the signal to our signal catcher thread
+ ALOGW("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);
+}
+
+pid_t ConsoleManagerThread::sSignalCatcherPid;
+#endif
+
#ifdef EGL_ANDROID_swap_rectangle
static constexpr bool kEGLAndroidSwapRectangle = true;
#else
@@ -83,6 +326,9 @@ DisplayDevice::DisplayDevice(
mPageFlipCount(),
mIsSecure(isSecure),
mSecureLayerVisible(false),
+#ifdef CONSOLE_MANAGER
+ mConsoleManagerThread(0),
+#endif
mLayerStack(NO_LAYER_STACK),
mOrientation(),
mPowerMode(HWC_POWER_MODE_OFF),
@@ -131,6 +377,9 @@ DisplayDevice::DisplayDevice(
switch (mType) {
case DISPLAY_PRIMARY:
mDisplayName = "Built-in Screen";
+#ifdef CONSOLE_MANAGER
+ mConsoleManagerThread = new ConsoleManagerThread(mFlinger, mDisplayToken);
+#endif
break;
case DISPLAY_EXTERNAL:
mDisplayName = "HDMI Screen";
@@ -149,6 +398,12 @@ DisplayDevice::~DisplayDevice() {
eglDestroySurface(mDisplay, mSurface);
mSurface = EGL_NO_SURFACE;
}
+#ifdef CONSOLE_MANAGER
+ if (mConsoleManagerThread != 0) {
+ mConsoleManagerThread->requestExitAndWait();
+ ALOGD("ConsoleManagerThread: destroy primary DisplayDevice");
+ }
+#endif
}
void DisplayDevice::disconnect(HWComposer& hwc) {
@@ -335,6 +590,11 @@ Region DisplayDevice::getDirtyRegion(bool repaintEverything) const {
// ----------------------------------------------------------------------------
void DisplayDevice::setPowerMode(int mode) {
mPowerMode = mode;
+#ifdef CONSOLE_MANAGER
+ if (mode != HWC_POWER_MODE_NORMAL && mConsoleManagerThread != 0) {
+ mConsoleManagerThread->releaseScreen();
+ }
+#endif
}
int DisplayDevice::getPowerMode() const {
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 8695a44..852141c 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -34,6 +34,7 @@
#include "Transform.h"
struct ANativeWindow;
+class ConsoleManagerThread;
namespace android {
@@ -205,6 +206,9 @@ private:
// Whether we have a visible secure layer on this display
bool mSecureLayerVisible;
+#ifdef CONSOLE_MANAGER
+ sp<ConsoleManagerThread> mConsoleManagerThread;
+#endif
/*
* Transaction state
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index fdc3650..48a4fbf 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -757,6 +757,20 @@ void SurfaceFlinger::waitForEvent() {
mEventQueue.waitMessage();
}
+#ifdef CONSOLE_MANAGER
+void SurfaceFlinger::screenReleased(const sp<IBinder>& display) {
+ // this may be called by a signal handler, we can't do too much in here
+ setPowerMode(display, HWC_POWER_MODE_OFF);
+ signalLayerUpdate();
+}
+
+void SurfaceFlinger::screenAcquired(const sp<IBinder>& display) {
+ // this may be called by a signal handler, we can't do too much in here
+ setPowerMode(display, HWC_POWER_MODE_NORMAL);
+ signalLayerUpdate();
+}
+#endif
+
void SurfaceFlinger::signalTransaction() {
mEventQueue.invalidate();
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index b3baadd..10a74da 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -134,6 +134,9 @@ public:
return *mRenderEngine;
}
+ void screenReleased(const sp<IBinder>& display);
+ void screenAcquired(const sp<IBinder>& display);
+
private:
friend class Client;
friend class DisplayEventConnection;