diff -r 000000000000 -r 4e1aa6a622a0 sysstatemgmt/systemstatemgr/cle/src/clesrv.cpp --- /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 +#include +#include +#include + +#include "clesrv.h" +#include "clesess.h" +#include + + +// 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(const_cast(&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(static_cast(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()); + } +