Ensure AnimatedVectorImageVisual doesn't hang app 62/246462/1
authorDavid Steele <david.steele@samsung.com>
Thu, 29 Oct 2020 16:58:41 +0000 (16:58 +0000)
committerDavid Steele <david.steele@samsung.com>
Thu, 29 Oct 2020 17:04:42 +0000 (17:04 +0000)
Currently, if the AnimatedVectorImageVisual is not destroyed
on Application::Terminate, e.g. if it's actor is kept alive,
then the shutdown order is undefined, and may end up
trying to pend on a mutex which has already been destroyed,
in the dali-extension plugin.

(TizenVectorAnimationManager, which creates the mutex, is a
singleton that is created when first needed, but stays alive
until main() completes)

Prevented the destructor from finalizing in the plugin if
core has already been shutdown.

Change-Id: I9fe547eab4dc3f3e5a4655f5c8dcf96bf664d7e3

dali-toolkit/internal/visuals/animated-vector-image/animated-vector-image-visual.cpp
dali-toolkit/internal/visuals/animated-vector-image/animated-vector-image-visual.h
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-manager.cpp
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-manager.h

index ea097e1..fead0e6 100644 (file)
@@ -94,25 +94,41 @@ AnimatedVectorImageVisual::AnimatedVectorImageVisual( VisualFactoryCache& factor
   mPlacementActor(),
   mPlayState( DevelImageVisual::PlayState::STOPPED ),
   mEventCallback( nullptr ),
-  mRendererAdded( false )
+  mRendererAdded( false ),
+  mCoreShutdown(false)
 {
   // the rasterized image is with pre-multiplied alpha format
   mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
 
   mVectorAnimationTask->UploadCompletedSignal().Connect( this, &AnimatedVectorImageVisual::OnUploadCompleted );
   mVectorAnimationTask->SetAnimationFinishedCallback( new EventThreadCallback( MakeCallback( this, &AnimatedVectorImageVisual::OnAnimationFinished ) ) );
+
+  auto& vectorAnimationManager = mFactoryCache.GetVectorAnimationManager();
+  vectorAnimationManager.AddObserver(*this);
 }
 
 AnimatedVectorImageVisual::~AnimatedVectorImageVisual()
 {
-  if( mEventCallback )
+  if( ! mCoreShutdown )
   {
-    mFactoryCache.GetVectorAnimationManager().UnregisterEventCallback( mEventCallback );
+    auto& vectorAnimationManager = mFactoryCache.GetVectorAnimationManager();
+    vectorAnimationManager.RemoveObserver(*this);
+
+    if( mEventCallback )
+    {
+      mFactoryCache.GetVectorAnimationManager().UnregisterEventCallback( mEventCallback );
+    }
+
+    // Finalize animation task and disconnect the signal in the main thread
+    mVectorAnimationTask->UploadCompletedSignal().Disconnect( this, &AnimatedVectorImageVisual::OnUploadCompleted );
+    mVectorAnimationTask->Finalize();
   }
+}
 
-  // Finalize animation task and disconnect the signal in the main thread
-  mVectorAnimationTask->UploadCompletedSignal().Disconnect( this, &AnimatedVectorImageVisual::OnUploadCompleted );
-  mVectorAnimationTask->Finalize();
+void AnimatedVectorImageVisual::VectorAnimationManagerDestroyed()
+{
+  // Core is shutting down. Don't talk to the plugin any more.
+  mCoreShutdown = true;
 }
 
 void AnimatedVectorImageVisual::GetNaturalSize( Vector2& naturalSize )
@@ -500,10 +516,11 @@ void AnimatedVectorImageVisual::StopAnimation()
 
 void AnimatedVectorImageVisual::TriggerVectorRasterization()
 {
-  if( !mEventCallback )
+  if( !mEventCallback && !mCoreShutdown )
   {
     mEventCallback = MakeCallback( this, &AnimatedVectorImageVisual::OnProcessEvents );
-    mFactoryCache.GetVectorAnimationManager().RegisterEventCallback( mEventCallback );
+    auto& vectorAnimationManager = mFactoryCache.GetVectorAnimationManager();
+    vectorAnimationManager.RegisterEventCallback( mEventCallback );
     Stage::GetCurrent().KeepRendering( 0.0f );  // Trigger event processing
   }
 }
index e09527a..6196e39 100644 (file)
@@ -30,6 +30,7 @@
 #include <dali-toolkit/internal/visuals/visual-url.h>
 #include <dali-toolkit/devel-api/visuals/animated-vector-image-visual-actions-devel.h>
 #include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h>
+#include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-manager.h>
 
 namespace Dali
 {
@@ -55,7 +56,7 @@ using AnimatedVectorImageVisualPtr = IntrusivePtr< AnimatedVectorImageVisual >;
  * | url                      | STRING           |
  *
  */
-class AnimatedVectorImageVisual: public Visual::Base, public ConnectionTracker
+class AnimatedVectorImageVisual: public Visual::Base, public ConnectionTracker, public VectorAnimationManager::LifecycleObserver
 {
 public:
 
@@ -97,6 +98,12 @@ public:  // from Visual
    */
   void DoCreateInstancePropertyMap( Property::Map& map ) const override;
 
+protected: // From VectorAnimationManager::LifecycleObserver:
+  /**
+   * @copydoc VectorAnimationManager::LifecycleObserver::VectorAnimationManagerDestroyed()
+   */
+  void VectorAnimationManagerDestroyed() override;
+
 protected:
 
   /**
@@ -221,6 +228,7 @@ private:
   DevelImageVisual::PlayState::Type            mPlayState;
   CallbackBase*                                mEventCallback;    // Not owned
   bool                                         mRendererAdded;
+  bool                                         mCoreShutdown;
 };
 
 } // namespace Internal
index 8e47d81..ad56227 100644 (file)
@@ -45,6 +45,7 @@ Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New( Debug::NoLogging,
 
 VectorAnimationManager::VectorAnimationManager()
 : mEventCallbacks(),
+  mLifecycleObservers(),
   mVectorAnimationThread( nullptr ),
   mProcessorRegistered( false )
 {
@@ -62,6 +63,26 @@ VectorAnimationManager::~VectorAnimationManager()
   {
     Adaptor::Get().UnregisterProcessor( *this );
   }
+
+  for( auto observer : mLifecycleObservers )
+  {
+    observer->VectorAnimationManagerDestroyed();
+  }
+}
+
+void VectorAnimationManager::AddObserver( VectorAnimationManager::LifecycleObserver& observer )
+{
+  DALI_ASSERT_DEBUG( mLifecycleObservers.end() == std::find( mLifecycleObservers.begin(), mLifecycleObservers.end(), &observer));
+  mLifecycleObservers.push_back( &observer );
+}
+
+void VectorAnimationManager::RemoveObserver( VectorAnimationManager::LifecycleObserver& observer)
+{
+  auto iterator=std::find(mLifecycleObservers.begin(), mLifecycleObservers.end(), &observer);
+  if( iterator != mLifecycleObservers.end() )
+  {
+    mLifecycleObservers.erase(iterator);
+  }
 }
 
 VectorAnimationThread& VectorAnimationManager::GetVectorAnimationThread()
index 510c07e..7fbc3ca 100644 (file)
@@ -43,6 +43,10 @@ class VectorAnimationThread;
 class VectorAnimationManager: public Integration::Processor
 {
 public:
+  struct LifecycleObserver
+  {
+    virtual void VectorAnimationManagerDestroyed() = 0;
+  };
 
   /**
    * @brief Constructor.
@@ -55,6 +59,18 @@ public:
   ~VectorAnimationManager() override;
 
   /**
+   * Add a lifecycle observer
+   * @param[in] observer The object watching this one
+   */
+  void AddObserver( LifecycleObserver& observer );
+
+  /**
+   * Remove a lifecycle observer
+   * @param[in] observer The object watching this one
+   */
+  void RemoveObserver( LifecycleObserver& observer );
+
+  /**
    * Get the vector animation thread.
    * @return A raw pointer pointing to the vector animation thread.
    */
@@ -93,6 +109,7 @@ private:
 private:
 
   std::vector< CallbackBase* >             mEventCallbacks;
+  std::vector<LifecycleObserver*>         mLifecycleObservers;
   std::unique_ptr< VectorAnimationThread > mVectorAnimationThread;
   bool                                     mProcessorRegistered;
 };