--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/systemhealthmanagement/systemhealthmgr/startsafesrc/startsafe.cpp Tue Feb 02 00:53:00 2010 +0200
@@ -0,0 +1,802 @@
+// Copyright (c) 2006-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 <startupproperties.h>
+#include "startsafe.h"
+#include "restartsys.h"
+#include <apastarter.h>
+
+#include "shmadebug.h"
+#include "shmapanic.h"
+
+_LIT(KApStartDLL, "apstart.dll");
+typedef CApaStarter* (*TFuncNewL)(void);
+
+const TInt KStartSafeMilliToMicro = 1000;
+const TInt KStartSafeRestartTimeout = 5000000;
+const TUint64 KStartSafeNullThreadId = 0;
+
+#ifdef SYMBIAN_SSM_GRACEFUL_SHUTDOWN
+_LIT(KRestartSysProxyDLL, "restartsys.dll");
+_LIT(KCustomisedRestartSysProxyDLL, "custrestartsys.dll");
+typedef TInt (*TFuncRestartL)(void);
+typedef TInt (*TFuncRestartWithModeL)(TInt);
+#endif //SYMBIAN_SSM_GRACEFUL_SHUTDOWN
+
+/**
+Used to create an instance of CStartSafe class
+@return An instance of CStartSafe
+@internalTechnology
+@deprecated
+*/
+EXPORT_C CStartSafe* CStartSafe::NewL()
+ {
+ CStartSafe* startSafe = new(ELeave) CStartSafe();
+ CleanupStack::PushL( startSafe );
+
+ startSafe->ConstructL();
+
+ CleanupStack::Pop( startSafe );
+ return startSafe;
+ }
+
+CStartSafe::CStartSafe()
+ {
+ }
+
+
+void CStartSafe::ConstructL()
+ {
+ LoadApStartLibL();
+ }
+
+
+CStartSafe::~CStartSafe()
+ {
+ delete iApaStarter;
+
+ iApStartLib.Close();
+#ifdef SYMBIAN_SSM_GRACEFUL_SHUTDOWN
+ iRestartSysLib.Close();
+#endif //SYMBIAN_SSM_GRACEFUL_SHUTDOWN
+ }
+
+
+
+/**
+Used to start a process or application and initiate monitoring.
+Use this for EFireAndForget or EWaitForStart. The case of EDeferredWaitForStart
+is treated as for EFireAndForget.
+The number-of-retries parameter in aStartupProperties applies to the startup procedure.
+If monitoring is not successfully setup, the started process is killed and this function
+leaves with the error code supplied by the system-monitor.
+
+@param aStartupProperties Startup properties provided by the caller.
+@param aProcess The newly created process.
+@param aNumRetried The number of retries made in starting the process.
+@leave KErrArgument if the monitor flag is not set in aStartupProperties.
+@leave Another of the system-wide error codes
+
+@internalTechnology
+@deprecated
+*/
+EXPORT_C void CStartSafe::StartAndMonitorL( const CStartupProperties &aStartupProperties, RProcess& aProcess, TInt& aNumRetried )
+ {
+
+ if( !aStartupProperties.Monitored() )
+ {
+ User::Leave( KErrArgument );
+ }
+
+
+ RSysMonSession sysMon;
+ CleanupClosePushL( sysMon );
+ sysMon.OpenL();
+
+ StartL( aStartupProperties, aProcess, aNumRetried );
+ TRAPD( err, sysMon.MonitorL( aStartupProperties, aProcess ) );
+
+ if( KErrNone != err )
+ {
+ aProcess.Kill( err );
+ User::Leave( err );
+ }
+
+ CleanupStack::PopAndDestroy( &sysMon );
+ }
+
+
+
+/**
+Used to start a process or application using EFireAndForget or EWaitForStart.
+The case of EDeferredWaitForStart is treated as EFireAndForget.
+
+@param aStartupProperties Startup properties provided by the caller.
+@param aProcess The newly created process.
+@param aNumRetried Number of retries made for starting the process.
+@panic ETimerValueInvalid if the timer value is invalid(<0)
+@leave KErrNoMemory if no memory.
+@leave KErrArgument if the TStartMethod enumeration in aStartupProperties is out of range.
+@leave KErrTimedOut if the Application or process failed to rendezvous within the interval specified in aStartupProperties.
+@leave KErrAbort if the startup and rendezvous was unsuccessful _and the call to restart the system was also unsuccessful.
+Otherwise,one of the system-wide error codes
+@internalTechnology
+@deprecated
+*/
+EXPORT_C void CStartSafe::StartL( const CStartupProperties &aStartupProperties, RProcess& aProcess, TInt& aNumRetried )
+ {
+
+ TInt err = KErrNone;
+
+ aNumRetried = 0;
+
+ switch( aStartupProperties.StartMethod() )
+ {
+
+ case EDeferredWaitForStart:
+ case EFireAndForget:
+ TRAP( err, DoFireAndForgetL( aStartupProperties, aProcess ) );
+ break;
+
+ case EWaitForStart:
+ TRAP( err, DoWaitForStartL( aStartupProperties, aProcess, aNumRetried ) );
+ break;
+
+ default:
+ User::Leave( KErrArgument);
+ break;
+ }
+
+
+ if ( KErrNone != err )
+ {
+ InstituteRestartL( aStartupProperties );
+
+ User::Leave( err );
+ }
+
+ }
+
+
+
+/**
+Used to start a process or application using EDeferredWaitForStart.
+Note: Retries are not attempted in this asynchronous form of the function.
+
+@param aStartupProperties Startup properties provided by the caller.
+@param aProcess The newly created process.
+@param aCommandTrs The request-status which is completed by the process rendezvous, or by this function in case of error.
+@leave KErrNotSupported if ApStart is not installed on the device.
+@leave KErrArgument if the CStartupProperties StartupType is not recognised, otherwise one of the system-wide error codes
+@internalTechnology
+@deprecated
+*/
+EXPORT_C void CStartSafe::StartL( const CStartupProperties &aStartupProperties, RProcess& aProcess, TRequestStatus& aCommandTrs )
+ {
+
+ TInt err = KErrNone;
+
+
+ switch( aStartupProperties.StartupType() )
+ {
+ case EStartApp:
+ {
+ // Guard against the case where there is no Apparc
+ if( !iApaStarter )
+ {
+ User::Leave( KErrNotSupported );
+ }
+
+ TThreadId threadId( KStartSafeNullThreadId );
+
+ TRAP( err,
+ {
+ iApaStarter->StartAppL( aStartupProperties.FileName(),
+ aStartupProperties.Args(),
+ aStartupProperties.Viewless(),
+ aStartupProperties.StartInBackground(),
+ threadId, aCommandTrs );
+ } );
+
+ // In the case of error here, we know Apparc has _not called RProcess::Rendezvous( aCommandTrs )
+ // on the process yet, so we must complete the TRS.
+ if ( KErrNone != err )
+ {
+ TRequestStatus* errorTrs = &aCommandTrs;
+ User::RequestComplete( errorTrs, err );
+
+ InstituteRestartL( aStartupProperties );
+ }
+
+ // In the case of error here, we know Apparc _has called RProcess::Rendezvous( aCommandTrs ) on the process,
+ // so do not complete the TRS, just leave.
+ TRAP( err, GetProcessHandleL(aProcess, threadId) );
+
+ if( KErrNone != err )
+ {
+ InstituteRestartL( aStartupProperties );
+ }
+
+ }
+ break;
+
+ case EStartProcess:
+ {
+ err = aProcess.Create( aStartupProperties.FileName(), aStartupProperties.Args() );
+
+ if ( KErrNone == err )
+ {
+ aProcess.Rendezvous( aCommandTrs );
+ // aProcess has not been Resumed yet
+ // but Rendezvous _can complete with KErrNoMemory, hence:-
+ if( aCommandTrs == KRequestPending )
+ {
+ aProcess.Resume();
+ }
+ else
+ {
+ aProcess.Kill( KErrGeneral );
+
+ InstituteRestartL( aStartupProperties );
+ // If a restart is specified, this Leave will not be called, but if a restart is not specified,
+ // InstituteRestartL() returns, therefore communicate the error by leaving with the TRS's value.
+ User::Leave( aCommandTrs.Int() );
+ }
+
+ }
+ else
+ {
+ InstituteRestartL( aStartupProperties );
+ // If a restart is specified, this Leave will not be called, but if a restart is not specified,
+ // InstituteRestartL() returns, therefore communicate the error by leaving with err.
+ User::Leave( err );
+ }
+
+ }
+ break;
+
+ default:
+ User::Leave( KErrArgument );
+ break;
+ }
+
+ }
+
+
+
+/**
+Waits for AppArc Server initialise.
+Note: This function is synchronous.
+@param aStatus Command Status
+@return TInt system error code
+@internalTechnology
+@deprecated
+*/
+EXPORT_C void CStartSafe::InitAppArcServer( TRequestStatus& aStatus )
+ {
+
+ TRequestStatus* pStatus = &aStatus;
+
+ // Guard against the case where there is no Apparc.
+ if( !iApaStarter )
+ {
+ User::RequestComplete( pStatus, KErrNotSupported );
+ return;
+ }
+
+
+ TRAPD( err, iApaStarter->WaitForApparcToInitialiseL() );
+ User::RequestComplete( pStatus, err );
+ }
+
+
+
+/**
+ Make a call to restart the system.
+
+ RestartSys currently requires the guard-time KStartSafeRestartTimeout.
+ The Leave() should never eventuate, except in case of a restart problem.
+*/
+void CStartSafe::InstituteRestartL( const CStartupProperties& aStartupProperties )
+ {
+
+ switch( aStartupProperties.RecoveryMethod() )
+ {
+ case ERestartOS:
+#ifdef SYMBIAN_SSM_GRACEFUL_SHUTDOWN
+ RestartSysDllL(EFalse);
+#else
+ User::LeaveIfError(RestartSys::RestartSystem());
+ User::After( KStartSafeRestartTimeout );
+ User::Leave( KErrAbort );
+#endif //SYMBIAN_SSM_GRACEFUL_SHUTDOWN
+ break;
+
+ case ERestartOSWithMode:
+#ifdef SYMBIAN_SSM_GRACEFUL_SHUTDOWN
+ RestartSysDllL(ETrue, aStartupProperties.RestartMode());
+#else
+ User::LeaveIfError( RestartSys::RestartSystem( aStartupProperties.RestartMode() ) );
+ User::After( KStartSafeRestartTimeout );
+ User::Leave( KErrAbort );
+#endif //SYMBIAN_SSM_GRACEFUL_SHUTDOWN
+ break;
+
+ case EIgnoreOnFailure:
+ default:
+ break;
+ }
+
+ }
+
+TInt CStartSafe::AwaitRendezvous( RProcess& aProcess, TInt aTimeout )
+ {
+ __ASSERT_DEBUG( aTimeout >= 0, PanicNow(KPanicStartSafe, ETimerValueInvalid) );
+
+ TInt err = KErrNone;
+ TRequestStatus processTrs;
+
+ // Initiate the rendezvous
+ aProcess.Rendezvous( processTrs );
+
+ // Ensure it hasn't completed immediately, eg KErrNoMemory
+ if( processTrs == KRequestPending )
+ {
+ aProcess.Resume();
+
+ if ( KStartSafeNoTimeout == aTimeout )
+ {
+ // Wait unconditionally
+ User::WaitForRequest( processTrs );
+ ShootBadProcess( aProcess, processTrs );
+ }
+ else
+ {
+ RTimer timer;
+ err = timer.CreateLocal();
+
+ if( KErrNone == err )
+ {
+ TRequestStatus timerTrs;
+
+ timer.After( timerTrs, TTimeIntervalMicroSeconds32(aTimeout * KStartSafeMilliToMicro) );
+ User::WaitForRequest( timerTrs, processTrs );
+
+ if( processTrs != KRequestPending )
+ {
+ // Rendezvous completed within the timeout period.
+ timer.Cancel();
+ User::WaitForRequest( timerTrs );
+ ShootBadProcess( aProcess, processTrs );
+ }
+ else
+ {
+ // Timer completed. Ensure it completed successfully
+ if( timerTrs == KErrNone )
+ {
+ // Rendezvous timed out
+ aProcess.Kill( KErrTimedOut );
+ }
+ // Wait for the Kill() to be signalled.
+ // Or if the timer completed with an error, wait unconditionally
+ User::WaitForRequest( processTrs );
+ }
+ }
+ else
+ {
+ // Creating the timer was unsuccessful so we must wait unconditionally after all.
+ User::WaitForRequest( processTrs );
+ ShootBadProcess( aProcess, processTrs );
+ }
+
+ timer.Close();
+ }
+
+ }
+ else
+ {
+ // The rendezvous completed before the call to ::Resume(). Perhaps KErrNoMemory
+ // The process exit reason should provide the return value KErrGeneral;
+ aProcess.Kill( KErrGeneral );
+ User::WaitForRequest( processTrs );
+ }
+
+
+
+
+ // Various clauses make the exit-code derivation non-concise.
+ if( KErrNone == err )
+ {
+ TInt exitType = aProcess.ExitType();
+ TInt exitReason = 0;
+
+
+ if( EExitPanic == exitType )
+ {
+ exitReason = aProcess.ExitReason();
+ }
+
+ // Guard against the potential ambiguity of the case where the process has been panicked with a reason of 0
+ if( (EExitPanic == exitType) && (0 == exitReason) )
+ {
+ err = KErrGeneral;
+ }
+ else
+ {
+ // If the process panicked, the trs will have been completed with KErrNone (ie 0), so return the exitReason
+ err = ( EExitPanic == exitType ) ? exitReason : processTrs.Int();
+ }
+ }
+
+ return err;
+ }
+
+
+
+/**
+Await completion of the TRS either unconditionally, or allow aTimeout for aProcess to start.
+*/
+TInt CStartSafe::AwaitProcessStartup( RProcess& aProcess, TInt aTimeout, TRequestStatus& aCommandTrs )
+ {
+ __ASSERT_DEBUG( aTimeout >= 0, PanicNow(KPanicStartSafe, ETimerValueInvalid));
+
+ TInt err = KErrNone;
+
+ if ( KStartSafeNoTimeout == aTimeout )
+ {
+ // Wait unconditionally.
+ User::WaitForRequest( aCommandTrs );
+ ShootBadProcess( aProcess, aCommandTrs );
+ }
+ else
+ {
+ RTimer timer;
+ err = timer.CreateLocal();
+
+ if( KErrNone == err )
+ {
+ TRequestStatus timerTrs;
+ timer.After( timerTrs, TTimeIntervalMicroSeconds32(aTimeout * KStartSafeMilliToMicro) );
+
+
+ User::WaitForRequest( timerTrs, aCommandTrs );
+
+ if( aCommandTrs != KRequestPending )
+ {
+ // App started within the timeout period.
+ timer.Cancel();
+ User::WaitForRequest( timerTrs );
+ ShootBadProcess( aProcess, aCommandTrs );
+ }
+ else
+ {
+ // App timed out.
+ aProcess.Kill( KErrTimedOut );
+ User::WaitForRequest( aCommandTrs );
+ }
+
+ }
+ else
+ {
+ // Creating the timer was unsuccessful, so we must wait unconditionally after all.
+ User::WaitForRequest( aCommandTrs );
+ ShootBadProcess( aProcess, aCommandTrs );
+ }
+
+ timer.Close();
+ }
+
+
+ // Various clauses make the exit-code derivation non-concise.
+ if ( KErrNone == err )
+ {
+ TInt exitType = aProcess.ExitType();
+ TInt exitReason = 0;
+
+
+ if( EExitPanic == exitType )
+ {
+ exitReason = aProcess.ExitReason();
+ }
+
+ // Guard against the potential ambiguity of the case where the process has been panicked with a reason of 0
+ if( (EExitPanic == exitType) && (0 == exitReason) )
+ {
+ err = KErrGeneral;
+ }
+ else
+ {
+ err = ( EExitPanic == exitType ) ? exitReason : aCommandTrs.Int();
+ }
+
+ }
+
+
+ return err;
+ }
+
+
+
+void CStartSafe::DoFireAndForgetL( const CStartupProperties& aStartupProperties, RProcess& aProcess )
+ {
+
+ switch( aStartupProperties.StartupType() )
+ {
+ case EStartApp:
+ DoStartAppL( aStartupProperties, aProcess );
+ break;
+
+ case EStartProcess:
+ DoStartProcessL( aStartupProperties, aProcess );
+ break;
+
+ default :
+ User::Leave( KErrArgument );
+ break;
+ }
+
+ }
+
+
+
+void CStartSafe::DoWaitForStartL( const CStartupProperties& aStartupProperties, RProcess& aProcess, TInt& aNumRetried )
+ {
+
+ switch( aStartupProperties.StartupType() )
+ {
+ case EStartApp:
+ User::LeaveIfError( DoStartAppWithRetries(aStartupProperties, aProcess, aNumRetried) );
+ break;
+
+ case EStartProcess:
+ User::LeaveIfError( DoStartProcessWithRetries(aStartupProperties, aProcess, aNumRetried) );
+ break;
+
+ default:
+ User::Leave( KErrArgument );
+ break;
+ }
+
+ }
+
+
+
+TInt CStartSafe::DoStartAppWithRetries( const CStartupProperties& aStartupProperties, RProcess& aProcess, TInt& aNumRetried )
+ {
+
+ // Guard against the case where there is no Apparc.
+ if( !iApaStarter )
+ {
+ return KErrNotSupported;
+ }
+
+ // Returned if NoOfRetries() is < 0.
+ TInt err = KErrArgument;
+ TRequestStatus commandTrs;
+
+ // Note: 1 attempt plus NoOfRetries. So a NoOfRetries of 0 results in one attempt.
+ for( aNumRetried = 0; aNumRetried <= aStartupProperties.NoOfRetries(); aNumRetried++ )
+ {
+ TThreadId threadId( KStartSafeNullThreadId );
+
+ TRAP( err, iApaStarter->StartAppL(aStartupProperties.FileName(),
+ aStartupProperties.Args(),
+ aStartupProperties.Viewless(), aStartupProperties.StartInBackground(), threadId, commandTrs) );
+
+ if( KErrNone != err )
+ {
+ continue;
+ }
+
+ TRAP( err, GetHandleAndWaitForProcessL(aStartupProperties, aProcess, threadId, commandTrs) );
+
+ if( KErrNone == err )
+ {
+ break;
+ }
+ else if(aNumRetried != aStartupProperties.NoOfRetries())
+ {
+ // If we are trying to restart the process on failure and this is not the last retry,
+ // then process handle should be closed as it would be leaked otherwise.
+ aProcess.Close();
+ }
+
+
+ }
+
+ return err;
+ }
+
+
+
+void CStartSafe::GetProcessHandleL( RProcess& aProcess, const TThreadId& aThreadId )
+ {
+
+ RThread thread;
+ CleanupClosePushL( thread );
+
+ User::LeaveIfError( thread.Open(aThreadId) );
+ User::LeaveIfError( thread.Process(aProcess) );
+
+ CleanupStack::PopAndDestroy( &thread );
+ }
+
+
+
+void CStartSafe::GetHandleAndWaitForProcessL( const CStartupProperties& aStartupProperties, RProcess& aProcess, TThreadId& aThreadId, TRequestStatus& aCommandTrs )
+ {
+
+ GetProcessHandleL( aProcess, aThreadId );
+ User::LeaveIfError( AwaitProcessStartup(aProcess, aStartupProperties.Timeout(), aCommandTrs) );
+ }
+
+
+
+TInt CStartSafe::DoStartProcessWithRetries( const CStartupProperties& aStartupProperties, RProcess& aProcess, TInt& aNumRetried )
+ {
+
+ // Returned if NoOfRetries() is < 0.
+ TInt err = KErrArgument;
+
+ // Note: 1 attempt plus NoOfRetries. So NoOfRetries of 0 results in one attempt
+ for( aNumRetried = 0; aNumRetried <= aStartupProperties.NoOfRetries(); aNumRetried++ )
+ {
+ err = aProcess.Create( aStartupProperties.FileName(), aStartupProperties.Args() );
+
+ if ( KErrNone == err )
+ {
+ // AwaitRendezvous() kills the process if unsuccessful.
+ err = AwaitRendezvous( aProcess, aStartupProperties.Timeout() );
+
+ if( KErrNone == err )
+ {
+ break;
+ }
+ else if(aNumRetried != aStartupProperties.NoOfRetries())
+ {
+ // If we are trying to restart the process on failure and this is not the last retry,
+ // then process handle should be closed as it would be leaked otherwise.
+ aProcess.Close();
+ }
+ }
+
+ }
+
+
+ return err;
+ }
+
+
+
+void CStartSafe::DoStartAppL( const CStartupProperties& aStartupProperties, RProcess& aProcess )
+ {
+
+ // Guard against the case where there is no Apparc
+ if( !iApaStarter )
+ {
+ User::Leave( KErrNotSupported );
+ }
+
+
+ TThreadId threadId( KStartSafeNullThreadId );
+
+ iApaStarter->StartAppL( aStartupProperties.FileName(),
+ aStartupProperties.Args(),
+ aStartupProperties.Viewless(),
+ aStartupProperties.StartInBackground(),
+ threadId );
+
+ // We need the process information only if we want to monitor.
+ if ( aStartupProperties.Monitored() || (aStartupProperties.StartMethod() == EDeferredWaitForStart) )
+ {
+ GetProcessHandleL( aProcess, threadId );
+ }
+
+ }
+
+
+
+void CStartSafe::DoStartProcessL( const CStartupProperties& aStartupProperties, RProcess& aProcess )
+ {
+ User::LeaveIfError( aProcess.Create( aStartupProperties.FileName(), aStartupProperties.Args()) );
+ aProcess.Resume();
+ }
+
+
+
+/**
+Load the library. Locate and call the ordinal corresponding to CApStart::NewL().
+
+Note: We do not leave in the case of being unable to load the libray, but assume Apparc is not present.
+ iApaStarter is checked for NULL before use passim and appropriate error code supplied if it is.
+ The return code is derived from the loader-server (Base) and is not closely specified in RLibrary docs or code.
+*/
+void CStartSafe::LoadApStartLibL()
+ {
+
+ if( KErrNone != iApStartLib.Load(KApStartDLL) )
+ {
+ return;
+ }
+
+ TFuncNewL apStartNewL = reinterpret_cast<TFuncNewL>( iApStartLib.Lookup(1) );
+
+ iApaStarter = apStartNewL();
+ }
+
+
+
+/**
+ See if the process rendezvoused with an error code and is still alive. If so then Kill() it.
+*/
+void CStartSafe::ShootBadProcess( RProcess& aProcess, const TRequestStatus& aStatus )
+ {
+ // Permit positive values of aStatus which may be used for (non-error) information
+ if( (aStatus < KErrNone) && (EExitPending == aProcess.ExitType()) )
+ {
+ aProcess.Terminate( aStatus.Int() );
+ }
+
+ }
+
+#ifdef SYMBIAN_SSM_GRACEFUL_SHUTDOWN
+void CStartSafe::RestartSysDllL(TBool aUseStartupMode, TInt aStartupMode)
+ {
+ if (!iRestartSysLoaded)
+ {
+ TInt err = iRestartSysLib.Load(KCustomisedRestartSysProxyDLL);
+ // if customised restartsys dll is not provided, we try to load the default
+ // restartsys dll
+ if(KErrNotFound == err)
+ {
+ DEBUGPRINT1(_L("CStartSafe: Loading default restartsys.dll as custrestartsys.dll is not found"));
+ err = iRestartSysLib.Load(KRestartSysProxyDLL);
+ }
+ if(KErrNone != err)
+ {
+ // restartsys dll (customised or defaut) should be present for ERestartOS and ERestartOSWithMode
+ // recovery policies we panic here if it is not present
+ DEBUGPRINT2(_L("CustRestartSys/ RestartSys failed to load - Error Code= %d"), err);
+ PanicNow(KPanicMonitor, ERestartSysLibNotPresent);
+ }
+ iRestartSysLoaded = ETrue;
+ }
+
+ if (aUseStartupMode)
+ {
+ TFuncRestartWithModeL restartSys = reinterpret_cast<TFuncRestartWithModeL>(iRestartSysLib.Lookup(1));
+ if (restartSys == NULL)
+ {
+ DEBUGPRINT1(_L("CStartSafe: Ordinal Lookup Error\n Expected Function prototype: RestartSystem(TInt aStartupMode)"));
+ User::Leave(KErrBadLibraryEntryPoint);
+ }
+ User::LeaveIfError(restartSys(aStartupMode)); // restart the system with give startup mode
+ }
+ else
+ {
+ TFuncRestartL restartSys = reinterpret_cast<TFuncRestartL>(iRestartSysLib.Lookup(2));
+ if (restartSys == NULL)
+ {
+ DEBUGPRINT1(_L("CStartSafe: Ordinal Lookup Error\n Expected Function prototype: RestartSystem()"));
+ User::Leave(KErrBadLibraryEntryPoint);
+ }
+ User::LeaveIfError(restartSys()); // restart the system
+ }
+
+ User::After(KStartSafeRestartTimeout);
+ User::Leave(KErrAbort);
+ }
+#endif //SYMBIAN_SSM_GRACEFUL_SHUTDOWN
+