sysstatemgmt/systemstatemgr/ssm/src/ssmstatetransitionengine.cpp
changeset 0 4e1aa6a622a0
child 41 c87e5f80c17d
equal deleted inserted replaced
-1:000000000000 0:4e1aa6a622a0
       
     1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <ssm/ssmcommandlist.h>
       
    17 
       
    18 #include "ssmdebug.h"
       
    19 #include "ssmserverpanic.h"
       
    20 #include "ssmstatetransitionengine.h"
       
    21 #include "ssmstatepolicyresolverproxy.h"
       
    22 #include "clesessionproxy.h"
       
    23 #include "ssmstatetransitionrequest.h"
       
    24 #include "ssmstatepolicyframe.h"
       
    25 #include "ssmcommandlistutils.h"
       
    26 
       
    27 
       
    28 CSsmStateTransitionEngine* CSsmStateTransitionEngine::NewL(MSsmStatePolicyResolverProxy* aResolver, MCleSessionProxy* aCleSession)
       
    29 	{
       
    30 	CSsmStateTransitionEngine* self = CSsmStateTransitionEngine::NewLC(aResolver, aCleSession);
       
    31 	CleanupStack::Pop(self);
       
    32 	return self;
       
    33 	}
       
    34 
       
    35 CSsmStateTransitionEngine* CSsmStateTransitionEngine::NewLC(MSsmStatePolicyResolverProxy* aResolver, MCleSessionProxy* aCleSession)
       
    36 	{
       
    37 	__ASSERT_DEBUG(aResolver,	PanicNow(KPanicSysStateMgr,ESsmStateEngineError5));
       
    38 	__ASSERT_DEBUG(aCleSession,	PanicNow(KPanicSysStateMgr,ESsmStateEngineError2));
       
    39 	CSsmStateTransitionEngine* self = new (ELeave) CSsmStateTransitionEngine(aResolver, aCleSession);
       
    40 	CleanupStack::PushL(self);
       
    41 	return self;
       
    42 	}
       
    43 
       
    44 CSsmStateTransitionEngine::CSsmStateTransitionEngine(MSsmStatePolicyResolverProxy* aResolver, MCleSessionProxy* aCleSession)
       
    45 	: CActive(CActive::EPriorityStandard),
       
    46 	iResolver(*aResolver),
       
    47 	iCleSession(*aCleSession),
       
    48 	iPerformCommandListValidation(ETrue),
       
    49 	iNextAction(EUnConnected)
       
    50 	{
       
    51 	CActiveScheduler::Add(this);
       
    52 	}
       
    53 
       
    54 CSsmStateTransitionEngine::~CSsmStateTransitionEngine()
       
    55 	{
       
    56 	CActive::Cancel();
       
    57 
       
    58 	iCleSession.ReleaseCle();
       
    59 	iResolver.ReleasePolicyResolver();
       
    60 
       
    61 	delete iQueuedTransition;
       
    62 	delete iCurrentTransition;
       
    63     delete iCommandList;
       
    64 	}
       
    65 
       
    66 TSsmStateTransition const* CSsmStateTransitionEngine::CurrentTransition() const
       
    67 	{
       
    68 	return iCurrentTransition ? &(iCurrentTransition->StateTransition()) : NULL;
       
    69 	}
       
    70 
       
    71 TSsmStateTransition const* CSsmStateTransitionEngine::QueuedTransition() const
       
    72 	{
       
    73 	return iQueuedTransition ? &(iQueuedTransition->StateTransition()) : NULL;
       
    74 	}
       
    75 
       
    76 MSsmStatePolicy::TResponse CSsmStateTransitionEngine::TransitionAllowed(const TSsmStateTransition& aRequest, const RMessagePtr2& aMessage)
       
    77 	{
       
    78 	return Policy()->CallTransitionAllowed(aRequest, CurrentTransition(), QueuedTransition(), aMessage);
       
    79 	}
       
    80 
       
    81 void CSsmStateTransitionEngine::SubmitL(const TSsmStateTransition& aRequest)
       
    82 	{
       
    83 	CSsmStateTransitionRequest* request = new (ELeave) CSsmStateTransitionRequest(aRequest);
       
    84 	DoSubmit(request);
       
    85 	}
       
    86 
       
    87 void CSsmStateTransitionEngine::SubmitL(const TSsmStateTransition& aRequest, const RMessage2& aMessage)
       
    88 	{
       
    89 	CSsmStateTransitionRequest* request = new (ELeave) CSsmStateTransitionRequest(aRequest, aMessage);
       
    90 	DoSubmit(request);
       
    91 	}
       
    92 /**
       
    93 If the current slot is free, aRequest is assigned to the current-slot (the queue-slot should be free).
       
    94 If the current slot is occupied, aRequest is assigned to the queue-slot. Any already existing
       
    95 queued request is lost.
       
    96 
       
    97 (You should adhere to the TResponse given by the policy's TransitionAllowed before calling this method)
       
    98 */
       
    99 void CSsmStateTransitionEngine::DoSubmit(CSsmStateTransitionRequest* aRequest)
       
   100 	{
       
   101 	if(iCurrentTransition)
       
   102 		{
       
   103 		//ECurrentRemainReplaceQueued
       
   104 		if(iQueuedTransition)
       
   105 			{
       
   106 			iQueuedTransition->Complete(KErrCancel);
       
   107 			delete iQueuedTransition;
       
   108 			iQueuedTransition = NULL;
       
   109 			}
       
   110 		iQueuedTransition = aRequest;
       
   111 		}
       
   112 	else
       
   113 		{
       
   114 		//EReplaceCurrentClearQueue
       
   115 		__ASSERT_DEBUG(NULL == iQueuedTransition, PanicNow(KPanicSysStateMgr,ESsmStateEngineError10)); // should be already be deleted by DoCancel
       
   116 		if(iQueuedTransition)
       
   117 			{
       
   118 			iQueuedTransition->Complete(KErrCancel);
       
   119 			delete iQueuedTransition;
       
   120 			iQueuedTransition = NULL;
       
   121 			}
       
   122 		iCurrentTransition = aRequest;
       
   123 		}
       
   124 
       
   125 	if(!IsActive())
       
   126 		{
       
   127 		if (EUnConnected == iNextAction)
       
   128 			{
       
   129 			Start();
       
   130 			}
       
   131 		else if (EIdle == iNextAction)	
       
   132 			{
       
   133 			iNextAction = iCleSession.IsConnected() ? EStartTransition : EUnConnected;
       
   134 			Start();
       
   135 			}
       
   136 		}
       
   137 	}
       
   138 
       
   139 void CSsmStateTransitionEngine::Start()
       
   140 	{
       
   141 	SetActive();
       
   142 	TRequestStatus* status = &iStatus;
       
   143 	User::RequestComplete(status, KErrNone);
       
   144 	}
       
   145 
       
   146 void CSsmStateTransitionEngine::Cancel(CSession2* aSession)
       
   147 	{
       
   148 	if(aSession)
       
   149 		{
       
   150 		//Client side request to cancel
       
   151 		if(iQueuedTransition && iQueuedTransition->OriginatesFrom(aSession))
       
   152 			{
       
   153 			iQueuedTransition->Complete(KErrCancel);
       
   154 			delete iQueuedTransition;
       
   155 			iQueuedTransition = NULL;
       
   156 			}
       
   157 
       
   158 		if(iCurrentTransition)
       
   159 			{
       
   160 			if(iCurrentTransition->OriginatesFrom(aSession) && !InTransition())
       
   161 				{
       
   162 				CActive::Cancel();
       
   163 				ShiftQueueIfNeeded();
       
   164 				if(iCurrentTransition)
       
   165 					{
       
   166 					iNextAction = EStartTransition;
       
   167 					Start();
       
   168 					}
       
   169 				}
       
   170 			}
       
   171 		}
       
   172 	else
       
   173 		{
       
   174 		//Server-side request, raised when the policy allows a new request with EReplaceCurrentClearQueue
       
   175 		if(iQueuedTransition)
       
   176 			{
       
   177 			iQueuedTransition->Complete(KErrCancel);
       
   178 			delete iQueuedTransition;
       
   179 			iQueuedTransition = NULL;
       
   180 			}
       
   181 
       
   182 		if(iCurrentTransition)
       
   183 			{
       
   184 			CActive::Cancel();
       
   185 			ShiftQueueIfNeeded();
       
   186 			}
       
   187 		}
       
   188 	}
       
   189 
       
   190 void CSsmStateTransitionEngine::DoCancel()
       
   191 	{
       
   192 	//Cancel any pending request this engine has submitted to external providers
       
   193 	CSsmStatePolicyFrame* policy = iResolver.Policy();
       
   194 	if(policy &&(iNextAction == EPrepareCommandList))
       
   195 		{
       
   196 		policy->CallInitializeCancel();
       
   197 		}
       
   198 	else if(policy &&(iNextAction == EExecuteCommandList))
       
   199 		{
       
   200 		policy->CallPrepareCommandListCancel();
       
   201 		}
       
   202 	else if(iNextAction == EReadNextTransition)
       
   203 		{
       
   204 		iCleSession.ExecuteCommandListCancel();
       
   205 		//iCommandList needs to be deleted when cancel has been called before completion of command 
       
   206 		if (iCommandList)
       
   207             {
       
   208             delete iCommandList;
       
   209             iCommandList = NULL;
       
   210             }
       
   211 		}
       
   212 
       
   213 	//Then Cancel the pending operations this engine has been asked to do
       
   214 	if(iCurrentTransition)
       
   215 		{
       
   216 		iCurrentTransition->Complete(KErrCancel);
       
   217 		delete iCurrentTransition;
       
   218 		iCurrentTransition = NULL;
       
   219 		}
       
   220 
       
   221 	//Reset internal state
       
   222 	if(iNextAction > EUnConnected)
       
   223 		{
       
   224 		iNextAction = EIdle;
       
   225 		}
       
   226 	}
       
   227 
       
   228 void CSsmStateTransitionEngine::RunL()
       
   229 	{
       
   230 	if(iNextAction != EReadNextTransition)
       
   231 		{
       
   232 		//Propagate all problems to RunError except the return value from CleSrv
       
   233 		SSMLOGLEAVEIFERROR(iStatus.Int()); //will leave in release builds as well
       
   234 		}
       
   235 
       
   236  	switch(iNextAction)
       
   237 	 	{
       
   238 		case EUnConnected:
       
   239 			DoConnectCleSessionL();
       
   240 			iNextAction = EStartTransition;
       
   241 			break;
       
   242 
       
   243 	 	case EStartTransition:
       
   244 	 		DoStartTransitionL();
       
   245 	 		iNextAction = EInitialize;
       
   246 	 		break;
       
   247 
       
   248 	 	case EInitialize:
       
   249 	 		DoInitialize();
       
   250 	 		iNextAction = EPrepareCommandList;
       
   251 	 		break;
       
   252 
       
   253 	 	case EPrepareCommandList:
       
   254 	 		DoPrepareCommandList();
       
   255 	 		iNextAction = EExecuteCommandList;
       
   256 	 		break;
       
   257 
       
   258 	 	case EExecuteCommandList:
       
   259 	 		DoExecuteCommandList();
       
   260 			iNextAction = EReadNextTransition;
       
   261 	 		break;
       
   262 
       
   263 		case EReadNextTransition:
       
   264 			{
       
   265 			if (iCommandList)
       
   266 				{
       
   267 				delete iCommandList;
       
   268 				iCommandList = NULL;
       
   269 				}
       
   270 			TBool furtherTransition = FurtherTransition();
       
   271 			iNextAction = iCleSession.IsConnected() ? EStartTransition : EUnConnected;
       
   272 			if(!furtherTransition && !iCurrentTransition)
       
   273 				{
       
   274 				iNextAction = EIdle;	// If no further transition and nothing was in queue --> set to idle
       
   275 				}
       
   276 			}
       
   277 			break;
       
   278 
       
   279 		case  EIdle:
       
   280 		default:
       
   281 			__ASSERT_DEBUG(EFalse, PanicNow(KPanicSysStateMgr,ESsmStateEngineError11));
       
   282 			break;
       
   283 		}
       
   284 	}
       
   285 
       
   286 /**
       
   287  Most errors cause a Panic followed by Kernel fault. The rationale behind this is that all 
       
   288  the state policies placed on the rom by the device manufacturer must be error free when
       
   289  the device is shipped. There is no case for graceful handling of missing commandlists,
       
   290  bad resource files or an unknown state.
       
   291 
       
   292  The only error which does not cause a panic is the return value from CleSrv. When a command
       
   293  execution results in an error, CleSrv reports the error-code back to CSsmStateTransitionEngine
       
   294  which forwards the error-code to the State Policy DLL in the call MSsmStatePolicy::GetNextState
       
   295  */
       
   296 TInt CSsmStateTransitionEngine::RunError(TInt aError)
       
   297 	{
       
   298 	DEBUGPRINT3(_L("CSsmStateTransitionEngine RunError: %d occured in operation: %d"), aError, iNextAction);
       
   299 
       
   300 	TSsmStateName name = iTargetSystemState.Name();
       
   301  	switch(iNextAction)
       
   302 	 	{
       
   303 	 	case EUnConnected:
       
   304 			{
       
   305 			iCurrentTransition->Complete(aError);
       
   306 			DEBUGPRINT3(_L("State transition to %S failed, could not connect to CleSrv, reason: %d"), &name, aError);
       
   307 			PanicNow(KPanicSysStateMgr,ESsmStateEngineError3);
       
   308 			break;
       
   309 			}
       
   310 	 	case EStartTransition:
       
   311 			{
       
   312 			DEBUGPRINT3(_L("State transition to %S failed, possibly due to policy file err: %d"), &name, aError);
       
   313 			PanicNow(KPanicSysStateMgr,ESsmStateEngineError7);
       
   314 	 		break;
       
   315 			}
       
   316 	 	case EInitialize:
       
   317 	 	case EPrepareCommandList:
       
   318 	 		{
       
   319 	 		DEBUGPRINT3(_L("State Policy DLL %S failed to initialize, leavecode: %d"), &name, aError);
       
   320 	 		PanicNow(KPanicSysStateMgr,ESsmStateEngineError6);
       
   321 	 		break;
       
   322 	 		}
       
   323 	 	case EExecuteCommandList:
       
   324 	 		{
       
   325 	 		DEBUGPRINT3(_L("Command list execution failed, target state %S, error: %d"), &name, aError);
       
   326 	 		PanicNow(KPanicSysStateMgr,ESsmStateEngineError8);
       
   327 	 		break;
       
   328 	 		}
       
   329 		case EReadNextTransition:
       
   330 			{
       
   331 			//This error will not be raised from the usual User::LeaveIfError at the top of RunL, but from a bad
       
   332 			//virtual implementation of GetNextState (which leaves despite this should be a non-leaving function).
       
   333 			DEBUGPRINT3(_L("State Policy error: %d occured during a call to GetNextState %S"), aError, &name);
       
   334 	 		PanicNow(KPanicSysStateMgr,ESsmStateEngineError4);
       
   335 	 		break;
       
   336 			}
       
   337 		default:
       
   338 		case EIdle:
       
   339 			__ASSERT_DEBUG(EFalse,	PanicNow(KPanicSysStateMgr,ESsmStateEngineError15));
       
   340 			break;
       
   341 		}
       
   342 
       
   343  	return KErrNone;
       
   344 	} //lint !e529 not subsequently referenced - dependent on debug
       
   345 
       
   346 /**
       
   347  Before this transition engine is used for the first time, we need to connect
       
   348  to (and probably start) the CleSrv.
       
   349  The session remains connected because we do not want to risk not being able to
       
   350  connect to CleSrv (due to low memory in kernel) if we get a request to transition
       
   351  to state ESsmFail.
       
   352  */
       
   353 void CSsmStateTransitionEngine::DoConnectCleSessionL()
       
   354 	{
       
   355 	iCleSession.ConnectL();
       
   356 	Start();
       
   357 	}
       
   358 
       
   359 void CSsmStateTransitionEngine::DoStartTransitionL()
       
   360 	{
       
   361 	//Let the client know this transition has started, from now on this transition can't be cancelled
       
   362 	//  note: in case this is called as part of a FurtherTransition(), complete will do nothing
       
   363 	iCurrentTransition->Complete(KErrNone);
       
   364 
       
   365 #ifdef _DEBUG
       
   366 	TSsmStateName name = iCurrentTransition->State().Name();
       
   367 	DEBUGPRINT2(_L("Initiating transition to state %S."), &name);
       
   368 #endif
       
   369 
       
   370 	//Start off by loading the correct state policy DLL
       
   371 	iTargetSystemState = iCurrentTransition->State();
       
   372 	iResolver.GetStatePolicyL(iTargetSystemState);
       
   373 	Start();
       
   374 	}
       
   375 
       
   376 void CSsmStateTransitionEngine::DoInitialize()
       
   377 	{
       
   378 	if(!Policy()->Initialized())
       
   379 		{
       
   380 		//Let the state policy do whatever it needs to do for example initialize its CSsmCommandListResourceReader
       
   381 		Policy()->CallInitialize(iStatus);
       
   382 		SetActive();
       
   383 		}
       
   384 	else
       
   385 		{
       
   386 		Start();
       
   387 		}
       
   388 	}
       
   389 
       
   390 void CSsmStateTransitionEngine::DoPrepareCommandList()
       
   391 	{
       
   392 	__ASSERT_DEBUG(iCurrentTransition, PanicNow(KPanicSysStateMgr,ESsmStateEngineError13));
       
   393 	Policy()->CallPrepareCommandList(iTargetSystemState, iCurrentTransition->Reason(), iStatus);
       
   394 	SetActive();
       
   395 	}
       
   396 
       
   397 void CSsmStateTransitionEngine::DoExecuteCommandList()
       
   398 	{
       
   399 	iCommandList = Policy()->CallCommandList();
       
   400 	if(iPerformCommandListValidation)
       
   401 		{
       
   402 		DoValidation();
       
   403 		}
       
   404 
       
   405 	if(iCommandList)
       
   406 		{
       
   407 		iCleSession.ExecuteCommandList(*iCommandList, iStatus, iSeverity);
       
   408 		SetActive();
       
   409 		}
       
   410 	else
       
   411 		{
       
   412 		Start();
       
   413 		}
       
   414 	}
       
   415 
       
   416 void CSsmStateTransitionEngine::DoValidation()
       
   417 	{
       
   418 	TBool valid = EFalse;
       
   419 	if(!iCommandList)
       
   420 		{
       
   421 		DEBUGPRINT1(_L("State Policy DLL returned NULL from CommandList()"));
       
   422 		}
       
   423 	else
       
   424 		{
       
   425 		valid = CSsmCommandListUtils::IsValidStateList(*iCommandList);
       
   426 		if(!valid)
       
   427 			{
       
   428 			DEBUGPRINT1(_L("State Policy DLL returned an invalid CommandList()"));
       
   429 			}
       
   430 		}
       
   431 	__ASSERT_ALWAYS( iCommandList && valid, PanicNow(KPanicSysStateMgr,ESsmStateEngineError9));
       
   432 	}
       
   433 
       
   434 TBool CSsmStateTransitionEngine::FurtherTransition()
       
   435 	{
       
   436 	__ASSERT_DEBUG(iCurrentTransition, PanicNow(KPanicSysStateMgr,ESsmStateEngineError14));
       
   437 	const TInt error = iStatus.Int();
       
   438 
       
   439 	// In case the server is no longer present
       
   440 	if(error == KErrServerTerminated)
       
   441 		{
       
   442 		// Closes the cle handle and marks it as disconnected
       
   443 		iCleSession.Close();
       
   444 		}
       
   445 	// Severity must be obtained from CLE somehow. This needs proper implementation.
       
   446 	TCmdErrorSeverity severity = ECmdIgnoreFailure;
       
   447 	if(KErrNone != error)
       
   448 		{
       
   449 		DEBUGPRINT3(_L("Commandlist execution reported error: %d, with severity %d."), error, severity);
       
   450 		severity = ECmdCriticalSeverity;
       
   451 		}
       
   452 
       
   453 	TSsmState nextSystemState;
       
   454 	const TBool moreTransitions = Policy()->CallGetNextState(iTargetSystemState,
       
   455 															 iCurrentTransition->Reason(),
       
   456 															 error,
       
   457 															 severity,
       
   458 															 nextSystemState);
       
   459 	if(!moreTransitions)
       
   460 		{
       
   461 		// Request completed
       
   462 #ifdef _DEBUG
       
   463 		TSsmStateName name = iCurrentTransition->State().Name();
       
   464 		DEBUGPRINT2(_L("Transition to state %S completed."), &name);
       
   465 #endif
       
   466 		delete iCurrentTransition;
       
   467 		iCurrentTransition = NULL;
       
   468 		// See if there is another request queued
       
   469 		ShiftQueueIfNeeded();
       
   470 		}
       
   471 	else
       
   472 		{
       
   473 		// FurtherTransition requested
       
   474 #ifdef _DEBUG
       
   475 		TSsmStateName name = nextSystemState.Name();
       
   476 		DEBUGPRINT2(_L("FurtherTransition requested to state %S."), &name);
       
   477 #endif
       
   478 		// Update the target system state (Note: We only update the SystemState, same reason is being re-used)
       
   479 		const TSsmStateTransition request(nextSystemState, iCurrentTransition->Reason());
       
   480 		iCurrentTransition->SetStateTransition(request);
       
   481 		}
       
   482 
       
   483 	if(moreTransitions || iCurrentTransition)
       
   484 		{
       
   485 		Start();
       
   486 		}
       
   487 
       
   488 	return moreTransitions;
       
   489 	}
       
   490 
       
   491 TBool CSsmStateTransitionEngine::InTransition() const
       
   492 	{
       
   493 	return (iNextAction > EStartTransition);
       
   494 	}
       
   495 
       
   496 void CSsmStateTransitionEngine::ShiftQueueIfNeeded()
       
   497 	{
       
   498 	if(iQueuedTransition && !iCurrentTransition)
       
   499 		{
       
   500 		iCurrentTransition = iQueuedTransition;
       
   501 		iQueuedTransition = NULL;
       
   502 		}
       
   503 	}
       
   504 
       
   505 CSsmStatePolicyFrame* CSsmStateTransitionEngine::Policy()
       
   506 	{
       
   507 	CSsmStatePolicyFrame* policy = iResolver.Policy();
       
   508 	__ASSERT_DEBUG( policy, PanicNow(KPanicSysStateMgr,ESsmStateEngineError1));
       
   509 	return policy;
       
   510 	}
       
   511 
       
   512 void CSsmStateTransitionEngine::PerformCommandListValidation(TBool aSetting)
       
   513 	{
       
   514 	iPerformCommandListValidation = aSetting;
       
   515 #ifdef _DEBUG
       
   516 	if(iPerformCommandListValidation)
       
   517 		{
       
   518 		DEBUGPRINT1(_L("Turning on State command list validation"));
       
   519 		}
       
   520 	else
       
   521 		{
       
   522 		DEBUGPRINT1(_L("Turning off State command list validation"));
       
   523 		}
       
   524 #endif
       
   525 	}
       
   526 
       
   527 /**
       
   528  * Only for test purposes
       
   529  * Cleanup the transition engine
       
   530  */
       
   531  #ifdef _DEBUG
       
   532 void CSsmStateTransitionEngine::CleanupTransitionEngine()
       
   533 	{
       
   534 	iResolver.ReleasePolicyResolver();
       
   535 	delete iQueuedTransition;
       
   536 	delete iCurrentTransition;
       
   537 	iCleSession.ReleaseCle();
       
   538 	}
       
   539 #endif