From 0a5c1757b235b8cc42a03f85f0be7bffb3e1b1d7 Mon Sep 17 00:00:00 2001 From: Chih-Wei Huang Date: Sun, 26 Oct 2014 15:38:15 +0800 Subject: [PATCH] SurfaceFlinger: 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. Change-Id: Iad3564502761a9f03f4cddbe0c1bfc4b2648d02a --- services/inputflinger/Android.bp | 2 + services/inputflinger/reader/EventHub.cpp | 16 ++ services/surfaceflinger/Android.bp | 3 + services/surfaceflinger/DisplayDevice.cpp | 271 +++++++++++++++++++++++++++++ services/surfaceflinger/DisplayDevice.h | 5 + services/surfaceflinger/SurfaceFlinger.cpp | 14 ++ services/surfaceflinger/SurfaceFlinger.h | 3 + 7 files changed, 314 insertions(+) diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index 73e57495e6..ab9e12e924 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -87,6 +87,8 @@ cc_library_shared { "libinputflinger_defaults", ], cflags: [ + "-DCONSOLE_MANAGER", + "-DANDROID_VT=7", // TODO(b/23084678): Move inputflinger to its own process and mark it hidden //-fvisibility=hidden ], diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index a2891d43b4..4b5b123c28 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -52,6 +52,8 @@ #include #include +#include + #include "EventHub.h" #define INDENT " " @@ -1544,6 +1546,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) { @@ -1618,6 +1628,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.bp b/services/surfaceflinger/Android.bp index eeb3f3a288..b3b1a0c335 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -54,6 +54,7 @@ cc_defaults { "libGLESv1_CM", "libGLESv2", "libgui", + "libhardware", "libhidlbase", "liblayers_proto", "liblog", @@ -202,6 +203,8 @@ cc_defaults { ], cflags: [ "-DLOG_TAG=\"SurfaceFlinger\"", + "-DCONSOLE_MANAGER", + "-DANDROID_VT=7", ], shared_libs: [ "android.frameworks.displayservice@1.0", diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 4445eea604..e8dc16481c 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -40,17 +40,268 @@ #include #include +#include +#include +#include +#include + #include "DisplayDevice.h" #include "Layer.h" #include "RefreshRateOverlay.h" #include "SurfaceFlinger.h" +// Duplicate enum values here, this avoids making SurfaceFlinger module +// depend on drm_gralloc, which is obsolete and will eventually go away. + +enum { + GRALLOC_MODULE_PERFORM_ENTER_VT = 0x80000005, + GRALLOC_MODULE_PERFORM_LEAVE_VT = 0x80000006, +}; + + namespace android { namespace hal = hardware::graphics::composer::hal; using android::base::StringAppendF; +#ifdef CONSOLE_MANAGER +class ConsoleManagerThread : public Thread { +public: + ConsoleManagerThread(const sp&, const wp&); + virtual ~ConsoleManagerThread(); + + status_t releaseScreen() const; + +private: + sp mFlinger; + wp 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& flinger, const wp& 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(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 + ui::Transform::RotationFlags DisplayDevice::sPrimaryDisplayRotationFlags = ui::Transform::ROT_0; DisplayDeviceCreationArgs::DisplayDeviceCreationArgs( @@ -72,6 +323,9 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args) mActiveModeFPSHwcTrace("ActiveModeFPS_HWC -" + to_string(getId())), mPhysicalOrientation(args.physicalOrientation), mSupportedModes(std::move(args.supportedModes)), +#ifdef CONSOLE_MANAGER + mConsoleManagerThread(0), +#endif mIsPrimary(args.isPrimary), mRefreshRateConfigs(std::move(args.refreshRateConfigs)) { mCompositionDisplay->editState().isSecure = args.isSecure; @@ -109,7 +363,16 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args) setProjection(ui::ROTATION_0, Rect::INVALID_RECT, Rect::INVALID_RECT); } +#ifdef CONSOLE_MANAGER +DisplayDevice::~DisplayDevice() { + if (mConsoleManagerThread != 0) { + mConsoleManagerThread->requestExitAndWait(); + ALOGD("ConsoleManagerThread: destroy primary DisplayDevice"); + } +} +#else DisplayDevice::~DisplayDevice() = default; +#endif void DisplayDevice::disconnect() { mCompositionDisplay->disconnect(); @@ -143,6 +406,11 @@ uint32_t DisplayDevice::getPageFlipCount() const { void DisplayDevice::setPowerMode(hal::PowerMode mode) { mPowerMode = mode; getCompositionDisplay()->setCompositionEnabled(mPowerMode != hal::PowerMode::OFF); +#ifdef CONSOLE_MANAGER + if (mode != hal::PowerMode::ON && mConsoleManagerThread != 0) { + mConsoleManagerThread->releaseScreen(); + } +#endif } void DisplayDevice::enableLayerCaching(bool enable) { @@ -257,6 +525,9 @@ void DisplayDevice::setProjection(ui::Rotation orientation, Rect layerStackSpace if (isPrimary()) { sPrimaryDisplayRotationFlags = ui::Transform::toRotationFlags(orientation); +#ifdef CONSOLE_MANAGER + mConsoleManagerThread = new ConsoleManagerThread(mFlinger, mDisplayToken); +#endif } if (!orientedDisplaySpaceRect.isValid()) { diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 4d435c7e47..05a93e71ec 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -58,6 +58,7 @@ class IGraphicBufferProducer; class Layer; class RefreshRateOverlay; class SurfaceFlinger; +class ConsoleManagerThread; struct CompositionInfo; struct DisplayDeviceCreationArgs; @@ -273,6 +274,10 @@ private: std::atomic mLastHwVsync = 0; +#ifdef CONSOLE_MANAGER + sp mConsoleManagerThread; +#endif + // TODO(b/74619554): Remove special cases for primary display. const bool mIsPrimary; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 758cc705f9..63729f114f 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1700,6 +1700,20 @@ sp SurfaceFlinger::createDisplayEventConnection( return mScheduler->createDisplayEventConnection(handle, eventRegistration); } +#ifdef CONSOLE_MANAGER +void SurfaceFlinger::screenReleased(const sp& display) { + // this may be called by a signal handler, we can't do too much in here + setPowerMode(display, static_cast(hal::PowerMode::OFF)); + signalLayerUpdate(); +} + +void SurfaceFlinger::screenAcquired(const sp& display) { + // this may be called by a signal handler, we can't do too much in here + setPowerMode(display, static_cast(hal::PowerMode::ON)); + signalLayerUpdate(); +} +#endif + void SurfaceFlinger::signalTransaction() { mScheduler->resetIdleTimer(); mPowerAdvisor.notifyDisplayUpdateImminent(); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 74fe7d97d0..93f3e7da4b 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -329,6 +329,9 @@ public: // won't accidentally hold onto the last strong reference. wp fromHandle(const sp& handle) const; + void screenReleased(const sp& display); + void screenAcquired(const sp& display); + // If set, disables reusing client composition buffers. This can be set by // debug.sf.disable_client_composition_cache bool mDisableClientCompositionCache = false; -- 2.11.0