Merge "Fix display projection transforms" into jb-mr1-dev
diff --git a/include/private/gui/ComposerService.h b/include/private/gui/ComposerService.h
index c2761b8..ff2f9bf 100644
--- a/include/private/gui/ComposerService.h
+++ b/include/private/gui/ComposerService.h
@@ -33,13 +33,26 @@
 
 // ---------------------------------------------------------------------------
 
+// This holds our connection to the composer service (i.e. SurfaceFlinger).
+// If the remote side goes away, we will re-establish the connection.
+// Users of this class should not retain the value from
+// getComposerService() for an extended period.
+//
+// (It's not clear that using Singleton is useful here anymore.)
 class ComposerService : public Singleton<ComposerService>
 {
-    // these are constants
     sp<ISurfaceComposer> mComposerService;
+    sp<IBinder::DeathRecipient> mDeathObserver;
+    Mutex mLock;
+
     ComposerService();
+    void connectLocked();
+    void composerServiceDied();
     friend class Singleton<ComposerService>;
 public:
+
+    // Get a connection to the Composer Service.  This will block until
+    // a connection is established.
     static sp<ISurfaceComposer> getComposerService();
 };
 
diff --git a/include/private/ui/RegionHelper.h b/include/private/ui/RegionHelper.h
index 421bdda..8c190dd 100644
--- a/include/private/ui/RegionHelper.h
+++ b/include/private/ui/RegionHelper.h
@@ -26,10 +26,10 @@
 template<typename RECT>
 class region_operator
 {
+public:
     typedef typename RECT::value_type TYPE;    
     static const TYPE max_value = 0x7FFFFFF;
 
-public:
     /* 
      * Common boolean operations:
      * value is computed as 0b101 op 0b110
diff --git a/include/ui/Region.h b/include/ui/Region.h
index 0049fde..43a4450 100644
--- a/include/ui/Region.h
+++ b/include/ui/Region.h
@@ -161,7 +161,8 @@
     static void translate(Region& reg, int dx, int dy);
     static void translate(Region& dst, const Region& reg, int dx, int dy);
 
-    static bool validate(const Region& reg, const char* name);
+    static bool validate(const Region& reg,
+            const char* name, bool silent = false);
     
     // mStorage is a (manually) sorted array of Rects describing the region
     // with an extra Rect as the last element which is set to the
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 814036e..9b43ae8 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -46,14 +46,49 @@
 
 ComposerService::ComposerService()
 : Singleton<ComposerService>() {
+    Mutex::Autolock _l(mLock);
+    connectLocked();
+}
+
+void ComposerService::connectLocked() {
     const String16 name("SurfaceFlinger");
     while (getService(name, &mComposerService) != NO_ERROR) {
         usleep(250000);
     }
+    assert(mComposerService != NULL);
+
+    // Create the death listener.
+    class DeathObserver : public IBinder::DeathRecipient {
+        ComposerService& mComposerService;
+        virtual void binderDied(const wp<IBinder>& who) {
+            ALOGW("ComposerService remote (surfaceflinger) died [%p]",
+                  who.unsafe_get());
+            mComposerService.composerServiceDied();
+        }
+     public:
+        DeathObserver(ComposerService& mgr) : mComposerService(mgr) { }
+    };
+
+    mDeathObserver = new DeathObserver(*const_cast<ComposerService*>(this));
+    mComposerService->asBinder()->linkToDeath(mDeathObserver);
 }
 
-sp<ISurfaceComposer> ComposerService::getComposerService() {
-    return ComposerService::getInstance().mComposerService;
+/*static*/ sp<ISurfaceComposer> ComposerService::getComposerService() {
+    ComposerService& instance = ComposerService::getInstance();
+    Mutex::Autolock _l(instance.mLock);
+    if (instance.mComposerService == NULL) {
+        ComposerService::getInstance().connectLocked();
+        assert(instance.mComposerService != NULL);
+        ALOGD("ComposerService reconnected");
+    }
+    return instance.mComposerService;
+}
+
+void ComposerService::composerServiceDied()
+{
+    Mutex::Autolock _l(mLock);
+    mComposerService = NULL;
+    mDeathObserver = NULL;
 }
 
 // ---------------------------------------------------------------------------
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index e21b65d..36a2af7 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -478,6 +478,7 @@
             }
             glFlush();
             int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync);
+            eglDestroySyncKHR(dpy, sync);
             if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
                 ST_LOGE("syncForReleaseLocked: error dup'ing native fence "
                         "fd: %#x", eglGetError());
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 94fb1d5..932ef68 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -20,6 +20,7 @@
 
 #include <utils/Log.h>
 #include <utils/String8.h>
+#include <utils/CallStack.h>
 
 #include <ui/Rect.h>
 #include <ui/Region.h>
@@ -113,10 +114,6 @@
     Rect rect(l,t,r,b);
     size_t where = mStorage.size() - 1;
     mStorage.insertAt(rect, where, 1);
