Merge "Lookup layer handle when registering region sampling listener" into rvc-dev
diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp
index dbd4ef9..6746b0a 100644
--- a/libs/gui/tests/RegionSampling_test.cpp
+++ b/libs/gui/tests/RegionSampling_test.cpp
@@ -240,6 +240,19 @@
     float const luma_gray = 0.50;
 };
 
+TEST_F(RegionSamplingTest, invalidLayerHandle_doesNotCrash) {
+    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    sp<Listener> listener = new Listener();
+    const Rect sampleArea{100, 100, 200, 200};
+    // Passing in composer service as the layer handle should not crash, we'll
+    // treat it as a layer that no longer exists and silently allow sampling to
+    // occur.
+    status_t status = composer->addRegionSamplingListener(sampleArea,
+                                                          IInterface::asBinder(composer), listener);
+    ASSERT_EQ(NO_ERROR, status);
+    composer->removeRegionSamplingListener(listener);
+}
+
 TEST_F(RegionSamplingTest, DISABLED_CollectsLuma) {
     fill_render(rgba_green);
 
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 68cd84f..19c204c 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -199,13 +199,8 @@
     }
 }
 
-void RegionSamplingThread::addListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
+void RegionSamplingThread::addListener(const Rect& samplingArea, const wp<Layer>& stopLayer,
                                        const sp<IRegionSamplingListener>& listener) {
-    wp<Layer> stopLayer;
-    if (stopLayerHandle != nullptr && stopLayerHandle->localBinder() != nullptr) {
-        stopLayer = static_cast<Layer::Handle*>(stopLayerHandle.get())->owner;
-    }
-
     sp<IBinder> asBinder = IInterface::asBinder(listener);
     asBinder->linkToDeath(this);
     std::lock_guard lock(mSamplingMutex);
diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h
index 99c07c2..b9b7a3c 100644
--- a/services/surfaceflinger/RegionSamplingThread.h
+++ b/services/surfaceflinger/RegionSamplingThread.h
@@ -69,7 +69,7 @@
 
     // Add a listener to receive luma notifications. The luma reported via listener will
     // report the median luma for the layers under the stopLayerHandle, in the samplingArea region.
-    void addListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
+    void addListener(const Rect& samplingArea, const wp<Layer>& stopLayer,
                      const sp<IRegionSamplingListener>& listener);
     // Remove the listener to stop receiving median luma notifications.
     void removeListener(const sp<IRegionSamplingListener>& listener);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 2ed23de..811c660 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1454,7 +1454,9 @@
     if (!listener || samplingArea == Rect::INVALID_RECT) {
         return BAD_VALUE;
     }
-    mRegionSamplingThread->addListener(samplingArea, stopLayerHandle, listener);
+
+    const wp<Layer> stopLayer = fromHandle(stopLayerHandle);
+    mRegionSamplingThread->addListener(samplingArea, stopLayer, listener);
     return NO_ERROR;
 }
 
@@ -3160,7 +3162,7 @@
         Mutex::Autolock _l(mStateLock);
         sp<Layer> parent;
         if (parentHandle != nullptr) {
-            parent = fromHandle(parentHandle);
+            parent = fromHandleLocked(parentHandle).promote();
             if (parent == nullptr) {
                 return NAME_NOT_FOUND;
             }
@@ -3534,7 +3536,7 @@
 
     sp<Layer> layer = nullptr;
     if (s.surface) {
-        layer = fromHandle(s.surface);
+        layer = fromHandleLocked(s.surface).promote();
     } else {
         // The client may provide us a null handle. Treat it as if the layer was removed.
         ALOGW("Attempt to set client state with a null layer handle");
@@ -3850,7 +3852,7 @@
 
     {
         Mutex::Autolock _l(mStateLock);
-        mirrorFrom = fromHandle(mirrorFromHandle);
+        mirrorFrom = fromHandleLocked(mirrorFromHandle).promote();
         if (!mirrorFrom) {
             return NAME_NOT_FOUND;
         }
@@ -5562,7 +5564,7 @@
     {
         Mutex::Autolock lock(mStateLock);
 
-        parent = fromHandle(layerHandleBinder);
+        parent = fromHandleLocked(layerHandleBinder).promote();
         if (parent == nullptr || parent->isRemovedFromCurrentState()) {
             ALOGE("captureLayers called with an invalid or removed parent");
             return NAME_NOT_FOUND;
@@ -5595,7 +5597,7 @@
         reqHeight = crop.height() * frameScale;
 
         for (const auto& handle : excludeHandles) {
-            sp<Layer> excludeLayer = fromHandle(handle);
+            sp<Layer> excludeLayer = fromHandleLocked(handle).promote();
             if (excludeLayer != nullptr) {
                 excludeLayers.emplace(excludeLayer);
             } else {
@@ -6058,7 +6060,12 @@
     mFlinger->setInputWindowsFinished();
 }
 
-sp<Layer> SurfaceFlinger::fromHandle(const sp<IBinder>& handle) {
+wp<Layer> SurfaceFlinger::fromHandle(const sp<IBinder>& handle) {
+    Mutex::Autolock _l(mStateLock);
+    return fromHandleLocked(handle);
+}
+
+wp<Layer> SurfaceFlinger::fromHandleLocked(const sp<IBinder>& handle) {
     BBinder* b = nullptr;
     if (handle) {
         b = handle->localBinder();
@@ -6068,7 +6075,7 @@
     }
     auto it = mLayersByLocalBinderToken.find(b);
     if (it != mLayersByLocalBinderToken.end()) {
-        return it->second.promote();
+        return it->second;
     }
     return nullptr;
 }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 484e3ed..5a8153e 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -331,7 +331,12 @@
         return mTransactionCompletedThread;
     }
 
-    sp<Layer> fromHandle(const sp<IBinder>& handle) REQUIRES(mStateLock);
+    // Converts from a binder handle to a Layer
+    // Returns nullptr if the handle does not point to an existing layer.
+    // Otherwise, returns a weak reference so that callers off the main-thread
+    // won't accidentally hold onto the last strong reference.
+    wp<Layer> fromHandle(const sp<IBinder>& handle);
+    wp<Layer> fromHandleLocked(const sp<IBinder>& handle) REQUIRES(mStateLock);
 
     // Inherit from ClientCache::ErasedRecipient
     void bufferErased(const client_cache_t& clientCacheId) override;
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index cccf314..ba640de 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -404,7 +404,6 @@
     auto& mutableUseFrameRateApi() { return mFlinger->useFrameRateApi; }
 
     auto fromHandle(const sp<IBinder>& handle) {
-        Mutex::Autolock _l(mFlinger->mStateLock);
         return mFlinger->fromHandle(handle);
     }
 
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index fbbb69c..2a48a22 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -322,7 +322,7 @@
 TEST_F(TransactionApplicationTest, FromHandle) {
     sp<IBinder> badHandle;
     auto ret = mFlinger.fromHandle(badHandle);
-    EXPECT_EQ(nullptr, ret.get());
+    EXPECT_EQ(nullptr, ret.promote().get());
 }
 } // namespace android