summaryrefslogtreecommitdiffstats
path: root/services/surfaceflinger/SurfaceFlinger.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'services/surfaceflinger/SurfaceFlinger.cpp')
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp132
1 files changed, 81 insertions, 51 deletions
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 33cb9a4..a9fa1ef 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -395,7 +395,7 @@ bool SurfaceFlinger::threadLoop()
if (LIKELY(mTransactionCount == 0)) {
// if we're in a global transaction, don't do anything.
const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
- uint32_t transactionFlags = peekTransactionFlags(mask);
+ uint32_t transactionFlags = getTransactionFlags(mask);
if (LIKELY(transactionFlags)) {
handleTransaction(transactionFlags);
}
@@ -480,26 +480,39 @@ void SurfaceFlinger::handleConsoleEvents()
void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
{
- Mutex::Autolock _l(mStateLock);
- const nsecs_t now = systemTime();
- mDebugInTransaction = now;
+ Vector< sp<LayerBase> > ditchedLayers;
- // Here we're guaranteed that some transaction flags are set
- // so we can call handleTransactionLocked() unconditionally.
- // We call getTransactionFlags(), which will also clear the flags,
- // with mStateLock held to guarantee that mCurrentState won't change
- // until the transaction is committed.
+ /*
+ * Perform and commit the transaction
+ */
- const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
- transactionFlags = getTransactionFlags(mask);
- handleTransactionLocked(transactionFlags);
+ { // scope for the lock
+ Mutex::Autolock _l(mStateLock);
+ const nsecs_t now = systemTime();
+ mDebugInTransaction = now;
+ handleTransactionLocked(transactionFlags, ditchedLayers);
+ mLastTransactionTime = systemTime() - now;
+ mDebugInTransaction = 0;
+ invalidateHwcGeometry();
+ // here the transaction has been committed
+ }
- mLastTransactionTime = systemTime() - now;
- mDebugInTransaction = 0;
- // here the transaction has been committed
+ /*
+ * Clean-up all layers that went away
+ * (do this without the lock held)
+ */
+
+ const size_t count = ditchedLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ if (ditchedLayers[i] != 0) {
+ //LOGD("ditching layer %p", ditchedLayers[i].get());
+ ditchedLayers[i]->ditch();
+ }
+ }
}
-void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
+void SurfaceFlinger::handleTransactionLocked(
+ uint32_t transactionFlags, Vector< sp<LayerBase> >& ditchedLayers)
{
const LayerVector& currentLayers(mCurrentState.layersSortedByZ);
const size_t count = currentLayers.size();
@@ -571,6 +584,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
const sp<LayerBase>& layer(previousLayers[i]);
if (currentLayers.indexOf( layer ) < 0) {
// this layer is not visible anymore
+ ditchedLayers.add(layer);
mDirtyRegionRemovedLayer.orSelf(layer->visibleRegionScreen);
}
}
@@ -1082,15 +1096,15 @@ status_t SurfaceFlinger::addLayer_l(const sp<LayerBase>& layer)
ssize_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
const sp<LayerBaseClient>& lbc)
{
- // attach this layer to the client
- size_t name = client->attachLayer(lbc);
-
Mutex::Autolock _l(mStateLock);
+ // attach this layer to the client
+ ssize_t name = client->attachLayer(lbc);
+
// add this layer to the current state list
addLayer_l(lbc);
- return ssize_t(name);
+ return name;
}
status_t SurfaceFlinger::removeLayer(const sp<LayerBase>& layer)
@@ -1141,11 +1155,6 @@ status_t SurfaceFlinger::invalidateLayerVisibility(const sp<LayerBase>& layer)
return NO_ERROR;
}
-uint32_t SurfaceFlinger::peekTransactionFlags(uint32_t flags)
-{
- return android_atomic_release_load(&mTransactionFlags);
-}
-
uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags)
{
return android_atomic_and(~flags, &mTransactionFlags) & flags;
@@ -1353,26 +1362,51 @@ status_t SurfaceFlinger::removeSurface(const sp<Client>& client, SurfaceID sid)
return err;
}
-status_t SurfaceFlinger::destroySurface(const wp<LayerBaseClient>& layer)
+status_t SurfaceFlinger::destroySurface(const sp<LayerBaseClient>& layer)
{
// called by ~ISurface() when all references are gone
- status_t err = NO_ERROR;
- sp<LayerBaseClient> l(layer.promote());
- if (l != NULL) {
- Mutex::Autolock _l(mStateLock);
- err = removeLayer_l(l);
- if (err == NAME_NOT_FOUND) {
- // The surface wasn't in the current list, which means it was
- // removed already, which means it is in the purgatory,
- // and need to be removed from there.
- ssize_t idx = mLayerPurgatory.remove(l);
- LOGE_IF(idx < 0,
- "layer=%p is not in the purgatory list", l.get());
- }
- LOGE_IF(err<0 && err != NAME_NOT_FOUND,
- "error removing layer=%p (%s)", l.get(), strerror(-err));
- }
- return err;
+
+ class MessageDestroySurface : public MessageBase {
+ SurfaceFlinger* flinger;
+ sp<LayerBaseClient> layer;
+ public:
+ MessageDestroySurface(
+ SurfaceFlinger* flinger, const sp<LayerBaseClient>& layer)
+ : flinger(flinger), layer(layer) { }
+ virtual bool handler() {
+ sp<LayerBaseClient> l(layer);
+ layer.clear(); // clear it outside of the lock;
+ Mutex::Autolock _l(flinger->mStateLock);
+ /*
+ * remove the layer from the current list -- chances are that it's
+ * not in the list anyway, because it should have been removed
+ * already upon request of the client (eg: window manager).
+ * However, a buggy client could have not done that.
+ * Since we know we don't have any more clients, we don't need
+ * to use the purgatory.
+ */
+ status_t err = flinger->removeLayer_l(l);
+ if (err == NAME_NOT_FOUND) {
+ // The surface wasn't in the current list, which means it was
+ // removed already, which means it is in the purgatory,
+ // and need to be removed from there.
+ // This needs to happen from the main thread since its dtor
+ // must run from there (b/c of OpenGL ES). Additionally, we
+ // can't really acquire our internal lock from
+ // destroySurface() -- see postMessage() below.
+ ssize_t idx = flinger->mLayerPurgatory.remove(l);
+ LOGE_IF(idx < 0,
+ "layer=%p is not in the purgatory list", l.get());
+ }
+
+ LOGE_IF(err<0 && err != NAME_NOT_FOUND,
+ "error removing layer=%p (%s)", l.get(), strerror(-err));
+ return true;
+ }
+ };
+
+ postMessageAsync( new MessageDestroySurface(this, layer) );
+ return NO_ERROR;
}
status_t SurfaceFlinger::setClientState(
@@ -2347,17 +2381,15 @@ status_t Client::initCheck() const {
return NO_ERROR;
}
-size_t Client::attachLayer(const sp<LayerBaseClient>& layer)
+ssize_t Client::attachLayer(const sp<LayerBaseClient>& layer)
{
- Mutex::Autolock _l(mLock);
- size_t name = mNameGenerator++;
+ int32_t name = android_atomic_inc(&mNameGenerator);
mLayers.add(name, layer);
return name;
}
void Client::detachLayer(const LayerBaseClient* layer)
{
- Mutex::Autolock _l(mLock);
// we do a linear search here, because this doesn't happen often
const size_t count = mLayers.size();
for (size_t i=0 ; i<count ; i++) {
@@ -2367,11 +2399,9 @@ void Client::detachLayer(const LayerBaseClient* layer)
}
}
}
-sp<LayerBaseClient> Client::getLayerUser(int32_t i) const
-{
- Mutex::Autolock _l(mLock);
+sp<LayerBaseClient> Client::getLayerUser(int32_t i) const {
sp<LayerBaseClient> lbc;
- wp<LayerBaseClient> layer(mLayers.valueFor(i));
+ const wp<LayerBaseClient>& layer(mLayers.valueFor(i));
if (layer != 0) {
lbc = layer.promote();
LOGE_IF(lbc==0, "getLayerUser(name=%d) is dead", int(i));