userlibandfileserver/domainmgr/src/domainsrv.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:26:05 +0100
branchRCL_3
changeset 136 743008598095
parent 0 a41df078684a
child 279 957c583b417b
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "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:
// domain\src\domainsrv.cpp
// 
//

#include <e32debug.h>
#include <e32base.h>
#include <e32base_private.h>
#include <e32property.h>
#include <f32file.h>

#include <domainpolicy.h>
#include "domainsrv.h"

#define __DS_PANIC(aError) User::Panic(_L("domainSrv.cpp"), (-(aError)) | (__LINE__ << 16))
#define __DS_ASSERT(aCond) ((aCond) || (User::Panic(_L("domainSrv.cpp; assertion failed"), __LINE__), 1))

//#define __DS_DEBUG

#ifdef __DS_DEBUG
#define __DS_TRACE(s) RDebug::Print s
#else
#define __DS_TRACE(s)
#endif

static _LIT_SECURITY_POLICY_PASS(KAllowAllPolicy);
static _LIT_SECURITY_POLICY_C1(KPowerMgmtPolicy,ECapabilityPowerMgmt);

// forward refs
class CSvrDomain;
class CDmHierarchy;
class CPowerUpHandler;
class CDmHierarchyPower;
class CDmSvrManager;
class CDmDomainServer;
class CDmDomainSession;
class CDmManagerServer;
class CDmManagerSession;



// CSvrDomain
class CSvrDomain : public CTimer
	{
public: 
	static CSvrDomain* New(CDmHierarchy& aHierarchy, const TDmDomainSpec&);

	// from CTimer
	void RunL();

	void Attach(CDmDomainSession*);
	void Detach(CDmDomainSession*);
	void AddChild(CSvrDomain*);
	CSvrDomain* Lookup(TDmDomainId);
	TBool CheckPropValue(TInt aPropValue);
	void RequestDomainTransition();
	void CompleteMemberTransition(TInt aError);
	void CancelTransition();
	void SetObserver(TBool aSet);
	TDmDomainState State();

private:
	CSvrDomain(CDmHierarchy& aHierarchy, const TDmDomainSpec*);
	void Construct(const TDmDomainSpec* spec);

	void RequestMembersTransition();
	void RequestChildrenTransition();
	void MembersTransitionDone();
	void ChildrenTransitionDone();
	void CompleteDomainTransition();

private:
	CDmHierarchy&		iHierarchy;
	CSvrDomain*			iParent;
	CSvrDomain*			iPeer;
	CSvrDomain*			iChild;
	RProperty			iProperty;
	CDmDomainSession*	iSessions;
	TUint16				iChildrenCount;
	TUint16				iTransCount;
	TTimeIntervalMicroSeconds32	iTransTimeBudget;

public:
	const TSecurityPolicy	iJoinPolicy;
	TBool iIsObserved;
	TDmDomainId			iId;
	};


// CDmHierarchy
class CDmHierarchy : public CBase
	{
public:
	static CDmHierarchy* New(TDmHierarchyId aHierarchyId, TDmHierarchyPolicy& aPolicy);

	CSvrDomain* LookupDomain(TDmDomainId aDomainId);
	TInt RequestDomainTransition(TDmDomainId, TDmDomainState aTargetState, TDmTraverseDirection aTraverseDirection, const RMessage2* aMessage);
	void RequestTransition(const RMessage2* aMessage);
	TInt StartObserver( TDmDomainId aDomainId,TDmNotifyType aNotifyType);
	void SetNotifyMessage(const RMessage2* aMessage);
	void CompleteNotification(TInt aError);
	TBool OutstandingNotification();
	void StopObserver();
	virtual TInt RequestSystemTransition(TDmDomainState aTargetState, TDmTraverseDirection aTraverseDirection, const RMessage2* aMessage);
	virtual void CompleteTransition(TInt aError);
	virtual void NotifyCompletion(TInt aReason);
	
protected:
	CDmHierarchy(TDmHierarchyId aHierarchyId, TDmHierarchyPolicy& aPolicy);
	void SetState(TDmDomainState aTargetState, TDmTraverseDirection aTraverseDirection = ETraverseDefault);

private:
	RMessagePtr2	iTransMessagePtr;
	RMessagePtr2	iObsvrMessagePtr;
	CSvrDomain*		iObservedDomain;
	TBool			iOutstandingNotification;
public:
	TDmHierarchyId	iHierarchyId;
	CSvrDomain*		iRootDomain;
	CSvrDomain*		iTransDomain;
	TInt			iTransPropValue;
	TDmDomainState	iTransState;
	TDmTraverseDirection	iTraverseDirection;
	TUint8			iTransId;
	CDmManagerSession* iControllerSession;	// only one controller per hierarchy
	TDmHierarchyPolicy iPolicy;
	RArray<TTransitionFailure> iTransitionFailures;
	
	// observer stuff
	TBool			iObserverStarted;
	TDmNotifyType	iNotifyType;
	RArray<TTransInfo>	iTransitions;
	CDmManagerSession* iObserverSession;	// only one observer per hierarchy
	TInt			iObservedChildren;
	};


// CPowerUpHandler
// Active object used to receive power-up notifications 
// from the Kernel-level power manager
class CPowerUpHandler : public CActive
	{
public: 
	static CPowerUpHandler* New(CDmHierarchyPower& aHierarchyPower);
	
	// from CActive
	void RunL();
	void DoCancel();

	void RequestWakeupEventNotification();
	void Cancel();

private:
	CPowerUpHandler(CDmHierarchyPower& aHierarchyPower);
	void Construct();

private:
	CDmHierarchyPower& iHierarchyPower;
	};


// CDmHierarchyPower
// CDmHierarchy-derived class 
// Interfaces to the Kernel-level power manager
class CDmHierarchyPower : public CDmHierarchy
	{
public:
	static CDmHierarchyPower* New(TDmHierarchyId aHierarchyId, TDmHierarchyPolicy& aPolicy);

	// from CDmHierarchy
	virtual TInt RequestSystemTransition(TDmDomainState, TDmTraverseDirection aTraverseDirection, const RMessage2* aMessage);
	virtual void CompleteTransition(TInt aError);
	virtual void NotifyCompletion(TInt aReason);

	void PowerUp();	// called from CPowerUpHandler

private:
	CDmHierarchyPower(TDmHierarchyId aHierarchyId, TDmHierarchyPolicy& aPolicy);
	void Construct();

private:
	enum 
		{
		EPoweringDown	= 0x01,
		};
	TUint8			iTransStatus;
	CPowerUpHandler* iPowerUpHandler;
	};


