sl@0: // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0: // All rights reserved.
sl@0: // This component and the accompanying materials are made available
sl@0: // under the terms of "Eclipse Public License v1.0"
sl@0: // which accompanies this distribution, and is available
sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0: //
sl@0: // Initial Contributors:
sl@0: // Nokia Corporation - initial contribution.
sl@0: //
sl@0: // Contributors:
sl@0: //
sl@0: // Description:
sl@0: // Implementation of CSchStartupStateMgr class which connects to
sl@0: // the Domain manager to keep aware of the current start-up
sl@0: // state and distributes the state changes to registered observers.
sl@0: // 
sl@0: //
sl@0: 
sl@0: /**
sl@0:  @file
sl@0:  @internalComponent
sl@0: */
sl@0: 
sl@0: #include "SchSSAMan.h"
sl@0: #include "SchLogger.h"
sl@0: 
sl@0: /**
sl@0: constructor of CSchStartupStateMgr
sl@0: @internalComponent
sl@0: */
sl@0: CSchStartupStateMgr::CSchStartupStateMgr(TDmHierarchyId aHierarchyId, TDmDomainId aDomainId) :
sl@0: 	CDmDomain(aHierarchyId,aDomainId),
sl@0: 	iCurrentStartupState(EStartupStateUndefined)
sl@0: 	 {
sl@0: 	 }
sl@0: 	 
sl@0: /**
sl@0: destructor of CSchStartupStateMgr
sl@0: @internalComponent
sl@0: */
sl@0: CSchStartupStateMgr::~CSchStartupStateMgr()
sl@0: 	{
sl@0: 	Cancel();
sl@0: 	iObserverList.Reset();
sl@0: 	}
sl@0: 	
sl@0: /**
sl@0: Getter
sl@0: @internalComponent
sl@0: @return the current startup state
sl@0: */
sl@0: TStartupStateIdentifier CSchStartupStateMgr::CurrentStartupState()
sl@0: 	{
sl@0: 	return iCurrentStartupState;
sl@0: 	}
sl@0: 	
sl@0: /**
sl@0: updates the MSchStartupStateObserver objects.
sl@0: @internalComponent
sl@0: */
sl@0: void CSchStartupStateMgr::UpdateStateAwareObjectsL(TStartupStateIdentifier aKnownState)
sl@0: 	{
sl@0: 	for (TInt i = 0; i < iObserverList.Count(); i++)
sl@0: 		{
sl@0: 		iObserverList[i]->ProcessSSAEventL(aKnownState);
sl@0: 		}
sl@0: 	}
sl@0: 	
sl@0: /**
sl@0: This method takes a a startup state which can be user defined
sl@0: state and maps it to a known startup state (KSS). KSS are
sl@0: Symbian defined states: undefined, critical static, critical dynamic,
sl@0: and non-critical.
sl@0: User defined states are refered to as USS - unknown startup state.
sl@0: 
sl@0: @internalComponent
sl@0: */
sl@0: TStartupStateIdentifier CSchStartupStateMgr::GetKnownStartupState(TDmDomainState aStartupState)
sl@0: 	{
sl@0: 	TStartupStateIdentifier knownStartupState = iCurrentStartupState;
sl@0: 	
sl@0: 	if (aStartupState >= EStartupStateNonCritical)
sl@0: 		{
sl@0: 		knownStartupState = EStartupStateNonCritical;
sl@0: 		}
sl@0: 	else if(aStartupState >= EStartupStateCriticalDynamic)
sl@0: 		{
sl@0: 		knownStartupState = EStartupStateCriticalDynamic;
sl@0: 		}
sl@0: 	else if(aStartupState >= EStartupStateCriticalStatic)
sl@0: 		{
sl@0: 		knownStartupState = EStartupStateCriticalStatic;
sl@0: 		}
sl@0: 	else 
sl@0: 		{
sl@0: 		knownStartupState = EStartupStateUndefined;
sl@0: 		}
sl@0: 	
sl@0: 	return knownStartupState;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Register the MSchStartupStateObserver object with the CServerStartupMgr.
sl@0: @internalComponent
sl@0: @param aObs the pointer to the MStartupStateObserver object to be registered with CServerStartupMgr.
sl@0: */
sl@0: void CSchStartupStateMgr::RegisterObserverL(const MSchStartupStateObserver* aObs)
sl@0: 	{
sl@0: 	User::LeaveIfError(iObserverList.Append(aObs));
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Handle the error if RunL leaves. Just tell the observers that
sl@0: we have reached the final state.
sl@0: 
sl@0: @internalComponent
sl@0: @param aError error code generated by the RunL(), not used here.
sl@0: @return KErrNone to avoid CActiveScheduler to panic.
sl@0: */
sl@0: TInt CSchStartupStateMgr::RunError(TInt /*aError*/)
sl@0: 	{
sl@0: 	LOGSTRING("CSchStartupStateMgr::RunL() leaves, set SS to final state.");
sl@0: 	TRAP_IGNORE(UpdateStateAwareObjectsL(KSchFinalStartupState));
sl@0: 	return KErrNone;
sl@0: 	}
sl@0: 	
sl@0: /**
sl@0: Finsish constructing the CSchStartupStateMgr and start
sl@0: interacting with Domain Manager to receive startup state
sl@0: changes. 
sl@0: All observers should have been registered before calling this method
sl@0: 
sl@0: @internalComponent
sl@0: */
sl@0: void CSchStartupStateMgr::InitialiseL()
sl@0: 	{
sl@0: 	TRAPD(err, CDmDomain::ConstructL());
sl@0: 	if (err != KErrNone)
sl@0: 		{
sl@0: 		// the ConstructL leaves, go to final state
sl@0: 		LOGSTRING2("CDmDomain::ConstructL leaves with %d. Goto final state", err);
sl@0: 		UpdateStateAwareObjectsL(KSchFinalStartupState);
sl@0: 		iCurrentStartupState = KSchFinalStartupState;
sl@0: 		return;
sl@0: 		}
sl@0: 			
sl@0: 	// Typical pattern of using P&S is to subscribe first then get
sl@0: 	// current state. Example implementation given
sl@0: 	// in SSA Adaptation How-to also does it this way.
sl@0: 	RequestTransitionNotification();
sl@0: 	
sl@0: 	// get the start up state from the Domain Manager.
sl@0: 	TDmDomainState rawstate = GetState();
sl@0: 
sl@0: 	// rawstate may be user defined. Map to known states.
sl@0: 	TStartupStateIdentifier nextKnownState = GetKnownStartupState(rawstate);
sl@0: 		
sl@0: 	// NB: nextKnownState can be KStartupStateUndefined for 2 reasons.
sl@0: 	// One is rawstate == 0 which we must check first. Second:
sl@0: 	// rawstate is user defined values lower than critical static. In
sl@0: 	// the second case we must wait for next state change.
sl@0: 	if (rawstate == EStartupStateUndefined || 
sl@0: 		nextKnownState == KSchFinalStartupState)
sl@0: 		{
sl@0: 		// If either something wrong with DM or final state is reached,
sl@0: 		// go to final state
sl@0: 		iCurrentStartupState = KSchFinalStartupState;
sl@0: 		UpdateStateAwareObjectsL(KSchFinalStartupState);
sl@0: 		Cancel();
sl@0: 		return;
sl@0: 		}
sl@0: 			
sl@0: 	iCurrentStartupState = nextKnownState;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Executed when the startup state change is done, it does the 
sl@0: same thing as the method InitialiseL() does
sl@0: @internalComponent
sl@0: */
sl@0: void CSchStartupStateMgr::RunL()
sl@0: 	{
sl@0: 	if(iStatus != KErrNone) // something wrong with the RequestTransitionNotification().
sl@0: 		{
sl@0: 		AcknowledgeLastState(iStatus.Int()); //Acknowledge the domainmanager in case of leaving, this to avoid the acknowledgement in RunError()
sl@0: 		User::LeaveIfError(iStatus.Int()); //RunError will handle this.
sl@0: 		}
sl@0: 
sl@0: 	RequestTransitionNotification();
sl@0: 
sl@0: 	TDmDomainState rawstate = GetState();
sl@0: 
sl@0: 	// Must first check the case rawstate == undefined and deal with it here.
sl@0: 	// GetKnowStartupState maps 1 to 15 to EStartupStateUndefined
sl@0: 	// which means a SS before critical static. It does not mean go
sl@0: 	// to final state.
sl@0: 
sl@0: 	//If the rawstate is EStartupStateUndefined there must be sth wrong.
sl@0: 	if(rawstate == EStartupStateUndefined) 
sl@0: 		{
sl@0: 		Cancel();
sl@0: 		AcknowledgeLastState(KErrBadHandle);
sl@0: 		User::Leave(KErrBadHandle); //RunError will handle this.
sl@0: 		}
sl@0: 
sl@0: 	// get the known state			
sl@0: 	TStartupStateIdentifier nextKnownState = GetKnownStartupState(rawstate);
sl@0: 	
sl@0: 	//Tell domain manager that we have processed the last state change before starting any time consuming work.
sl@0: 	AcknowledgeLastState(KErrNone);
sl@0: 	
sl@0: 	//Sleep 2 tickperiods this allows the acknowledgement reach the domain manager.
sl@0: 	TTimeIntervalMicroSeconds32 tickPeriod;
sl@0: 	UserHal::TickPeriod(tickPeriod);	
sl@0: 	User::After(2*tickPeriod.Int()); 
sl@0: 
sl@0: 	// Schsvr only want to know transition to non-critical.
sl@0: 	// Ignore all states below that level.
sl@0: 	if (iCurrentStartupState < KSchFinalStartupState && nextKnownState == KSchFinalStartupState)
sl@0: 		{
sl@0: 		UpdateStateAwareObjectsL(nextKnownState);
sl@0: 		}
sl@0: 	
sl@0: 	iCurrentStartupState = nextKnownState;	
sl@0: 	
sl@0: 	//do not request transition notification if we have reached the last state
sl@0: 	if(iCurrentStartupState == KSchFinalStartupState)
sl@0: 		{
sl@0: 		Cancel();
sl@0: 		}
sl@0: 	}