sysstatemgmt/systemstatemgr/ss/src/rvobserver.cpp
changeset 0 4e1aa6a622a0
child 76 cb32bcc88bad
equal deleted inserted replaced
-1:000000000000 0:4e1aa6a622a0
       
     1 // Copyright (c) 2007-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 "rvobserver.h"
       
    17 #include <ssm/ssmstartupproperties.h>
       
    18 #include <ssm/ssmcmd.hrh>
       
    19 #include "timeoutwaiter.h"
       
    20 #include "rvobservernotification.h"
       
    21 #include "ssconst.h"
       
    22 #include "ssmdebug.h"
       
    23 	
       
    24 /**
       
    25  We are either starting for the first time, or an app or process has rendezvouzed.
       
    26  If the latter, check if it has done so without error and behave as appropriate.
       
    27 */
       
    28 void CRvObserver::RunL()
       
    29 	{
       
    30 	switch( iObserverState )
       
    31 		{
       
    32 		case ERvObserverStateNotInvoked:
       
    33 			{
       
    34 			iObserverState = ERvObserverStateAwaitingRv;
       
    35 			InvokeL();
       
    36 			}
       
    37 			break;
       
    38 			
       
    39 		case ERvObserverStateAwaitingRv:
       
    40 			{
       
    41 			NotifyOrRetryL();
       
    42 			}
       
    43 			break;
       
    44 			
       
    45 		default:
       
    46 			User::Leave( KErrUnknown );
       
    47 			break;
       
    48 		}
       
    49 	}
       
    50 
       
    51 
       
    52 
       
    53 /**
       
    54  Leaves here occur in the context of RunL, therefore error notification is performed via RunError()
       
    55  */
       
    56 void CRvObserver::InvokeL()
       
    57 	{
       
    58 	switch( iStartupProperties->CommandType() )
       
    59 		{
       
    60 		case ESsmCmdStartApp:
       
    61 			{
       
    62 			if( !iApaStarter )
       
    63 				{
       
    64 				User::Leave( KErrNotSupported );
       
    65 				}
       
    66 			SetActive();
       
    67 			
       
    68 			TRAPD( err, iApaStarter->StartAppL( iStartupProperties->FileName(), 
       
    69 									iStartupProperties->Args(), 
       
    70 									iStartupProperties->Viewless(), 
       
    71 									iStartupProperties->StartInBackground(), iThreadId, iStatus );
       
    72 				);
       
    73 			
       
    74 			if( KErrNone != err )
       
    75 				{
       
    76 				// In the case of error here, we know that Apparc has not called Rendezvous()
       
    77 				TRequestStatus* trs = &iStatus;
       
    78 				User::RequestComplete( trs, err );
       
    79 				}
       
    80 			
       
    81 			}
       
    82 			break;
       
    83 		
       
    84 		case ESsmCmdStartProcess:
       
    85 			{
       
    86 			SetActive(); 
       
    87 			
       
    88 			TInt err = iProcess.Create( iStartupProperties->FileName(), iStartupProperties->Args() );
       
    89 			
       
    90 			if( KErrNone != err )
       
    91 				{
       
    92 				// In case of error here, copmplete self with err.
       
    93 				TRequestStatus* trs = &iStatus;
       
    94 				User::RequestComplete( trs, err );
       
    95 				
       
    96 				return;
       
    97 				}	
       
    98 			
       
    99 			iProcess.Rendezvous( iStatus );
       
   100 			// Rendezvous() can complete with KErrNoMemory, hence:-
       
   101 			if( iStatus == KRequestPending )
       
   102 				{
       
   103 				iProcess.Resume();
       
   104 				}
       
   105 		
       
   106 			}
       
   107 			break;
       
   108 	
       
   109 		default:
       
   110 			User::Leave( KErrArgument );
       
   111 		}
       
   112 	
       
   113 	
       
   114 	if( iTimeoutWaiter && !iTimeoutWaiter->IsActive())
       
   115 		{
       
   116 		iTimeoutWaiter->ActuateTimer();
       
   117 		}
       
   118 	}
       
   119 
       
   120 
       
   121 
       
   122 /**
       
   123  Calls here are only relevant in the case of StartApp.
       
   124 */
       
   125 TInt CRvObserver::GetProcessHandle( RProcess& aProcess, const TThreadId& aThreadId )
       
   126 	{
       
   127 	TInt err = KErrNone;
       
   128 	if( ESsmCmdStartApp == iStartupProperties->CommandType() )
       
   129 		{
       
   130 		RThread thread;
       
   131 		err = thread.Open(aThreadId);
       
   132 		if( KErrNone == err )
       
   133 			{
       
   134 			err = thread.Process(aProcess);
       
   135 			}
       
   136 		thread.Close();
       
   137 		}
       
   138 	return err;
       
   139 	}
       
   140 
       
   141 /**
       
   142  Leaves here occur in the context of RunL, therefore error notification is performed via RunError()
       
   143 */
       
   144 void CRvObserver::NotifyOrRetryL()
       
   145 	{
       
   146 	if( GoodStart() )
       
   147 		{
       
   148 		// Rendezvous succeeded. If ESsmCmdStartApp, the process handle has been supplied in GoodStart
       
   149 		iStarter.NotifyCompletion( iStatus.Int() );
       
   150 		}
       
   151 	else
       
   152 		{
       
   153 		//Launches the application if it is not timedout or retries if not exhausted.
       
   154 		--iRetries; 
       
   155 		if( iRetries < 0 || ( iRetries < 0 && iTimeOut ) )
       
   156 			{
       
   157 			iTimeOut = EFalse;
       
   158 			// We have not succeeded and retries, if any, have been exhausted.
       
   159 			iStarter.NotifyCompletion( iStatus.Int() );
       
   160 			}
       
   161 		else
       
   162 			{
       
   163 			InvokeL();
       
   164 			}
       
   165 		}
       
   166 	}
       
   167 
       
   168 
       
   169 
       
   170 /**
       
   171  Has the process rv'd with an error? If so terminate it.
       
   172  Has the process been panicked with KErrNone? If so translate that error to KErrGeneral;
       
   173  If the process has panicked or been killed, the Exit reason should be conveyed via iStatus.
       
   174  Any leave here occurs in the context of RunL, therefore any such notifications are performed via RunError().
       
   175  An error code of KErrAlreadyExists is presumed to imply that an attempt has been made to start a 
       
   176  pre-existing server. This is translated to KErrNone which allows CSsmStartSafe::StartAndMonitorL()
       
   177  to apply monitoring to the running server.
       
   178 */
       
   179 TBool CRvObserver::GoodStart()
       
   180 	{
       
   181 	TBool goodStart( ETrue );
       
   182 	TInt err = KErrNone;
       
   183 	if(iStatus == KErrAlreadyExists && iStartupProperties->IsMonitoringRequired())
       
   184 		{
       
   185 		// This is done only when trying to start an already running server(process), as when we try to start an application 
       
   186 		// which is already running, it doesn't return KErrAlreadyExists.  It would be started as another instance of same application.
       
   187 		TFullName searchTerm(iStartupProperties->FileName());
       
   188 		_LIT(KSearchAny, "*");
       
   189 		searchTerm += KSearchAny;
       
   190  	    TFindProcess find(searchTerm);
       
   191 		TFullName name;
       
   192 		err = find.Next(name);
       
   193 		if(err == KErrNone)
       
   194 			{
       
   195 			err = iProcess.Open(find);
       
   196 			DEBUGPRINT2A("Tried to Open process which is already running with %d", err);
       
   197 			}
       
   198 		}
       
   199 	// In the case of pre-existing servers.
       
   200 	iStatus = ( iStatus == KErrAlreadyExists ) ? KErrNone : iStatus.Int(); 
       
   201 
       
   202 	// In the case of StartApp
       
   203 	err = GetProcessHandle( iProcess, iThreadId );
       
   204 
       
   205 	if( iStatus.Int() != KErrNone || err != KErrNone )
       
   206 		{
       
   207 		goodStart = EFalse;
       
   208 		if(KErrNone == err && iProcess.Handle() && (EExitPending == iProcess.ExitType()))
       
   209 			{
       
   210 			iProcess.Terminate( iStatus.Int() );
       
   211 			iProcess.Close();
       
   212 			}
       
   213 		}	
       
   214 	else if(err == KErrNone &&  iProcess.Handle() && (EExitPanic == iProcess.ExitType()))
       
   215 		{
       
   216 		goodStart = EFalse;
       
   217 		//We can't use the 'exit reason' if the process has panicked as this is the 
       
   218 		//panic 'reason' and may be '0' which cannot be distinguished from KErrNone
       
   219 		iStatus = KErrGeneral;
       
   220 		}
       
   221 	
       
   222 	return goodStart;
       
   223 	}
       
   224 
       
   225 
       
   226 
       
   227 void CRvObserver::DoCancel()
       
   228 	{
       
   229 	if( iTimeoutWaiter )
       
   230 		{
       
   231 		iTimeoutWaiter->Cancel();
       
   232 		}
       
   233 	// Relevant if StartApp
       
   234 	TInt err = GetProcessHandle(iProcess, iThreadId); 
       
   235 	if( KErrNone == err )
       
   236 		{
       
   237 		err = iProcess.RendezvousCancel( iStatus );
       
   238 		}
       
   239 	
       
   240 	// Docs say iStatus should be completed with KErrCancel, but I am observing KErrNone, therefore:-
       
   241 	TInt factoredCompletionCode = ( KErrNone == err ) ? KErrCancel : err ;
       
   242 	iStarter.NotifyCancellation( factoredCompletionCode );
       
   243 	}
       
   244 
       
   245 
       
   246 
       
   247 TInt CRvObserver::RunError( TInt aError )
       
   248 	{
       
   249 	DEBUGPRINT2A("CRvObserver::RunError called with error %d", aError);
       
   250 	iStarter.NotifyCompletion( aError );
       
   251 	return KErrNone;
       
   252 	}
       
   253 
       
   254 
       
   255 
       
   256 void CRvObserver::RvAndObserveL( CSsmStartupProperties* aStartupProperties )
       
   257 	{
       
   258 	// Are we already running?
       
   259 	if( ERvObserverStateNotInvoked != iObserverState )
       
   260 		{
       
   261 		User::Leave( KErrInUse );
       
   262 		}
       
   263 	
       
   264 	if( (ESsmCmdStartApp == aStartupProperties->CommandType()) && !iApaStarter  )
       
   265 		{
       
   266 		User::Leave( KErrNotSupported );
       
   267 		}
       
   268 	
       
   269 	iStartupProperties = aStartupProperties;
       
   270 	iRetries = iStartupProperties->Retries();
       
   271 	
       
   272 	// If timeout is zero (or negative), we will wait indefinitely.
       
   273 	if( iStartupProperties->Timeout() > KSsmStartSafeNoTimeout )
       
   274 		{
       
   275 		iTimeoutWaiter = CTimeoutWaiter::NewL( iStartupProperties->Timeout(), *this );
       
   276 		}
       
   277 	
       
   278 	SetActive();
       
   279 	TRequestStatus* trs = &iStatus;
       
   280 	User::RequestComplete( trs, KErrNone );
       
   281 	}
       
   282 
       
   283 
       
   284 
       
   285 /**
       
   286  From MTimeoutWaiterNotification
       
   287 */
       
   288 void CRvObserver::NotifyTimeout()
       
   289 	{
       
   290 	// Relevant if StartApp
       
   291 	TInt err = GetProcessHandle(iProcess, iThreadId); 
       
   292 	if( KErrNone == err )
       
   293 		{
       
   294 		// No more retries would be done
       
   295 		iProcess.Terminate( KErrTimedOut ); 
       
   296 		iTimeOut = ETrue;
       
   297 		}
       
   298 	}
       
   299 
       
   300 
       
   301 
       
   302 CRvObserver* CRvObserver::NewL( RProcess& aProcess, MRvObserverNotification& aObserved, CApaStarter* aApaStarter )
       
   303 	{
       
   304 	CRvObserver* self = NewLC( aProcess, aObserved, aApaStarter );
       
   305 	CleanupStack::Pop();
       
   306 	return self;
       
   307 	}
       
   308 
       
   309 
       
   310 
       
   311 CRvObserver* CRvObserver::NewLC( RProcess& aProcess, MRvObserverNotification& aObserved, CApaStarter* aApaStarter )
       
   312 	{
       
   313 	CRvObserver* self = new(ELeave) CRvObserver( aProcess, aObserved, aApaStarter );
       
   314 	CleanupStack::PushL( self );
       
   315 	self->ConstructL();
       
   316 	return self;
       
   317 	}
       
   318 
       
   319 
       
   320 
       
   321 CRvObserver::~CRvObserver()
       
   322 	{
       
   323 	Cancel();
       
   324 	delete iTimeoutWaiter;
       
   325 	}
       
   326 
       
   327 
       
   328 
       
   329 CRvObserver::CRvObserver( RProcess& aProcess, MRvObserverNotification& aObserved, CApaStarter* aApaStarter )
       
   330 : CActive( EPriorityStandard ), 
       
   331   iApaStarter( aApaStarter ),
       
   332   iStarter( aObserved ), 
       
   333   iThreadId( KSsmStartSafeNullThreadId ),
       
   334   iProcess( aProcess ),
       
   335   iTimeOut(EFalse)
       
   336 	{
       
   337 	CActiveScheduler::Add( this );
       
   338 	}
       
   339 
       
   340 
       
   341 
       
   342 void CRvObserver::ConstructL()
       
   343 	{
       
   344 	}
       
   345