-
-#if VALIDATE_REGIONS
-    validate(*this, "addRectUnchecked");
-#endif
 }
 
 // ----------------------------------------------------------------------------
@@ -338,47 +335,72 @@
     }
 };
 
-bool Region::validate(const Region& reg, const char* name)
+bool Region::validate(const Region& reg, const char* name, bool silent)
 {
     bool result = true;
     const_iterator cur = reg.begin();
     const_iterator const tail = reg.end();
-    const_iterator prev = cur++;
+    const_iterator prev = cur;
     Rect b(*prev);
     while (cur != tail) {
-        b.left   = b.left   < cur->left   ? b.left   : cur->left;
-        b.top    = b.top    < cur->top    ? b.top    : cur->top;
-        b.right  = b.right  > cur->right  ? b.right  : cur->right;
-        b.bottom = b.bottom > cur->bottom ? b.bottom : cur->bottom;
-        if (cur->top == prev->top) {
-            if (cur->bottom != prev->bottom) {
-                ALOGE("%s: invalid span %p", name, cur);
+        if (cur->isValid() == false) {
+            ALOGE_IF(!silent, "%s: region contains an invalid Rect", name);
+            result = false;
+        }
+        if (cur->right > region_operator<Rect>::max_value) {
+            ALOGE_IF(!silent, "%s: rect->right > max_value", name);
+            result = false;
+        }
+        if (cur->bottom > region_operator<Rect>::max_value) {
+            ALOGE_IF(!silent, "%s: rect->right > max_value", name);
+            result = false;
+        }
+        if (prev != cur) {
+            b.left   = b.left   < cur->left   ? b.left   : cur->left;
+            b.top    = b.top    < cur->top    ? b.top    : cur->top;
+            b.right  = b.right  > cur->right  ? b.right  : cur->right;
+            b.bottom = b.bottom > cur->bottom ? b.bottom : cur->bottom;
+            if ((*prev < *cur) == false) {
+                ALOGE_IF(!silent, "%s: region's Rects not sorted", name);
                 result = false;
-            } else if (cur->left < prev->right) {
-                ALOGE("%s: spans overlap horizontally prev=%p, cur=%p",
+            }
+            if (cur->top == prev->top) {
+                if (cur->bottom != prev->bottom) {
+                    ALOGE_IF(!silent, "%s: invalid span %p", name, cur);
+                    result = false;
+                } else if (cur->left < prev->right) {
+                    ALOGE_IF(!silent,
+                            "%s: spans overlap horizontally prev=%p, cur=%p",
+                            name, prev, cur);
+                    result = false;
+                }
+            } else if (cur->top < prev->bottom) {
+                ALOGE_IF(!silent,
+                        "%s: spans overlap vertically prev=%p, cur=%p",
                         name, prev, cur);
                 result = false;
             }
-        } else if (cur->top < prev->bottom) {
-            ALOGE("%s: spans overlap vertically prev=%p, cur=%p",
-                    name, prev, cur);
-            result = false;
+            prev = cur;
         }
-        prev = cur;
         cur++;
     }
     if (b != reg.getBounds()) {
         result = false;
-        ALOGE("%s: invalid bounds [%d,%d,%d,%d] vs. [%d,%d,%d,%d]", name,
+        ALOGE_IF(!silent,
+                "%s: invalid bounds [%d,%d,%d,%d] vs. [%d,%d,%d,%d]", name,
                 b.left, b.top, b.right, b.bottom,
                 reg.getBounds().left, reg.getBounds().top, 
                 reg.getBounds().right, reg.getBounds().bottom);
     }
     if (reg.mStorage.size() == 2) {
-        ALOGE("mStorage size is 2, which is never valid");
+        result = false;
+        ALOGE_IF(!silent, "%s: mStorage size is 2, which is never valid", name);
     }
-    if (result == false) {
+    if (result == false && !silent) {
         reg.dump(name);
+        CallStack stack;
+        stack.update();
+        stack.dump("");
     }
     return result;
 }
@@ -564,27 +586,37 @@
 }
 
 status_t Region::flatten(void* buffer) const {
+#if VALIDATE_REGIONS
+    validate(*this, "Region::flatten");
+#endif
     Rect* rects = reinterpret_cast<Rect*>(buffer);
     memcpy(rects, mStorage.array(), mStorage.size() * sizeof(Rect));
     return NO_ERROR;
 }
 
 status_t Region::unflatten(void const* buffer, size_t size) {
-    mStorage.clear();
+    Region result;
     if (size >= sizeof(Rect)) {
         Rect const* rects = reinterpret_cast<Rect const*>(buffer);
         size_t count = size / sizeof(Rect);
         if (count > 0) {
-            ssize_t err = mStorage.insertAt(0, count);
+            result.mStorage.clear();
+            ssize_t err = result.mStorage.insertAt(0, count);
             if (err < 0) {
                 return status_t(err);
             }
-            memcpy(mStorage.editArray(), rects, count*sizeof(Rect));
+            memcpy(result.mStorage.editArray(), rects, count*sizeof(Rect));
         }
     }
 #if VALIDATE_REGIONS
-    validate(*this, "Region::unflatten");
+    validate(result, "Region::unflatten");
 #endif
+
+    if (!result.validate(result, "Region::unflatten", true)) {
+        ALOGE("Region::unflatten() failed, invalid region");
+        return BAD_VALUE;
+    }
+    mStorage = result.mStorage;
     return NO_ERROR;
 }
 
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index eea79f8..31bfcd7 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -57,6 +57,10 @@
   LOCAL_CFLAGS += -DMAX_EGL_CACHE_ENTRY_SIZE=$(MAX_EGL_CACHE_ENTRY_SIZE)
 endif
 
+ifneq ($(MAX_EGL_CACHE_KEY_SIZE),)
+  LOCAL_CFLAGS += -DMAX_EGL_CACHE_KEY_SIZE=$(MAX_EGL_CACHE_KEY_SIZE)
+endif
+
 ifneq ($(MAX_EGL_CACHE_SIZE),)
   LOCAL_CFLAGS += -DMAX_EGL_CACHE_SIZE=$(MAX_EGL_CACHE_SIZE)
 endif
diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp
index ed2bef3..72655df 100644
--- a/opengl/libs/EGL/egl_cache.cpp
+++ b/opengl/libs/EGL/egl_cache.cpp
@@ -29,12 +29,16 @@
 #define MAX_EGL_CACHE_ENTRY_SIZE (16 * 1024);
 #endif
 
+#ifndef MAX_EGL_CACHE_KEY_SIZE
+#define MAX_EGL_CACHE_KEY_SIZE (1024);
+#endif
+
 #ifndef MAX_EGL_CACHE_SIZE
 #define MAX_EGL_CACHE_SIZE (64 * 1024);
 #endif
 
 // Cache size limits.
-static const size_t maxKeySize = 1024;
+static const size_t maxKeySize = MAX_EGL_CACHE_KEY_SIZE;
 static const size_t maxValueSize = MAX_EGL_CACHE_ENTRY_SIZE;
 static const size_t maxTotalSize = MAX_EGL_CACHE_SIZE;
 
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index f85f604..5fba3f6 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -33,21 +33,12 @@
 #include <ui/GraphicBuffer.h>
 
 #include "DisplayHardware/FramebufferSurface.h"
+#include "DisplayHardware/HWComposer.h"
 
 // ----------------------------------------------------------------------------
 namespace android {
 // ----------------------------------------------------------------------------
 
-sp<FramebufferSurface> FramebufferSurface::create() {
-    sp<FramebufferSurface> result = new FramebufferSurface();
-    if (result->fbDev == NULL) {
-        result = NULL;
-    }
-    return result;
-}
-
-// ----------------------------------------------------------------------------
-
 class GraphicBufferAlloc : public BnGraphicBufferAlloc {
 public:
     GraphicBufferAlloc() { };
@@ -66,36 +57,21 @@
  *
  */
 
-FramebufferSurface::FramebufferSurface():
+FramebufferSurface::FramebufferSurface(HWComposer& hwc) :
     ConsumerBase(new BufferQueue(true, new GraphicBufferAlloc())),
-    fbDev(0),
     mCurrentBufferSlot(-1),
-    mCurrentBuffer(0)
+    mCurrentBuffer(0),
+    mHwc(hwc)
 {
-    hw_module_t const* module;
-
-    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
-        int stride;
-        int err;
-        int i;
-        err = framebuffer_open(module, &fbDev);
-        ALOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));
-
-        // bail out if we can't initialize the modules
-        if (!fbDev)
-            return;
-
-        mName = "FramebufferSurface";
-        mBufferQueue->setConsumerName(mName);
-        mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_FB |
-                GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER);
-        mBufferQueue->setDefaultBufferFormat(fbDev->format);
-        mBufferQueue->setDefaultBufferSize(fbDev->width, fbDev->height);
-        mBufferQueue->setSynchronousMode(true);
-        mBufferQueue->setDefaultMaxBufferCount(NUM_FRAME_BUFFERS);
-    } else {
-        ALOGE("Couldn't get gralloc module");
-    }
+    mName = "FramebufferSurface";
+    mBufferQueue->setConsumerName(mName);
+    mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_FB |
+                                       GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER);
+    mBufferQueue->setDefaultBufferFormat(mHwc.getFormat(HWC_DISPLAY_PRIMARY));
+    mBufferQueue->setDefaultBufferSize(mHwc.getResolutionX(HWC_DISPLAY_PRIMARY),
+                                       mHwc.getResolutionY(HWC_DISPLAY_PRIMARY));
+    mBufferQueue->setSynchronousMode(true);
+    mBufferQueue->setDefaultMaxBufferCount(NUM_FRAME_BUFFERS);
 }
 
 status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>* buffer) {
@@ -145,12 +121,7 @@
     return NO_ERROR;
 }
 
