systemhealthmanagement/systemhealthmgr/startsafesrc/startsafe.cpp
changeset 0 4e1aa6a622a0
equal deleted inserted replaced
-1:000000000000 0:4e1aa6a622a0
       
     1 // Copyright (c) 2006-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 <startupproperties.h>
       
    17 #include "startsafe.h"
       
    18 #include "restartsys.h"
       
    19 #include <apastarter.h>
       
    20 
       
    21 #include "shmadebug.h"
       
    22 #include "shmapanic.h"
       
    23 
       
    24 _LIT(KApStartDLL, "apstart.dll");
       
    25 typedef CApaStarter* (*TFuncNewL)(void);
       
    26 
       
    27 const TInt KStartSafeMilliToMicro = 1000;
       
    28 const TInt KStartSafeRestartTimeout = 5000000;
       
    29 const TUint64 KStartSafeNullThreadId = 0;
       
    30 
       
    31 #ifdef SYMBIAN_SSM_GRACEFUL_SHUTDOWN
       
    32 _LIT(KRestartSysProxyDLL, "restartsys.dll");
       
    33 _LIT(KCustomisedRestartSysProxyDLL, "custrestartsys.dll");
       
    34 typedef TInt (*TFuncRestartL)(void);
       
    35 typedef TInt (*TFuncRestartWithModeL)(TInt);
       
    36 #endif	//SYMBIAN_SSM_GRACEFUL_SHUTDOWN
       
    37 
       
    38 /**
       
    39 Used to create an instance of CStartSafe class
       
    40 @return An instance of CStartSafe
       
    41 @internalTechnology
       
    42 @deprecated
       
    43 */
       
    44 EXPORT_C CStartSafe* CStartSafe::NewL()
       
    45 	{
       
    46 	CStartSafe* startSafe = new(ELeave) CStartSafe();
       
    47 	CleanupStack::PushL( startSafe );
       
    48 	
       
    49 	startSafe->ConstructL();
       
    50 	
       
    51 	CleanupStack::Pop( startSafe );
       
    52 	return startSafe;	
       
    53 	}
       
    54 
       
    55 CStartSafe::CStartSafe()
       
    56 	{
       
    57 	}
       
    58 
       
    59  
       
    60 void CStartSafe::ConstructL()
       
    61 	{
       
    62 	LoadApStartLibL();		
       
    63 	}
       
    64 	
       
    65 	
       
    66 CStartSafe::~CStartSafe()
       
    67 	{
       
    68 	delete iApaStarter;
       
    69 		
       
    70 	iApStartLib.Close();
       
    71 #ifdef SYMBIAN_SSM_GRACEFUL_SHUTDOWN
       
    72 	iRestartSysLib.Close();
       
    73 #endif //SYMBIAN_SSM_GRACEFUL_SHUTDOWN
       
    74 	}
       
    75 
       
    76 
       
    77 
       
    78 /**
       
    79 Used to start a process or application and initiate monitoring. 
       
    80 Use this for EFireAndForget or EWaitForStart. The case of EDeferredWaitForStart
       
    81 is treated as for EFireAndForget.
       
    82 The number-of-retries parameter in aStartupProperties applies to the startup procedure.
       
    83 If monitoring is not successfully setup, the started process is killed and this function
       
    84 leaves with the error code supplied by the system-monitor.
       
    85 
       
    86 @param aStartupProperties Startup properties provided by the caller.
       
    87 @param aProcess The newly created process.
       
    88 @param aNumRetried The number of retries made in starting the process. 
       
    89 @leave KErrArgument if the monitor flag is not set in aStartupProperties. 
       
    90 @leave Another of the system-wide error codes
       
    91 
       
    92 @internalTechnology
       
    93 @deprecated
       
    94 */
       
    95 EXPORT_C void CStartSafe::StartAndMonitorL( const CStartupProperties &aStartupProperties, RProcess& aProcess, TInt& aNumRetried )
       
    96 	{
       
    97 
       
    98 	if( !aStartupProperties.Monitored() )
       
    99 		{
       
   100 		User::Leave( KErrArgument );	
       
   101 		}
       
   102 
       
   103 
       
   104 	RSysMonSession sysMon;
       
   105 	CleanupClosePushL( sysMon );
       
   106 	sysMon.OpenL();
       
   107 	
       
   108 	StartL( aStartupProperties, aProcess, aNumRetried );
       
   109 	TRAPD( err, sysMon.MonitorL( aStartupProperties, aProcess ) );
       
   110 	
       
   111 	if( KErrNone != err )
       
   112 		{
       
   113 		aProcess.Kill( err );
       
   114 		User::Leave( err );	
       
   115 		}
       
   116 	
       
   117 	CleanupStack::PopAndDestroy( &sysMon );
       
   118 	}
       
   119 
       
   120 
       
   121 
       
   122 /**
       
   123 Used to start a process or application using EFireAndForget or EWaitForStart.
       
   124 The case of EDeferredWaitForStart is treated as EFireAndForget.
       
   125  
       
   126 @param aStartupProperties Startup properties provided by the caller.
       
   127 @param aProcess The newly created process.
       
   128 @param aNumRetried Number of retries made for starting the process. 
       
   129 @panic ETimerValueInvalid if the timer value is invalid(<0)
       
   130 @leave KErrNoMemory if no memory. 
       
   131 @leave KErrArgument if the TStartMethod enumeration in aStartupProperties is out of range. 
       
   132 @leave KErrTimedOut if the Application or process failed to rendezvous within the interval specified in aStartupProperties. 
       
   133 @leave KErrAbort if the startup and rendezvous was unsuccessful _and the call to restart the system was also unsuccessful. 
       
   134 Otherwise,one of the system-wide error codes
       
   135 @internalTechnology
       
   136 @deprecated
       
   137 */
       
   138 EXPORT_C void CStartSafe::StartL( const CStartupProperties &aStartupProperties, RProcess& aProcess, TInt& aNumRetried )	
       
   139 	{
       
   140 	
       
   141 	TInt err = KErrNone;	
       
   142 	
       
   143 	aNumRetried = 0;
       
   144 	
       
   145 	switch( aStartupProperties.StartMethod() )
       
   146 	 	{ 	
       
   147 	 	
       
   148 	 	case EDeferredWaitForStart:
       
   149 	 	case EFireAndForget:
       
   150 	 		TRAP( err, DoFireAndForgetL( aStartupProperties, aProcess ) );
       
   151  	 		break;
       
   152 
       
   153 	 	case EWaitForStart:
       
   154 	 		TRAP( err, DoWaitForStartL( aStartupProperties, aProcess, aNumRetried ) );					
       
   155 			break;
       
   156 			
       
   157 		default:
       
   158 			User::Leave( KErrArgument);
       
   159 			break;
       
   160 	 	}
       
   161 	 	
       
   162 	 
       
   163 	if ( KErrNone != err ) 
       
   164 		{
       
   165 		InstituteRestartL( aStartupProperties );
       
   166 		
       
   167 		User::Leave( err );
       
   168 		}
       
   169 	
       
   170 	}
       
   171 	
       
   172 	
       
   173 
       
   174 /**
       
   175 Used to start a process or application using EDeferredWaitForStart. 
       
   176 Note: Retries are not attempted in this asynchronous form of the function.
       
   177 
       
   178 @param aStartupProperties Startup properties provided by the caller.
       
   179 @param aProcess The newly created process.
       
   180 @param aCommandTrs The request-status which is completed by the process rendezvous, or by this function in case of error.
       
   181 @leave KErrNotSupported if ApStart is not installed on the device.
       
   182 @leave KErrArgument if the CStartupProperties StartupType is not recognised, otherwise one of the system-wide error codes
       
   183 @internalTechnology
       
   184 @deprecated
       
   185 */
       
   186 EXPORT_C void CStartSafe::StartL( const CStartupProperties &aStartupProperties, RProcess& aProcess, TRequestStatus& aCommandTrs )
       
   187 	{
       
   188 	
       
   189 	TInt err = KErrNone;
       
   190 	
       
   191 	
       
   192 	switch( aStartupProperties.StartupType() )
       
   193 		{
       
   194 		case EStartApp:
       
   195 			{	
       
   196 			// Guard against the case where there is no Apparc
       
   197 			if( !iApaStarter )
       
   198 				{
       
   199 				User::Leave( KErrNotSupported );	
       
   200 				}
       
   201 				
       
   202 			TThreadId threadId( KStartSafeNullThreadId );
       
   203 	
       
   204 			TRAP( err, 
       
   205 					{
       
   206 					iApaStarter->StartAppL( aStartupProperties.FileName(), 
       
   207 											aStartupProperties.Args(), 
       
   208 											aStartupProperties.Viewless(),
       
   209 										 	aStartupProperties.StartInBackground(), 
       
   210 											threadId, aCommandTrs );
       
   211 					} );
       
   212 					
       
   213 			// In the case of error here, we know Apparc has _not called RProcess::Rendezvous( aCommandTrs ) 
       
   214 			// on the process yet, so  we must complete the TRS.	
       
   215 			if ( KErrNone != err )
       
   216 				{	
       
   217 	 			TRequestStatus* errorTrs = &aCommandTrs;
       
   218 				User::RequestComplete( errorTrs, err );
       
   219 				
       
   220 				InstituteRestartL( aStartupProperties );
       
   221 				}
       
   222 				
       
   223 			// In the case of error here, we know Apparc _has called RProcess::Rendezvous( aCommandTrs ) on the process,
       
   224 			// so do not complete the TRS, just leave.
       
   225 			TRAP( err, GetProcessHandleL(aProcess, threadId) );
       
   226 			
       
   227 			if( KErrNone != err )
       
   228 				{
       
   229 				InstituteRestartL( aStartupProperties );
       
   230 				}
       
   231 
       
   232 			}
       
   233 			break;
       
   234 		
       
   235 		case EStartProcess:
       
   236 			{
       
   237 		 	err = aProcess.Create( aStartupProperties.FileName(), aStartupProperties.Args() );
       
   238 		
       
   239 			if ( KErrNone == err )
       
   240 				{		
       
   241 				aProcess.Rendezvous( aCommandTrs );
       
   242 				// aProcess has not been Resumed yet
       
   243 				// but Rendezvous _can complete with KErrNoMemory, hence:-
       
   244 				if( aCommandTrs == KRequestPending ) 
       
   245 					{
       
   246 					aProcess.Resume();
       
   247 					}
       
   248 				else
       
   249 					{
       
   250 					aProcess.Kill( KErrGeneral );
       
   251 					
       
   252 					InstituteRestartL( aStartupProperties );
       
   253 					// If a restart is specified, this Leave will not be called, but if a restart is not specified,
       
   254 					// InstituteRestartL() returns, therefore communicate the error by leaving with the TRS's value.
       
   255 					User::Leave( aCommandTrs.Int() );
       
   256 					}
       
   257 					
       
   258 				}
       
   259 			else
       
   260 				{
       
   261 				InstituteRestartL( aStartupProperties );
       
   262 				// If a restart is specified, this Leave will not be called, but if a restart is not specified, 
       
   263 				// InstituteRestartL() returns, therefore communicate the error by leaving with err.
       
   264 				User::Leave( err );
       
   265 				}
       
   266 					
       
   267 			}		
       
   268 			break;
       
   269 			
       
   270 		default:
       
   271 			User::Leave( KErrArgument );
       
   272 			break;	
       
   273 		}
       
   274 
       
   275 	}
       
   276 	
       
   277 
       
   278 
       
   279 /**
       
   280 Waits for AppArc Server initialise.
       
   281 Note: This function is synchronous.
       
   282 @param aStatus Command Status
       
   283 @return TInt system error code
       
   284 @internalTechnology
       
   285 @deprecated
       
   286 */			
       
   287 EXPORT_C void CStartSafe::InitAppArcServer( TRequestStatus& aStatus )
       
   288 	{
       
   289 	
       
   290 	TRequestStatus* pStatus = &aStatus;
       
   291 	
       
   292 	// Guard against the case where there is no Apparc.
       
   293 	if( !iApaStarter )
       
   294 		{
       
   295 		User::RequestComplete( pStatus, KErrNotSupported );	
       
   296 		return;
       
   297 		}
       
   298 		
       
   299 		
       
   300 	TRAPD( err, iApaStarter->WaitForApparcToInitialiseL() );
       
   301 	User::RequestComplete( pStatus, err );
       
   302 	}
       
   303 
       
   304 
       
   305 
       
   306 /**
       
   307  Make a call to restart the system.
       
   308  
       
   309  RestartSys currently requires the guard-time KStartSafeRestartTimeout. 
       
   310  The Leave() should never eventuate, except in case of a restart problem.
       
   311 */
       
   312 void CStartSafe::InstituteRestartL( const CStartupProperties& aStartupProperties )
       
   313 	{
       
   314 
       
   315 	switch( aStartupProperties.RecoveryMethod() )
       
   316 		{
       
   317 	case ERestartOS:
       
   318 #ifdef SYMBIAN_SSM_GRACEFUL_SHUTDOWN
       
   319 		RestartSysDllL(EFalse);
       
   320 #else
       
   321 		User::LeaveIfError(RestartSys::RestartSystem());
       
   322 		User::After( KStartSafeRestartTimeout );
       
   323 		User::Leave( KErrAbort );
       
   324 #endif	//SYMBIAN_SSM_GRACEFUL_SHUTDOWN
       
   325 		break;
       
   326 
       
   327 	case ERestartOSWithMode:
       
   328 #ifdef SYMBIAN_SSM_GRACEFUL_SHUTDOWN
       
   329 		RestartSysDllL(ETrue, aStartupProperties.RestartMode());
       
   330 #else
       
   331 		User::LeaveIfError( RestartSys::RestartSystem( aStartupProperties.RestartMode() ) );
       
   332 		User::After( KStartSafeRestartTimeout );
       
   333 		User::Leave( KErrAbort );
       
   334 #endif	//SYMBIAN_SSM_GRACEFUL_SHUTDOWN
       
   335 		break;
       
   336 		
       
   337 	case EIgnoreOnFailure:
       
   338 	default:
       
   339 		break;
       
   340 		}
       
   341 
       
   342 	}
       
   343 
       
   344 TInt CStartSafe::AwaitRendezvous( RProcess& aProcess, TInt aTimeout )
       
   345 	{
       
   346 	__ASSERT_DEBUG( aTimeout >= 0, PanicNow(KPanicStartSafe, ETimerValueInvalid) );
       
   347 
       
   348 	TInt err = KErrNone;
       
   349 	TRequestStatus processTrs;
       
   350 		 	 
       
   351 	// Initiate the rendezvous	
       
   352 	aProcess.Rendezvous( processTrs );
       
   353 		
       
   354 	// Ensure it hasn't completed immediately, eg KErrNoMemory
       
   355 	if( processTrs == KRequestPending ) 
       
   356 		{
       
   357 		aProcess.Resume();
       
   358 		
       
   359 		if ( KStartSafeNoTimeout == aTimeout )
       
   360 			{
       
   361 			// Wait unconditionally
       
   362 			User::WaitForRequest( processTrs );
       
   363 			ShootBadProcess( aProcess, processTrs );
       
   364 			}
       
   365 		else
       
   366 			{
       
   367 			RTimer timer;
       
   368 			err = timer.CreateLocal();
       
   369 			
       
   370 			if( KErrNone == err )
       
   371 				{		
       
   372 				TRequestStatus timerTrs;
       
   373 				
       
   374 				timer.After( timerTrs, TTimeIntervalMicroSeconds32(aTimeout * KStartSafeMilliToMicro) );
       
   375 				User::WaitForRequest( timerTrs, processTrs );
       
   376 				
       
   377 				if( processTrs != KRequestPending )
       
   378 					{
       
   379 					// Rendezvous completed within the timeout period.
       
   380 					timer.Cancel();
       
   381 					User::WaitForRequest( timerTrs );
       
   382 					ShootBadProcess( aProcess, processTrs );	
       
   383 					}
       
   384 				else
       
   385 					{
       
   386 					// Timer completed. Ensure it completed successfully
       
   387 					if( timerTrs == KErrNone )
       
   388 						{
       
   389 						// Rendezvous timed out	
       
   390 						aProcess.Kill( KErrTimedOut );
       
   391 						}
       
   392 					// Wait for the Kill() to be signalled.
       
   393 					// Or if the timer completed with an error, wait unconditionally 
       
   394 					User::WaitForRequest( processTrs );							
       
   395 					}														
       
   396 				}
       
   397 			else
       
   398 				{
       
   399 				// Creating the timer was unsuccessful so we must wait unconditionally after all.
       
   400 				User::WaitForRequest( processTrs );	
       
   401 				ShootBadProcess( aProcess, processTrs );
       
   402 				}
       
   403 						
       
   404 			timer.Close();
       
   405 			}
       
   406 					
       
   407 		}
       
   408 	else
       
   409 		{
       
   410 		// The rendezvous completed before the call to ::Resume(). Perhaps KErrNoMemory
       
   411 		// The process exit reason should provide the return value KErrGeneral;
       
   412 		aProcess.Kill( KErrGeneral );
       
   413 		User::WaitForRequest( processTrs );
       
   414 		}
       
   415 	
       
   416 	
       
   417 	
       
   418 	
       
   419 	// Various clauses make the exit-code derivation non-concise.
       
   420 	if( KErrNone == err )
       
   421 		{
       
   422 		TInt exitType = aProcess.ExitType();
       
   423 		TInt exitReason = 0;
       
   424 		
       
   425 		
       
   426 		if( EExitPanic == exitType )
       
   427 			{
       
   428 			exitReason = aProcess.ExitReason();	
       
   429 			}
       
   430 
       
   431 		// Guard against the potential ambiguity of the case where the process has been panicked with a reason of 0
       
   432 		if( (EExitPanic == exitType) && (0 == exitReason) )
       
   433 			{
       
   434 			err = KErrGeneral;	
       
   435 			}
       
   436 		else
       
   437 			{
       
   438 			// If the process panicked, the trs will have been completed with KErrNone (ie 0), so return the exitReason
       
   439 			err = ( EExitPanic == exitType ) ? exitReason : processTrs.Int();	
       
   440 			}
       
   441 		}
       
   442 
       
   443 	return err;	
       
   444 	}
       
   445 
       
   446 
       
   447 
       
   448 /**
       
   449 Await completion of the TRS either unconditionally, or allow aTimeout for aProcess to start.
       
   450 */
       
   451 TInt CStartSafe::AwaitProcessStartup( RProcess& aProcess, TInt aTimeout, TRequestStatus& aCommandTrs )
       
   452 	{		
       
   453 	__ASSERT_DEBUG( aTimeout >= 0, PanicNow(KPanicStartSafe, ETimerValueInvalid));
       
   454 					 
       
   455 	TInt err = KErrNone;
       
   456 	
       
   457 	if ( KStartSafeNoTimeout == aTimeout )
       
   458 		{ 
       
   459 		 // Wait unconditionally.
       
   460 		User::WaitForRequest( aCommandTrs );
       
   461 		ShootBadProcess( aProcess, aCommandTrs );
       
   462 		}
       
   463 	else
       
   464 		{						
       
   465 		RTimer timer;
       
   466 		err = timer.CreateLocal();
       
   467 		
       
   468 		if( KErrNone == err )
       
   469 			{
       
   470 			TRequestStatus timerTrs;
       
   471 			timer.After( timerTrs, TTimeIntervalMicroSeconds32(aTimeout * KStartSafeMilliToMicro) );
       
   472 			
       
   473 		
       
   474 			User::WaitForRequest( timerTrs, aCommandTrs );
       
   475 			
       
   476 			if( aCommandTrs != KRequestPending )
       
   477 				{
       
   478 				// App started within the timeout period.
       
   479 				timer.Cancel();
       
   480 				User::WaitForRequest( timerTrs );
       
   481 				ShootBadProcess( aProcess, aCommandTrs );
       
   482 				}
       
   483 			else
       
   484 				{
       
   485 				// App timed out.
       
   486 				aProcess.Kill( KErrTimedOut );			 
       
   487 				User::WaitForRequest( aCommandTrs );				
       
   488 				}
       
   489 				
       
   490 			}
       
   491 		else
       
   492 			{
       
   493 			// Creating the timer was unsuccessful, so we must wait unconditionally after all.
       
   494 			User::WaitForRequest( aCommandTrs );
       
   495 			ShootBadProcess( aProcess, aCommandTrs );	
       
   496 			}
       
   497 		
       
   498 		timer.Close();
       
   499 		}
       
   500 
       
   501 		
       
   502 	// Various clauses make the exit-code derivation non-concise. 
       
   503 	if ( KErrNone == err )
       
   504 		{
       
   505 		TInt exitType = aProcess.ExitType();
       
   506 		TInt exitReason = 0;
       
   507 		
       
   508 		
       
   509 		if( EExitPanic == exitType )
       
   510 			{
       
   511 			exitReason = aProcess.ExitReason();	
       
   512 			}
       
   513 
       
   514 		// Guard against the potential ambiguity of the case where the process has been panicked with a reason of 0
       
   515 		if( (EExitPanic == exitType) && (0 == exitReason) )
       
   516 			{
       
   517 			err = KErrGeneral;	
       
   518 			}
       
   519 		else
       
   520 			{
       
   521 			err = ( EExitPanic == exitType ) ? exitReason : aCommandTrs.Int();
       
   522 			}
       
   523 			
       
   524 		}
       
   525 	  
       
   526 	  
       
   527 	return err; 	
       
   528 	}
       
   529 
       
   530 
       
   531 
       
   532 void CStartSafe::DoFireAndForgetL( const CStartupProperties& aStartupProperties, RProcess& aProcess )
       
   533 	{
       
   534 	
       
   535 	switch(  aStartupProperties.StartupType() )
       
   536 		{
       
   537 		case EStartApp:
       
   538 			DoStartAppL( aStartupProperties, aProcess );
       
   539 			break;
       
   540 			
       
   541 		case EStartProcess:
       
   542 			DoStartProcessL( aStartupProperties, aProcess );
       
   543 			break;
       
   544 			
       
   545 		default :
       
   546 			User::Leave( KErrArgument );
       
   547 			break;
       
   548 		}
       
   549 
       
   550 	}
       
   551 	
       
   552 	
       
   553 	
       
   554 void CStartSafe::DoWaitForStartL( const CStartupProperties& aStartupProperties, RProcess& aProcess, TInt& aNumRetried )
       
   555 	{
       
   556 	
       
   557 	switch( aStartupProperties.StartupType() )
       
   558 		{
       
   559 		case EStartApp:
       
   560 			User::LeaveIfError( DoStartAppWithRetries(aStartupProperties, aProcess, aNumRetried) );
       
   561 			break;
       
   562 			
       
   563 		case EStartProcess:
       
   564 			 User::LeaveIfError( DoStartProcessWithRetries(aStartupProperties, aProcess, aNumRetried) );
       
   565 			break;
       
   566 			
       
   567 		default:
       
   568 			User::Leave( KErrArgument );
       
   569 			break;
       
   570 		}
       
   571 
       
   572 	}
       
   573 
       
   574 
       
   575 
       
   576 TInt CStartSafe::DoStartAppWithRetries( const CStartupProperties& aStartupProperties, RProcess& aProcess, TInt& aNumRetried )
       
   577 	{
       
   578 
       
   579 	// Guard against the case where there is no Apparc.
       
   580 	if( !iApaStarter )
       
   581 		{
       
   582 		return KErrNotSupported;	
       
   583 		}
       
   584 
       
   585 	// Returned if NoOfRetries() is < 0.
       
   586 	TInt err = KErrArgument;
       
   587 	TRequestStatus commandTrs;
       
   588 	
       
   589 	// Note: 1 attempt plus NoOfRetries. So a NoOfRetries of 0 results in one attempt.
       
   590 	for( aNumRetried = 0; aNumRetried <= aStartupProperties.NoOfRetries(); aNumRetried++ )
       
   591 		{		
       
   592 		TThreadId threadId( KStartSafeNullThreadId );
       
   593 		
       
   594 		TRAP( err, iApaStarter->StartAppL(aStartupProperties.FileName(), 
       
   595 				   aStartupProperties.Args(), 
       
   596 				   aStartupProperties.Viewless(), aStartupProperties.StartInBackground(), threadId, commandTrs) );
       
   597 
       
   598 		if( KErrNone != err )
       
   599 			{
       
   600 			continue;				
       
   601 			}
       
   602 
       
   603 		TRAP( err, GetHandleAndWaitForProcessL(aStartupProperties, aProcess, threadId, commandTrs) );
       
   604 		
       
   605 		if( KErrNone == err )
       
   606 			{
       
   607 			break;
       
   608 			}
       
   609 		else if(aNumRetried != aStartupProperties.NoOfRetries())
       
   610 			{
       
   611 			// If we are trying to restart the process on failure and this is not the last retry, 
       
   612 			// then process handle should be closed as it would be leaked otherwise.
       
   613 			aProcess.Close();
       
   614 			}
       
   615 	
       
   616 				
       
   617 		}
       
   618 	
       
   619 	return err;		
       
   620 	}
       
   621 	
       
   622 	
       
   623 	
       
   624 void CStartSafe::GetProcessHandleL( RProcess& aProcess, const TThreadId& aThreadId )
       
   625 	{
       
   626 	
       
   627 	RThread thread;
       
   628 	CleanupClosePushL( thread );
       
   629 	
       
   630 	User::LeaveIfError( thread.Open(aThreadId) );  
       
   631 	User::LeaveIfError( thread.Process(aProcess) );	
       
   632 	
       
   633 	CleanupStack::PopAndDestroy( &thread );	
       
   634 	}
       
   635 
       
   636 
       
   637 
       
   638 void CStartSafe::GetHandleAndWaitForProcessL( const CStartupProperties& aStartupProperties, RProcess& aProcess, TThreadId& aThreadId, TRequestStatus& aCommandTrs )
       
   639 	{
       
   640 
       
   641 	GetProcessHandleL( aProcess, aThreadId );
       
   642 	User::LeaveIfError( AwaitProcessStartup(aProcess, aStartupProperties.Timeout(), aCommandTrs) );
       
   643 	}
       
   644 	
       
   645 	
       
   646 
       
   647 TInt CStartSafe::DoStartProcessWithRetries( const CStartupProperties& aStartupProperties, RProcess& aProcess, TInt& aNumRetried )
       
   648 	{
       
   649 
       
   650 	// Returned if NoOfRetries() is < 0.	
       
   651 	TInt err = KErrArgument;
       
   652 			
       
   653 	// Note: 1 attempt plus NoOfRetries. So NoOfRetries of 0 results in one attempt
       
   654 	for( aNumRetried = 0; aNumRetried <= aStartupProperties.NoOfRetries(); aNumRetried++ )
       
   655 		{		
       
   656 		err = aProcess.Create( aStartupProperties.FileName(), aStartupProperties.Args() );
       
   657 		
       
   658 		if ( KErrNone == err )
       
   659 			{
       
   660 			// AwaitRendezvous() kills the process if unsuccessful. 
       
   661 			err = AwaitRendezvous( aProcess, aStartupProperties.Timeout() );
       
   662 			
       
   663 			if( KErrNone == err )
       
   664 				{
       
   665 				break;					
       
   666 				}
       
   667 			else if(aNumRetried != aStartupProperties.NoOfRetries())
       
   668 				{
       
   669 				// If we are trying to restart the process on failure and this is not the last retry, 
       
   670 				// then process handle should be closed as it would be leaked otherwise.
       
   671 				aProcess.Close();
       
   672 				}
       
   673 			}
       
   674 			
       
   675 		}
       
   676 		
       
   677 	
       
   678 	return err;	
       
   679 	}
       
   680 
       
   681 
       
   682 
       
   683 void CStartSafe::DoStartAppL( const CStartupProperties& aStartupProperties, RProcess& aProcess )
       
   684 	{
       
   685 
       
   686 	// Guard against the case where there is no Apparc
       
   687 	if( !iApaStarter )
       
   688 		{
       
   689 		User::Leave( KErrNotSupported );	
       
   690 		}
       
   691 
       
   692 
       
   693 	TThreadId threadId( KStartSafeNullThreadId );
       
   694 	
       
   695 	iApaStarter->StartAppL( aStartupProperties.FileName(), 
       
   696 							aStartupProperties.Args(), 
       
   697 							aStartupProperties.Viewless(), 
       
   698 						 	aStartupProperties.StartInBackground(), 
       
   699 							threadId );	
       
   700 					
       
   701 	// We need the process information only if we want to monitor.				
       
   702 	if ( aStartupProperties.Monitored() || (aStartupProperties.StartMethod() == EDeferredWaitForStart) ) 
       
   703 		{
       
   704 		GetProcessHandleL( aProcess, threadId );	
       
   705 		}
       
   706 	
       
   707 	}
       
   708 	
       
   709 	
       
   710 	
       
   711 void CStartSafe::DoStartProcessL( const CStartupProperties& aStartupProperties, RProcess& aProcess )
       
   712 	{
       
   713 	User::LeaveIfError( aProcess.Create( aStartupProperties.FileName(), aStartupProperties.Args()) );
       
   714 	aProcess.Resume();	
       
   715 	}
       
   716 
       
   717 
       
   718 
       
   719 /**
       
   720 Load the library. Locate and call the ordinal corresponding to CApStart::NewL().
       
   721 
       
   722 Note: We do not leave in the case of being unable to load the libray, but assume Apparc is not present.
       
   723       iApaStarter is checked for NULL before use passim and appropriate error code supplied if it is. 
       
   724       The return code is derived from the loader-server (Base) and is not closely specified in RLibrary docs or code.
       
   725 */
       
   726 void CStartSafe::LoadApStartLibL()
       
   727 	{
       
   728 	
       
   729 	 if( KErrNone != iApStartLib.Load(KApStartDLL) )
       
   730 	 	{
       
   731 	 	return;	
       
   732 	 	}
       
   733 	 
       
   734 	TFuncNewL apStartNewL = reinterpret_cast<TFuncNewL>( iApStartLib.Lookup(1) );
       
   735 
       
   736 	iApaStarter = apStartNewL();
       
   737 	}
       
   738 
       
   739 
       
   740 
       
   741 /**
       
   742  See if the process rendezvoused with an error code and is still alive. If so then Kill() it.
       
   743 */
       
   744 void CStartSafe::ShootBadProcess( RProcess& aProcess, const TRequestStatus& aStatus )
       
   745 	{
       
   746 	// Permit positive values of aStatus which may be used for (non-error) information
       
   747 	if( (aStatus < KErrNone) && (EExitPending == aProcess.ExitType()) )
       
   748 		{
       
   749 		aProcess.Terminate( aStatus.Int() );	
       
   750 		}
       
   751 		
       
   752 	}
       
   753 
       
   754 #ifdef SYMBIAN_SSM_GRACEFUL_SHUTDOWN
       
   755 void CStartSafe::RestartSysDllL(TBool aUseStartupMode, TInt aStartupMode)
       
   756 	{
       
   757 	if (!iRestartSysLoaded)
       
   758 		{	
       
   759 		TInt err = iRestartSysLib.Load(KCustomisedRestartSysProxyDLL);
       
   760 		// if customised restartsys dll is not provided, we try to load the default
       
   761 		// restartsys dll
       
   762 		if(KErrNotFound == err)
       
   763 			{
       
   764 			DEBUGPRINT1(_L("CStartSafe: Loading default restartsys.dll as custrestartsys.dll is not found"));
       
   765 			err = iRestartSysLib.Load(KRestartSysProxyDLL);
       
   766 			}
       
   767 		if(KErrNone != err)
       
   768 	 		{
       
   769 			// restartsys dll (customised or defaut) should be present for ERestartOS and ERestartOSWithMode 
       
   770 			// recovery policies we panic here if it is not present
       
   771 			DEBUGPRINT2(_L("CustRestartSys/ RestartSys failed to load - Error Code= %d"), err);
       
   772 	 		PanicNow(KPanicMonitor, ERestartSysLibNotPresent);
       
   773 	 		}
       
   774 		iRestartSysLoaded = ETrue;
       
   775 		}
       
   776 
       
   777 	if (aUseStartupMode)
       
   778 		{
       
   779 		TFuncRestartWithModeL restartSys = reinterpret_cast<TFuncRestartWithModeL>(iRestartSysLib.Lookup(1));
       
   780 		if (restartSys == NULL)
       
   781 			{
       
   782 			DEBUGPRINT1(_L("CStartSafe: Ordinal Lookup Error\n Expected Function prototype: RestartSystem(TInt aStartupMode)"));
       
   783 			User::Leave(KErrBadLibraryEntryPoint);
       
   784 			}
       
   785 		User::LeaveIfError(restartSys(aStartupMode));	// restart the system with give startup mode
       
   786 		}
       
   787 	else
       
   788 		{
       
   789 		TFuncRestartL restartSys = reinterpret_cast<TFuncRestartL>(iRestartSysLib.Lookup(2));
       
   790 		if (restartSys == NULL)
       
   791 			{
       
   792 			DEBUGPRINT1(_L("CStartSafe: Ordinal Lookup Error\n Expected Function prototype: RestartSystem()"));
       
   793 			User::Leave(KErrBadLibraryEntryPoint);
       
   794 			}
       
   795 		User::LeaveIfError(restartSys());	// restart the system
       
   796 		}
       
   797 
       
   798 	User::After(KStartSafeRestartTimeout);
       
   799 	User::Leave(KErrAbort);
       
   800 	}
       
   801 #endif	//SYMBIAN_SSM_GRACEFUL_SHUTDOWN
       
   802