blob: 90f628743285319f09f8100d3e5b38adb77f2b6c [file] [log] [blame]
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "SurfaceFlinger"
18
19#include <assert.h>
20#include <errno.h>
21#include <stdlib.h>
22#include <stdio.h>
23#include <string.h>
24
25#include <unistd.h>
26#include <fcntl.h>
27#include <signal.h>
28#include <termios.h>
29#include <sys/ioctl.h>
30#include <sys/mman.h>
31#include <sys/time.h>
32#include <sys/types.h>
33#include <sys/resource.h>
34
35#include <linux/unistd.h>
36
37#include <utils/Log.h>
38
39#include "DisplayHardware/DisplayHardwareBase.h"
40#include "SurfaceFlinger.h"
41
42// ----------------------------------------------------------------------------
43// the sim build doesn't have gettid
44
45#ifndef HAVE_GETTID
46# define gettid getpid
47#endif
48
49// ----------------------------------------------------------------------------
50namespace android {
51
52static char const * const kSleepFileName = "/sys/android_power/wait_for_fb_sleep";
53static char const * const kWakeFileName = "/sys/android_power/wait_for_fb_wake";
54
55// This dir exists if the framebuffer console is present, either built into
56// the kernel or loaded as a module.
57static char const * const kFbconSysDir = "/sys/class/graphics/fbcon";
58
59// ----------------------------------------------------------------------------
60
61DisplayHardwareBase::DisplayEventThreadBase::DisplayEventThreadBase(
62 const sp<SurfaceFlinger>& flinger)
63 : Thread(false), mFlinger(flinger) {
64}
65
66DisplayHardwareBase::DisplayEventThreadBase::~DisplayEventThreadBase() {
67}
68
69// ----------------------------------------------------------------------------
70
71DisplayHardwareBase::DisplayEventThread::DisplayEventThread(
72 const sp<SurfaceFlinger>& flinger)
73 : DisplayEventThreadBase(flinger)
74{
75}
76
77DisplayHardwareBase::DisplayEventThread::~DisplayEventThread()
78{
79}
80
81bool DisplayHardwareBase::DisplayEventThread::threadLoop()
82{
83 int err = 0;
84 char buf;
85 int fd;
86
87 fd = open(kSleepFileName, O_RDONLY, 0);
88 do {
89 err = read(fd, &buf, 1);
90 } while (err < 0 && errno == EINTR);
91 close(fd);
92 LOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
93 if (err >= 0) {
94 sp<SurfaceFlinger> flinger = mFlinger.promote();
95 LOGD("About to give-up screen, flinger = %p", flinger.get());
96 if (flinger != 0) {
97 mBarrier.close();
98 flinger->screenReleased(0);
99 mBarrier.wait();
100 }
101 }
102 fd = open(kWakeFileName, O_RDONLY, 0);
103 do {
104 err = read(fd, &buf, 1);
105 } while (err < 0 && errno == EINTR);
106 close(fd);
107 LOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
108 if (err >= 0) {
109 sp<SurfaceFlinger> flinger = mFlinger.promote();
110 LOGD("Screen about to return, flinger = %p", flinger.get());
111 if (flinger != 0)
112 flinger->screenAcquired(0);
113 }
114 return true;
115}
116
117status_t DisplayHardwareBase::DisplayEventThread::releaseScreen() const
118{
119 mBarrier.open();
120 return NO_ERROR;
121}
122
123status_t DisplayHardwareBase::DisplayEventThread::readyToRun()
124{
125 if (access(kSleepFileName, R_OK) || access(kWakeFileName, R_OK)) {
126 LOGE("Couldn't open %s or %s", kSleepFileName, kWakeFileName);
127 return NO_INIT;
128 }
129 return NO_ERROR;
130}
131
132status_t DisplayHardwareBase::DisplayEventThread::initCheck() const
133{
134 return (access(kSleepFileName, R_OK) == 0 &&
135 access(kWakeFileName, R_OK) == 0 &&
136 access(kFbconSysDir, F_OK) != 0) ? NO_ERROR : NO_INIT;
137}
138
139// ----------------------------------------------------------------------------
140
141pid_t DisplayHardwareBase::ConsoleManagerThread::sSignalCatcherPid = 0;
142
143DisplayHardwareBase::ConsoleManagerThread::ConsoleManagerThread(
144 const sp<SurfaceFlinger>& flinger)
145 : DisplayEventThreadBase(flinger), consoleFd(-1)
146{
147 sSignalCatcherPid = 0;
148
149 // create a new console
150 char const * const ttydev = "/dev/tty0";
151 int fd = open(ttydev, O_RDWR | O_SYNC);
152 if (fd<0) {
153 LOGE("Can't open %s", ttydev);
154 this->consoleFd = -errno;
155 return;
156 }
157
158 // to make sure that we are in text mode
159 int res = ioctl(fd, KDSETMODE, (void*) KD_TEXT);
160 if (res<0) {
161 LOGE("ioctl(%d, KDSETMODE, ...) failed, res %d (%s)",
162 fd, res, strerror(errno));
163 }
164
165 // get the current console
166 struct vt_stat vs;
167 res = ioctl(fd, VT_GETSTATE, &vs);
168 if (res<0) {
169 LOGE("ioctl(%d, VT_GETSTATE, ...) failed, res %d (%s)",
170 fd, res, strerror(errno));
171 this->consoleFd = -errno;
172 return;
173 }
174
175 // switch to console 7 (which is what X normaly uses)
176 int vtnum = 7;
177 do {
178 res = ioctl(fd, VT_ACTIVATE, (void*)vtnum);
179 } while(res < 0 && errno == EINTR);
180 if (res<0) {
181 LOGE("ioctl(%d, VT_ACTIVATE, ...) failed, %d (%s) for %d",
182 fd, errno, strerror(errno), vtnum);
183 this->consoleFd = -errno;
184 return;
185 }
186
187 do {
188 res = ioctl(fd, VT_WAITACTIVE, (void*)vtnum);
189 } while(res < 0 && errno == EINTR);
190 if (res<0) {
191 LOGE("ioctl(%d, VT_WAITACTIVE, ...) failed, %d %d %s for %d",
192 fd, res, errno, strerror(errno), vtnum);
193 this->consoleFd = -errno;
194 return;
195 }
196
197 // open the new console
198 close(fd);
199 fd = open(ttydev, O_RDWR | O_SYNC);
200 if (fd<0) {
201 LOGE("Can't open new console %s", ttydev);
202 this->consoleFd = -errno;
203 return;
204 }
205
206 /* disable console line buffer, echo, ... */
207 struct termios ttyarg;
208 ioctl(fd, TCGETS , &ttyarg);
209 ttyarg.c_iflag = 0;
210 ttyarg.c_lflag = 0;
211 ioctl(fd, TCSETS , &ttyarg);
212
213 // set up signals so we're notified when the console changes
214 // we can't use SIGUSR1 because it's used by the java-vm
215 vm.mode = VT_PROCESS;
216 vm.waitv = 0;
217 vm.relsig = SIGUSR2;
218 vm.acqsig = SIGUNUSED;
219 vm.frsig = 0;
220
221 struct sigaction act;
222 sigemptyset(&act.sa_mask);
223 act.sa_handler = sigHandler;
224 act.sa_flags = 0;
225 sigaction(vm.relsig, &act, NULL);
226
227 sigemptyset(&act.sa_mask);
228 act.sa_handler = sigHandler;
229 act.sa_flags = 0;
230 sigaction(vm.acqsig, &act, NULL);
231
232 sigset_t mask;
233 sigemptyset(&mask);
234 sigaddset(&mask, vm.relsig);
235 sigaddset(&mask, vm.acqsig);
236 sigprocmask(SIG_BLOCK, &mask, NULL);
237
238 // switch to graphic mode
239 res = ioctl(fd, KDSETMODE, (void*)KD_GRAPHICS);
240 LOGW_IF(res<0,
241 "ioctl(%d, KDSETMODE, KD_GRAPHICS) failed, res %d", fd, res);
242
243 this->prev_vt_num = vs.v_active;
244 this->vt_num = vtnum;
245 this->consoleFd = fd;
246}
247
248DisplayHardwareBase::ConsoleManagerThread::~ConsoleManagerThread()
249{
250 if (this->consoleFd >= 0) {
251 int fd = this->consoleFd;
252 int prev_vt_num = this->prev_vt_num;
253 int res;
254 ioctl(fd, KDSETMODE, (void*)KD_TEXT);
255 do {
256 res = ioctl(fd, VT_ACTIVATE, (void*)prev_vt_num);
257 } while(res < 0 && errno == EINTR);
258 do {
259 res = ioctl(fd, VT_WAITACTIVE, (void*)prev_vt_num);
260 } while(res < 0 && errno == EINTR);
261 close(fd);
262 char const * const ttydev = "/dev/tty0";
263 fd = open(ttydev, O_RDWR | O_SYNC);
264 ioctl(fd, VT_DISALLOCATE, 0);
265 close(fd);
266 }
267}
268
269status_t DisplayHardwareBase::ConsoleManagerThread::readyToRun()
270{
271 if (this->consoleFd >= 0) {
272 sSignalCatcherPid = gettid();
273
274 sigset_t mask;
275 sigemptyset(&mask);
276 sigaddset(&mask, vm.relsig);
277 sigaddset(&mask, vm.acqsig);
278 sigprocmask(SIG_BLOCK, &mask, NULL);
279
280 int res = ioctl(this->consoleFd, VT_SETMODE, &vm);
281 if (res<0) {
282 LOGE("ioctl(%d, VT_SETMODE, ...) failed, %d (%s)",
283 this->consoleFd, errno, strerror(errno));
284 }
285 return NO_ERROR;
286 }
287 return this->consoleFd;
288}
289
290void DisplayHardwareBase::ConsoleManagerThread::requestExit()
291{
292 Thread::requestExit();
293 if (sSignalCatcherPid != 0) {
294 // wake the thread up
295 kill(sSignalCatcherPid, SIGINT);
296 // wait for it...
297 }
298}
299
300void DisplayHardwareBase::ConsoleManagerThread::sigHandler(int sig)
301{
302 // resend the signal to our signal catcher thread
303 LOGW("received signal %d in thread %d, resending to %d",
304 sig, gettid(), sSignalCatcherPid);
305
306 // we absolutely need the delays below because without them
307 // our main thread never gets a chance to handle the signal.
308 usleep(10000);
309 kill(sSignalCatcherPid, sig);
310 usleep(10000);
311}
312
313status_t DisplayHardwareBase::ConsoleManagerThread::releaseScreen() const
314{
315 int fd = this->consoleFd;
316 int err = ioctl(fd, VT_RELDISP, (void*)1);
317 LOGE_IF(err<0, "ioctl(%d, VT_RELDISP, 1) failed %d (%s)",
318 fd, errno, strerror(errno));
319 return (err<0) ? (-errno) : status_t(NO_ERROR);
320}
321
322bool DisplayHardwareBase::ConsoleManagerThread::threadLoop()
323{
324 sigset_t mask;
325 sigemptyset(&mask);
326 sigaddset(&mask, vm.relsig);
327 sigaddset(&mask, vm.acqsig);
328
329 int sig = 0;
330 sigwait(&mask, &sig);
331
332 if (sig == vm.relsig) {
333 sp<SurfaceFlinger> flinger = mFlinger.promote();
334 //LOGD("About to give-up screen, flinger = %p", flinger.get());
335 if (flinger != 0)
336 flinger->screenReleased(0);
337 } else if (sig == vm.acqsig) {
338 sp<SurfaceFlinger> flinger = mFlinger.promote();
339 //LOGD("Screen about to return, flinger = %p", flinger.get());
340 if (flinger != 0)
341 flinger->screenAcquired(0);
342 }
343
344 return true;
345}
346
347status_t DisplayHardwareBase::ConsoleManagerThread::initCheck() const
348{
349 return consoleFd >= 0 ? NO_ERROR : NO_INIT;
350}
351
352// ----------------------------------------------------------------------------
353
354DisplayHardwareBase::DisplayHardwareBase(const sp<SurfaceFlinger>& flinger,
355 uint32_t displayIndex)
356 : mCanDraw(true)
357{
358 mDisplayEventThread = new DisplayEventThread(flinger);
359 if (mDisplayEventThread->initCheck() != NO_ERROR) {
360 // fall-back on the console
361 mDisplayEventThread = new ConsoleManagerThread(flinger);
362 }
363}
364
365DisplayHardwareBase::~DisplayHardwareBase()
366{
367 // request exit
368 mDisplayEventThread->requestExitAndWait();
369}
370
371
372bool DisplayHardwareBase::canDraw() const
373{
374 return mCanDraw;
375}
376
377void DisplayHardwareBase::releaseScreen() const
378{
379 status_t err = mDisplayEventThread->releaseScreen();
380 if (err >= 0) {
381 //LOGD("screen given-up");
382 mCanDraw = false;
383 }
384}
385
386void DisplayHardwareBase::acquireScreen() const
387{
388 status_t err = mDisplayEventThread->acquireScreen();
389 if (err >= 0) {
390 //LOGD("screen returned");
391 mCanDraw = true;
392 }
393}
394
395}; // namespace android