surfaceflinger: make vsync injection more robust

There are more issues than I expected :)

 - no lock to synchronize enable/disable and injection
 - Every time injection is diabled and enabled, a new EventThread is
   created
 - mCallback might be nullptr
 - ENABLE_VSYNC_INJECTIONS/INJECT_VSYNC should require special
   permission
 - MessageQueue::setEventThread must be called from the main thread
 - MessageQueue::setEventThread does not handle EventThread switch
   well

Bug: 65483324
Test: manual
Change-Id: I7d7b98d1f57afc64af0f2065a9bc7c8ad004ca9f
diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp
index bca3430..0b1199c 100644
--- a/services/surfaceflinger/MessageQueue.cpp
+++ b/services/surfaceflinger/MessageQueue.cpp
@@ -91,6 +91,14 @@
 
 void MessageQueue::setEventThread(const sp<EventThread>& eventThread)
 {
+    if (mEventThread == eventThread) {
+        return;
+    }
+
+    if (mEventTube.getFd() >= 0) {
+        mLooper->removeFd(mEventTube.getFd());
+    }
+
     mEventThread = eventThread;
     mEvents = eventThread->createEventConnection();
     mEvents->stealReceiveChannel(&mEventTube);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 54c040d..05c76fc 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -570,7 +570,9 @@
 
     virtual void onInjectSyncEvent(nsecs_t when) {
         std::lock_guard<std::mutex> lock(mCallbackMutex);
-        mCallback->onVSyncEvent(when);
+        if (mCallback) {
+            mCallback->onVSyncEvent(when);
+        }
     }
 
     virtual void setVSyncEnabled(bool) {}
@@ -1066,28 +1068,34 @@
 }
 
 status_t SurfaceFlinger::enableVSyncInjections(bool enable) {
-    if (enable == mInjectVSyncs) {
-        return NO_ERROR;
-    }
+    sp<LambdaMessage> enableVSyncInjections = new LambdaMessage([&]() {
+        Mutex::Autolock _l(mStateLock);
 
-    if (enable) {
-        mInjectVSyncs = enable;
-        ALOGV("VSync Injections enabled");
-        if (mVSyncInjector.get() == nullptr) {
-            mVSyncInjector = new InjectVSyncSource();
-            mInjectorEventThread = new EventThread(mVSyncInjector, *this, false);
+        if (mInjectVSyncs == enable) {
+            return;
         }
-        mEventQueue.setEventThread(mInjectorEventThread);
-    } else {
+
+        if (enable) {
+            ALOGV("VSync Injections enabled");
+            if (mVSyncInjector.get() == nullptr) {
+                mVSyncInjector = new InjectVSyncSource();
+                mInjectorEventThread = new EventThread(mVSyncInjector, *this, false);
+            }
+            mEventQueue.setEventThread(mInjectorEventThread);
+        } else {
+            ALOGV("VSync Injections disabled");
+            mEventQueue.setEventThread(mSFEventThread);
+        }
+
         mInjectVSyncs = enable;
-        ALOGV("VSync Injections disabled");
-        mEventQueue.setEventThread(mSFEventThread);
-        mVSyncInjector.clear();
-    }
+    });
+    postMessageSync(enableVSyncInjections);
     return NO_ERROR;
 }
 
 status_t SurfaceFlinger::injectVSync(nsecs_t when) {
+    Mutex::Autolock _l(mStateLock);
+
     if (!mInjectVSyncs) {
         ALOGE("VSync Injections not enabled");
         return BAD_VALUE;
@@ -3983,6 +3991,8 @@
         case GET_ANIMATION_FRAME_STATS:
         case SET_POWER_MODE:
         case GET_HDR_CAPABILITIES:
+        case ENABLE_VSYNC_INJECTIONS:
+        case INJECT_VSYNC:
         {
             // codes that require permission check
             IPCThreadState* ipc = IPCThreadState::self();