--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sysstatemgmt/systemstatemgr/ss/src/ssmstartsafe.cpp Tue Feb 02 00:53:00 2010 +0200
@@ -0,0 +1,443 @@
+// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+
+#include <ssm/ssmstartsafe.h>
+
+#include <ssm/ssmstartupproperties.h>
+#include "startandretry.h"
+#include "rvobserver.h"
+#include "fireandforget.h"
+#include "activewaiter.h"
+#include <ssm/ssmcmd.hrh>
+#include <ssm/ssmloadsysmon.h>
+#include <apastarter.h>
+
+_LIT(KApStartDLL, "apstart.dll");
+_LIT( KSysMonProxyDLL, "loadsysmon.dll" );
+typedef CApaStarter* (*TFuncNewL)( void );
+typedef MSsmLoadSysMon* (*TFuncCreateL)( void );
+
+
+
+/**
+Used to start a process or application and initiate monitoring.
+Use this for ESsmWaitForSignal or ESsmDeferredWaitForSignal.
+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 Handle on the process to be created.
+@leave KErrArgument if the monitor flag is not set in aStartupProperties, or if the execution behaviour is ESsmFireandForget.
+@leave KErrNotSupported if the system monitor sub-system is not installed.
+@leave Another of the system-wide error codes @see StartL
+
+@internalTechnology
+@released
+*/
+EXPORT_C void CSsmStartSafe::StartAndMonitorL( const CSsmStartupProperties& aStartupProperties, RProcess& aProcess )
+ {
+
+ if( !aStartupProperties.IsMonitoringRequired() )
+ {
+ User::Leave( KErrArgument );
+ }
+
+ if( !iSysMonCli )
+ {
+ User::Leave( KErrNotSupported );
+ }
+
+ StartL( aStartupProperties, aProcess );
+
+ // Monitor the process only if the behavior is not EFireAndForget
+ // The monitor for process/app with EFireAndForget behavior is started only after the process/app is started
+ // Hence the monitor is started in the CFireAndForget object
+ if (ESsmFireAndForget != aStartupProperties.ExecutionBehaviour())
+ {
+ iSysMonCli->OpenL();
+ TRAPD( err, iSysMonCli->MonitorL( aStartupProperties, aProcess ) );
+ iSysMonCli->Close();
+ if( KErrNone != err )
+ {
+ aProcess.Terminate( err );
+ User::Leave( err );
+ }
+ }
+
+ }
+
+
+
+/**
+ Synchronous function to start a process or application.
+ Note: This API should be used only if one synchronous call to StartL at any one time can be assured.
+
+@param aStartupProperties Startup properties provided by the caller.
+@param aProcess Handle on the process to be created.
+@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 Or one of the system-wide error codes
+@internalTechnology
+@released
+*/
+EXPORT_C void CSsmStartSafe::StartL( const CSsmStartupProperties &aStartupProperties, RProcess& aProcess )
+ {
+ // The index is not required as a parameter because this function is synchronous and must only be used consecutively.
+ TInt callerIndex = 0;
+ CActiveWaiter* waiter = new(ELeave) CActiveWaiter;
+ CleanupStack::PushL( waiter );
+
+ Start( aStartupProperties, aProcess, waiter->iStatus, callerIndex );
+ waiter->WaitActive();
+
+ User::LeaveIfError(waiter->iStatus.Int());
+
+ CleanupStack::PopAndDestroy( waiter );
+ }
+
+
+
+/**
+ Asynchronous function to start a process or application.
+
+@param aStartupProperties The startup-properties defining the app or process to be started.
+@param aProcess Handle on the process to be created.
+@param aCommandTrs The TRequestStatus which is completed as a result of the process rendezvous or any error arising from the attempt.
+@param aCallerIndex The index integer supplied by this call. This value should be perserved and passed in the case of a call to StartCancel()
+@internalTechnology
+@released
+*/
+EXPORT_C void CSsmStartSafe::Start( const CSsmStartupProperties& aStartupProperties, RProcess& aProcess, TRequestStatus& aCommandTrs, TInt& aCallerIndex )
+ {
+
+ aCommandTrs = KRequestPending;
+
+ if (ESsmFireAndForget == aStartupProperties.ExecutionBehaviour())
+ {
+ TRequestStatus* status = &aCommandTrs;
+
+ CFireAndForget* fireAndForget = NULL;
+ // F&F destroys itself.
+ TRAPD(err,fireAndForget = CFireAndForget::NewL(aStartupProperties));
+
+ if(KErrNone == err)
+ {
+ fireAndForget->FireD();
+ }
+ User::RequestComplete(status, err);
+ }
+ else
+ {
+ TInt err = RegisterCall( aCallerIndex, aCommandTrs );
+
+ if (err != KErrNone)
+ {
+ aCallerIndex = KErrNotFound;
+ TRequestStatus* status = &aCommandTrs;
+ User::RequestComplete( status, err );
+ return;
+ }
+
+ TRAP( err, iStartSafeEntryArray[ aCallerIndex ].iStartAndRetry = CStartAndRetry::NewL( *this, aStartupProperties, aProcess, aCallerIndex, iApaStarter ));
+ if (err != KErrNone)
+ {
+ DeRegisterCall( aCallerIndex ); //should complete the request with KErrCancel
+ return;
+ }
+ iStartSafeEntryArray[ aCallerIndex ].iStartAndRetry->Actuate();
+ }
+ }
+
+/**
+Waits for AppArc Server to initialise.
+@return KErrNotSupported if AppArc is not installed
+@return TInt system error code
+@internalTechnology
+@released
+*/
+EXPORT_C TInt CSsmStartSafe::InitAppArcServer()
+ {
+
+ // Guard against the case of no Apparc.
+ if( !iApaStarter )
+ {
+ return KErrNotSupported;
+ }
+
+ TRAPD( err, iApaStarter->WaitForApparcToInitialiseL() );
+
+ return err;
+ }
+
+/**
+Async call to wait for Apparc Server to initialise.
+@param aCommandTrs The TRequestStatus which is completed when applist is populated.
+@internalTechnology
+@released
+*/
+EXPORT_C void CSsmStartSafe::InitApparcServer(TRequestStatus& aStatus)
+ {
+ aStatus = KRequestPending;
+ // Guard against the case of no Apparc.
+ if( !iApaStarter )
+ {
+ TRequestStatus* status = &aStatus;
+ User::RequestComplete(status, KErrNotSupported);
+ return;
+ }
+
+ iApaStarter->InitApparcServer(aStatus);
+ }
+
+/**
+Cancel Apparc Server initialization.
+@internalTechnology
+@released
+*/
+EXPORT_C void CSsmStartSafe::InitApparcServerCancel()
+ {
+ if (iApaStarter)
+ {
+ iApaStarter->InitApparcServerCancel();
+ }
+ }
+
+/**
+ Calling cancel precipitates the destruction of the rendezvous-observer/timeoutwaiter.
+ These are AOs and so cancellation of any outstanding rendezvous is implied.
+ @param aCallerIndex the index value supplied by the async CSsmStartSafe::StartL(). This is set to a large negative value upon completion
+ of the operation to guard against multiple calls, or KErrArgument if the index is out of range.
+*/
+EXPORT_C void CSsmStartSafe::StartCancel( TInt& aCallerIndex )
+ {
+
+ const TInt KSsNegValue = -9999;
+
+ if( KErrNone != DeRegisterCall(aCallerIndex) )
+ {
+ aCallerIndex = KErrArgument;
+ }
+ else
+ {
+ aCallerIndex = KSsNegValue;
+ }
+
+ }
+
+/**
+ Inherited from MStartAndRetryNotifications
+*/
+void CSsmStartSafe::RendezvousComplete( TInt aComplete, TInt aCallerIndex )
+ {
+
+ User::RequestComplete( iStartSafeEntryArray[ aCallerIndex ].iCallerTrs, aComplete );
+
+ DeRegisterCall( aCallerIndex );
+ }
+
+
+
+void CSsmStartSafe::CancellationComplete( TInt aComplete, TInt aCallerIndex )
+ {
+ User::RequestComplete( iStartSafeEntryArray[ aCallerIndex ].iCallerTrs, aComplete );
+ }
+
+
+
+/**
+ Add the caller to the array of callers. Supply an index which identifies the caller.
+ In the case a call to one of the cancel functions, the caller identifies themselves
+ by this index.
+*/
+TInt CSsmStartSafe::RegisterCall( TInt& aCallerIndex, TRequestStatus& aStatus )
+ {
+ const TInt count = iStartSafeEntryArray.Count();
+ TBool slotFound = EFalse;
+ for(TInt i = 0; i < count; i++ )
+ {
+ if( !iStartSafeEntryArray[ i ].iInUse )
+ {
+ iStartSafeEntryArray[ i ].iInUse = ETrue;
+ iStartSafeEntryArray[ i ].iStartAndRetry = NULL;
+ iStartSafeEntryArray[ i ].iCallerTrs = &aStatus;
+ iStartSafeEntryArray[ i ].iCallerIndex = aCallerIndex;
+ aCallerIndex = i;
+ slotFound = ETrue;
+ iCallerCount++;
+ break;
+ }
+ }
+ TInt err = KErrNone;
+ if( !slotFound )
+ {
+ TSsmStartSafeEntry entry;
+ entry.iStartAndRetry = NULL;
+ entry.iCallerTrs = &aStatus;
+ entry.iInUse = ETrue;
+ err = iStartSafeEntryArray.Append( entry );
+ if( KErrNone == err )
+ {
+ aCallerIndex = iCallerCount++;
+ }
+ }
+ return err;
+ }
+
+
+
+TInt CSsmStartSafe::DeRegisterCall(TInt aCallerIndex )
+ {
+ if( !__IN_RANGE(aCallerIndex, iStartSafeEntryArray.Count()) )
+ {
+ return KErrArgument;
+ }
+
+ if( iStartSafeEntryArray[ aCallerIndex ].iInUse )
+ {
+ delete iStartSafeEntryArray[ aCallerIndex ].iStartAndRetry;
+ iStartSafeEntryArray[ aCallerIndex ].iStartAndRetry = NULL;
+ iStartSafeEntryArray[ aCallerIndex ].iInUse = EFalse;
+
+ // In case of call from destructor. Actually, the other classes look after themselves
+ // so this conditional shouldn't evaluate to true.
+ TRequestStatus* trs = iStartSafeEntryArray[ aCallerIndex ].iCallerTrs;
+
+ if( trs && (*trs == KRequestPending) )
+ {
+ User::RequestComplete( iStartSafeEntryArray[ aCallerIndex ].iCallerTrs, KErrCancel );
+ }
+
+ iCallerCount--;
+
+ // Remove unused elements at the end of the array, so iStartSafeEntryArray can be (granular)shrunk
+ const TInt count = iStartSafeEntryArray.Count();
+ TBool slotRemoved = EFalse;
+ for(TInt i = count-1; i >= 0 ; i-- )
+ {
+ if( !iStartSafeEntryArray[ i ].iInUse )
+ {
+ iStartSafeEntryArray.Remove(i);
+ slotRemoved = ETrue;
+ }
+ else
+ {
+ break;
+ }
+ }
+ if (slotRemoved)
+ {
+ iStartSafeEntryArray.GranularCompress();
+ }
+ }
+
+ return KErrNone;
+ }
+
+
+
+/**
+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 not closely specified in RLibrary docs or code.
+*/
+void CSsmStartSafe::LoadApStartLibL()
+ {
+ if( KErrNone != iApStartLib.Load(KApStartDLL) )
+ {
+ return;
+ }
+
+ TFuncNewL apStartNewL = reinterpret_cast<TFuncNewL>( iApStartLib.Lookup(1) );
+ iApaStarter = apStartNewL();
+ }
+
+
+
+/**
+ Load the dll interfacing between us and the System Monitor component, if installed.
+*/
+void CSsmStartSafe::LoadMonitorProxyLibL()
+ {
+ if( KErrNone != iSysMonProxyLib.Load(KSysMonProxyDLL) )
+ {
+ return;
+ }
+
+ TFuncCreateL sysMonProxyCreateL = reinterpret_cast<TFuncCreateL>( iSysMonProxyLib.Lookup(1) );
+ iSysMonCli = sysMonProxyCreateL();
+ }
+
+
+
+/**
+Used to create an instance of CSsmStartSafe class
+@return A pointer to an instance of CSsmStartSafe
+@internalTechnology
+@released
+*/
+EXPORT_C CSsmStartSafe* CSsmStartSafe::NewL()
+ {
+ CSsmStartSafe* self = NewLC();
+ CleanupStack::Pop( self );
+
+ return self;
+ }
+
+
+
+EXPORT_C CSsmStartSafe* CSsmStartSafe::NewLC()
+ {
+ CSsmStartSafe* self = new(ELeave) CSsmStartSafe();
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ return self;
+ }
+
+
+
+CSsmStartSafe::CSsmStartSafe()
+ {
+ }
+
+
+
+void CSsmStartSafe::ConstructL()
+ {
+ LoadApStartLibL();
+ LoadMonitorProxyLibL();
+ }
+
+
+
+CSsmStartSafe::~CSsmStartSafe()
+ {
+ const TInt count = iStartSafeEntryArray.Count();
+ for(TInt i = 0; i < count; i++ )
+ {
+ DeRegisterCall( i );
+ }
+
+ delete iApaStarter;
+ delete iSysMonCli;
+ iStartSafeEntryArray.Close();
+ iApStartLib.Close();
+ iSysMonProxyLib.Close();
+ }
+