Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
michael@0 | 1 | /* Copyright 2013 Mozilla Foundation and Mozilla contributors |
michael@0 | 2 | * |
michael@0 | 3 | * Licensed under the Apache License, Version 2.0 (the "License"); |
michael@0 | 4 | * you may not use this file except in compliance with the License. |
michael@0 | 5 | * You may obtain a copy of the License at |
michael@0 | 6 | * |
michael@0 | 7 | * http://www.apache.org/licenses/LICENSE-2.0 |
michael@0 | 8 | * |
michael@0 | 9 | * Unless required by applicable law or agreed to in writing, software |
michael@0 | 10 | * distributed under the License is distributed on an "AS IS" BASIS, |
michael@0 | 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
michael@0 | 12 | * See the License for the specific language governing permissions and |
michael@0 | 13 | * limitations under the License. |
michael@0 | 14 | */ |
michael@0 | 15 | |
michael@0 | 16 | #include "GonkDisplayICS.h" |
michael@0 | 17 | #include <ui/FramebufferNativeWindow.h> |
michael@0 | 18 | |
michael@0 | 19 | #include <hardware/hardware.h> |
michael@0 | 20 | #include <hardware/gralloc.h> |
michael@0 | 21 | #include <hardware/hwcomposer.h> |
michael@0 | 22 | #include <hardware_legacy/power.h> |
michael@0 | 23 | #include <cutils/log.h> |
michael@0 | 24 | #include <fcntl.h> |
michael@0 | 25 | |
michael@0 | 26 | #include "mozilla/FileUtils.h" |
michael@0 | 27 | #include "mozilla/NullPtr.h" |
michael@0 | 28 | #include "mozilla/FileUtils.h" |
michael@0 | 29 | |
michael@0 | 30 | #include "BootAnimation.h" |
michael@0 | 31 | |
michael@0 | 32 | using namespace android; |
michael@0 | 33 | |
michael@0 | 34 | |
michael@0 | 35 | namespace { |
michael@0 | 36 | static const char* kSleepFile = "/sys/power/wait_for_fb_sleep"; |
michael@0 | 37 | static const char* kWakeFile = "/sys/power/wait_for_fb_wake"; |
michael@0 | 38 | static mozilla::GonkDisplay::OnEnabledCallbackType sEnabledCallback; |
michael@0 | 39 | static pthread_t sFramebufferWatchThread; |
michael@0 | 40 | |
michael@0 | 41 | static void * |
michael@0 | 42 | frameBufferWatcher(void *) |
michael@0 | 43 | { |
michael@0 | 44 | int len = 0; |
michael@0 | 45 | char buf; |
michael@0 | 46 | |
michael@0 | 47 | while (true) { |
michael@0 | 48 | // Cannot use epoll here because kSleepFile and kWakeFile are |
michael@0 | 49 | // always ready to read and blocking. |
michael@0 | 50 | { |
michael@0 | 51 | mozilla::ScopedClose fd(open(kSleepFile, O_RDONLY, 0)); |
michael@0 | 52 | do { |
michael@0 | 53 | len = read(fd.get(), &buf, 1); |
michael@0 | 54 | } while (len < 0 && errno == EINTR); |
michael@0 | 55 | NS_WARN_IF_FALSE(len >= 0, "WAIT_FOR_FB_SLEEP failed"); |
michael@0 | 56 | } |
michael@0 | 57 | sEnabledCallback(false); |
michael@0 | 58 | |
michael@0 | 59 | { |
michael@0 | 60 | mozilla::ScopedClose fd(open(kWakeFile, O_RDONLY, 0)); |
michael@0 | 61 | do { |
michael@0 | 62 | len = read(fd.get(), &buf, 1); |
michael@0 | 63 | } while (len < 0 && errno == EINTR); |
michael@0 | 64 | NS_WARN_IF_FALSE(len >= 0, "WAIT_FOR_FB_WAKE failed"); |
michael@0 | 65 | } |
michael@0 | 66 | sEnabledCallback(true); |
michael@0 | 67 | } |
michael@0 | 68 | |
michael@0 | 69 | return nullptr; |
michael@0 | 70 | } |
michael@0 | 71 | |
michael@0 | 72 | } // anonymous namespace |
michael@0 | 73 | |
michael@0 | 74 | |
michael@0 | 75 | namespace mozilla { |
michael@0 | 76 | |
michael@0 | 77 | static GonkDisplayICS* sGonkDisplay = nullptr; |
michael@0 | 78 | |
michael@0 | 79 | static int |
michael@0 | 80 | FramebufferNativeWindowCancelBufferNoop(ANativeWindow* aWindow, |
michael@0 | 81 | android_native_buffer_t* aBuffer) |
michael@0 | 82 | { |
michael@0 | 83 | return 0; |
michael@0 | 84 | } |
michael@0 | 85 | |
michael@0 | 86 | GonkDisplayICS::GonkDisplayICS() |
michael@0 | 87 | : mModule(nullptr) |
michael@0 | 88 | , mHwc(nullptr) |
michael@0 | 89 | { |
michael@0 | 90 | // Some gralloc HALs need this in order to open the |
michael@0 | 91 | // framebuffer device after we restart with the screen off. |
michael@0 | 92 | // |
michael@0 | 93 | // this *must* run BEFORE allocating the |
michael@0 | 94 | // FramebufferNativeWindow. |
michael@0 | 95 | set_screen_state(1); |
michael@0 | 96 | |
michael@0 | 97 | // For some devices, it takes a while for the framebuffer to become |
michael@0 | 98 | // usable. So we wait until the framebuffer has woken up before we |
michael@0 | 99 | // try to open it. |
michael@0 | 100 | { |
michael@0 | 101 | char buf; |
michael@0 | 102 | int len = 0; |
michael@0 | 103 | ScopedClose fd(open("/sys/power/wait_for_fb_wake", O_RDONLY, 0)); |
michael@0 | 104 | do { |
michael@0 | 105 | len = read(fd.get(), &buf, 1); |
michael@0 | 106 | } while (len < 0 && errno == EINTR); |
michael@0 | 107 | if (len < 0) { |
michael@0 | 108 | LOGE("BootAnimation: wait_for_fb_sleep failed errno: %d", errno); |
michael@0 | 109 | } |
michael@0 | 110 | } |
michael@0 | 111 | |
michael@0 | 112 | mFBSurface = new FramebufferNativeWindow(); |
michael@0 | 113 | |
michael@0 | 114 | // ICS FramebufferNativeWindow doesn't set the |cancelBuffer| |
michael@0 | 115 | // function pointer. |
michael@0 | 116 | // It will crash when deleting the EGL window surface. |
michael@0 | 117 | if (!mFBSurface->cancelBuffer) { |
michael@0 | 118 | mFBSurface->cancelBuffer = FramebufferNativeWindowCancelBufferNoop; |
michael@0 | 119 | } |
michael@0 | 120 | |
michael@0 | 121 | int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule); |
michael@0 | 122 | LOGW_IF(err, "%s module not found", HWC_HARDWARE_MODULE_ID); |
michael@0 | 123 | if (!err) { |
michael@0 | 124 | err = hwc_open(mModule, &mHwc); |
michael@0 | 125 | LOGE_IF(err, "%s device failed to initialize (%s)", |
michael@0 | 126 | HWC_HARDWARE_COMPOSER, strerror(-err)); |
michael@0 | 127 | } |
michael@0 | 128 | |
michael@0 | 129 | xdpi = mFBSurface->xdpi; |
michael@0 | 130 | |
michael@0 | 131 | const framebuffer_device_t *fbdev = mFBSurface->getDevice(); |
michael@0 | 132 | surfaceformat = fbdev->format; |
michael@0 | 133 | |
michael@0 | 134 | StartBootAnimation(); |
michael@0 | 135 | } |
michael@0 | 136 | |
michael@0 | 137 | GonkDisplayICS::~GonkDisplayICS() |
michael@0 | 138 | { |
michael@0 | 139 | if (mHwc) |
michael@0 | 140 | hwc_close(mHwc); |
michael@0 | 141 | } |
michael@0 | 142 | |
michael@0 | 143 | ANativeWindow* |
michael@0 | 144 | GonkDisplayICS::GetNativeWindow() |
michael@0 | 145 | { |
michael@0 | 146 | StopBootAnimation(); |
michael@0 | 147 | return static_cast<ANativeWindow *>(mFBSurface.get()); |
michael@0 | 148 | } |
michael@0 | 149 | |
michael@0 | 150 | void |
michael@0 | 151 | GonkDisplayICS::SetEnabled(bool enabled) |
michael@0 | 152 | { |
michael@0 | 153 | set_screen_state(enabled); |
michael@0 | 154 | } |
michael@0 | 155 | |
michael@0 | 156 | void |
michael@0 | 157 | GonkDisplayICS::OnEnabled(OnEnabledCallbackType callback) |
michael@0 | 158 | { |
michael@0 | 159 | if (sEnabledCallback) |
michael@0 | 160 | return; |
michael@0 | 161 | sEnabledCallback = callback; |
michael@0 | 162 | |
michael@0 | 163 | // Watching screen on/off state by using a pthread |
michael@0 | 164 | // which implicitly calls exit() when the main thread ends |
michael@0 | 165 | if (pthread_create(&sFramebufferWatchThread, NULL, frameBufferWatcher, NULL)) { |
michael@0 | 166 | NS_RUNTIMEABORT("Failed to create framebufferWatcherThread, aborting..."); |
michael@0 | 167 | } |
michael@0 | 168 | } |
michael@0 | 169 | |
michael@0 | 170 | |
michael@0 | 171 | void* |
michael@0 | 172 | GonkDisplayICS::GetHWCDevice() |
michael@0 | 173 | { |
michael@0 | 174 | return mHwc; |
michael@0 | 175 | } |
michael@0 | 176 | |
michael@0 | 177 | void* |
michael@0 | 178 | GonkDisplayICS::GetFBSurface() |
michael@0 | 179 | { |
michael@0 | 180 | return mFBSurface.get(); |
michael@0 | 181 | } |
michael@0 | 182 | |
michael@0 | 183 | bool |
michael@0 | 184 | GonkDisplayICS::SwapBuffers(EGLDisplay dpy, EGLSurface sur) |
michael@0 | 185 | { |
michael@0 | 186 | // Should be called when composition rendering is complete for a frame. |
michael@0 | 187 | // Only HWC v1.0 needs this call. ICS gonk always needs the call. |
michael@0 | 188 | mFBSurface->compositionComplete(); |
michael@0 | 189 | |
michael@0 | 190 | if (!mHwc) |
michael@0 | 191 | return eglSwapBuffers(dpy, sur); |
michael@0 | 192 | |
michael@0 | 193 | mHwc->prepare(mHwc, nullptr); |
michael@0 | 194 | return !mHwc->set(mHwc, dpy, sur, 0); |
michael@0 | 195 | } |
michael@0 | 196 | |
michael@0 | 197 | ANativeWindowBuffer* |
michael@0 | 198 | GonkDisplayICS::DequeueBuffer() |
michael@0 | 199 | { |
michael@0 | 200 | ANativeWindow *window = static_cast<ANativeWindow *>(mFBSurface.get()); |
michael@0 | 201 | ANativeWindowBuffer *buf = nullptr; |
michael@0 | 202 | window->dequeueBuffer(window, &buf); |
michael@0 | 203 | return buf; |
michael@0 | 204 | } |
michael@0 | 205 | |
michael@0 | 206 | bool |
michael@0 | 207 | GonkDisplayICS::QueueBuffer(ANativeWindowBuffer *buf) |
michael@0 | 208 | { |
michael@0 | 209 | ANativeWindow *window = static_cast<ANativeWindow *>(mFBSurface.get()); |
michael@0 | 210 | return !window->queueBuffer(window, buf); |
michael@0 | 211 | } |
michael@0 | 212 | |
michael@0 | 213 | void |
michael@0 | 214 | GonkDisplayICS::UpdateFBSurface(EGLDisplay dpy, EGLSurface sur) |
michael@0 | 215 | { |
michael@0 | 216 | eglSwapBuffers(dpy, sur); |
michael@0 | 217 | } |
michael@0 | 218 | |
michael@0 | 219 | void |
michael@0 | 220 | GonkDisplayICS::SetFBReleaseFd(int fd) |
michael@0 | 221 | { |
michael@0 | 222 | } |
michael@0 | 223 | |
michael@0 | 224 | __attribute__ ((visibility ("default"))) |
michael@0 | 225 | GonkDisplay* |
michael@0 | 226 | GetGonkDisplay() |
michael@0 | 227 | { |
michael@0 | 228 | if (!sGonkDisplay) |
michael@0 | 229 | sGonkDisplay = new GonkDisplayICS(); |
michael@0 | 230 | return sGonkDisplay; |
michael@0 | 231 | } |
michael@0 | 232 | |
michael@0 | 233 | } // namespace mozilla |