// CDmSvrManager
class CDmSvrManager : public CBase
	{
public:
	static CDmSvrManager* New();

	TInt BuildDomainTree(TDmHierarchyId aHierarchyId, CDmHierarchy*& aHierarchy);
	CDmHierarchy* LookupHierarchy(TDmHierarchyId aHierarchyId);
	TInt LookupDomain(TDmHierarchyId aHierarchyId, TDmDomainId aDomainId, CSvrDomain*& aDomain);

private:
	CDmSvrManager();
	void Construct();

private:
	RPointerArray<CDmHierarchy> iDomainHierarchies;
	};

// CDmDomainServer
class CDmDomainServer : public CServer2
	{
public: 
	// from CServer2
	CSession2* NewSessionL(const TVersion& aVer) const;
	CSession2* NewSessionL(const TVersion& aVer, const RMessage2& aMessage) const;

	CDmDomainServer(CDmSvrManager* aManager) : CServer2(CActive::EPriorityStandard), iManager(aManager)
		{}

public:
	CDmSvrManager*	iManager;
	};

// CDmDomainSession
class CDmDomainSession : public CSession2
	{
public: 
	// from CBase
	~CDmDomainSession();

	// from CSession2
	void ServiceL(const RMessage2& aMessage);

private:
	CSvrDomain*			iDomain;

public:
	CDmDomainSession*	iNext;
	TUint8				iPending;
	TBool				iNotificationEnabled;
	};

class CDmManagerServer : public CServer2
	{
public: 
	// from CServer2
	CSession2* NewSessionL(const TVersion& aVer) const;
	CSession2* NewSessionL(const TVersion& aVer, const RMessage2&) const;

	CDmManagerServer(CDmSvrManager* aManager) : CServer2(CActive::EPriorityStandard), iManager(aManager)
		{}
	CDmSvrManager*	iManager;
	};

class CDmManagerSession : public CSession2
	{
public: 
	// from CBase
	~CDmManagerSession();
	
	// from CSession2
	void ServiceL(const RMessage2& aMessage);

	CDmManagerSession();
private:
	CDmHierarchy* iHierarchy;	// not owned
	};




//*********************************************************
// TTransitionFailure
//*********************************************************
/**
@internalTechnology

Constructor for transition failure info.

@param aDomainID	Id of the domain of interest
@param aError		error code of transition	 
*/
TTransitionFailure::TTransitionFailure(TDmDomainId aDomainId, TInt aError) :
	iDomainId(aDomainId), iError(aError)
	{
	}

//*********************************************************
// TTransInfo
//*********************************************************

/**
@internalTechnology

Constructor for transition failure info.

@param aDomainID	Id of the domain of interest
@param aState		State of the domain after transition
@param aError		error code of transition	 
*/
TTransInfo::TTransInfo(TDmDomainId aDomainId, TDmDomainState aState, TInt aError) :
	iDomainId(aDomainId), iState(aState), iError(aError)
	{
	}

//*********************************************************
// CSvrDomain
//*********************************************************


CSvrDomain::CSvrDomain(CDmHierarchy& aHierarchy, const TDmDomainSpec* spec)
	:	CTimer(CActive::EPriorityStandard), 
		iHierarchy(aHierarchy),
		iTransTimeBudget(spec->iTimeBudgetUs),
		iJoinPolicy(spec->iJoinPolicy),
		iId(spec->iId)
	{}

CSvrDomain* CSvrDomain::New(CDmHierarchy& aHierarchy, const TDmDomainSpec& aSpec)
	{

	CSvrDomain* self = new CSvrDomain(aHierarchy, &aSpec);

	if (!self)
		__DS_PANIC(KErrNoMemory);
	self->Construct(&aSpec);
	return self;
	}

void CSvrDomain::Construct(const TDmDomainSpec* spec)
	{
	TInt r = iProperty.Define(
		KUidDmPropertyCategory, 
		DmStatePropertyKey(iHierarchy.iHierarchyId, iId), 
		RProperty::EInt,
		KAllowAllPolicy,KPowerMgmtPolicy);

	if (r != KErrNone)
		__DS_PANIC(r);
	
	r = iProperty.Attach(KUidDmPropertyCategory, DmStatePropertyKey(
		iHierarchy.iHierarchyId, 
		iId));

	if (r != KErrNone)
		__DS_PANIC(r);

	r = iProperty.Set(DmStatePropertyValue(0, spec->iInitState));
	if (r != KErrNone)
		__DS_PANIC(r);

	TRAP(r, CTimer::ConstructL());
	if (r != KErrNone)
		__DS_PANIC(r);
	CActiveScheduler::Add(this);
	}

void CSvrDomain::Attach(CDmDomainSession* aSession)
	{
	aSession->iNext = iSessions;
	iSessions = aSession;
	}

void CSvrDomain::Detach(CDmDomainSession* aSession)
	{
	CDmDomainSession** prevp = &iSessions;
	while (*prevp != aSession)
		{
		prevp = &((*prevp)->iNext);
		__DS_ASSERT(*prevp);
		}
	*(prevp) = aSession->iNext;
	}

void CSvrDomain::AddChild(CSvrDomain* aChild)
	{
	++iChildrenCount;
	aChild->iParent = this;
	if(iIsObserved)
		aChild->iIsObserved=ETrue;
	// Insert the child in the list of its peers
	aChild->iPeer = iChild;
	iChild = aChild;
	}

CSvrDomain* CSvrDomain::Lookup(TDmDomainId aDomainId)
	{
	if (iId == aDomainId)
		return this;

	CSvrDomain* child = iChild;
	while (child)
		{
		CSvrDomain* domain = child->Lookup(aDomainId);
		if (domain)
			return domain;
		child = child->iPeer;
		}
	return NULL;
	}

