featuremgmt/featuremgr/src/serverexe/burstate.cpp
changeset 0 08ec8eefde2f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/featuremgmt/featuremgr/src/serverexe/burstate.cpp	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,417 @@
+// Copyright (c) 2008-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:
+//
+
+/**
+ @file
+*/
+
+#include "burstate.h"
+#include <babackup.h>
+#include "featmgrdebug.h"
+#include "featmgrserver.h"
+
+CBurState::CBurState()
+	{
+	return;
+	}
+
+/**
+ * The Backup and Restore state machine.
+ * This state machine has two state tables. The first table defines the correct modes of operation
+ * and the second describe the pathways arrising from error conditions. By seperating the normal
+ * pathways from the error pathways we can simplify the state machine into two parts. The function 
+ * SetUpBurStruct() will define the pathways for both these tables.
+ * Each table has three items per row: a current state, an ending state, and a pointer to a function 
+ * that transforms between these two states safely. 
+ * Given that we already know where we are, and where we are told to goto, the state machine
+ * function BUR_StateMachine() will search the normal operation table for a match, and then apply
+ * the function through the pointer. If no match is found, then the goto state is set to Error, and
+ * the error table is searched and applied. Because all the state are covered within the error table
+ * we can always return to a normal more of operation through the application of the error
+ * functions.
+ */ 
+CBurState::CBurState(CFeatMgrServer* aServer) : iCurrentBURStatus( EFeatMgrBURState_None ), iServer( aServer )
+	{
+	SetUpBurStruct();
+	return;
+	}
+
+CBurState::~CBurState()
+	{
+	return;
+	}
+
+CBurState* CBurState::NewLC()
+	{
+	CBurState* self = new (ELeave)CBurState();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;
+	}
+
+CBurState* CBurState::NewL()
+	{
+	CBurState* self=CBurState::NewLC();
+	CleanupStack::Pop(); // self;
+	return self;
+	}
+
+void CBurState::ConstructL()
+	{
+	return;
+	}
+
+/**
+ * This function checks the arguments that are passed into HandleBackupOperationEventL. 
+ * The TBackupOperationAttributes are checked against known values and an error is returned if
+ * the Feature Manager doesn't recognise the events.
+ */ 
+TInt CBurState::CheckBURArguments(  const TBackupOperationAttributes& aBackupOperationAttributes )
+	{
+	TInt error( KErrNone );
+    iBURLockFlag = aBackupOperationAttributes.iFileFlag;
+    iBUROpType   = aBackupOperationAttributes.iOperation;
+    
+	// determine the operation type (backup or restore)
+	switch( iBURLockFlag )	
+		{
+		case MBackupObserver::EReleaseLockReadOnly:
+			INFO_LOG( "MBackupObserver::EReleaseLockReadOnly" );
+			break;
+		case MBackupObserver::EReleaseLockNoAccess:
+			INFO_LOG( "MBackupObserver::EReleaseLockNoAccess" );
+			break;
+		case MBackupObserver::ETakeLock:
+			INFO_LOG( "MBackupObserver::ETakeLock" );
+			break;
+		default:
+			INFO_LOG( "CheckBURArguments iBURLockFlag default" );
+			error = KErrNotFound;
+			break;
+		}
+		
+	// determine the operation status (e.g. starting, ending)
+	switch( iBUROpType )
+		{
+		case MBackupOperationObserver::ENone:
+			INFO_LOG( "ENone" );
+			break;
+		case MBackupOperationObserver::EStart:
+			INFO_LOG( "EStart" );
+			break;
+		case MBackupOperationObserver::EEnd:
+			INFO_LOG( "EEnd" );
+			break;
+		case MBackupOperationObserver::EAbort:
+			INFO_LOG( "EAbort" );	
+			break;
+		default:
+			INFO_LOG( "CheckBURArguments iOperation default" );	
+			error = KErrNotFound;
+			break;
+		}
+
+	return error;
+	}
+
+/**
+ * Sets up the array entries for the possible backup/restore state vectors. 
+ *               from           -> to             : function
+ * State vector: None           -> BackupStarted  : Goto_StartBackupState
+ * State vector: BackupStarted  -> BackupEnded    : EndBackupState
+ * State vector: BackupEnded    -> None           : Goto_NormalState
+ * State vector: None           -> RestoreStarted : Goto_StartRestoreState
+ * State vector: RestoreStarted -> RestoreEnded   : Goto_EndRestoreState
+ * State vector: RestoreEnded   -> None           : Goto_NormalState
+ */
+void CBurState::SetUpBurStruct()
+	{
+	BURStruct bStruct;
+
+	// Backup states
+
+	// State vector: None -> BackupStarted : Goto_StartBackupState
+	bStruct.iCurrent = EFeatMgrBURState_None;
+	bStruct.iGoto = EFeatMgrBURState_BackupStarted;
+	bStruct.iFunc = &CFeatMgrServer::Goto_StartBackupState;
+	iBURStructArray[0] = bStruct;
+
+	// State vector: BackupStarted -> BackupEnded : EndBackupState
+	bStruct.iCurrent = EFeatMgrBURState_BackupStarted;
+	bStruct.iGoto = EFeatMgrBURState_BackupEnded;
+	bStruct.iFunc = &CFeatMgrServer::Goto_EndBackupState;
+	iBURStructArray[1] = bStruct;
+
+	// State vector: BackupEnded -> None : Goto_NormalState
+	bStruct.iCurrent = EFeatMgrBURState_BackupEnded;
+	bStruct.iGoto = EFeatMgrBURState_None;
+	bStruct.iFunc = &CFeatMgrServer::Goto_NormalState;
+	iBURStructArray[2] = bStruct;
+
+	// Valid restore states
+	
+	// State vector: None -> RestoreStarted : Goto_StartRestoreState
+	bStruct.iCurrent = EFeatMgrBURState_None;
+	bStruct.iGoto = EFeatMgrBURState_RestoreStarted;
+	bStruct.iFunc = &CFeatMgrServer::Goto_StartRestoreState;
+	iBURStructArray[3] = bStruct;
+
+	// State vector: RestoreStarted -> RestoreEnded : Goto_EndRestoreState
+	bStruct.iCurrent = EFeatMgrBURState_RestoreStarted;
+	bStruct.iGoto = EFeatMgrBURState_RestoreEnded;
+	bStruct.iFunc = &CFeatMgrServer::Goto_EndRestoreState;
+	iBURStructArray[4] = bStruct;
+
+	// State vector: RestoreEnded -> None : Goto_NormalState
+	bStruct.iCurrent = EFeatMgrBURState_RestoreEnded;
+	bStruct.iGoto = EFeatMgrBURState_None;
+	bStruct.iFunc = &CFeatMgrServer::Goto_NormalState;
+	iBURStructArray[6] = bStruct;
+
+	// State vector: None -> None : Goto_NormalState
+	bStruct.iCurrent = EFeatMgrBURState_None;
+	bStruct.iGoto = EFeatMgrBURState_None;
+	bStruct.iFunc = &CFeatMgrServer::Goto_NormalState;
+	iBURStructArray[5] = bStruct;
+
+	
+	//
+	// Error states
+
+	// State vector: RestoreStarted -> Error : Goto_ErrorState
+	bStruct.iCurrent = EFeatMgrBURState_RestoreStarted;
+	bStruct.iGoto = EFeatMgrBURState_Error;
+	bStruct.iFunc = &CFeatMgrServer::Goto_ErrorState;
+	iBURStructErrorArray[0] = bStruct;
+
+	// State vector: RestoreEnded -> Error : Goto_ErrorState
+	bStruct.iCurrent = EFeatMgrBURState_RestoreEnded;
+	bStruct.iGoto = EFeatMgrBURState_Error;
+	bStruct.iFunc = &CFeatMgrServer::Goto_ErrorState;
+	iBURStructErrorArray[1] = bStruct;
+
+	// State vector: BackupStarted -> None : Goto_ErrorState
+	bStruct.iCurrent = EFeatMgrBURState_BackupStarted;
+	bStruct.iGoto = EFeatMgrBURState_Error;
+	bStruct.iFunc = &CFeatMgrServer::Goto_ErrorState;
+	iBURStructErrorArray[2] = bStruct;
+	
+	// State vector: BackupEnded -> None : Goto_ErrorState
+	bStruct.iCurrent = EFeatMgrBURState_BackupEnded;
+	bStruct.iGoto = EFeatMgrBURState_Error;
+	bStruct.iFunc = &CFeatMgrServer::Goto_ErrorState;
+	iBURStructErrorArray[3] = bStruct;
+	
+	// State vector: Error -> None : Goto_NormalState
+	bStruct.iCurrent = EFeatMgrBURState_Error;
+	bStruct.iGoto = EFeatMgrBURState_None;
+	bStruct.iFunc = &CFeatMgrServer::Goto_NormalState;
+	iBURStructErrorArray[4] = bStruct;
+	
+	return;
+	}
+
+/**
+ * Convert from the type provided in TBackupOperationAttributes into more sensible BUR types that
+ * can be handles by the BUR_StateMachine. This step is necessary for two reasons, the first is
+ * simplification and the second is a lexical check for invalid type MBackupObserver::TFileLockFlags.
+ */
+BURStatus CBurState::ConvertToBURState(  const TBackupOperationAttributes& aBackupOperationAttributes )
+	{
+	BURStatus status = EFeatMgrBURState_Error;
+    iBURLockFlag = aBackupOperationAttributes.iFileFlag;
+    iBUROpType   = aBackupOperationAttributes.iOperation;
+	// we ignore the iOperation state
+    
+	if( iBURLockFlag == MBackupObserver::ETakeLock )
+		{
+		// ending (this doesn't define whether it was a backup
+		// or a restore ending, just that file writing can now start 
+		// again).
+		INFO_LOG("ChangeFileLockL() BUR ending");
+		switch( iCurrentBURStatus )
+			{
+			case( EFeatMgrBURState_BackupStarted ):
+				status = EFeatMgrBURState_BackupEnded;
+				break;
+			case( EFeatMgrBURState_RestoreStarted ):
+				status = EFeatMgrBURState_RestoreEnded;
+				break;
+			case( EFeatMgrBURState_None ):
+				status = EFeatMgrBURState_None;
+				break;
+			default:
+				status = EFeatMgrBURState_Error;
+				break;
+			}
+		}
+	else if( (iBURLockFlag & MBackupObserver::EReleaseLockReadOnly) &&
+		(iBURLockFlag & ~MBackupObserver::EReleaseLockNoAccess) )
+		{
+		// starting (making the file read-only is a sign that we are
+		// in "backup" mode).
+		INFO_LOG("ChangeFileLockL() backup starting");
+		status = EFeatMgrBURState_BackupStarted;
+		}
+	else if( iBURLockFlag & MBackupObserver::EReleaseLockNoAccess )
+		{
+		// starting (now read/write access is used to signify that a
+		// restore has been started).
+		INFO_LOG("ChangeFileLockL() restore starting");
+		status = EFeatMgrBURState_RestoreStarted;
+		}
+	else
+		{
+		// unhandled flag states
+		INFO_LOG("ChangeFileLockL() error state");
+		status = EFeatMgrBURState_Error;
+		}
+	
+	return status;
+	}
+
+/**
+ * This function is called from within featmgr server when a backup event occurs
+ * There are two state variables coming into Feature Manager as types MBackupObserver::TFileLockFlags 
+ * and TOperationType. Only certain combinations of these two state variables are valid for Feature
+ * Manager and if the combination is not valid (because there is no way of returning an error) 
+ * it will just set the internal state machine into an "error" state.
+ * Given our current state and our goto state (i.e. where we are at the moment and where we want to goto)
+ * the state machine checks that this is a valid path in our state machine and then perform the correct 
+ * operations to get us to the next valid state.
+ */
+void CBurState::BUROperationL( const TBackupOperationAttributes& aBackupOperationAttributes )
+	{
+	BURStatus gotoState    = EFeatMgrBURState_Error;  // fail safe
+	BURStatus currentState = iCurrentBURStatus;       // where in the state machine we are at the moment
+	
+	// Check that the arguments are within valid limits
+	if( KErrNone == CheckBURArguments( aBackupOperationAttributes ) )
+		{
+		// Now convert into states that the Feature Manager understands.
+		gotoState = ConvertToBURState( aBackupOperationAttributes );
+		}
+	
+	// Check that this is a valid path and then perform the correct operations to get to the next valid state
+	iCurrentBURStatus = BUR_StateMachine( currentState, gotoState );
+	
+	return;
+	}
+
+/**
+ * The state machine for the backup and restore of the featmgr 
+ * The logic that goes into changing states in the state machine.
+ */
+BURStatus CBurState::BUR_StateMachine( BURStatus aCurrent, BURStatus aGoto )
+	{
+	TInt count = 0;
+	TBool found = EFalse;
+
+	// Fail safe default state values
+	BURStatus newState			= EFeatMgrBURState_Error;
+	BURStatus stateTableGoto    = EFeatMgrBURState_Error;
+	BURStatus stateTableCurrent = EFeatMgrBURState_Error;
+	
+	// Normal operation
+	//
+	do
+		{
+		// Get the n-th state table [current,goto] state vector
+		stateTableCurrent = iBURStructArray[count].iCurrent;
+		stateTableGoto    = iBURStructArray[count].iGoto;
+		
+		// if the state table matches what we are given
+		if( (aCurrent == stateTableCurrent) && 
+			(aGoto    == stateTableGoto) )
+			{
+			// process the relevant state function
+			if( NULL != iBURStructArray[count].iFunc )
+				{
+				newState = (iServer->*iBURStructArray[count].iFunc)( aCurrent );
+
+				// check result: when from the state machine is not what we expected from the state table
+				if( newState != stateTableGoto )
+					{
+					// put state machine into an error state and break "normal" loop
+					aCurrent = newState;
+					aGoto    = EFeatMgrBURState_Error;
+					break;
+					}
+				else
+					{
+					found = ETrue;
+					}
+				}
+			
+			// self-perpetuate in certain cases
+			if( (EFeatMgrBURState_BackupEnded == newState) || 
+				(EFeatMgrBURState_RestoreEnded == newState) )
+				{
+				aCurrent = newState;
+				aGoto = EFeatMgrBURState_None;
+				found = EFalse;
+				count = 0;
+				}
+			}
+		count++;
+		}
+	while( (!found) && count < KBURArrayLength );
+	
+
+	// Error recovery
+	//
+	if( EFeatMgrBURState_Error == aGoto ||
+		EFalse == found )
+		{
+		// reset 
+		aGoto = EFeatMgrBURState_Error;
+		count = 0;
+		found = EFalse;
+
+		do
+			{
+			// Get the n-th state table [current,goto] state vector in the error array
+			stateTableCurrent = iBURStructErrorArray[count].iCurrent;
+			stateTableGoto    = iBURStructErrorArray[count].iGoto;
+			
+			// if the state table matches what we are given
+			if( ((aCurrent == stateTableCurrent) && (aGoto == stateTableGoto))  )
+				{
+				// process the relevant state function
+				if( NULL != iBURStructErrorArray[count].iFunc )
+					{
+					newState = (iServer->*iBURStructErrorArray[count].iFunc)( aCurrent );
+					// there is no error recovery from error recovery.
+					found = ETrue;
+					}
+				
+				// self-perpetuate in certain cases
+				if( EFeatMgrBURState_Error == newState )
+					{
+					aCurrent = newState;
+					aGoto = EFeatMgrBURState_None;
+					found = EFalse;
+					count = 0;
+					}
+				}
+			count++;
+			}
+		while( (!found) && count < KBURErrorArrayLength );
+		
+		}
+	
+	return newState;
+	}
+