diff options
author | Chih-Wei Huang <cwhuang@linux.org.tw> | 2014-10-26 15:38:15 +0800 |
---|---|---|
committer | Chih-Wei Huang <cwhuang@linux.org.tw> | 2016-05-06 01:57:08 +0800 |
commit | 26be90a0bf2651184fcdbf3b1397edf398a78bfd (patch) | |
tree | 6b6c7bddfd1c625e15d07b2afde8521084286635 | |
parent | 93bfb8724aa5479d1af3e82d6477dc0d5aec321b (diff) | |
download | frameworks_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.mk | 3 | ||||
-rw-r--r-- | services/inputflinger/EventHub.cpp | 16 | ||||
-rw-r--r-- | services/surfaceflinger/Android.mk | 6 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayDevice.cpp | 260 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayDevice.h | 4 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 14 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 3 |
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; |