diff options
Diffstat (limited to 'services/surfaceflinger/SurfaceFlinger.cpp')
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 132 |
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)); |