-FramebufferSurface::~FramebufferSurface() {
-    if (fbDev) {
-        framebuffer_close(fbDev);
-    }
-}
-
+// Overrides ConsumerBase::onFrameAvailable(), does not call base class impl.
 void FramebufferSurface::onFrameAvailable() {
     // XXX: The following code is here temporarily as part of the transition
     // away from the framebuffer HAL.
@@ -161,7 +132,7 @@
                 strerror(-err), err);
         return;
     }
-    err = fbDev->post(fbDev, buf->handle);
+    err = mHwc.fbPost(buf->handle);
     if (err != NO_ERROR) {
         ALOGE("error posting framebuffer: %d", err);
     }
@@ -181,19 +152,11 @@
 
 status_t FramebufferSurface::compositionComplete()
 {
-    if (fbDev->compositionComplete) {
-        return fbDev->compositionComplete(fbDev);
-    }
-    return INVALID_OPERATION;
+    return mHwc.fbCompositionComplete();
 }
 
 void FramebufferSurface::dump(String8& result) {
-    if (fbDev->common.version >= 1 && fbDev->dump) {
-        const size_t SIZE = 4096;
-        char buffer[SIZE];
-        fbDev->dump(fbDev, buffer, SIZE);
-        result.append(buffer);
-    }
+    mHwc.fbDump(result);
     ConsumerBase::dump(result);
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index bfa500b..fd7c520 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -30,13 +30,13 @@
 
 class Rect;
 class String8;
+class HWComposer;
 
 // ---------------------------------------------------------------------------
 
 class FramebufferSurface : public ConsumerBase {
 public:
-
-    static sp<FramebufferSurface> create();
+    FramebufferSurface(HWComposer& hwc);
 
     bool isUpdateOnDemand() const { return false; }
     status_t setUpdateRectangle(const Rect& updateRect);
@@ -49,22 +49,12 @@
     // BufferQueue.  The new buffer is returned in the 'buffer' argument.
     status_t nextBuffer(sp<GraphicBuffer>* buffer);
 
-    // FIXME: currently there are information we can only get from the
-    // FB HAL, and FB HAL can only be instantiated once on some devices.
-    // Eventually this functionality will have to move in HWC or somewhere else.
-    const framebuffer_device_t* getFbHal() const {
-        return fbDev;
-    }
-
 private:
-    FramebufferSurface();
-    virtual ~FramebufferSurface(); // this class cannot be overloaded
+    virtual ~FramebufferSurface() { }; // this class cannot be overloaded
 
     virtual void onFrameAvailable();
     virtual void freeBufferLocked(int slotIndex);
 
-    framebuffer_device_t* fbDev;
-
     // mCurrentBufferIndex is the slot index of the current buffer or
     // INVALID_BUFFER_SLOT to indicate that either there is no current buffer
     // or the buffer is not associated with a slot.
@@ -73,6 +63,9 @@
     // mCurrentBuffer is the current buffer or NULL to indicate that there is
     // no current buffer.
     sp<GraphicBuffer> mCurrentBuffer;
+
+    // Hardware composer, owned by SurfaceFlinger.
+    HWComposer& mHwc;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index dca27ba..992d067 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -90,10 +90,9 @@
 
 HWComposer::HWComposer(
         const sp<SurfaceFlinger>& flinger,
-        EventHandler& handler,
-        framebuffer_device_t const* fbDev)
+        EventHandler& handler)
     : mFlinger(flinger),
-      mModule(0), mHwc(0), mNumDisplays(1),
+      mFbDev(0), mHwc(0), mNumDisplays(1),
       mCBContext(new cb_context),
       mEventHandler(handler),
       mVSyncCount(0), mDebugForceFakeVSync(false)
@@ -107,71 +106,69 @@
     mDebugForceFakeVSync = atoi(value);
 
     bool needVSyncThread = true;
-    int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule);
-    ALOGW_IF(err, "%s module not found", HWC_HARDWARE_MODULE_ID);
-    if (err == 0) {
-        err = hwc_open_1(mModule, &mHwc);
-        ALOGE_IF(err, "%s device failed to initialize (%s)",
-                HWC_HARDWARE_COMPOSER, strerror(-err));
-        if (err == 0) {
-            if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_0) ||
-                    hwcHeaderVersion(mHwc) < MIN_HWC_HEADER_VERSION ||
-                    hwcHeaderVersion(mHwc) > HWC_HEADER_VERSION) {
-                ALOGE("%s device version %#x unsupported, will not be used",
-                        HWC_HARDWARE_COMPOSER, mHwc->common.version);
-                hwc_close_1(mHwc);
-                mHwc = NULL;
-            }
+
+    // Note: some devices may insist that the FB HAL be opened before HWC.
+    loadFbHalModule();
+    loadHwcModule();
+
+    // If we have no HWC, or a pre-1.1 HWC, an FB dev is mandatory.
+    if ((!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
+            && !mFbDev) {
+        ALOGE("ERROR: failed to open framebuffer, aborting");
+        abort();
+    }
+
+    if (mHwc) {
+        ALOGI("Using %s version %u.%u", HWC_HARDWARE_COMPOSER,
+              (hwcApiVersion(mHwc) >> 24) & 0xff,
+              (hwcApiVersion(mHwc) >> 16) & 0xff);
+        if (mHwc->registerProcs) {
+            mCBContext->hwc = this;
+            mCBContext->procs.invalidate = &hook_invalidate;
+            mCBContext->procs.vsync = &hook_vsync;
+            if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
+                mCBContext->procs.hotplug = &hook_hotplug;
+            else
+                mCBContext->procs.hotplug = NULL;
+            memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero));
+            mHwc->registerProcs(mHwc, &mCBContext->procs);
         }
 
