--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sysstatemgmt/systemstatemgr/cmd/src/cmdcustomcommand.cpp Tue Feb 02 00:53:00 2010 +0200
@@ -0,0 +1,562 @@
+// Copyright (c) 2008-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/ssmcustomcommand.h>
+#include <ssm/ssmcustomcommandinfo.h>
+#include <f32file.h>
+#include <s32file.h>
+
+#include "cmdcustomcommand.h"
+#include "ssmcommandparameters.h"
+#include "ssmcommandutilprovider.h"
+
+#include "ssmdebug.h"
+#include "ssmpanic.h"
+
+// This file is used to store the handles of the libraries which has unload option as ENeverUnload.
+// This is also defined in the CleSrv and these handles are used to release those libraries from
+// CleSrv destrcutor.
+_LIT(KNeverUnloadLibHandleFile, ":\\private\\2000d75b\\temp\\unloadlibhandles.bin");
+
+/**
+Used to create an instance of CCmdCustomCommand class from a read stream.
+CSsmCommandList::InternalizeL() uses this method to construct a command from stream.
+
+@param aReadStream Read stream containing data through which object can be created
+@return A pointer to an object of type CCmdCustomCommand.
+*/
+CCmdCustomCommand* CCmdCustomCommand::NewL(RReadStream& aReadStream)
+ {
+ CCmdCustomCommand* self = new (ELeave) CCmdCustomCommand();
+ CleanupStack::PushL(self);
+ self->ConstructL(aReadStream);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+/**
+Used to create an instance of CCmdCustomCommand class from given parameters.
+This method is used by SsmCommandFactory to create a command.
+
+@param aSeverity The severity of the command
+@param aExecutionBehaviour Execution behaviour of this command
+@param aInfo CustomCommand-specific info
+@param aPriority The priority of the command in the list
+@return A pointer to an object of type CCmdCustomCommand.
+*/
+CCmdCustomCommand* CCmdCustomCommand::NewL(TCmdErrorSeverity aSeverity, TSsmExecutionBehaviour aExecutionBehaviour,
+ const CSsmCustomCommandInfo& aInfo, const TUint16 aPriority)
+ {
+ CCmdCustomCommand* self = new (ELeave) CCmdCustomCommand(aSeverity, aExecutionBehaviour, aPriority);
+ CleanupStack::PushL(self);
+ self->ConstructL(aInfo);
+ CleanupStack::Pop(self);
+ return self;
+ }
+#endif
+
+/**
+Used to create an instance of CCmdCustomCommand class from given parameters.
+This method is used by SsmCommandFactory to create a command.
+
+@param aSeverity The severity of the command
+@param aExecutionBehaviour Execution behaviour of this command
+@param aInfo CustomCommand-specific info
+@return A pointer to an object of type CCmdCustomCommand.
+*/
+CCmdCustomCommand* CCmdCustomCommand::NewL(TCmdErrorSeverity aSeverity, TSsmExecutionBehaviour aExecutionBehaviour, const CSsmCustomCommandInfo& aInfo)
+ {
+ CCmdCustomCommand* self = new (ELeave) CCmdCustomCommand(aSeverity, aExecutionBehaviour);
+ CleanupStack::PushL(self);
+ self->ConstructL(aInfo);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+/**
+Used to create an instance of CCmdCustomCommand class from resource.
+
+@param aCommandParameters Object data from a resource file
+@return A pointer to an object of type CCmdCustomCommand.
+*/
+CCmdCustomCommand* CCmdCustomCommand::NewL(TSsmCommandParameters& aCommandParameters)
+ {
+ CCmdCustomCommand* self = new (ELeave) CCmdCustomCommand();
+ CleanupStack::PushL(self);
+ self->ConstructL(aCommandParameters);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+/**
+Used to create an instance of CCmdCustomCommand class from CCmdCustomCommand object
+Must be used only by CLE
+@param aCmdCustomCommand CCmdCustomCommand reference
+@param aUtilProvider CSsmCommandUtilProvider reference
+@return A pointer to an object of type CCmdCustomCommand.
+*/
+CCmdCustomCommand* CCmdCustomCommand::NewLC(const CCmdCustomCommand& aCmdCustomCommand, CSsmCommandUtilProvider* aUtilProvider)
+ {
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+ CCmdCustomCommand* self = new (ELeave) CCmdCustomCommand(aCmdCustomCommand.Severity(),aCmdCustomCommand.ExecutionBehaviour(),
+ aCmdCustomCommand.Priority());
+#else
+ CCmdCustomCommand* self = new (ELeave) CCmdCustomCommand(aCmdCustomCommand.Severity(),aCmdCustomCommand.ExecutionBehaviour());
+#endif
+ CleanupStack::PushL(self);
+ self->ConstructL(aCmdCustomCommand, aUtilProvider);
+ return self;
+ }
+
+void CCmdCustomCommand::ConstructL(const CCmdCustomCommand& aCmdCustomCommand, CSsmCommandUtilProvider* aUtilProvider)
+ {
+ iConditionalResourceId = aCmdCustomCommand.ConditionalInformation();
+ SetUtilProvider(*aUtilProvider);
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+ if (iConditionalResourceId != 0)
+ {
+ SetCommandResourceFileNameL(aCmdCustomCommand.GetCommandResourceFileName());
+ }
+#endif
+ iInfo = new (ELeave) CSsmCustomCommandInfo();
+ (*iInfo) = aCmdCustomCommand.SsmCustomCommandInfo();
+ }
+
+/**
+Destructor
+*/
+CCmdCustomCommand::~CCmdCustomCommand()
+ {
+ Cancel();
+
+ if (iCustomCommand) // we requested it so we are responsible for deleting it
+ {
+ iCustomCommand->Release();
+ }
+
+ if (iInfo)
+ {
+ // release the DLL if instructed, DLL's with ENeverUnload option needs unloading atleast when the server dies.
+ if (iInfo->Unloading() == EUnloadOnCommandCompletion)
+ {
+ iLibrary.Close();
+ }
+
+ delete iInfo;
+ }
+ if(iCmdEnv)
+ {
+ delete iCmdEnv;
+ }
+ }
+
+/**
+Initialises the BIC's active object and initiates the command
+
+@param aStatus the TRequestStatus of the active object calling this BIC
+*/
+void CCmdCustomCommand::Execute(TRequestStatus& aStatus)
+ {
+ aStatus = KRequestPending;
+ iExecuteRequest = &aStatus;
+ iAction = EPrepareDll;
+
+ if (iExecutionBehaviour != ESsmWaitForSignal)
+ {
+ CompleteExecuteRequest(KErrNone);
+ }
+
+ CompleteRequest(iStatus, KErrNone);
+ SetActive();
+ }
+
+/**
+Releases resources associated with this BIC
+*/
+void CCmdCustomCommand::Release()
+ {
+ delete this;
+ }
+
+/**
+Initiates a Cancel on the object.
+*/
+void CCmdCustomCommand::ExecuteCancel()
+ {
+ Cancel();
+ CompleteDeferredExecuteRequest(KErrCancel);
+ }
+
+/**
+Returns the type of the BIC
+
+@return The type of the BIC
+*/
+TSsmCommandType CCmdCustomCommand::Type() const
+ {
+ return (ESsmCmdCustomCommand);
+ }
+
+/**
+Returns the Version of the BIC
+
+@return The maximum supported version of the BIC
+*/
+TInt CCmdCustomCommand::MaxSupportedVersion()
+ {
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+ return (static_cast<TInt>(ECmdCustomCommandVersionWithPriority));
+#else
+ return (static_cast<TInt>(ECmdCustomCommandInitialVersion));
+#endif
+ }
+
+/**
+Configures the BIC using data contained in a ReadStream
+
+@param aReadStream A read stream containing BIC data
+*/
+void CCmdCustomCommand::InternalizeL(RReadStream& aReadStream)
+ {
+ iSeverity = static_cast<TCmdErrorSeverity>(aReadStream.ReadInt16L());
+ iExecutionBehaviour = static_cast<TSsmExecutionBehaviour>(aReadStream.ReadUint8L());
+
+ iInfo = new (ELeave) CSsmCustomCommandInfo();
+ iInfo->InternalizeL(aReadStream);
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+ iPriority = aReadStream.ReadUint16L();
+#endif
+ }
+
+/**
+Externalises the configuration of the BIC
+
+@param aWriteStream A write stream to write BIC data to
+@leave One of the system-wide error codes.
+*/
+void CCmdCustomCommand::ExternalizeL(RWriteStream& aWriteStream) const
+ {
+ aWriteStream.WriteInt16L(iSeverity);
+ aWriteStream.WriteUint8L(iExecutionBehaviour);
+ iInfo->ExternalizeL(aWriteStream);
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+ aWriteStream.WriteUint16L(iPriority);
+#endif
+ }
+
+/**
+Performs the tasks of the BIC
+
+@leave One of the system-wide error codes.
+*/
+void CCmdCustomCommand::RunL()
+ {
+ switch(iAction)
+ {
+ case EPrepareDll:
+ {
+ PrepareCustomCmdL();
+ break;
+ }
+ case EInitialiseDll:
+ {
+ InitialiseCmdL();
+ break;
+ }
+ case EExecuteMethod:
+ {
+ SSMLOGLEAVEIFNULL(iCustomCommand);
+ iCustomCommand->Execute(iInfo->Params(), iStatus);
+ MoveToNextStateL(KErrNone, EClose, EFalse); // custom command will complete this request
+ break;
+ }
+ case EClose:
+ {
+ TInt err = iStatus.Int();
+ if (err != KErrNone)
+ {
+ // custom cmd call failed so try it again
+ MoveToNextStateL(err, EExecuteMethod);
+ }
+ else
+ {
+ SSMLOGLEAVEIFNULL(iCustomCommand);
+ iCustomCommand->Close();
+ CompleteDeferredExecuteRequest(KErrNone); // success
+ }
+ break;
+ }
+ default:
+ {
+ PanicNow(KPanicCmdCustomCommand, EInvalidRunLAction);
+ break;
+ }
+ };
+ }
+
+/**
+Called to handle any cleanup if RunL leaves
+
+@param aError The error to finish with
+@return KErrNone
+*/
+TInt CCmdCustomCommand::RunError(TInt aError)
+ {
+ CompleteDeferredExecuteRequest(aError);
+ return KErrNone;
+ }
+
+/**
+Called during cancellation of the active BIC
+*/
+void CCmdCustomCommand::DoCancel()
+ {
+ if (iCustomCommand) // only cancel if Execute has been called
+ {
+ iCustomCommand->ExecuteCancel();
+ }
+ }
+
+/**
+ Default Constructor.
+ */
+CCmdCustomCommand::CCmdCustomCommand()
+ {
+ }
+
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+/**
+ Overloaded constructor.
+ @param aSeverity The severity of the command
+ @param aExecutionBehaviour The execution behaviour of the command
+ @param aPriority The priority of the command in the list
+ */
+CCmdCustomCommand::CCmdCustomCommand(TCmdErrorSeverity aSeverity, TSsmExecutionBehaviour aExecutionBehaviour,const TUint16 aPriority)
+ : CSsmDeferrableCommand(aSeverity, aExecutionBehaviour, aPriority)
+ {
+ }
+#endif
+
+/**
+ Overloaded constructor.
+ @param aSeverity The severity of the command
+ @param aExecutionBehaviour The execution behaviour of the command
+ */
+CCmdCustomCommand::CCmdCustomCommand(TCmdErrorSeverity aSeverity, TSsmExecutionBehaviour aExecutionBehaviour)
+ : CSsmDeferrableCommand(aSeverity, aExecutionBehaviour)
+ {
+ }
+
+/**
+ Constructs the object from custom command info.
+ @param aInfo A custom command info object containing BIC data
+*/
+void CCmdCustomCommand::ConstructL(const CSsmCustomCommandInfo& aInfo)
+ {
+ iInfo = new (ELeave) CSsmCustomCommandInfo();
+ (*iInfo) = aInfo;
+ ValidateL();
+ }
+
+/**
+ Constructs the object through read stream.
+ @param aReadStream A read stream containing BIC data
+*/
+void CCmdCustomCommand::ConstructL(RReadStream& aReadStream)
+ {
+ InternalizeL(aReadStream);
+ ValidateL();
+ }
+
+/**
+ Constructs an object from resource file.
+ @param aCommandParameters Object data from a resource file
+*/
+void CCmdCustomCommand::ConstructL(TSsmCommandParameters& aCommandParameters)
+ {
+ RResourceReader& reader = aCommandParameters.MainReader();
+ const TSsmCommandType type = static_cast<TSsmCommandType>(reader.ReadInt16L());
+ SSMLOGLEAVEIFFALSE(type == Type(), KErrNotSupported);
+ const TInt version = reader.ReadInt16L();
+ SSMLOGLEAVEIFFALSE(__COMPARE_VERSION(version, CCmdCustomCommand::MaxSupportedVersion()), KErrNotSupported);
+ iSeverity = static_cast<TCmdErrorSeverity>(reader.ReadInt16L());
+ iExecutionBehaviour = static_cast<TSsmExecutionBehaviour>(reader.ReadUint8L());
+ const TPtrC name = reader.ReadTPtrCL();
+ const TInt32 ordinal = reader.ReadInt32L();
+ TCmdCustomCommandLibUnloading unloading = static_cast<TCmdCustomCommandLibUnloading>(reader.ReadUint8L());
+ TInt16 retries = reader.ReadInt16L();
+
+ // read dll data
+ const TInt32 paramDataId = reader.ReadUint32L();
+ HBufC8* params = NULL;
+ if (paramDataId > 0)
+ {
+ params = aCommandParameters.AllocBufferForResourceIdL(paramDataId);
+ }
+ else
+ {
+ params = HBufC8::NewL(0);
+ }
+ CleanupStack::PushL(params);
+
+ iInfo = new (ELeave) CSsmCustomCommandInfo();
+ iInfo->SetL(name, ordinal, unloading, retries, *params);
+
+ ValidateL();
+ CleanupStack::PopAndDestroy(params);
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+ iPriority = (version > ECmdCustomCommandInitialVersion) ? reader.ReadUint16L() : KDefaultCommandPriority;
+#endif
+ }
+
+/**
+ Loads and sets up the custom command dll
+*/
+void CCmdCustomCommand::PrepareCustomCmdL()
+ {
+ TInt err = KErrNone;
+ if (!iLoaded)
+ {
+ // load the dll
+ DEBUGPRINT2(_L("Loading library %S..."), &iInfo->FileName());
+ err = iLibrary.Load(iInfo->FileName());
+ if (err == KErrNone)
+ {
+ iLoaded = ETrue;
+ if(iInfo->Unloading() == ENeverUnload)
+ {
+ //Record the handle into the file.
+ //If it fails to write the handle, ignore it.
+ //We don't want to stop the processing of the command due to this failure.
+ TRAP_IGNORE(WriteHandleToFileL(iLibrary.Handle()));
+ }
+ }
+ }
+
+ if (iLoaded)
+ {
+ err = KErrNotFound;
+
+ // get a pointer to the function
+ DEBUGPRINT2A("Looking up ordinal %d...", iInfo->Ordinal());
+ TLibraryFunction function = iLibrary.Lookup(iInfo->Ordinal());
+ if (function)
+ {
+ // cast the pointer to our custom cmd type
+ CustomCmdFunctionType customCmdFunction = reinterpret_cast<CustomCmdFunctionType>(function);
+ iCustomCommand = (*customCmdFunction)();
+ if (iCustomCommand)
+ {
+ err = KErrNone;
+ }
+ }
+ }
+
+ MoveToNextStateL(err, EInitialiseDll);
+ }
+
+void CCmdCustomCommand::WriteHandleToFileL(TInt aHandle)
+ {
+ const TChar sysDrive = RFs::GetSystemDriveChar();
+ RBuf filename;
+ filename.CreateL(KNeverUnloadLibHandleFile().Length() + 1);
+ filename.Append(sysDrive);
+ filename.Append(KNeverUnloadLibHandleFile());
+ filename.CleanupClosePushL();
+ RFs fs;
+ User::LeaveIfError(fs.Connect());
+ CleanupClosePushL(fs);
+
+ fs.MkDirAll(filename); // ignore any error
+ RFile file;
+ CleanupClosePushL(file);
+ TInt err=KErrNone;
+ TInt pos = 0;
+ if(KErrNotFound == (err = file.Open(fs, filename, EFileShareExclusive|EFileStream|EFileWrite)))
+ {
+ User::LeaveIfError(file.Replace(fs, filename, EFileShareExclusive|EFileStream|EFileWrite));
+ }
+ else
+ {
+ User::LeaveIfError(err);
+ file.Seek(ESeekEnd, pos);
+ }
+ RFileWriteStream targetStream;
+ targetStream.Attach(file, pos); // file gets closed by this call, but that's okay, we don't need it any more (targetStream has its own copy of this RFile object that it owns)
+ CleanupClosePushL(targetStream);
+ targetStream.WriteInt32L(aHandle);
+ targetStream.CommitL();
+ CleanupStack::PopAndDestroy(4);
+ }
+
+/**
+ Calls the Initialize() method on the DLL
+*/
+void CCmdCustomCommand::InitialiseCmdL()
+ {
+ SSMLOGLEAVEIFNULL(iCustomCommand);
+ SSMLOGLEAVEIFNULL(iUtilProvider);
+ iCmdEnv = CSsmCustomCommandEnv::NewL(iUtilProvider->RfsL());
+ TInt err = iCustomCommand->Initialize(iCmdEnv);
+ if (err!=KErrNone)
+ {
+ iCustomCommand->Close();
+ delete iCmdEnv;
+ iCmdEnv=NULL;
+ }
+ MoveToNextStateL(err, EExecuteMethod);
+ }
+
+/**
+ Sets the command up to run for another iteration
+*/
+void CCmdCustomCommand::MoveToNextStateL(TInt aError, TCustomCmdAction aNextState, TBool aCompleteRequest)
+ {
+ if (aError == KErrNone)
+ {
+ iAction = aNextState;
+ }
+ else
+ {
+ if (++iAttempts >= iInfo->Retries())
+ {
+ DEBUGPRINT4A("Error encountered %d attempt %d retries %d", aError, iAttempts, iInfo->Retries());
+ SSMLOGLEAVE(aError);
+ }
+ }
+
+ if (aCompleteRequest)
+ {
+ CompleteRequest(iStatus, aError);
+ }
+
+ SetActive();
+ }
+
+/**
+ Performs command-specific validation
+*/
+void CCmdCustomCommand::ValidateL()
+ {
+ CSsmDeferrableCommand::ValidateL();
+
+ SSMLOGLEAVEIFFALSE(iInfo->FileName().Length()>0, KErrArgument);
+ SSMLOGLEAVEIFFALSE(iInfo->Ordinal()>0, KErrArgument);
+ SSMLOGLEAVEIFFALSE(iInfo->Unloading()>=EUnloadOnCommandCompletion, KErrArgument);
+ SSMLOGLEAVEIFFALSE(iInfo->Unloading()<=ENeverUnload, KErrArgument);
+ SSMLOGLEAVEIFFALSE(iInfo->Retries()>=0, KErrArgument);
+ }
+