TBool CSvrDomain::CheckPropValue(TInt aPropValue)
	{ return iHierarchy.iTransPropValue == aPropValue; }

void CSvrDomain::RequestMembersTransition()
	{
	__DS_TRACE((_L("CSvrDomain::RequestMembersTransition() hierarchy=%d, domain=0x%x"), iHierarchy.iHierarchyId, iId));
	__DS_ASSERT(iTransCount == 0);
	
	for(CDmDomainSession* s = iSessions; s; s = s->iNext)
		if (s->iNotificationEnabled)
			{
			++iTransCount;
			s->iPending = ETrue;
			// notifications will be disabled until the client makes another 
			// call to RDmDomain::RequestTransitionNotification()
			s->iNotificationEnabled = EFalse;
			}

	if(iIsObserved)
		{
		if((iHierarchy.iNotifyType&EDmNotifyTransRequest)==EDmNotifyTransRequest)
			{
			TTransInfo transInfo(iId,State(),KDmErrOutstanding);
			iHierarchy.iTransitions.Append(transInfo);
			if(iHierarchy.OutstandingNotification())
					iHierarchy.CompleteNotification(KErrNone);	
			}
		}
	if (iTransCount > 0)
		CTimer::After(iTransTimeBudget);
	iProperty.Set(iHierarchy.iTransPropValue);
	if (iTransCount == 0)
		MembersTransitionDone();
	}


void CSvrDomain::RequestChildrenTransition()
	{
	__DS_TRACE((_L("CSvrDomain::RequestChildrenTransition() hierarchy=%d, domain=0x%x"), iHierarchy.iHierarchyId, iId));
	__DS_ASSERT(iTransCount == 0);
	iTransCount = iChildrenCount;
	if (iTransCount)
		{
		CSvrDomain* child = iChild;
		__DS_ASSERT(child);
		do	{
			child->RequestDomainTransition();
			child = child->iPeer;
			}
		while(child);
		}
	else
		ChildrenTransitionDone();
	}

void CSvrDomain::RequestDomainTransition()
	{
	__DS_TRACE((_L("CSvrDomain::RequestDomainTransition() hierarchy=%d, domain=0x%x state=0x%x prop=0x%x"), 
						iHierarchy.iHierarchyId, iId, iHierarchy.iTransState, iHierarchy.iTransPropValue));
	__DS_ASSERT(iTransCount == 0);
	if (iHierarchy.iTraverseDirection == ETraverseChildrenFirst)
		RequestChildrenTransition();
	else
		RequestMembersTransition();
	}
		
void CSvrDomain::MembersTransitionDone()
	{
	__DS_TRACE((_L("CSvrDomain::MembersTransitionDone() hierarchy=%d, domain=0x%x"), iHierarchy.iHierarchyId, iId));
	__DS_ASSERT(iTransCount == 0);
	if (iHierarchy.iTraverseDirection == ETraverseChildrenFirst)
		CompleteDomainTransition();
	else
		RequestChildrenTransition();
	}

void CSvrDomain::ChildrenTransitionDone()
	{
	__DS_TRACE((_L("CSvrDomain::ChildrenTransitionDone() hierarchy=%d, domain=0x%x"), iHierarchy.iHierarchyId, iId));
	__DS_ASSERT(iTransCount == 0);
	if (iHierarchy.iTraverseDirection == ETraverseChildrenFirst)
		RequestMembersTransition();
	else
		CompleteDomainTransition();
	}

void CSvrDomain::CompleteMemberTransition(TInt aError)
	{
	__DS_TRACE((_L("CSvrDomain::CompleteMemberTransition() hierarchy=%d, domain=0x%x, aError = %d"), iHierarchy.iHierarchyId, iId, aError));
	__DS_ASSERT(iTransCount);

	if (aError)
		{
		// Add a transition failure to the array
		TTransitionFailure failure(iId, aError);
		iHierarchy.iTransitionFailures.Append(failure);
		
		if(iIsObserved)
			{
				if((iHierarchy.iNotifyType&EDmNotifyFail)==EDmNotifyFail)
				{
				TTransInfo transInfo(iId,State(),aError);
				iHierarchy.iTransitions.Append(transInfo);
				if(iHierarchy.OutstandingNotification())
					iHierarchy.CompleteNotification(KErrNone);
				}
			}
		// examine the failure policy to work out what to do
		if (iHierarchy.iPolicy.iFailurePolicy == ETransitionFailureStop)
			{
			iHierarchy.CompleteTransition(aError);
			return;
			}
		}
	else if(iIsObserved)
			{
				if((iHierarchy.iNotifyType&EDmNotifyPass) == EDmNotifyPass)
				{
				TTransInfo transInfo(iId,State(),aError);
				iHierarchy.iTransitions.Append(transInfo);
				if(iHierarchy.OutstandingNotification())
					iHierarchy.CompleteNotification(KErrNone);
				}
			}

	if (--iTransCount == 0)
		{
		CTimer::Cancel();
		MembersTransitionDone();
		}
	}

void CSvrDomain::RunL()
	{ // Timer expired 
	__DS_TRACE((_L("CSvrDomain::RunL() Members transition timeout hierarchy=%d, domain=0x%x"), iHierarchy.iHierarchyId, iId));

	// Add a transition failure to the array
	TTransitionFailure failure(iId,KErrTimedOut);
	iHierarchy.iTransitionFailures.Append(failure);


	// examine the failure policy to work out what to do
	if (iHierarchy.iPolicy.iFailurePolicy == ETransitionFailureStop)
		{
		iHierarchy.CompleteTransition(KErrTimedOut);
		return;
		}

	if (iTransCount)
		{ // Complete transition of all members
		CDmDomainSession* session = iSessions;
		while (session)
			{
			session->iPending = EFalse;
			session = session->iNext;
			}
		iTransCount = 0;
		MembersTransitionDone();
		}
	}


