SurfaceFlinger: add animation transactions

This change adds a transaction flag for WindowManager to indicate that a
transaction is being used to animate windows around the screen.  SurfaceFlinger
will not allow more than one of these transactions to be outstanding at a time
to prevent the animation "frames" from being dropped.

Bug: 7353840
Change-Id: I6488a6e0e1ed13d27356d2203c9dc766dc6b1759
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index 5d2d8d7..002aafc 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -46,6 +46,7 @@
     // flags for setTransactionState()
     enum {
         eSynchronous = 0x01,
+        eAnimation   = 0x02,
     };
 
     enum {
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index 581ec8d..21d16a9 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -101,10 +101,13 @@
 
     //! Open a composer transaction on all active SurfaceComposerClients.
     static void openGlobalTransaction();
-        
+
     //! Close a composer transaction on all active SurfaceComposerClients.
     static void closeGlobalTransaction(bool synchronous = false);
 
+    //! Flag the currently open transaction as an animation transaction.
+    static void setAnimationTransaction();
+
     status_t    hide(SurfaceID id);
     status_t    show(SurfaceID id);
     status_t    setFlags(SurfaceID id, uint32_t flags, uint32_t mask);
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 3efd086..8586ed2 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -115,12 +115,15 @@
     SortedVector<ComposerState> mComposerStates;
     SortedVector<DisplayState > mDisplayStates;
     uint32_t                    mForceSynchronous;
+    bool                        mAnimation;
 
     Composer() : Singleton<Composer>(),
-        mForceSynchronous(0)
+        mForceSynchronous(0),
+        mAnimation(false)
     { }
 
     void closeGlobalTransactionImpl(bool synchronous);
+    void setAnimationTransactionImpl();
 
     layer_state_t* getLayerStateLocked(
             const sp<SurfaceComposerClient>& client, SurfaceID id);
@@ -159,6 +162,10 @@
             const Rect& layerStackRect,
             const Rect& displayRect);
 
+    static void setAnimationTransaction() {
+        Composer::getInstance().setAnimationTransactionImpl();
+    }
+
     static void closeGlobalTransaction(bool synchronous) {
         Composer::getInstance().closeGlobalTransactionImpl(synchronous);
     }
@@ -194,12 +201,22 @@
         if (synchronous || mForceSynchronous) {
             flags |= ISurfaceComposer::eSynchronous;
         }
+        if (mAnimation) {
+            flags |= ISurfaceComposer::eAnimation;
+        }
+
         mForceSynchronous = false;
+        mAnimation = false;
     }
 
    sm->setTransactionState(transaction, displayTransaction, flags);
 }
 
+void Composer::setAnimationTransactionImpl() {
+    Mutex::Autolock _l(mLock);
+    mAnimation = true;
+}
+
 layer_state_t* Composer::getLayerStateLocked(
         const sp<SurfaceComposerClient>& client, SurfaceID id) {
 
@@ -471,6 +488,10 @@
     Composer::closeGlobalTransaction(synchronous);
 }
 
+void SurfaceComposerClient::setAnimationTransaction() {
+    Composer::setAnimationTransaction();
+}
+
 // ----------------------------------------------------------------------------
 
 status_t SurfaceComposerClient::setCrop(SurfaceID id, const Rect& crop) {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 492d1cf..e21e2bf 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -86,7 +86,8 @@
 SurfaceFlinger::SurfaceFlinger()
     :   BnSurfaceComposer(), Thread(false),
         mTransactionFlags(0),
-        mTransationPending(false),
+        mTransactionPending(false),
+        mAnimTransactionPending(false),
         mLayersRemoved(false),
         mRepaintEverything(0),
         mBootTime(systemTime()),
@@ -1264,7 +1265,8 @@
     }
 
     mDrawingState = mCurrentState;
-    mTransationPending = false;
+    mTransactionPending = false;
+    mAnimTransactionPending = false;
     mTransactionCV.broadcast();
 }
 
@@ -1665,6 +1667,21 @@
     Mutex::Autolock _l(mStateLock);
     uint32_t transactionFlags = 0;
 
+    if (flags & eAnimation) {
+        // For window updates that are part of an animation we must wait for
+        // previous animation "frames" to be handled.
+        while (mAnimTransactionPending) {
+            status_t err = mTransactionCV.waitRelative(mStateLock, 500 * 1000);
+            if (CC_UNLIKELY(err != NO_ERROR)) {
+                // just in case something goes wrong in SF, return to the
+                // caller after a few hundred microseconds.
+                ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!");
+                mAnimTransactionPending = false;
+                break;
+            }
+        }
+    }
+
     size_t count = displays.size();
     for (size_t i=0 ; i<count ; i++) {
         const DisplayState& s(displays[i]);
@@ -1685,15 +1702,18 @@
         // if this is a synchronous transaction, wait for it to take effect
         // before returning.
         if (flags & eSynchronous) {
-            mTransationPending = true;
+            mTransactionPending = true;
         }
-        while (mTransationPending) {
+        if (flags & eAnimation) {
+            mAnimTransactionPending = true;
+        }
+        while (mTransactionPending) {
             status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
             if (CC_UNLIKELY(err != NO_ERROR)) {
                 // just in case something goes wrong in SF, return to the
                 // called after a few seconds.
-                ALOGW_IF(err == TIMED_OUT, "closeGlobalTransaction timed out!");
-                mTransationPending = false;
+                ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!");
+                mTransactionPending = false;
                 break;
             }
         }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 6d36719..efe34af 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -398,7 +398,8 @@
     volatile int32_t mTransactionFlags;
     Condition mTransactionCV;
     SortedVector<sp<LayerBase> > mLayerPurgatory;
-    bool mTransationPending;
+    bool mTransactionPending;
+    bool mAnimTransactionPending;
     Vector<sp<LayerBase> > mLayersPendingRemoval;
 
     // protected by mStateLock (but we could use another lock)