diff -r 000000000000 -r 4e1aa6a622a0 sysstatemgmt/systemstateplugins/gsapolicy/src/gsastatepolicystartup.cpp --- /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 +#include +#include +#include +#include +#include + +#include +#include +#ifdef SYMBIAN_SSM_GRACEFUL_SHUTDOWN +#include +#include +#endif + +#include +#include +#include + +#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//startup//" +*/ +_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//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; + } +