-        if (mHwc) {
-            ALOGI("Using %s version %u.%u", HWC_HARDWARE_COMPOSER,
-                    (hwcApiVersion(mHwc) >> 24) & 0xff,
-                    (hwcApiVersion(mHwc) >> 16) & 0xff);
-            if (mHwc->registerProcs) {
-                mCBContext->hwc = this;
-                mCBContext->procs.invalidate = &hook_invalidate;
-                mCBContext->procs.vsync = &hook_vsync;
-                if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
-                    mCBContext->procs.hotplug = &hook_hotplug;
-                else
-                    mCBContext->procs.hotplug = NULL;
-                memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero));
-                mHwc->registerProcs(mHwc, &mCBContext->procs);
-            }
+        // don't need a vsync thread if we have a hardware composer
+        needVSyncThread = false;
+        // always turn vsync off when we start
+        mHwc->eventControl(mHwc, HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);
 
-            // always turn vsync off when we start
-            needVSyncThread = false;
-            mHwc->eventControl(mHwc, HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);
+        // these IDs are always reserved
+        for (size_t i=0 ; i<HWC_NUM_DISPLAY_TYPES ; i++) {
+            mAllocatedDisplayIDs.markBit(i);
+        }
 
-            // these IDs are always reserved
-            for (size_t i=0 ; i<HWC_NUM_DISPLAY_TYPES ; i++) {
-                mAllocatedDisplayIDs.markBit(i);
-            }
-
-            // the number of displays we actually have depends on the
-            // hw composer version
-            if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_2)) {
-                // 1.2 adds support for virtual displays
-                mNumDisplays = MAX_DISPLAYS;
-            } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
-                // 1.1 adds support for multiple displays
-                mNumDisplays = HWC_NUM_DISPLAY_TYPES;
-            } else {
-                mNumDisplays = 1;
-            }
+        // the number of displays we actually have depends on the
+        // hw composer version
+        if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_2)) {
+            // 1.2 adds support for virtual displays
+            mNumDisplays = MAX_DISPLAYS;
+        } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+            // 1.1 adds support for multiple displays
+            mNumDisplays = HWC_NUM_DISPLAY_TYPES;
+        } else {
+            mNumDisplays = 1;
         }
     }
 