void CSvrDomain::CompleteDomainTransition()
	{
	__DS_TRACE((_L("CSvrDomain::CompleteDomainTransition() hierarchy=%d, domain=0x%x"), iHierarchy.iHierarchyId, iId));
	__DS_ASSERT(iTransCount == 0);
	if (iHierarchy.iTransDomain == this)
		{
		const TInt err = (iHierarchy.iTransitionFailures.Count() > 0)? 
			iHierarchy.iTransitionFailures[0].iError : KErrNone;
		iHierarchy.CompleteTransition(err);
		}
	else
		{
		__DS_ASSERT(iParent);
		__DS_ASSERT(iParent->iTransCount);
		if (--iParent->iTransCount == 0)
			iParent->ChildrenTransitionDone();
		}
	}

void CSvrDomain::CancelTransition()
	{
	__DS_TRACE((_L("CSvrDomain::CancelTransition() hierarchy=%d, domain=0x%x"), iHierarchy.iHierarchyId, iId));
	CTimer::Cancel();
	CSvrDomain* child = iChild;
	while (child)
		{
		child->CancelTransition();
		child = child->iPeer;
		}
	CDmDomainSession* session = iSessions;
	while (session)
		{
		session->iPending = EFalse;
		session = session->iNext;
		}
	iTransCount = 0;
	}

void CSvrDomain::SetObserver(TBool aSet)
	{
	iIsObserved=aSet;
	if(aSet)
		{
		iHierarchy.iObservedChildren++;
		}
	else 
		{
		// this should be zero at the end
		iHierarchy.iObservedChildren--;
		}
	if(iChildrenCount!=0)
		{
		CSvrDomain* domain=iChild;
		do	{
			domain->SetObserver(aSet);
			domain = domain->iPeer;
			}
		while(domain);
		}
	}

TDmDomainState CSvrDomain::State()
	{
	TInt value;
	iProperty.Get(value);
	return DmStateFromPropertyValue(value);
	}

//*********************************************************
// CDmHierarchy
//*********************************************************

CDmHierarchy* CDmHierarchy::New(TDmHierarchyId aHierarchyId, TDmHierarchyPolicy& aPolicy)
	{
	CDmHierarchy* self;
	
	if (aHierarchyId == KDmHierarchyIdPower)
		self = CDmHierarchyPower::New(aHierarchyId, aPolicy);
	else 
		self = new CDmHierarchy(aHierarchyId, aPolicy);

	if (!self)
		__DS_PANIC(KErrNoMemory);

	return self;
	}

CDmHierarchy::CDmHierarchy(TDmHierarchyId aHierarchyId, TDmHierarchyPolicy& aPolicy) :
	iOutstandingNotification(EFalse),
	iHierarchyId(aHierarchyId),
	iPolicy(aPolicy)
	{
	iTransitionFailures.Reset();
	}

CSvrDomain* CDmHierarchy::LookupDomain(TDmDomainId aDomainId)
	{
	return iRootDomain ? iRootDomain->Lookup(aDomainId) : NULL;
	}

void CDmHierarchy::RequestTransition(const RMessage2* aMessage)
	{
	// reset the array of transition failures
	iTransitionFailures.Reset();

	if (aMessage)
		iTransMessagePtr = *aMessage;
	iTransPropValue = DmStatePropertyValue(++iTransId, iTransState);

	iTransDomain->RequestDomainTransition();
	}


TInt CDmHierarchy::StartObserver(TDmDomainId aDomainId,TDmNotifyType aNotifyType)
	{
	iObservedDomain = LookupDomain(aDomainId);
		
	if(iObservedDomain==NULL)
		return KDmErrBadDomainId;
	

	iObservedDomain->SetObserver(ETrue);
	iNotifyType=aNotifyType;
	iObserverStarted=ETrue;
	return KErrNone;
	}

void CDmHierarchy::SetNotifyMessage(const RMessage2* aMessage)
	{
	if (aMessage)
		{
		iObsvrMessagePtr = *aMessage;
		iOutstandingNotification=ETrue;
		}		
	}

TBool CDmHierarchy::OutstandingNotification()
	{
	return iOutstandingNotification;
	}

void CDmHierarchy::CompleteNotification(TInt aError)
	{
	if(iOutstandingNotification)
		{
		iObsvrMessagePtr.Complete(aError);
		iOutstandingNotification=EFalse;
		}
	}

void CDmHierarchy::StopObserver()
	{
	
	iObservedDomain->SetObserver(EFalse);
	iTransitions.Reset();
	iObserverStarted=EFalse;
	}
void CDmHierarchy::NotifyCompletion(TInt aReason)
	{
	iTransDomain = NULL;
	iTransPropValue = 0;
	iTransMessagePtr.Complete(aReason);
	}

TInt CDmHierarchy::RequestSystemTransition(TDmDomainState aTargetState, TDmTraverseDirection aTraverseDirection, const RMessage2* aMessage)
	{
	iTransDomain = iRootDomain;
	SetState(aTargetState, aTraverseDirection);
	RequestTransition(aMessage);
	return KErrNone;
	}


TInt CDmHierarchy::RequestDomainTransition(
	TDmDomainId aDomainId, 
	TDmDomainState aTargetState, 
	TDmTraverseDirection aTraverseDirection, 
	const RMessage2* aMessage)
	{
	__DS_TRACE((_L("CDmHierarchy::RequestTransition() hierarchy=%d domain=0x%x state=0x%x"), iHierarchyId, aDomainId, aTargetState)); 
	iTransDomain = LookupDomain(aDomainId);
	if (!iTransDomain)
		return KDmErrBadDomainId;
	SetState(aTargetState, aTraverseDirection);
	RequestTransition(aMessage);
	return KErrNone;
	}

void CDmHierarchy::CompleteTransition(TInt aError)
	{
	if (!iTransDomain)
		return;

	__DS_TRACE((_L("CDmHierarchy::CompleteTransition() hierarchy=%d, domain=0x%x, aError=%d"), iHierarchyId, iTransDomain->iId, aError));

	if (iTransDomain)
		{
		iTransDomain->CancelTransition();
		NotifyCompletion(aError);
		}
	}

