OSDN Git Service

SurfaceFlinger: enable console management
authorChih-Wei Huang <cwhuang@linux.org.tw>
Sun, 26 Oct 2014 07:38:15 +0000 (15:38 +0800)
committerChih-Wei Huang <cwhuang@linux.org.tw>
Sun, 10 Dec 2017 15:21:07 +0000 (23:21 +0800)
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.

services/inputflinger/Android.bp
services/inputflinger/EventHub.cpp
services/surfaceflinger/Android.mk
services/surfaceflinger/DisplayDevice.cpp
services/surfaceflinger/DisplayDevice.h
services/surfaceflinger/SurfaceFlinger.cpp
services/surfaceflinger/SurfaceFlinger.h
services/surfaceflinger/SurfaceFlinger_hwc1.cpp

index 4fd98e2..64a7b4a 100644 (file)
@@ -37,6 +37,8 @@ cc_library_shared {
     ],
 
     cflags: [
+        "-DCONSOLE_MANAGER",
+        "-DANDROID_VT=7",
         "-Wno-unused-parameter",
         // TODO: Move inputflinger to its own process and mark it hidden
         //-fvisibility=hidden
index 3f45adb..bb0e8d7 100644 (file)
@@ -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.
@@ -810,6 +812,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) {
@@ -864,6 +874,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);
index 38529b6..233c150 100644 (file)
@@ -43,11 +43,13 @@ LOCAL_SRC_FILES := \
 LOCAL_MODULE := libsurfaceflinger
 LOCAL_C_INCLUDES := \
     frameworks/native/vulkan/include \
+    external/drm_gralloc \
     external/vulkan-validation-layers/libs/vkjson \
     system/libhwbinder/fast_msgq/include \
 
 LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+LOCAL_CFLAGS += -DCONSOLE_MANAGER -DANDROID_VT=7
 
 ifeq ($(TARGET_USES_HWC2),true)
     LOCAL_CFLAGS += -DUSE_HWC2
index b28c9ba..fdc682c 100644 (file)
 #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>
@@ -46,6 +51,7 @@
 #include "DisplayDevice.h"
 #include "SurfaceFlinger.h"
 #include "Layer.h"
+#include "gralloc_drm.h"
 
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 #include <configstore/Utils.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
@@ -110,6 +353,9 @@ DisplayDevice::DisplayDevice(
       mFlags(),
       mPageFlipCount(),
       mIsSecure(isSecure),
+#ifdef CONSOLE_MANAGER
+      mConsoleManagerThread(0),
+#endif
       mLayerStack(NO_LAYER_STACK),
       mOrientation(),
       mPowerMode(HWC_POWER_MODE_OFF),
@@ -174,6 +420,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";
@@ -196,6 +445,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) {
@@ -416,6 +671,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 {
index 8636e2a..1d743a4 100644 (file)
@@ -44,6 +44,7 @@
 #endif
 
 struct ANativeWindow;
+class ConsoleManagerThread;
 
 namespace android {
 
@@ -242,6 +243,10 @@ private:
     // list of visible layers on that display
     Vector< sp<Layer> > mVisibleLayersSortedByZ;
 
+#ifdef CONSOLE_MANAGER
+    sp<ConsoleManagerThread> mConsoleManagerThread;
+#endif
+
     /*
      * Transaction state
      */
index bb0e33c..45bf686 100644 (file)
@@ -1088,6 +1088,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();
 }
index 7606e10..7fe4262 100644 (file)
@@ -228,6 +228,9 @@ public:
     bool authenticateSurfaceTextureLocked(
         const sp<IGraphicBufferProducer>& bufferProducer) const;
 
+    void screenReleased(const sp<IBinder>& display);
+    void screenAcquired(const sp<IBinder>& display);
+
 private:
     friend class Client;
     friend class DisplayEventConnection;
index b28fe68..169d2cb 100644 (file)
@@ -948,6 +948,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();
 }