-    if (fbDev) {
+    if (mFbDev) {
         ALOG_ASSERT(!(mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)),
                 "should only have fbdev if no hwc or hwc is 1.0");
 
         DisplayData& disp(mDisplayData[HWC_DISPLAY_PRIMARY]);
-        disp.xdpi = fbDev->xdpi;
-        disp.ydpi = fbDev->ydpi;
+        disp.xres = mFbDev->width;
+        disp.yres = mFbDev->height;
+        disp.format = mFbDev->format;
+        disp.xdpi = mFbDev->xdpi;
+        disp.ydpi = mFbDev->ydpi;
         if (disp.refresh == 0) {
-            disp.refresh = nsecs_t(1e9 / fbDev->fps);
+            disp.refresh = nsecs_t(1e9 / mFbDev->fps);
             ALOGW("getting VSYNC period from fb HAL: %lld", disp.refresh);
         }
         if (disp.refresh == 0) {
@@ -190,16 +187,66 @@
 }
 
 HWComposer::~HWComposer() {
-    mHwc->eventControl(mHwc, 0, EVENT_VSYNC, 0);
+    if (mHwc) {
+        mHwc->eventControl(mHwc, 0, EVENT_VSYNC, 0);
+    }
     if (mVSyncThread != NULL) {
         mVSyncThread->requestExitAndWait();
     }
     if (mHwc) {
         hwc_close_1(mHwc);
     }
+    if (mFbDev) {
+        framebuffer_close(mFbDev);
+    }
     delete mCBContext;
 }
 
+// Load and prepare the hardware composer module.  Sets mHwc.
+void HWComposer::loadHwcModule()
+{
+    hw_module_t const* module;
+
+    if (hw_get_module(HWC_HARDWARE_MODULE_ID, &module) != 0) {
+        ALOGE("%s module not found", HWC_HARDWARE_MODULE_ID);
+        return;
+    }
+
+    int err = hwc_open_1(module, &mHwc);
+    if (err) {
+        ALOGE("%s device failed to initialize (%s)",
+              HWC_HARDWARE_COMPOSER, strerror(-err));
+        return;
+    }
+
+    if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_0) ||
+            hwcHeaderVersion(mHwc) < MIN_HWC_HEADER_VERSION ||
+            hwcHeaderVersion(mHwc) > HWC_HEADER_VERSION) {
+        ALOGE("%s device version %#x unsupported, will not be used",
+              HWC_HARDWARE_COMPOSER, mHwc->common.version);
+        hwc_close_1(mHwc);
+        mHwc = NULL;
+        return;
+    }
+}
+
+// Load and prepare the FB HAL, which uses the gralloc module.  Sets mFbDev.
+void HWComposer::loadFbHalModule()
+{
+    hw_module_t const* module;
+
+    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) != 0) {
+        ALOGE("%s module not found", GRALLOC_HARDWARE_MODULE_ID);
+        return;
+    }
+
+    int err = framebuffer_open(module, &mFbDev);
+    if (err) {
+        ALOGE("framebuffer_open failed (%s)", strerror(-err));
+        return;
+    }
+}
+
 status_t HWComposer::initCheck() const {
     return mHwc ? NO_ERROR : NO_INIT;
 }