void CDmHierarchy::SetState(TDmDomainState aTargetState, TDmTraverseDirection aTraverseDirection)
	{
	__DS_ASSERT(iTransDomain);


	if (aTraverseDirection == ETraverseDefault)
		{
		TDmDomainState oldState = iTransDomain->State();

		if (aTargetState >= oldState)
			iTraverseDirection = iPolicy.iPositiveTransitions;
		else
			iTraverseDirection = iPolicy.iNegativeTransitions;
		}
	else
		iTraverseDirection = aTraverseDirection;

	__DS_ASSERT(iTraverseDirection < ETraverseMax);

	iTransState = aTargetState;
	}

//*********************************************************
// CPowerUpHandler
//*********************************************************

CPowerUpHandler* CPowerUpHandler::New(CDmHierarchyPower& aHierarchyPower)
	{
	CPowerUpHandler* self = new CPowerUpHandler(aHierarchyPower);
	if (!self)
		__DS_PANIC(KErrNoMemory);
	self->Construct();
	return self;
	}

CPowerUpHandler::CPowerUpHandler(CDmHierarchyPower& aHierarchyPower) : 
	CActive(CActive::EPriorityStandard),
	iHierarchyPower(aHierarchyPower)
	{
	}

void CPowerUpHandler::Construct()
	{
	CActiveScheduler::Add(this);
	}


void CPowerUpHandler::RequestWakeupEventNotification()
	{
	Power::RequestWakeupEventNotification(iStatus);
	SetActive();
	}


void CPowerUpHandler::Cancel()
	{
	CActive::Cancel();
	}

void CPowerUpHandler::RunL()
	{ 
	// power wakeup event
	iHierarchyPower.PowerUp();
	}


void CPowerUpHandler::DoCancel()
	{
	Power::DisableWakeupEvents();
	Power::CancelWakeupEventNotification(); 
	}



//*********************************************************
// CDmHierarchyPower
//*********************************************************
CDmHierarchyPower* CDmHierarchyPower::New(TDmHierarchyId aHierarchyId, TDmHierarchyPolicy& aPolicy)
	{
	CDmHierarchyPower* self;

	self = new CDmHierarchyPower(aHierarchyId, aPolicy);

	if (!self)
		__DS_PANIC(KErrNoMemory);

	self->Construct();

	return self;
	}

CDmHierarchyPower::CDmHierarchyPower(TDmHierarchyId aHierarchyId, TDmHierarchyPolicy& aPolicy) :
	CDmHierarchy(aHierarchyId, aPolicy)
	{
	}


void CDmHierarchyPower::Construct()
	{
	iPowerUpHandler = CPowerUpHandler::New(*this);
	if (!iPowerUpHandler)
		__DS_PANIC(KErrNoMemory);
	}

void CDmHierarchyPower::NotifyCompletion(TInt aReason)
	{
	iTransStatus = 0;
	CDmHierarchy::NotifyCompletion(aReason);
	}

TInt CDmHierarchyPower::RequestSystemTransition(TDmDomainState aTargetState, TDmTraverseDirection aTraverseDirection, const RMessage2* aMessage)
	{
	__DS_TRACE((_L("CDmSvrManager::RequestSystemTransition() state = 0x%x"), aTargetState));
	
	TInt r = Power::EnableWakeupEvents((TPowerState) aTargetState);
	if (r != KErrNone)
		return r;
	
	iPowerUpHandler->RequestWakeupEventNotification();

	iTransStatus |= EPoweringDown;

	return CDmHierarchy::RequestSystemTransition(aTargetState, aTraverseDirection, aMessage);
	}

void CDmHierarchyPower::CompleteTransition(TInt aError)
	{
	if (!iTransDomain)
		return;

	__DS_TRACE((_L("CDmHierarchyPower::CompleteTransition() domain=0x%x"), iTransDomain->iId));

	if (iTransDomain && aError == KErrCancel)
		iPowerUpHandler->Cancel();

	if (iTransStatus & EPoweringDown)
		{
		RFs fs;
		TInt r=fs.Connect();
		__DS_ASSERT(r==KErrNone);	
		__DS_TRACE((_L("CDmSvrManager::CompleteTransition() Calling FinaliseDrives")));
		r=fs.FinaliseDrives();
		__DS_TRACE((_L("CDmSvrManager::CompleteTransition()  Finalise returned %d"),r)); 
		fs.Close();

		Power::PowerDown();
		__DS_ASSERT(iTransState != (TDmDomainState) EPwOff);
		__DS_ASSERT(iPowerUpHandler->iStatus.Int() == KErrNone);
		}	
	else
		{
		CDmHierarchy::CompleteTransition(aError);
		}
	}


void CDmHierarchyPower::PowerUp()
	{
	__DS_TRACE((_L("CDmHierarchyPower::RunL() Wakeup Event")));
	__DS_ASSERT(iTransDomain);

	Power::DisableWakeupEvents();

	iTransStatus &= ~EPoweringDown;
	iTransDomain->CancelTransition();
	SetState((TDmDomainState) EPwActive);
	RequestTransition(NULL);
	}


//*********************************************************
// CDmSvrManager
//*********************************************************

CDmSvrManager* CDmSvrManager::New()
	{
	CDmSvrManager* self = new CDmSvrManager();
	if (!self)
		__DS_PANIC(KErrNoMemory);
	self->Construct();
	return self;
	}

CDmSvrManager::CDmSvrManager()
	{
	}

void CDmSvrManager::Construct()
	{
	// load the power hierarchy-  Other hieratchies need to be loaded 
	// explicitly using RDmDomainManager::AddDomainHierarchy()
	CDmHierarchy* hierarchy;
	TInt r = BuildDomainTree(KDmHierarchyIdPower, hierarchy);
	if (r != KErrNone)
		__DS_PANIC(r);


	RProperty prop;
	r = prop.Define(KUidDmPropertyCategory, KDmPropertyKeyInit, RProperty::EInt,
							KAllowAllPolicy,KPowerMgmtPolicy);
	if (r != KErrNone)
		__DS_PANIC(r);

	prop.Set(KUidDmPropertyCategory, KDmPropertyKeyInit, ETrue);
	}

