#include <system/window.h>
#include <ui/GraphicTypes.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+
#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<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
+
ui::Transform::RotationFlags DisplayDevice::sPrimaryDisplayRotationFlags = ui::Transform::ROT_0;
DisplayDeviceCreationArgs::DisplayDeviceCreationArgs(
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;
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();
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) {
if (isPrimary()) {
sPrimaryDisplayRotationFlags = ui::Transform::toRotationFlags(orientation);
+#ifdef CONSOLE_MANAGER
+ mConsoleManagerThread = new ConsoleManagerThread(mFlinger, mDisplayToken);
+#endif
}
if (!orientedDisplaySpaceRect.isValid()) {