@@ -265,6 +312,7 @@
 void HWComposer::queryDisplayProperties(int disp) {
     ALOG_ASSERT(mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1));
 
+    // use zero as default value for unspecified attributes
     int32_t values[NUM_DISPLAY_ATTRIBUTES - 1];
     memset(values, 0, sizeof(values));
 
@@ -283,12 +331,10 @@
             mDisplayData[disp].refresh = nsecs_t(values[i]);
             break;
         case HWC_DISPLAY_RESOLUTION_X:
-            // TODO: we'll probably want to remember this eventually
-            w = values[i];
+            mDisplayData[disp].xres = values[i];
             break;
         case HWC_DISPLAY_RESOLUTION_Y:
-            // TODO: we'll probably want to remember this eventually
-            h = values[i];
+            mDisplayData[disp].yres = values[i];
             break;
         case HWC_DISPLAY_DPI_X:
             mDisplayData[disp].xdpi = values[i] / 1000.0f;
@@ -336,25 +382,37 @@
     return NO_ERROR;
 }
 
-nsecs_t HWComposer::getRefreshPeriod() const {
-    return mDisplayData[HWC_DISPLAY_PRIMARY].refresh;
+nsecs_t HWComposer::getRefreshPeriod(int disp) const {
+    return mDisplayData[disp].refresh;
 }
 
-nsecs_t HWComposer::getRefreshTimestamp() const {
+nsecs_t HWComposer::getRefreshTimestamp(int disp) const {
     // this returns the last refresh timestamp.
     // if the last one is not available, we estimate it based on
     // the refresh period and whatever closest timestamp we have.
     Mutex::Autolock _l(mLock);
     nsecs_t now = systemTime(CLOCK_MONOTONIC);
-    return now - ((now - mLastHwVSync) %  mDisplayData[HWC_DISPLAY_PRIMARY].refresh);
+    return now - ((now - mLastHwVSync) %  mDisplayData[disp].refresh);
 }
 
-float HWComposer::getDpiX() const {
-    return mDisplayData[HWC_DISPLAY_PRIMARY].xdpi;
+uint32_t HWComposer::getResolutionX(int disp) const {
+    return mDisplayData[disp].xres;
 }
 
-float HWComposer::getDpiY() const {
-    return mDisplayData[HWC_DISPLAY_PRIMARY].ydpi;
+uint32_t HWComposer::getResolutionY(int disp) const {
+    return mDisplayData[disp].yres;
+}
+
+uint32_t HWComposer::getFormat(int disp) const {
+    return mDisplayData[disp].format;
+}
+
+float HWComposer::getDpiX(int disp) const {
+    return mDisplayData[disp].xdpi;
+}
+
+float HWComposer::getDpiY(int disp) const {
+    return mDisplayData[disp].ydpi;
 }
 
 void HWComposer::eventControl(int event, int enabled) {
@@ -493,6 +551,30 @@
             mDisplayData[id].list->numHwLayers : 0;
 }
 
+int HWComposer::fbPost(buffer_handle_t buffer)
+{
+    return mFbDev->post(mFbDev, buffer);
+}
+
+int HWComposer::fbCompositionComplete()
+{
+    if (mFbDev->compositionComplete) {
+        return mFbDev->compositionComplete(mFbDev);
+    } else {
+        return INVALID_OPERATION;
+    }
+}
+
+void HWComposer::fbDump(String8& result) {
+    if (mFbDev->common.version >= 1 && mFbDev->dump) {
+        const size_t SIZE = 4096;
+        char buffer[SIZE];
+        mFbDev->dump(mFbDev, buffer, SIZE);
+        result.append(buffer);
+    }
+}
+
+
 /*
  * Helper template to implement a concrete HWCLayer
  * This holds the pointer to the concrete hwc layer type
@@ -680,7 +762,7 @@
 HWComposer::VSyncThread::VSyncThread(HWComposer& hwc)
     : mHwc(hwc), mEnabled(false),
       mNextFakeVSync(0),
-      mRefreshPeriod(hwc.getRefreshPeriod())
+      mRefreshPeriod(hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY))
 {
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index a49a023..4c520b1 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -64,8 +64,7 @@
 
     HWComposer(
             const sp<SurfaceFlinger>& flinger,
-            EventHandler& handler,
-            framebuffer_device_t const* fbDev);
+            EventHandler& handler);
 
     ~HWComposer();
 
@@ -107,6 +106,11 @@
     // needed forward declarations
     class LayerListIterator;
 
+    // Forwarding to FB HAL for pre-HWC-1.1 code (see FramebufferSurface).
+    int fbPost(buffer_handle_t buffer);
+    int fbCompositionComplete();
+    void fbDump(String8& result);
+
     /*
      * Interface to hardware composer's layers functionality.
      * This abstracts the HAL interface to layers which can evolve in
@@ -208,10 +212,15 @@
 
     void eventControl(int event, int enabled);
 
-    nsecs_t getRefreshPeriod() const;
-    nsecs_t getRefreshTimestamp() const;
-    float getDpiX() const;
-    float getDpiY() const;
+    // Query display parameters.  Pass in a display index (e.g.
+    // HWC_DISPLAY_PRIMARY).
+    nsecs_t getRefreshPeriod(int disp) const;
+    nsecs_t getRefreshTimestamp(int disp) const;
+    uint32_t getResolutionX(int disp) const;
+    uint32_t getResolutionY(int disp) const;
+    uint32_t getFormat(int disp) const;
+    float getDpiX(int disp) const;
+    float getDpiY(int disp) const;
 
     // this class is only used to fake the VSync event on systems that don't
     // have it.
@@ -236,6 +245,8 @@
             const Vector< sp<LayerBase> >& visibleLayersSortedByZ) const;
 
 private:
+    void loadHwcModule();
+    void loadFbHalModule();
 
     LayerListIterator getLayerIterator(int32_t id, size_t index);
     size_t getNumLayers(int32_t id) const;
@@ -261,6 +272,9 @@
         ~DisplayData() {
             free(list);
         }
+        uint32_t xres;
+        uint32_t yres;
+        uint32_t format;    // pixel format from FB hal, for pre-hwc-1.1
         float xdpi;
         float ydpi;
         nsecs_t refresh;
@@ -271,7 +285,7 @@
     };
 
     sp<SurfaceFlinger>              mFlinger;
-    hw_module_t const*              mModule;
+    framebuffer_device_t*           mFbDev;
     struct hwc_composer_device_1*   mHwc;
     // invariant: mLists[0] != NULL iff mHwc != NULL
     // mLists[i>0] can be NULL. that display is to be ignored
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index e78059d..75eff9f 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -515,7 +515,7 @@
         const size_t offset = mFrameLatencyOffset;
         mFrameStats[offset].timestamp = mSurfaceTexture->getTimestamp();
         mFrameStats[offset].set = systemTime();
-        mFrameStats[offset].vsync = hwc.getRefreshTimestamp();
+        mFrameStats[offset].vsync = hwc.getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
         mFrameLatencyOffset = (mFrameLatencyOffset + 1) % 128;
         mFrameLatencyNeeded = false;
     }
@@ -726,7 +726,8 @@
 {
     LayerBaseClient::dumpStats(result, buffer, SIZE);
     const size_t o = mFrameLatencyOffset;
-    const nsecs_t period = mFlinger->getHwComposer().getRefreshPeriod();
+    const nsecs_t period =
+            mFlinger->getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
     result.appendFormat("%lld\n", period);
     for (size_t i=0 ; i<128 ; i++) {
         const size_t index = (o+i) % 128;
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 311d95f..b61770c 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -439,7 +439,7 @@
             "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), "
             "isOpaque=%1d, needsDithering=%1d, invalidate=%1d, "
             "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
-            s.z, s.layerStack, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h,
+            s.layerStack, s.z, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h,
             s.active.crop.left, s.active.crop.top,
             s.active.crop.right, s.active.crop.bottom,
             isOpaque(), needsDithering(), contentDirty,
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ef910d9..6542acd 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -366,13 +366,18 @@
     ALOGI(  "SurfaceFlinger's main thread ready to run. "
             "Initializing graphics H/W...");
 
-    // initialize EGL
+    // initialize EGL for the default display
     mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     eglInitialize(mEGLDisplay, NULL, NULL);
 
+    // Initialize the H/W composer object.  There may or may not be an
+    // actual hardware composer underneath.
+    mHwc = new HWComposer(this,
+            *static_cast<HWComposer::EventHandler *>(this));
+
     // Initialize the main display
     // create native window to main display
-    sp<FramebufferSurface> fbs = FramebufferSurface::create();
+    sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc);
     if (fbs == NULL) {
         ALOGE("Display subsystem failed to initialize. check logs. exiting...");
         exit(0);
@@ -408,11 +413,6 @@
     mEventThread = new EventThread(this);
     mEventQueue.setEventThread(mEventThread);
 
-    // initialize the H/W composer
-    mHwc = new HWComposer(this,
-            *static_cast<HWComposer::EventHandler *>(this),
-            fbs->getFbHal());
-
     // initialize our drawing state
     mDrawingState = mCurrentState;
 
@@ -500,8 +500,8 @@
     }
 
     const HWComposer& hwc(getHwComposer());
-    float xdpi = hwc.getDpiX();
-    float ydpi = hwc.getDpiY();
+    float xdpi = hwc.getDpiX(HWC_DISPLAY_PRIMARY);
+    float ydpi = hwc.getDpiY(HWC_DISPLAY_PRIMARY);
 
     // TODO: Not sure if display density should handled by SF any longer
     class Density {
@@ -538,7 +538,7 @@
     info->h = hw->getHeight();
     info->xdpi = xdpi;
     info->ydpi = ydpi;
-    info->fps = float(1e9 / hwc.getRefreshPeriod());
+    info->fps = float(1e9 / hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY));
     info->density = density;
     info->orientation = hw->getOrientation();
     // TODO: this needs to go away (currently needed only by webkit)
@@ -618,6 +618,13 @@
 }
 
 void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {
+    if (mEventThread == NULL) {
+        // This is a temporary workaround for b/7145521.  A non-null pointer
+        // does not mean EventThread has finished initializing, so this
+        // is not a correct fix.
+        ALOGW("WARNING: EventThread not started, ignoring vsync");
+        return;
+    }
     if (uint32_t(type) < DisplayDevice::NUM_DISPLAY_TYPES) {
         // we should only receive DisplayDevice::DisplayType from the vsync callback
         const wp<IBinder>& token(mDefaultDisplays[type]);
@@ -746,27 +753,29 @@
         ATRACE_CALL();
         mVisibleRegionsDirty = false;
         invalidateHwcGeometry();
+
         const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
         for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+            Region opaqueRegion;
+            Region dirtyRegion;
+            Vector< sp<LayerBase> > layersSortedByZ;
             const sp<DisplayDevice>& hw(mDisplays[dpy]);
             const Transform& tr(hw->getTransform());
             const Rect bounds(hw->getBounds());
+            if (hw->canDraw()) {
+                SurfaceFlinger::computeVisibleRegions(currentLayers,
+                        hw->getLayerStack(), dirtyRegion, opaqueRegion);
 
-            Region opaqueRegion;
-            Region dirtyRegion;
-            computeVisibleRegions(currentLayers,
-                    hw->getLayerStack(), dirtyRegion, opaqueRegion);
-
-            Vector< sp<LayerBase> > layersSortedByZ;
-            const size_t count = currentLayers.size();
-            for (size_t i=0 ; i<count ; i++) {
-                const sp<LayerBase>& layer(currentLayers[i]);
-                const Layer::State& s(layer->drawingState());
-                if (s.layerStack == hw->getLayerStack()) {
-                    Region visibleRegion(tr.transform(layer->visibleRegion));
-                    visibleRegion.andSelf(bounds);
-                    if (!visibleRegion.isEmpty()) {
-                        layersSortedByZ.add(layer);
+                const size_t count = currentLayers.size();
+                for (size_t i=0 ; i<count ; i++) {
+                    const sp<LayerBase>& layer(currentLayers[i]);
+                    const Layer::State& s(layer->drawingState());
+                    if (s.layerStack == hw->getLayerStack()) {
+                        Region visibleRegion(tr.transform(layer->visibleRegion));
+                        visibleRegion.andSelf(bounds);
+                        if (!visibleRegion.isEmpty()) {
+                            layersSortedByZ.add(layer);
+                        }
                     }
                 }
             }
@@ -1769,6 +1778,7 @@
         mEventThread->onScreenReleased();
         hw->releaseScreen();
         getHwComposer().release();
+        mVisibleRegionsDirty = true;
         // from this point on, SF will stop drawing
     }
 }
@@ -2018,9 +2028,9 @@
             mLastSwapBufferTime/1000.0,
             mLastTransactionTime/1000.0,
             mTransactionFlags,
-            1e9 / hwc.getRefreshPeriod(),
-            hwc.getDpiX(),
-            hwc.getDpiY());
+            1e9 / hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY),
+            hwc.getDpiX(HWC_DISPLAY_PRIMARY),
+            hwc.getDpiY(HWC_DISPLAY_PRIMARY));
     result.append(buffer);
 
     snprintf(buffer, SIZE, "  eglSwapBuffers time: %f us\n",
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index ea03e2d..ffe68c6 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -351,8 +351,8 @@
      * Compositing
      */
     void invalidateHwcGeometry();
-    void computeVisibleRegions(const LayerVector& currentLayers,
-            uint32_t layerStack,
+    static void computeVisibleRegions(
+            const LayerVector& currentLayers, uint32_t layerStack,
             Region& dirtyRegion, Region& opaqueRegion);
 
     void preComposition();