--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sysstatemgmt/systemstatemgr/cle/src/clesrv.cpp Tue Feb 02 00:53:00 2010 +0200
@@ -0,0 +1,429 @@
+// 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 <e32debug.h>
+#include <e32math.h>
+#include <f32file.h>
+#include <s32file.h>
+
+#include "clesrv.h"
+#include "clesess.h"
+#include <ssm/ssmcmd.hrh>
+
+
+// This file is used to store the handles of the libraries which has unload option as ENeverUnload.
+// This is also defined in cmdcustomcommand.cpp and the handles are written to this file if
+// the unload option is ENeverUnload.
+_LIT(KNeverUnloadLibHandleFile, ":\\private\\2000d75b\\temp\\unloadlibhandles.bin");
+
+// ------------------- Policy Server Security Setup ----------------------
+
+const TInt KSsmServerSid = 0x2000D75B; //UID3 of sysstatemgr.exe
+
+const TUint KRangeCount = 3;
+const TInt KRanges[KRangeCount] =
+ {
+ 0,
+ ECleSrvExecuteCmdList,
+ EEndOfCleOpCodes
+ };
+
+/**
+ Maps to index 0 in the array KPolicyElements
+ */
+const TInt KSsmServerSidCheck = 0;
+
+/**
+ Specifies the appropriate action for each range in KRanges.
+ The nth element of KElementsIndex specifies the appropriate action for the nth range in KRanges.
+ */
+const TUint8 KElementsIndex[KRangeCount] =
+ {
+ CPolicyServer::ENotSupported,
+ KSsmServerSidCheck,
+ CPolicyServer::ENotSupported,
+ };
+
+/**
+ Array containing the different security checks performed by this server
+ */
+const CPolicyServer::TPolicyElement KPolicyElements[] =
+ {
+ {_INIT_SECURITY_POLICY_S0(KSsmServerSid), CPolicyServer::EFailClient} //lint !e778 suppress Constant expression evaluates to 0 in operation '+'
+ };
+
+/**
+ Setup a security policy which requires all caps to be used by the SsmServer for all requests
+ including creating a connection. We do not yet have a usecase for anyone else other than
+ SsmServer using SusUtilServer. The caller's SID is matched against SsmServer's
+ SID in each ServiceL call
+ */
+const CPolicyServer::TPolicy KCleServerPolicy =
+ {
+ KSsmServerSidCheck, // map connection attempts as well to index [0] in KPolicyElements[]
+ KRangeCount,
+ KRanges,
+ KElementsIndex,
+ KPolicyElements
+ };
+
+
+
+void CCleServer::ExecuteCommandListL( CSsmCommandList* aCommandList, const RMessage2& aMessage, const TInt aSessionIndex )
+ {
+ __ASSERT_DEBUG( aCommandList->Count() > 0, User::Panic( KCleCmdListEmpty, KCleSrvBadCmdList) );
+ __ASSERT_DEBUG( __IN_RANGE(aSessionIndex, iSessionInfoArray.Count()), User::Panic( KCleSrvBadIdx, KCleSrvArrayIndexInvalid ) );
+
+ if( (0 == aCommandList->Count()) || !__IN_RANGE(aSessionIndex, iSessionInfoArray.Count()) )
+ {
+ User::Leave( KErrArgument );
+ }
+
+ CSsmCmdListExecutor* executor = CSsmCmdListExecutor::NewL( *this, aSessionIndex );
+
+ iSessionInfoArray[ aSessionIndex ].iExecutor = executor;
+ iSessionInfoArray[ aSessionIndex ].iMessagePtr = aMessage;
+
+ executor->StartL( aCommandList );
+ }
+
+
+
+/**
+ * Locate the CommandListExecutor associated with the session calling CommandListCancel.
+ * Delete the Command list (which cancels its AO) then complete the client's RMessage with KErrCancel.
+ */
+void CCleServer::ExecuteCommandListCancel( TInt aSessionIndex )
+ {
+ __ASSERT_DEBUG( __IN_RANGE( aSessionIndex, iSessionInfoArray.Count()), User::Panic( KCleSrvBadIdx, KCleSrvArrayIndexInvalid ) );
+
+ if( iSessionInfoArray[ aSessionIndex ].iExecutor )
+ {
+ iSessionInfoArray[ aSessionIndex ].iMessagePtr.Complete( KErrCancel );
+ delete iSessionInfoArray[ aSessionIndex ].iExecutor;
+ iSessionInfoArray[ aSessionIndex ].iExecutor = NULL;
+ }
+ }
+
+
+
+/**
+ * This function is inherited from MCommandListExecutionObserver
+ * and called from CSsmCmdListExecutor to signal the completion of command list processing.
+ */
+void CCleServer::ListExecutionComplete( TInt aComplete, TInt aSessionIndex ,TCmdErrorSeverity /* aSeverity */ )
+ {
+ __ASSERT_DEBUG( __IN_RANGE(aSessionIndex, iSessionInfoArray.Count()), User::Panic( KCleSrvBadIdx, KCleSrvArrayIndexInvalid ) );
+ iSessionInfoArray[ aSessionIndex ].iMessagePtr.Complete( aComplete );
+ delete iSessionInfoArray[ aSessionIndex ].iExecutor;
+ iSessionInfoArray[ aSessionIndex ].iExecutor = NULL;
+ }
+
+
+
+/**
+ Used to create a new server-side session.
+ @return A pointer to the new instance of CSession2.
+ @leave KErrNotSupported if versions are incompatible.
+ @publishedPartner
+ @released
+*/
+EXPORT_C CSession2* CCleServer::NewSessionL( const TVersion& aVersion, const RMessage2& /*aMessage*/ ) const
+ {
+ if( !User::QueryVersionSupported(iVersion, aVersion) )
+ {
+ User::Leave( KErrNotSupported );
+ }
+
+ CCleServer& mutatedSelf = const_cast< CCleServer& >( *this );
+
+ return CCleSession::NewL( mutatedSelf );
+ }
+
+
+
+/**
+ Iterate through iSessionInfoArray to find an unused array element
+ If found, use it. Otherwise, Append() a new SCleSessionInfo.
+ This function is called during CSession construction.
+*/
+void CCleServer::RegisterSessionL( TInt& aSessionIndex )
+ {
+ const TInt count = iSessionInfoArray.Count();
+ TBool slotFound = EFalse;
+
+ for(TInt i = 0; i < count; i++ )
+ {
+ if( !iSessionInfoArray[ i ].iInUse )
+ {
+ iSessionInfoArray[ i ].iInUse = ETrue;
+ ASSERT( NULL == iSessionInfoArray[ i ].iExecutor );
+ aSessionIndex = i;
+ slotFound = ETrue;
+ iSessionCount++;
+ break;
+ }
+ }
+
+ if( !slotFound )
+ {
+ SCleSessionInfo sessionInfo;
+ sessionInfo.iExecutor = NULL;
+ sessionInfo.iInUse = ETrue;
+ iSessionInfoArray.AppendL( sessionInfo );
+ aSessionIndex = iSessionCount++;
+ }
+
+ DEBUGPRINT2( _L("***** Registered in slot %d"), aSessionIndex );
+ }
+
+
+
+/**
+ Called from CSession destructor.
+*/
+void CCleServer::DeregisterSession( const TInt& aSessionIndex )
+ {
+ __ASSERT_DEBUG( __IN_RANGE(aSessionIndex, iSessionInfoArray.Count()), User::Panic(KCleSrvBadIdx, KCleSrvArrayIndexInvalid) );
+
+ if( iSessionInfoArray[ aSessionIndex ].iExecutor )
+ {
+ delete iSessionInfoArray[ aSessionIndex ].iExecutor;
+ iSessionInfoArray[ aSessionIndex ].iExecutor = NULL;
+ }
+
+ iSessionInfoArray[ aSessionIndex ].iInUse = EFalse;
+ iSessionCount--;
+
+ // Remove unused elements at the end of the array, so iSessionInfoArray can be (granular) shrunk
+ const TInt count = iSessionInfoArray.Count();
+ TBool slotRemoved = EFalse;
+ for(TInt i = count-1; i >= 0 ; i-- )
+ {
+ if( !iSessionInfoArray[ i ].iInUse )
+ {
+ iSessionInfoArray.Remove(i);
+ slotRemoved = ETrue;
+ }
+ else
+ {
+ break;
+ }
+ }
+ if (slotRemoved)
+ {
+ iSessionInfoArray.GranularCompress();
+ }
+
+ DEBUGPRINT2( _L("***** De-registered slot %d"), aSessionIndex );
+ }
+
+// Release the libraries loaded by custom commands which has the unload option set to 'ENeverUnload'
+TInt CCleServer::CloseNeverUnloadLibrariesL()
+ {
+ 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);
+ RFile file;
+ CleanupClosePushL(file);
+ TInt libsReleased = 0;
+ const TInt error=file.Open(fs, filename, EFileShareReadersOnly|EFileStream|EFileRead);
+ if (error==KErrNone)
+ {
+ RFileReadStream readStream;
+ readStream.Attach(file);
+ CleanupClosePushL(readStream);
+ TInt handle=0;
+ RLibrary lib;
+ TRAPD(ret, handle = readStream.ReadInt32L());
+ while(ret != KErrEof && handle > 0)
+ {
+ lib.SetHandle(handle);
+ lib.Close();
+ libsReleased++;
+ TRAP(ret, handle = readStream.ReadInt32L());
+ }
+ CleanupStack::PopAndDestroy(&readStream);
+ }
+ fs.Delete(filename);//Ignore the error. Perhaps the file does not exist.
+ CleanupStack::PopAndDestroy(3);
+ return libsReleased;
+ }
+
+
+/**
+ * Used to create a new CCleServer
+ * @return A pointer to the CCleServer
+ * @leave One of the system-wide error codes if construction fails.
+ * @publishedPartner
+ * @released
+ */
+EXPORT_C CCleServer* CCleServer::NewL(const TDesC& aServerName)
+ {
+ CCleServer* self = NewLC(aServerName);
+ CleanupStack::Pop();
+ return self;
+ }
+
+
+
+/**
+ * Used to create a new CCleServer
+ * @return A pointer to the CCleServer
+ * @leave One of the system-wide error codes if construction fails.
+ * @publishedPartner
+ * @released
+ */
+EXPORT_C CCleServer* CCleServer::NewLC(const TDesC& aServerName)
+ {
+ CCleServer* self = new(ELeave) CCleServer;
+ CleanupStack::PushL( self );
+ self->ConstructL(aServerName);
+ return self;
+ }
+
+
+
+/**
+ * Static function used to create and start CCleServer
+ *
+ * @return KErrAlreadyExists if the server is already running
+ * @publishedPartner
+ * @released
+ */
+EXPORT_C TInt CCleServer::StartCleSrv(const TDesC& aServerName)
+ {
+ TAny* threadParam = reinterpret_cast<TAny*>(const_cast<TDesC*>(&aServerName));
+ // Create a Unique name for the thread name
+ TName name(aServerName);
+ _LIT(KUnderScore, "_");
+ name.Append(KUnderScore);
+ name.AppendNum(Math::Random(), EHex);
+
+ const TInt KCleSrvMinHeapSize = 0x2000;
+ const TInt KCleSrvMaxHeapSize = 10 * KCleSrvMinHeapSize;
+ RThread srvThread;
+ TInt err = srvThread.Create( name, &CCleServer::CleSrvThreadFn,
+ KDefaultStackSize, KCleSrvMinHeapSize, KCleSrvMaxHeapSize,
+ threadParam, EOwnerProcess );
+
+ if( KErrNone == err )
+ {
+ TRequestStatus trs;
+
+ srvThread.Rendezvous( trs );
+ srvThread.Resume();
+ srvThread.Close();
+
+ User::WaitForRequest( trs );
+ err = trs.Int();
+ }
+
+ return err;
+ }
+
+
+
+TInt CCleServer::CleSrvThreadFn( TAny* aAny )
+ {
+ const TDesC* serverName = const_cast<const TDesC*>(static_cast<TDesC*>(aAny));
+ TInt err = KErrNoMemory;
+ CTrapCleanup* cleanup = CTrapCleanup::New();
+ if( cleanup )
+ {
+ TRAP( err,
+ {
+ CActiveScheduler* sched = new(ELeave) CActiveScheduler();
+ CleanupStack::PushL( sched );
+ CActiveScheduler::Install( sched );
+
+ CCleServer* cleSrv = CCleServer::NewLC(*serverName);
+ RThread::Rendezvous( KErrNone );
+ // Must not use serverName after rendezvousing with client
+ serverName = NULL;
+
+ CActiveScheduler::Start();
+
+ CleanupStack::PopAndDestroy( cleSrv );
+ CleanupStack::PopAndDestroy( sched );
+ });
+
+ delete cleanup;
+ }
+
+ return err;
+ }
+
+
+/**
+
+ */
+CCleServer::CCleServer()
+: CPolicyServer( EPriorityHigh, KCleServerPolicy, EUnsharableSessions ),
+ iVersion( KCleSrvVersionMajor, KCleSrvVersionMinor, KCleSrvVersionBuild )
+ {
+ }
+
+
+
+void CCleServer::ConstructL(const TDesC& aServerName)
+ {
+ //If the ENeverUnload file is left over, then it should be cleaned up.
+ //Ignore the error. We don't want the server to be stopped due to this error.
+ TRAP_IGNORE(CleanHandlesFileL());
+
+ StartL( aServerName );
+ // The starting thread is signalled in the thread function.
+ }
+
+
+// Delete the file which stores the handles of those libraries used by custom commands which has unload option set to ENeverUnload.
+// Generally it will be deleted from the destructor. If it could not be deleted for some reason from the destructor,
+// then it should be deleted while starting the server.
+void CCleServer::CleanHandlesFileL()
+ {
+ 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());
+ fs.Delete(filename);//Ignore the error. Perhaps the file does not exist.
+ fs.Close();
+ CleanupStack::PopAndDestroy();
+ }
+
+CCleServer::~CCleServer()
+ {
+ const TInt count = iSessionInfoArray.Count();
+ for(TInt i = 0; i < count; i++ )
+ {
+ delete iSessionInfoArray[ i ].iExecutor;
+ iSessionInfoArray[ i ].iExecutor = NULL;
+ }
+ iSessionInfoArray.Close();
+
+ //Server is being destructed, so no need to leave from here.
+ TRAP_IGNORE(CloseNeverUnloadLibrariesL());
+ }
+