TInt CDmSvrManager::BuildDomainTree(TDmHierarchyId aHierarchyId, CDmHierarchy*& aHierarchy)
	{

	aHierarchy = NULL;

	// assume we have already checked that the hierarchy doesn't already exist

	// Get the name of the policy Dll
	// This will be "domainPolicy.dll" for the power hierarchy
	// and "domainPolicy<n>.dll" for other hierarchies where <n> is the hierarchy ID.
	//
	// If the hierarchy ID is less than KMaxCriticalPolicyDll, load only from ROM

	TFullName dllName;

	// is this policy "critical" i.e non-replaceable ?
	_LIT(KSysBin,"z:\\sys\\bin\\");	
	// const TInt KMaxCriticalPolicyDll = 1000;
	// if (aHierarchyId < KMaxCriticalPolicyDll) // <-- cannot be false while aHierarchyId is a TUint8 (typedef'd to TDmHierarchyId)
	dllName.Append(KSysBin);

	dllName.Append(_L("domainPolicy"));
	if (aHierarchyId != KDmHierarchyIdPower)
		dllName.AppendNum(aHierarchyId);

	dllName.Append(_L(".dll"));
	RLibrary lib;
	TInt r = lib.Load(dllName);
	if (r == KErrNotFound)
		return KErrBadHierarchyId;
	else if (r != KErrNone)
		return r;

	TLibraryFunction ordinal1 = lib.Lookup(EDmPolicyGetDomainSpecs);
	DmPolicyGetDomainSpecs getDomainSpecs = reinterpret_cast<DmPolicyGetDomainSpecs>(ordinal1);
	if (getDomainSpecs == NULL)
		r = KErrBadHierarchyId;

	TLibraryFunction ordinal2 = lib.Lookup(EDmPolicyRelease);
	DmPolicyRelease release = reinterpret_cast<DmPolicyRelease>(ordinal2);
	if (release == NULL)
		r = KErrBadHierarchyId;

	TLibraryFunction ordinal3 = lib.Lookup(EDmPolicyGetPolicy);
	DmPolicyGetPolicy getPolicy = reinterpret_cast<DmPolicyGetPolicy>(ordinal3);
	if (getPolicy == NULL)
		r = KErrBadHierarchyId;


	// get the domain spec for this hierarchy
	const TDmDomainSpec* spec = NULL;

	if (r == KErrNone)
		{
		spec = (*getDomainSpecs)();
		if (spec == NULL)
			r = KErrBadHierarchyId;
		}
	// get the policy
	TDmHierarchyPolicy hierarchyPolicy;
	if (r == KErrNone)
		{
		r = (*getPolicy)(hierarchyPolicy);
		if (r == KErrNone)
			{
			__DS_ASSERT(hierarchyPolicy.iPositiveTransitions < ETraverseMax);
			__DS_ASSERT(hierarchyPolicy.iNegativeTransitions < ETraverseMax);
			}
		}

	if (r != KErrNone)
		{
		lib.Close();
		return r;
		}

	CDmHierarchy* hierarchy = CDmHierarchy::New(aHierarchyId, hierarchyPolicy);
	if (hierarchy == NULL)
		__DS_PANIC(KErrNoMemory);

	while (r == KErrNone && spec->iId != KDmIdNone)
		{
		// make sure the domain doesn't already exist in this hierarchy
		CSvrDomain* domain = hierarchy->LookupDomain(spec->iId);
		if (domain)
			{
			r = KErrBadHierarchyId;
			break;
			}

		domain = CSvrDomain::New(*hierarchy, *spec);
		__DS_ASSERT(domain);
	
		if (spec->iParentId == KDmIdNone)
			{
			if (hierarchy->iRootDomain)
				{
				r = KDmErrBadDomainSpec;
				break;
				}
			hierarchy->iRootDomain = domain;
			}
		else
			{
			CSvrDomain* parent = hierarchy->LookupDomain(spec->iParentId);
			if (!parent)
				{
				r = KDmErrBadDomainSpec;
				break;
				}
			parent->AddChild(domain);
			}
		++spec;
		}

	if (spec)
		(*release)(spec);


	if (r == KErrNone)
		{
		__DS_ASSERT(hierarchy->iRootDomain);
		iDomainHierarchies.Append(hierarchy);
		aHierarchy = hierarchy;
		}
	else
		{
		delete hierarchy;
		hierarchy = NULL;
		}

	lib.Close();

	return r;
	}

CDmHierarchy* CDmSvrManager::LookupHierarchy(TDmHierarchyId aHierarchyId)

	{
	// need to find the correct hierarchy first
	TInt len = iDomainHierarchies.Count();

	CDmHierarchy* hierarchy = NULL;
	for (TInt n=0; n<len; n++)
		{
		if (iDomainHierarchies[n]->iHierarchyId == aHierarchyId)
			{
			hierarchy = iDomainHierarchies[n];
			break;
			}
		}

	return hierarchy;
	}
	

TInt CDmSvrManager::LookupDomain(TDmHierarchyId aHierarchyId, TDmDomainId aDomainId, CSvrDomain*& aDomain)
	{
	// need to find the correct hierarchy first
	CDmHierarchy* hierarchy = LookupHierarchy(aHierarchyId);
	if (hierarchy == NULL)
		return KErrBadHierarchyId;

	aDomain = hierarchy->LookupDomain(aDomainId);
	if (aDomain == NULL)
		return KDmErrBadDomainId;
	
	return KErrNone;
	}
	
CSession2* CDmManagerServer::NewSessionL(const TVersion&, const RMessage2& aMessage) const
	{

    // If the client does not have ECapabilityPowerMgmt capability, then it has no
    // right to make this request. Blow it up.
    if (!KPowerMgmtPolicy.CheckPolicy(aMessage))
		{

        User::Leave(KErrPermissionDenied);

		}

	return new CDmManagerSession();
	}

CSession2* CDmManagerServer::NewSessionL(const TVersion&) const
	{
	__DS_PANIC(KErrGeneral);
	return 0;
	}

CDmManagerSession::CDmManagerSession()
	{}

CDmManagerSession::~CDmManagerSession()
	{
	if (iHierarchy && iHierarchy->iControllerSession == this)
		iHierarchy->iControllerSession = NULL;
	if (iHierarchy && iHierarchy->iObserverSession == this)
		iHierarchy->iObserverSession = NULL;
	}

class MyMessage : public RMessage2
	{
public:
	TInt* ArgRef(TInt i)
		{ return &iArgs[i]; }
	};

