FELIX-384 Possible deadlock on framework startlevel change

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@580873 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/AbstractComponentManager.java b/scr/src/main/java/org/apache/felix/scr/AbstractComponentManager.java
index 53e136e..c530daa 100644
--- a/scr/src/main/java/org/apache/felix/scr/AbstractComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/AbstractComponentManager.java
@@ -299,75 +299,90 @@
      *   4. Call the activate method, if present
      *   [5. Register provided services]
      */
-    private synchronized void activateInternal()
+    private void activateInternal()
     {
-        // CONCURRENCY NOTE: This method is only called from within the
-        //     ComponentActorThread to enable, activate or reactivate the
-        //     component. Still we use the setStateConditional to not create
-        //     a race condition with the deactivateInternal method
-        if ( !setStateConditional( STATE_ENABLED | STATE_UNSATISFIED, STATE_ACTIVATING ) )
-        {
-            return;
-        }
-
-        // we cannot activate if the component activator is shutting down
-        if ( !isActive() )
-        {
-            getActivator().log( LogService.LOG_DEBUG,
-                "Component cannot be activated because the Activator is being disposed", m_componentMetadata, null );
-            setState( STATE_UNSATISFIED );
-            return;
-        }
-
-        getActivator().log( LogService.LOG_DEBUG, "Activating component", m_componentMetadata, null );
-
-        // Before creating the implementation object, we are going to
-        // test if all the mandatory dependencies are satisfied
-        Iterator it = m_dependencyManagers.iterator();
-        while ( it.hasNext() )
-        {
-            DependencyManager dm = ( DependencyManager ) it.next();
-            if ( !dm.isSatisfied() )
-            {
-                // at least one dependency is not satisfied
-                getActivator().log( LogService.LOG_INFO, "Dependency not satisfied: " + dm.getName(),
-                    m_componentMetadata, null );
-                setState( STATE_UNSATISFIED );
-            }
-            
-            // if at least one dependency is missing, we cannot continue and
-            // have to return
-            if (getState() == STATE_UNSATISFIED)
+        synchronized (this) {
+            // CONCURRENCY NOTE: This method is only called from within the
+            //     ComponentActorThread to enable, activate or reactivate the
+            //     component. Still we use the setStateConditional to not create
+            //     a race condition with the deactivateInternal method
+            if ( !setStateConditional( STATE_ENABLED | STATE_UNSATISFIED, STATE_ACTIVATING ) )
             {
                 return;
             }
+
+            // we cannot activate if the component activator is shutting down
+            if ( !isActive() )
+            {
+                getActivator().log( LogService.LOG_DEBUG,
+                    "Component cannot be activated because the Activator is being disposed", m_componentMetadata, null );
+                setState( STATE_UNSATISFIED );
+                return;
+            }
+
+            getActivator().log( LogService.LOG_DEBUG, "Activating component", m_componentMetadata, null );
+
+            // Before creating the implementation object, we are going to
+            // test if all the mandatory dependencies are satisfied
+            Iterator it = m_dependencyManagers.iterator();
+            while ( it.hasNext() )
+            {
+                DependencyManager dm = ( DependencyManager ) it.next();
+                if ( !dm.isSatisfied() )
+                {
+                    // at least one dependency is not satisfied
+                    getActivator().log( LogService.LOG_INFO, "Dependency not satisfied: " + dm.getName(),
+                        m_componentMetadata, null );
+                    setState( STATE_UNSATISFIED );
+                }
+
+                // if at least one dependency is missing, we cannot continue and
+                // have to return
+                if (getState() == STATE_UNSATISFIED)
+                {
+                    return;
+                }
+            }
+
+            // 1. Load the component implementation class
+            // 2. Create the component instance and component context
+            // 3. Bind the target services
+            // 4. Call the activate method, if present
+            if ( !createComponent() )
+            {
+                // component creation failed, not active now
+                getActivator().log( LogService.LOG_ERROR, "Component instance could not be created, activation failed",
+                    m_componentMetadata, null );
+
+                // set state to unsatisfied
+                setState( STATE_UNSATISFIED );
+
+                return;
+            }
+
+            // Validation occurs before the services are provided, otherwhise the
+            // service provider's service may be called by a service requester
+            // while it is still ACTIVATING
+            setState( getSatisfiedState() );
         }
 
-        // 1. Load the component implementation class
-        // 2. Create the component instance and component context
-        // 3. Bind the target services
-        // 4. Call the activate method, if present
-        if ( !createComponent() )
-        {
-            // component creation failed, not active now
-            getActivator().log( LogService.LOG_ERROR, "Component instance could not be created, activation failed",
-                m_componentMetadata, null );
-
-            // set state to unsatisfied
-            setState( STATE_UNSATISFIED );
-
-            return;
-        }
-
-        // Validation occurs before the services are provided, otherwhise the
-        // service provider's service may be called by a service requester
-        // while it is still ACTIVATING
-        setState( getSatisfiedState() );
-
         // 5. Register provided services
-        m_serviceRegistration = registerComponentService();
+        // call this outside of the synchronization to prevent a possible
+        // deadlock if service registration tries to lock the framework or
+        // owning bundle during registration (see FELIX-384)
+        try
+        {
+            m_serviceRegistration = registerComponentService();
+            getActivator().log( LogService.LOG_DEBUG, "Component activated", m_componentMetadata, null );
+        }
+        catch ( IllegalStateException ise )
+        {
+            // thrown by service registration if the bundle is stopping
+            // we just log this at debug level but ignore it
+            getActivator().log( LogService.LOG_DEBUG, "Component activation failed while registering the service",
+                m_componentMetadata, ise );
+        }
 
-        getActivator().log( LogService.LOG_DEBUG, "Component activated", m_componentMetadata, null );
     }
 
 
@@ -466,7 +481,7 @@
     * Method is called by {@link #activate()} in STATE_ACTIVATING or by
     * {@link DelayedComponentManager#getService(Bundle, ServiceRegistration)}
     * in STATE_REGISTERED.
-    * 
+    *
     * @return <code>true</code> if creation of the component succeeded. If
     *       <code>false</code> is returned, the cause should have been logged.
     */
@@ -679,7 +694,7 @@
      * Otherwise the state is not changed and <code>false</code> is returned.
      * <p>
      * This method atomically checks the current state and sets the new state.
-     * 
+     *
      * @param requiredStates The set of states required for the state change to
      *          happen.
      * @param newState The new state to go into.