summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Stoza <stoza@google.com>2016-08-09 13:21:03 -0700
committerDan Stoza <stoza@google.com>2016-08-09 13:47:42 -0700
commit92cd24e5f648175944deef5899258981807a9ca4 (patch)
tree53d4d8e69aa07232b992d5f4838099ee0ea35011
parentcf6e673296e8a3a7072f055770da59543935ae48 (diff)
downloadnative-92cd24e5f648175944deef5899258981807a9ca4.tar.gz
SF: Fix a couple of Layer ref count issues
This is an attempt at fixing two reference counting issues for Layers. The first issue is that since we were holding an sp<IBinder> (really a reference to a LayerCleaner) inside the layer state for deferred transactions, there was a possibility that it could end up being the last strong reference to the LayerCleaner such that when it was destroyed while applying a non-deferred transaction, it would attempt to grab the SurfaceFlinger main lock to destroy its Layer. Since this occurred in the main SurfaceFlinger loop, which was already holding the lock to process transactions, this would cause a deadlock. To fix this, the sp<IBinder> inside the layer state was changed to a wp<IBinder>, only being promoted when it actually needs to be accessed (i.e., when the deferred transaction is created). The second issue is that we were promoting and holding a strong reference to a Layer before calling into SurfaceFlinger to destroy it on the onLayerDestroyed path (triggered when a LayerCleaner is destroyed). After returning from the attempt to grab the SurfaceFlinger main lock, it was possible that this strong reference was the last one keeping the Layer alive, and destroying it at this point could cause the HWC2 version of the layer to be destroyed at effectively any point, even between validate/present. To fix this, the promotion of the weak Layer reference was moved inside the critical section where the SurfaceFlinger main lock is held. Bug: 30503916 Bug: 30281222 Change-Id: I1c6a271f9a7b5d6eea9a9db61d971f262d0cfe84
-rw-r--r--services/surfaceflinger/Client.cpp5
-rw-r--r--services/surfaceflinger/Layer.cpp11
-rw-r--r--services/surfaceflinger/Layer.h2
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp17
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h2
-rw-r--r--services/surfaceflinger/SurfaceFlinger_hwc1.cpp17
6 files changed, 27 insertions, 27 deletions
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 415bdcae2e..e14a59b46d 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -43,10 +43,7 @@ Client::~Client()
{
const size_t count = mLayers.size();
for (size_t i=0 ; i<count ; i++) {
- sp<Layer> layer(mLayers.valueAt(i).promote());
- if (layer != 0) {
- mFlinger->removeLayer(layer);
- }
+ mFlinger->removeLayer(mLayers.valueAt(i));
}
}
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 2b899398be..785df1a288 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1331,9 +1331,14 @@ void Layer::pushPendingState() {
// If this transaction is waiting on the receipt of a frame, generate a sync
// point and send it to the remote layer.
if (mCurrentState.handle != nullptr) {
- sp<Handle> handle = static_cast<Handle*>(mCurrentState.handle.get());
- sp<Layer> handleLayer = handle->owner.promote();
- if (handleLayer == nullptr) {
+ sp<IBinder> strongBinder = mCurrentState.handle.promote();
+ sp<Handle> handle = nullptr;
+ sp<Layer> handleLayer = nullptr;
+ if (strongBinder != nullptr) {
+ handle = static_cast<Handle*>(strongBinder.get());
+ handleLayer = handle->owner.promote();
+ }
+ if (strongBinder == nullptr || handleLayer == nullptr) {
ALOGE("[%s] Unable to promote Layer handle", mName.string());
// If we can't promote the layer we are intended to wait on,
// then it is expired or otherwise invalid. Allow this transaction
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index c070539da8..65339530b4 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -128,7 +128,7 @@ public:
// If set, defers this state update until the Layer identified by handle
// receives a frame with the given frameNumber
- sp<IBinder> handle;
+ wp<IBinder> handle;
uint64_t frameNumber;
// the transparentRegion hint is a bit special, it's latched only
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 820c332a9c..d6d23a832a 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2203,8 +2203,14 @@ status_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
return NO_ERROR;
}
-status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer) {
+status_t SurfaceFlinger::removeLayer(const wp<Layer>& weakLayer) {
Mutex::Autolock _l(mStateLock);
+ sp<Layer> layer = weakLayer.promote();
+ if (layer == nullptr) {
+ // The layer has already been removed, carry on
+ return NO_ERROR;
+ }
+
ssize_t index = mCurrentState.layersSortedByZ.remove(layer);
if (index >= 0) {
mLayersPendingRemoval.push(layer);
@@ -2545,14 +2551,7 @@ status_t SurfaceFlinger::onLayerDestroyed(const wp<Layer>& layer)
{
// called by ~LayerCleaner() when all references to the IBinder (handle)
// are gone
- status_t err = NO_ERROR;
- sp<Layer> l(layer.promote());
- if (l != NULL) {
- err = removeLayer(l);
- ALOGE_IF(err<0 && err != NAME_NOT_FOUND,
- "error removing layer=%p (%s)", l.get(), strerror(-err));
- }
- return err;
+ return removeLayer(layer);
}
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index f50f9e7918..b99acfcee6 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -324,7 +324,7 @@ private:
status_t onLayerDestroyed(const wp<Layer>& layer);
// remove a layer from SurfaceFlinger immediately
- status_t removeLayer(const sp<Layer>& layer);
+ status_t removeLayer(const wp<Layer>& layer);
// add a layer to SurfaceFlinger
status_t addClientLayer(const sp<Client>& client,
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 34240b4dd3..2ade006a52 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -2120,8 +2120,14 @@ status_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
return NO_ERROR;
}
-status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer) {
+status_t SurfaceFlinger::removeLayer(const wp<Layer>& weakLayer) {
Mutex::Autolock _l(mStateLock);
+ sp<Layer> layer = weakLayer.promote();
+ if (layer == nullptr) {
+ // The layer has already been removed, carry on
+ return NO_ERROR;
+ }
+
ssize_t index = mCurrentState.layersSortedByZ.remove(layer);
if (index >= 0) {
mLayersPendingRemoval.push(layer);
@@ -2462,14 +2468,7 @@ status_t SurfaceFlinger::onLayerDestroyed(const wp<Layer>& layer)
{
// called by ~LayerCleaner() when all references to the IBinder (handle)
// are gone
- status_t err = NO_ERROR;
- sp<Layer> l(layer.promote());
- if (l != NULL) {
- err = removeLayer(l);
- ALOGE_IF(err<0 && err != NAME_NOT_FOUND,
- "error removing layer=%p (%s)", l.get(), strerror(-err));
- }
- return err;
+ return removeLayer(layer);
}
// ---------------------------------------------------------------------------