void CDmManagerSession::ServiceL(const RMessage2& aMessage)
	{
	TInt r;
	CDmSvrManager* manager = ((CDmManagerServer*) Server()) -> iManager;

	// Check client has ECapabilityPowerMgmt capability
/*	
    if (!KPowerMgmtPolicy.CheckPolicy(aMessage))
		{
		aMessage.Complete(KErrPermissionDenied);
		return;
		}
*/
	switch (aMessage.Function())
		{
		case EDmHierarchyAdd:
			{
			r = KErrNone;
			TDmHierarchyId hierarchyId = (TDmHierarchyId) aMessage.Int0();

			CDmHierarchy* hierarchy = manager->LookupHierarchy(hierarchyId);
			if (hierarchy == NULL)
				r = manager->BuildDomainTree(hierarchyId, hierarchy);
			aMessage.Complete(r);
			}
			break;

		case EDmHierarchyJoin:
			{
			r = KErrNone;
			TDmHierarchyId hierarchyId = (TDmHierarchyId) aMessage.Int0();

			iHierarchy = manager->LookupHierarchy(hierarchyId);
			if (iHierarchy == NULL)
				r = KErrBadHierarchyId;

			if (r == KErrNone)
				{
				// is the hierarchy already in use ?
				if (iHierarchy->iControllerSession)
					r = KErrInUse;
				else
					iHierarchy->iControllerSession = this;
				}

			aMessage.Complete(r);
			}
			break;

		case EDmRequestSystemTransition:
			if (iHierarchy==NULL)
				{
				aMessage.Complete(KErrBadHierarchyId);
				break;
				}
			if (iHierarchy->iTransDomain)
				{
				aMessage.Complete(KDmErrBadSequence);
				break;
				}

			r = iHierarchy->RequestSystemTransition(
				(TDmDomainState) aMessage.Int0(),
				(TDmTraverseDirection) aMessage.Int1(),
				&aMessage);

			if (r != KErrNone)
				aMessage.Complete(r);
			break;

		case EDmRequestDomainTransition:
			if (iHierarchy==NULL)
				{
				aMessage.Complete(KErrBadHierarchyId);
				break;
				}
			if (iHierarchy->iTransDomain)
				{
				aMessage.Complete(KDmErrBadSequence);
				break;
				}
			r = iHierarchy->RequestDomainTransition(
				(TDmDomainId) aMessage.Int0(), 
				(TDmDomainState) aMessage.Int1(), 
				(TDmTraverseDirection) aMessage.Int2(),
				&aMessage);

			if (r != KErrNone)
				aMessage.Complete(r);
			break;

		case EDmGetTransitionFailureCount:
			{
			if (iHierarchy==NULL)
				{
				aMessage.Complete(KErrBadHierarchyId);
				break;
				}
			TInt failureCount = iHierarchy->iTransitionFailures.Count();
			aMessage.Complete(failureCount);
			}
			break;
		
		case EDmGetTransitionFailures:
			{
			if (iHierarchy==NULL)
				{
				aMessage.Complete(KErrBadHierarchyId);
				break;
				}
			TInt failureCount = iHierarchy->iTransitionFailures.Count();
			TInt clientFailureSize = aMessage.GetDesMaxLength(0);
			TInt clientFailureCount = clientFailureSize / sizeof(TTransitionFailure);
			__DS_ASSERT( (clientFailureSize % sizeof(TTransitionFailure)) == 0);
			__DS_ASSERT(failureCount >= clientFailureCount);
			
			HBufC8* hBuf = HBufC8::New(clientFailureSize);
			if(hBuf == NULL)
				{
				aMessage.Complete(KErrNoMemory);
				break;
				}
			TPtr8 pBuf = hBuf->Des();
			pBuf.Zero();
			for (TInt i=0; i<clientFailureCount; i++)
				{
				TPtrC8 ptr = TPtrC8((TUint8*) &iHierarchy->iTransitionFailures[i], sizeof(TTransitionFailure));
				pBuf.Append(ptr);
				}
			r = aMessage.Write(0, pBuf);
			delete hBuf;

			aMessage.Complete(r);
			}
			break;

		case EDmCancelTransition:
			if (iHierarchy == NULL)
				{
				aMessage.Complete(KErrBadHierarchyId);
				break;
				}
			iHierarchy->CompleteTransition(KErrCancel);
			if (iHierarchy->iObserverStarted)
				{
				iHierarchy->CompleteNotification(KErrCancel);
				iHierarchy->StopObserver();
				}
			aMessage.Complete(KErrNone);
			break;
		case EDmObserverCancel:
			if (iHierarchy == NULL)
				{
				aMessage.Complete(KErrBadHierarchyId);
				break;
				}
			if(!iHierarchy->iObserverSession)
				{
				aMessage.Complete(KDmErrBadSequence);
				break;
				}
			if (iHierarchy->iObserverStarted)
				{
				iHierarchy->CompleteNotification(KErrCancel);
				iHierarchy->StopObserver();
				}
			aMessage.Complete(KErrNone);
			break;

		case EDmObserverJoin:
			{
			TDmHierarchyId hierarchyId = (TDmHierarchyId) aMessage.Int0();

			iHierarchy = manager->LookupHierarchy(hierarchyId);
			if(iHierarchy==NULL)
				{
				aMessage.Complete(KErrBadHierarchyId);
				break;
				}
			if(iHierarchy->iObserverSession)
				{
				aMessage.Complete(KDmErrBadSequence);
				break;
				}
			iHierarchy->iTransitions.Reset();
			iHierarchy->iObserverSession = this;
			aMessage.Complete(KErrNone);
			}
			break;

		case EDmObserverStart:
			{
			if (iHierarchy==NULL)
				{
				aMessage.Complete(KErrBadHierarchyId);
				break;
				}
			
			if(iHierarchy->iObserverStarted || iHierarchy->iObserverSession != this)
				{
				aMessage.Complete(KDmErrBadSequence); 
				break;
				}
			TInt ret= iHierarchy->StartObserver((TDmDomainId)aMessage.Int0(),(TDmNotifyType)aMessage.Int1());
			aMessage.Complete(ret);
			}
			break;

		case EDmObserverNotify:
			{
			if (iHierarchy==NULL)
				{
				aMessage.Complete(KErrBadHierarchyId);
				break;
				}
			if(!iHierarchy->iObserverStarted || iHierarchy->iObserverSession != this)
				{
				aMessage.Complete(KDmErrBadSequence); 
				break;
				}
			//	Check to see if we have any events stored 
			//	If so, then notify the client
			if(iHierarchy->iTransitions.Count()>0)
				{
				aMessage.Complete(KErrNone);
				break;
				}
			//	No events are stored. complete this message later
			iHierarchy->SetNotifyMessage(&aMessage);
			}
			break;
		
		case EDmObserverEventCount:
			{
			if (iHierarchy==NULL)
				{
				aMessage.Complete(KErrBadHierarchyId);
				break;
				}
			if(!iHierarchy->iObserverStarted || iHierarchy->iObserverSession != this)
				{
				aMessage.Complete(KDmErrBadSequence);
				break;
				}
			TInt count = iHierarchy->iTransitions.Count();
			aMessage.Complete(count);
			}
			break;
		
		case EDmObserverGetEvent:
			{
			if (iHierarchy==NULL)
				{
				aMessage.Complete(KErrBadHierarchyId);
				break;
				}
			if(!iHierarchy->iObserverStarted || iHierarchy->iObserverSession != this)
				{
				aMessage.Complete(KDmErrBadSequence);
				break;
				}
			TInt transitionCount = iHierarchy->iTransitions.Count();
			TInt clientTransitionSize = aMessage.GetDesMaxLength(0);
			TInt clientTransitionCount = clientTransitionSize / sizeof(TTransInfo);
			__DS_ASSERT( (clientTransitionSize % sizeof(TTransInfo)) == 0);
			__DS_ASSERT(transitionCount >= clientTransitionCount);
			
			HBufC8* hBuf = HBufC8::New(clientTransitionSize);
			if(hBuf == NULL)
				{
				aMessage.Complete(KErrNoMemory);
				break;
				}
			TPtr8 pBuf = hBuf->Des();
			pBuf.Zero();
			for (TInt i=0; i<clientTransitionCount; i++)
				{
				TPtrC8 ptr = TPtrC8((TUint8*) &iHierarchy->iTransitions[0], sizeof(TTransInfo));
				pBuf.Append(ptr);
				iHierarchy->iTransitions.Remove(0);
				}
			r = aMessage.Write(0, pBuf);
			delete hBuf;

			aMessage.Complete(r);
			}
			break;
		case EDmObserveredCount:
			{
			if (iHierarchy==NULL)
				{
				aMessage.Complete(KErrBadHierarchyId);
				break;
				}
			if(!iHierarchy->iObserverStarted || iHierarchy->iObserverSession != this)
				{
				aMessage.Complete(KDmErrBadSequence);
				break;
				}
			aMessage.Complete(iHierarchy->iObservedChildren);
			}
			break;
		default:
			aMessage.Complete(KDmErrBadRequest);
			break;
		}
	}

