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