sysstatemgmt/systemstateplugins/gsapolicy/src/gsastatepolicystartup.cpp
changeset 0 4e1aa6a622a0
child 70 653a8b91b95e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sysstatemgmt/systemstateplugins/gsapolicy/src/gsastatepolicystartup.cpp	Tue Feb 02 00:53:00 2010 +0200
@@ -0,0 +1,480 @@
+// Copyright (c) 2007-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:
+//
+
+#include <barsc2.h>
+#include <barsread2.h>
+#include <e32property.h>
+#include <e32uid.h>
+#include <e32std.h>
+#include <bautils.h>
+
+#include <ssm/ssmcmd.hrh>
+#include <ssm/ssmsubstates.hrh>
+#ifdef SYMBIAN_SSM_GRACEFUL_SHUTDOWN
+#include <ssm/ssmpatchableconstants.h>
+#include <ssm/conditiontypes.hrh>
+#endif
+
+#include <ssm/ssmstatetransition.h>
+#include <ssm/ssmcommandlistresourcereader.h>
+#include <ssm/ssmmaxbootattempts_patch.h>
+
+#include "gsastatepolicystartup.h"
+#include "ssmdebug.h"
+#include "ssmpanic.h" 
+#include "s32file.h" 
+
+_LIT(KBootUpFile, ":\\private\\2000d75b\\bootupinfo\\bootupcount.bin");
+
+/**
+ Attempt to reboot the device (forever) on boot failure. Used when KSsmMaxBootAttempts is set to '0xFFFFFFFF'.
+*/
+const TInt KSsmAttemptRebootForever = 0xFFFFFFFF;
+
+/**
+Panic used by Startup policy plug-in when resource reader is invalid.
+Strings must not be longer than 16 characters or they will be truncated by User::Panic()
+*/
+_LIT(KPanicGsaStartupState, "StartupPolicy");
+
+/**
+ Start-up state policy resource file path format : "z:/private/<SID of SSM>/startup/<Value of KSystemStartupModeKey>/"
+*/
+_LIT(KCommandListPath, "z:\\private\\2000D75B\\startup\\%d\\");
+
+/**
+ Commandlist path to launch 'sysstart.exe' when a resource file for 'start-up' is not found.
+ fallback to 'sysstart.exe' resource file path format : "z:/private/<SID of SSM>/startup/fallback/"
+*/
+_LIT(KFallbackCmdListPath, "z:\\private\\2000D75B\\startup\\fallback\\");
+
+/**
+Used to create an instance of MSsmStatePolicy class.
+
+@return A pointer to an instance of MSsmStatePolicy
+*/
+EXPORT_C MSsmStatePolicy* CGsaStatePolicyStartup::NewL()
+	{
+	CGsaStatePolicyStartup* self = new (ELeave) CGsaStatePolicyStartup;
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+/**
+Gets the hardware reason for KSystemStartupModeKey and makes a RFs connection.
+Creates Command list path and the resource reader for startup.
+
+@leave One of the error value returned by 
+	    RProperty::Get() 
+	    RFs::Connect() 
+	    RArray::AppendL() 
+	    NewL()
+@see RProperty::Get
+*/
+void CGsaStatePolicyStartup::ConstructL()
+	{
+	// Read the hardware reason
+	User::LeaveIfError(RProperty::Get(KUidSystemCategory, KSystemStartupModeKey, iHardwareReason));
+	User::LeaveIfError(iFs.Connect());
+	
+	// Add supported transitions from Startup 'ESsmStartup'
+	iCurrentlySupportedTransitions.AppendL(TSsmState(ESsmFail, KSsmAnySubState));
+	iCurrentlySupportedTransitions.AppendL(TSsmState(ESsmShutdown, KSsmAnySubState));
+	iCurrentlySupportedTransitions.AppendL(TSsmState(ESsmShutdown, ESsmShutdownSubStateCritical));
+
+	TFileName cmdListPath;
+	GetCommandListPath(iHardwareReason, cmdListPath);
+	DEBUGPRINT2(_L("Startup Policy : Startup command list path : %S"), &cmdListPath);
+
+	// create resource reader
+	iCommandListResourceReader = CSsmCommandListResourceReader::NewL(iFs, cmdListPath, *this);	
+	}
+
+/**
+default CTOR
+*/
+CGsaStatePolicyStartup::CGsaStatePolicyStartup()
+	{
+	}
+
+/**
+DTOR
+*/
+CGsaStatePolicyStartup::~CGsaStatePolicyStartup()
+	{
+	delete iCommandListResourceReader;
+	iSubStates.Close();
+	iFs.Close();
+	iCurrentlySupportedTransitions.Close();
+	}
+
+/**
+Initializes command list resource reader.
+
+@param aStatus to complete when the initialization operation has finished
+@panic EInvalidResourceReader if the command list resource reader is invalid
+
+@see MSsmStatePolicy::Initialize
+*/
+void CGsaStatePolicyStartup::Initialize(TRequestStatus& aStatus)
+	{
+	__ASSERT_DEBUG(iCommandListResourceReader, PanicNow(KPanicGsaStartupState, EInvalidResourceReader));
+	
+	// initialise command list resource reader.
+	iCommandListResourceReader->Initialise(aStatus);
+	}
+
+/**
+Cancels an asynchronous Initialize operation.
+
+@see MSsmStatePolicy::InitializeCancel
+*/
+void CGsaStatePolicyStartup::InitializeCancel()
+	{
+	iCommandListResourceReader->InitialiseCancel();
+	}
+
+/** 
+Deletes all resources and frees itself.
+
+@see MSsmStatePolicy::Release
+*/
+void CGsaStatePolicyStartup::Release()
+	{
+	delete this;
+	}
+
+/** 
+Determines if an incoming startup state transition request should be accepted or rejected.
+Clients calling this API should posess 'ECapabilityPowerMgmt', else the API will return ENotAllowed.
+
+@param aRequest Contains information about the new request
+@param aCurrent Contains NULL or the first accepted but not yet completed transition request
+@param aQueued Contains NULL or a second accepted but not yet started transition request
+@param aMessage Message sent by SSM server, used to check if the client has 'ECapabilityPowerMgmt'
+
+@return one of the TResponse value
+@see MSsmStatePolicy::TransitionAllowed
+@see MSsmStatePolicy::TResponse
+*/
+MSsmStatePolicy::TResponse CGsaStatePolicyStartup::TransitionAllowed(const TSsmStateTransition& aRequest, TSsmStateTransition const* aCurrent, 
+																TSsmStateTransition const* aQueued, const RMessagePtr2& aMessage)
+	{
+	TResponse response = ENotAllowed;
+	if (!aMessage.HasCapability(ECapabilityPowerMgmt))
+		{
+		DEBUGPRINT1(_L ("Startup Policy : Capability Check Failed."));
+		return response;
+		}
+
+	//Check if the requested transition is supported from current state
+	if(TransitionSupported(aRequest.State()))
+		{
+		if((NULL == aCurrent) && (NULL == aQueued))
+			{
+			// SsmServer is idle
+			response = EDefinitelyAllowed;
+			}
+		else if((aRequest.State().MainState() == ESsmFail) || (aRequest.State().MainState() == ESsmShutdown))
+			{
+			// Going into failed state or shutdown state will override anything currently ongoing or queued
+			response = EReplaceCurrentClearQueue;
+			}
+		}
+
+#ifdef _DEBUG
+	TSsmStateName name = aRequest.State().Name();
+	if(ENotAllowed == response)
+		{
+		DEBUGPRINT3(_L("Startup Policy : Transition (Requested State: %S) is not allowed (Response: %d)."), &name, response);
+		}
+	else
+		{
+		DEBUGPRINT3(_L("Startup Policy : Transition (Requested State %S) is allowed (Response %d)."), &name, response);		
+		}
+#endif
+	return response;
+	}
+
+/** 
+Create the command list associated with a sub state transition.
+
+@param aState Contains the state and substate that identifies the command list to create
+@param aReason Contains the reason as given by the request
+@param aStatus to complete when the operation has finished
+@panic EInvalidResourceReader if the command list resource reader is invalid
+@see MSsmStatePolicy::PrepareCommandList
+*/ 
+void CGsaStatePolicyStartup::PrepareCommandList(TSsmState aState, TInt aReason, TRequestStatus& aStatus)
+	{
+	__ASSERT_DEBUG(iCommandListResourceReader, PanicNow(KPanicGsaStartupState, EInvalidResourceReader));
+
+	iSoftwareReason = aReason;
+
+	//Let's start from the beginning if no specific minor state is selected
+	iRequestedSubState = ((aState.SubState() == KSsmAnySubState) ? ESsmStartupSubStateCriticalStatic : aState.SubState());
+	TSsmState publishState;
+	publishState.Set(aState.MainState(), iRequestedSubState);
+
+	const TInt commandListId = publishState.SubState();
+
+	//Build the commandlist from resource
+	iCommandListResourceReader->PrepareCommandList(commandListId, publishState, aStatus);
+	} //lint !e1746 Suppress parameter 'aState' could be made const reference
+
+/**
+Cancels asynchronous PrepareCommandList operation.
+
+@see MSsmStatePolicy::PrepareCommandListCancel
+*/
+void CGsaStatePolicyStartup::PrepareCommandListCancel()
+	{
+	iCommandListResourceReader->PrepareCommandListCancel();
+	}
+
+/**	
+Return the command list once the  PrepareCommandList has completed.
+Ownership of the returned command list is transferred to the caller.
+@panic EInvalidResourceReader if the command list resource reader is invalid
+@return The command list created during the preceding PrepareCommandList step
+*/
+CSsmCommandList* CGsaStatePolicyStartup::CommandList()
+	{
+	__ASSERT_DEBUG(iCommandListResourceReader , PanicNow(KPanicGsaStartupState, EInvalidResourceReader));
+
+	return iCommandListResourceReader->GetCommandList();
+	}
+
+/**
+Determines the next sub state transition.
+@param aCurrentTransition Contains the last executed state
+@param aReason Contains the reason as given by the request
+@param aError Contains the completion code from the last executed sub-state transition
+@param aSeverity Contains the severity of the failed command in case the sub-state transition ended with an error
+@param aNextState The next System State to head for, if there is one
+@panic EInvalidStartupstate if the current state is not startup
+@return 	ETrue if aNextState contains another System State to head for, or 
+		EFalse if there is no further transitions to do.
+@see MSsmStatePolicy::GetNextState
+*/
+TBool CGsaStatePolicyStartup::GetNextState(TSsmState aCurrentTransition, TInt /*aReason*/, TInt aError, TInt /*aSeverity*/, TSsmState& aNextState)
+	{
+	__ASSERT_ALWAYS(aCurrentTransition.MainState() == ESsmStartup, PanicNow(KPanicGsaStartupState, EInvalidStartupState));
+
+	if (KErrNone != aError)	// Handle CLE error here
+		{
+		if (iLaunchSysStart)	// 'sysstart.exe' was launched unsuccessfully so launch 'sysagt2srv.exe' and 'wserv.exe'
+			{
+			iLaunchSysStart = EFalse;
+			iLaunchSysAgt2SrvAndWServ = ETrue;
+			DEBUGPRINT2(_L("Startup Policy : sysstart.exe launched with error : %d"), aError);
+			aNextState = TSsmState(ESsmStartup, ESsmStartupSubStateCriticalDynamic);
+			return ETrue;
+			}
+
+#ifdef __WINS__	// on emulator
+			{
+			DEBUGPRINT2(_L("Startup Policy : CLE returned with (error : %d), Panic on Emulator"), aError);
+			DEBUGPRINT1(_L("Startup Policy : Emulator (__WINS__) does not support a re-start, so Fail Policy is not invoked."));
+			PanicNow(KPanicGsaStartupState, EEmulatorPowerOff);
+			}
+#else	// on hardware/device
+			{
+			aNextState = TSsmState(ESsmFail, ESsmFailSubStateRestart);
+			if (KSsmAttemptRebootForever != KSsmMaxBootAttempts)
+				{
+				// Get number of boot attempts made till now from bootup log file
+				TInt bootCount = -1;
+				TRAPD(err, bootCount = GetBootupCountL());	// ignore failure and restart the device, we should get the value next time.
+				if (err!=KErrNone)
+					{
+					DEBUGPRINT2(_L("Startup Policy : GetBootupCountL() failed with (error: %d), error is deliberately ignored."), aError);
+					}
+				if (bootCount < KSsmMaxBootAttempts)
+					{
+					aNextState = TSsmState(ESsmFail, ESsmFailSubStateRestart);
+					}
+				else	// Maximum allowed boot attempts has been made. Device needs a poweroff. Probable candidate for a reset/reflash.
+					{
+					aNextState = TSsmState(ESsmFail, ESsmFailSubStatePowerOff);
+					}
+				}
+	#ifdef _DEBUG
+			TSsmStateName name = aNextState.Name();
+			DEBUGPRINT3(_L("Startup Policy : CLE returned with (error : %d) so moving to Fail State : %S."), aError, &name);
+	#endif
+			return ETrue;
+			}
+#endif
+		}
+	else if(iLaunchSysStart || iLaunchSysAgt2SrvAndWServ)	// If either sysstart or sysagt2srv and wserv was launched and CLE did not return an error
+		{
+		if (iLaunchSysStart)
+			{
+			iLaunchSysStart = EFalse;
+			DEBUGPRINT1(_L("Startup Policy : sysstart.exe launched successfully."));
+			}
+		if (iLaunchSysAgt2SrvAndWServ)
+			{
+			iLaunchSysAgt2SrvAndWServ = EFalse;
+			DEBUGPRINT1(_L("Startup Policy : sysagt2srv.exe and wserv.exe launched successfully."));
+			}
+		aNextState = TSsmState(ESsmNormal, KSsmAnySubState);	// move to Normal state
+		return ETrue;
+		}
+	else	// have to move one with the next substates in this state
+		{
+		// Get the sub states from resource reader only once
+		if (!iSubStatesCount)
+			{
+			// Get sub states list from resource reader
+			TRAPD(err, iCommandListResourceReader->GetCommandListIdsL(iSubStates));
+			if (err)
+				{
+				DEBUGPRINT2(_L("Startup Policy : Command list ids prepared with error: %d"), err);
+				}
+			else
+				{
+				iSubStatesCount = iSubStates.Count();
+				}
+			}
+
+		TInt index = iSubStates.Find(iRequestedSubState);
+
+		if (KErrNotFound == index)
+			{
+			DEBUGPRINT2(_L("Startup Policy : SubState for transition not found: %d"), index);
+			PanicNow(KPanicGsaStartupState, ESubStateIndexNotFound);
+			}
+		else if (index == (iSubStatesCount - 1))	// transition complete, move to Normal state
+			{
+			TInt retVal = EFalse;
+			// moving to next state as the transition is completed for ESsmStartup
+			if (iSubStatesCount && (iRequestedSubState == iSubStates[iSubStatesCount-1]))
+				{
+				aNextState = TSsmState(ESsmNormal, KSsmAnySubState);
+				retVal = ETrue;
+				}
+			return retVal;
+			}
+		else		// there is a substate available for transition, moved ahead
+			{
+			iRequestedSubState = iSubStates[++index];
+			aNextState = TSsmState(ESsmStartup, iRequestedSubState);
+#ifdef _DEBUG
+			TSsmStateName name = aNextState.Name();
+			DEBUGPRINT2(_L("Startup Policy : Transition to next state is : %S"), &name);
+#endif				
+			return ETrue;
+			}
+		}
+	return EFalse;
+	} //lint !e1746 Suppress parameter 'aCurrentTransition' could be made const reference
+
+/**
+Callback used by CSsmCommandListResourceReader when a decision needs to be made
+on whether to include a command in a command list or not.
+
+@param aResourceFile Instance of CResourceFile
+@param aResourceId Resource id of SSM_SYMBIAN_CONDITIONAL_INFORMATION struct for command
+@return ETrue in case the command needs to be included in command list, else EFalse.
+
+@see MSsmConditionalCallback::ConditionalCommandAllowedL
+*/
+#ifdef SYMBIAN_SSM_GRACEFUL_SHUTDOWN 
+TBool CGsaStatePolicyStartup::ConditionalCommandAllowedL(CResourceFile& aResourceFile, TInt aResourceId)
+#else
+TBool CGsaStatePolicyStartup::ConditionalCommandAllowedL(CResourceFile& /*aResourceFile*/, TInt /*aResourceId*/)
+#endif
+	{
+	TBool isAllowed = EFalse;        
+#ifdef SYMBIAN_SSM_GRACEFUL_SHUTDOWN
+   	HBufC8* buf = aResourceFile.AllocReadLC(aResourceId);
+   	TResourceReader reader; 
+	reader.SetBuffer(buf);
+	//Read the type of the command from the resource file
+	TUint16 type = reader.ReadUint16();
+	CleanupStack::PopAndDestroy(buf);
+	// check that the type is equal to "EGracefulShutdown"
+	if(type == EGracefulShutdown)    
+		{
+		//Check whether SSM graceful shutdown is enabled or not
+		if(IsSsmGracefulShutdown())   
+			{
+			isAllowed = ETrue;
+			}
+		}
+#else
+	// no commands use 'conditional_information' in Startup state command list.
+	PanicNow(KPanicGsaStartupState, EConditionalInfoNotImplemented);
+#endif
+	return isAllowed;
+	}
+
+/*
+Helper function to check whether requested transition is supported or not.
+*/
+TBool CGsaStatePolicyStartup::TransitionSupported(const TSsmState& aRequestedState) const
+	{
+	return (iCurrentlySupportedTransitions.Find(aRequestedState) > KErrNotFound);
+	}
+
+/*
+Helper function to create command list path for start-up.
+Implements fallback mechanism to launch 'sysstart.exe' if static command list for 'start-up' state is not found.
+This temporary implementation is required during migration from existing 'sysstart' to 'ssma start-up'.
+*/
+void CGsaStatePolicyStartup::GetCommandListPath(TUint aBootMode, TDes& aCmdListPath)
+	{
+	aCmdListPath.Format(KCommandListPath, aBootMode);
+	TBool found = BaflUtils::FolderExists(iFs, aCmdListPath);
+
+	// This Fallback mechanism is used internally during migration from 'sysstart' to 'ssma start-up' and is not required otherwise.
+	if (!found)
+		{
+		aCmdListPath.Copy(KFallbackCmdListPath());
+		iLaunchSysStart = ETrue;	// launch 'sysstart.exe'
+		}
+	}
+
+/*
+Helper function to get the boot count
+*/
+TInt CGsaStatePolicyStartup::GetBootupCountL()
+	{
+	RBuf bootupInfoPath;
+	CleanupClosePushL(bootupInfoPath);
+	const TChar drive = RFs::GetSystemDriveChar();
+	TInt length = KBootUpFile().Length() + 1; /* for RFs::GetSystemDriveChar() */
+	bootupInfoPath.CreateL(length);
+	bootupInfoPath.Append(drive);
+	bootupInfoPath.Append(KBootUpFile());
+	TBool found = BaflUtils::FileExists(iFs, bootupInfoPath);
+ 	if(!found)
+ 		{
+		User::Leave(EBootupCountFileNotFound);
+		}
+
+	RFileReadStream file;
+	CleanupClosePushL(file);
+	User::LeaveIfError(file.Open(iFs, bootupInfoPath, EFileRead));
+	TInt bootCount = file.ReadUint8L();
+	CleanupStack::PopAndDestroy(&file);
+	CleanupStack::PopAndDestroy(&bootupInfoPath);
+	return bootCount;
+	}
+