CSession2* CDmDomainServer::NewSessionL(const TVersion&, const RMessage2&) const
	{

	return new CDmDomainSession();
	}

CSession2* CDmDomainServer::NewSessionL(const TVersion&) const
	{
	__DS_PANIC(KErrGeneral);
	return 0;
	}

CDmDomainSession::~CDmDomainSession()
	{
	if (iPending)
		iDomain->CompleteMemberTransition(KErrNone);
	if (iDomain)
		iDomain->Detach(this);
	}

void CDmDomainSession::ServiceL(const RMessage2& aMessage)
	{
	TInt r = KErrNone;
	CDmSvrManager* manager = ((CDmManagerServer*) Server()) -> iManager;

	switch (aMessage.Function())
		{
	case EDmDomainJoin:
		{
		TDmHierarchyId hierarchyId = (TDmHierarchyId) aMessage.Int0();
		TDmDomainId domainId = (TDmDomainId) aMessage.Int1();

		r = manager->LookupDomain(hierarchyId, domainId, iDomain);

		if (r != KErrNone)
			break;

		// Check client has capability to join the domain
		if (!iDomain->iJoinPolicy.CheckPolicy(aMessage))
			{
			r = KErrPermissionDenied;
			iDomain = NULL;
			break;
			}

		iDomain->Attach(this);
		break;
		}

	case EDmStateRequestTransitionNotification:
		iNotificationEnabled = ETrue;
		break;

	case EDmStateCancelTransitionNotification:
		iNotificationEnabled = EFalse;
		break;

	case EDmStateAcknowledge:
		{
		TInt propValue = aMessage.Int0();
		TInt error = aMessage.Int1();
		if (!iDomain)
			{
			r = KDmErrNotJoin;
			break;
			}
		if (iPending && iDomain->CheckPropValue(propValue))
			{
			iPending = EFalse;
			iDomain->CompleteMemberTransition(error);
			}
		}
		break;
	default:
		r = KDmErrBadRequest;
		break;
		}
	aMessage.Complete(r);
	}

	
TInt E32Main()
	{
	CTrapCleanup* cleanupStack = CTrapCleanup::New();
	if(!cleanupStack)
		__DS_PANIC(KErrNoMemory);

	CActiveScheduler* sched = new CActiveScheduler();
	if (!sched)
		__DS_PANIC(KErrNoMemory);

	CActiveScheduler::Install(sched);

	CDmSvrManager* mngr = CDmSvrManager::New();
	__DS_ASSERT(mngr);

	CDmManagerServer* msrv = new CDmManagerServer(mngr);
	if (!msrv)
		__DS_PANIC(KErrNoMemory);

	TInt r=msrv->Start(KDmManagerServerNameLit);
	if (r != KErrNone)
		__DS_PANIC(r);

	CDmDomainServer* dsrv = new CDmDomainServer(mngr);
	if (!dsrv)
		__DS_PANIC(KErrNoMemory);

	r=dsrv->Start(KDmDomainServerNameLit);
	if (r != KErrNone)
		__DS_PANIC(r);

	CActiveScheduler::Start();

	__DS_PANIC(0);

	return KErrNone;
	}