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 33cb9a41a6..a9fa1ef424 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));  |