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