filesystemuis/memscaneng/serversrc/memscanserv.cpp
branchRCL_3
changeset 39 65326cf895ed
parent 0 6a9f87576119
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/filesystemuis/memscaneng/serversrc/memscanserv.cpp	Wed Sep 01 12:31:07 2010 +0100
@@ -0,0 +1,621 @@
+/*
+* Copyright (c) 2006-2006 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:  Memory Scan Server
+*
+*/
+
+
+
+// SYSTEM INCLUDES
+#include <e32svr.h>
+#include <s32mem.h> // RBufWriteStream
+
+// USER INCLUDES
+#include "memscanserv.h"
+#include "memscanutils.h" // traces
+
+    
+// ---------------------------------------------------------------------------
+// Server startup code
+// ---------------------------------------------------------------------------
+
+// Perform all server initialisation, in particular creation of the
+// scheduler and server and then run the scheduler
+// 
+static void RunServerL()
+    {
+    // naming the server thread after the server helps to debug panics
+    User::LeaveIfError(User::RenameThread(KMemScanServName));
+
+    // create and install the active scheduler we need
+    CActiveScheduler* scheduler=new(ELeave) CActiveScheduler;
+    CleanupStack::PushL(scheduler);
+    CActiveScheduler::Install(scheduler);
+    // create the server (leave it on the cleanup stack)
+    CMemScanServ::NewLC();
+    // Initialisation complete, now signal the client
+
+    RProcess::Rendezvous(KErrNone);
+
+    // Ready to run
+    TRACES( RDebug::Print(_L("MemScanServ: server fully running")) );
+    CActiveScheduler::Start();
+    // Cleanup the server and scheduler
+    CleanupStack::PopAndDestroy(2, scheduler);
+    }
+
+// Server process entry-point
+TInt E32Main()
+    {
+    __UHEAP_MARK;
+    TRACES( RDebug::Print(_L("MemScanServ: E32Main")) ); 
+    CTrapCleanup* cleanup=CTrapCleanup::New();
+    TInt r=KErrNoMemory;
+    if (cleanup)
+        {
+        TRAP(r,RunServerL());
+        delete cleanup;
+        }
+    __UHEAP_MARKEND;
+    return r;
+    }
+    
+// RMessagePtr2::Panic() also completes the message. This is:
+// (a) important for efficient cleanup within the kernel
+// (b) a problem if the message is completed a second time
+void PanicClient(const RMessagePtr2& aMessage,TMemScanServPanic aPanic)
+    {
+    _LIT(KPanic,"MemScanServ");
+    aMessage.Panic(KPanic,aPanic);
+    }
+
+    
+// ---------------------------------------------------------------------------
+// CShutDown
+// ---------------------------------------------------------------------------
+inline CShutdown::CShutdown()
+    :CTimer(-1)
+    {
+    CActiveScheduler::Add(this);
+    }
+    
+inline void CShutdown::ConstructL()
+    {
+    CTimer::ConstructL();
+    }
+
+inline void CShutdown::Start()
+    {
+    TRACES( RDebug::Print(_L("MemScanServ: starting shutdown timeout")) );
+    After(EMemScanServShutdownDelay);
+    }
+
+void CShutdown::RunL()
+    {
+    TRACES( RDebug::Print(_L("MemScanServ: server timeout ... closing")) );
+    CActiveScheduler::Stop();
+    }
+
+// ---------------------------------------------------------------------------
+// CMemScanServ
+// ---------------------------------------------------------------------------
+inline CMemScanServ::CMemScanServ()
+    :CPolicyServer(0, KMemScanServPolicy, ESharableSessions)
+    {
+    }
+    
+CServer2* CMemScanServ::NewLC()
+    {
+    TRACES( RDebug::Print(_L("MemScanServ: CMemScanServ::NewLC")) );
+    CMemScanServ* self=new(ELeave) CMemScanServ;
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    return self;
+    }
+
+// 2nd phase construction - ensure the timer and server objects are running
+void CMemScanServ::ConstructL()
+    {
+    StartL(KMemScanServName);
+    iShutdown.ConstructL();
+    // ensure the server still exits even if the 1st client fails to connect
+    if( !iShutdown.IsActive() )
+        {
+        iShutdown.Start();
+        }
+    }
+
+
+// Create a new client session.
+CSession2* CMemScanServ::NewSessionL(const TVersion& aVersion, const RMessage2&) const
+    {
+    TRACES( RDebug::Print(_L("MemScanServ: CMemScanServ::NewSessionL")) );
+
+    // Client-Server version check
+	TVersion version(KMemScanServMajor, KMemScanServMinor, KMemScanServBuild);
+	if( !User::QueryVersionSupported( version, aVersion ) )
+	    {
+	    User::Leave( KErrNotSupported );
+	    }
+
+    return new (ELeave) CMemScanServSession();
+    }
+
+// A new session is being created
+// Cancel the shutdown timer if it was running
+void CMemScanServ::AddSession()
+    {
+    TRACES( RDebug::Print(_L("MemScanServ: CMemScanServ::AddSession")) );
+    ++iSessionCount;
+    iShutdown.Cancel();
+    }
+
+// A session is being destroyed
+// Start the shutdown timer if it is the last session.
+void CMemScanServ::DropSession()
+    {
+    TRACES( RDebug::Print(_L("MemScanServ: CMemScanServ::DropSession")) );
+    if (--iSessionCount==0)
+        {
+        if( !iShutdown.IsActive() )
+            {
+            iShutdown.Start();
+            }
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CMemScanServSession
+// ---------------------------------------------------------------------------
+inline CMemScanServSession::CMemScanServSession()
+    {
+    TRACES( RDebug::Print(_L("MemScanServer: CMemScanServSession::CMemScanServSession")); )
+    }
+    
+inline CMemScanServ& CMemScanServSession::Server()
+    {
+    return *static_cast<CMemScanServ*>(const_cast<CServer2*>(CSession2::Server()));
+    }
+
+// 2nd phase construct for sessions - called by the CServer framework
+void CMemScanServSession::CreateL()
+    {
+    TRACES( RDebug::Print(_L("MemScanServ: CMemScanServSession::CreateL")); )
+    Server().AddSession();
+        
+    // Create a transfer buffer
+    iTransferBuffer = CBufFlat::NewL(KMemScanServTransferBufferExpandSize);
+    }
+
+CMemScanServSession::~CMemScanServSession()
+    {
+    TRACES( RDebug::Print(_L("MemScanServ: CMemScanServSession::~CMemScanServSession")); )
+    
+    
+    delete iTransferBuffer;
+    delete iMseng;
+    
+    
+    iEventBuffer.Close();
+    Server().DropSession();
+    }
+
+
+// Handle a client request.
+// Leaving is handled by CMemScanServSession::ServiceError() which reports
+// the error code to the client
+void CMemScanServSession::ServiceL(const RMessage2& aMessage)
+    {
+    TRACES( RDebug::Print(_L("MemScanServ: CMemScanServSession::ServiceL; %d"),aMessage.Function()); )
+    switch (aMessage.Function())
+        {
+        case EMemScanPrepareDataGroups:
+            {
+            PrepareDataGroupsL( aMessage );
+            break;
+            }
+        case EMemScanGetDataGroups:
+            {
+            GetDataGroupsL( aMessage );
+            break;
+            }            
+        case EMemScanStartScan:
+            {
+            MemScanL( aMessage );
+            break;
+            }
+        case EMemScanPrepareScanResults:
+            {
+            PrepareScanResultsL( aMessage );
+            break;
+            }
+        case EMemScanGetScanResults:
+            {
+            GetScanResultsL( aMessage );
+            break;
+            }                       
+        case EMemScanRequestScanEvents:
+            {
+            RequestScanEventsL( aMessage );
+            break;
+            }
+        case EMemScanRequestScanEventsCancel:
+            {
+            RequestScanEventsCancel( aMessage );
+            break;
+            }
+        case EMemScanInProgress:
+            {
+            ScanInProgress( aMessage );
+            break;
+            }
+
+        default:
+            {
+            TRACES( RDebug::Print(_L("MemScanServ: CMemScanServSession::ServiceL; %d"),aMessage.Function()); )
+            PanicClient(aMessage,EPanicIllegalFunction);
+            break;
+            }
+            
+        }
+    }
+
+// Handle an error from CMemScanServSession::ServiceL()
+void CMemScanServSession::ServiceError(const RMessage2& aMessage,TInt aError)
+    {
+    TRACES( RDebug::Print(_L("MemScanServ: CMemScanServSession::ServiceError %d"),aError); )
+    CSession2::ServiceError(aMessage,aError);
+    }
+
+
+// ***************************************************************************
+// Internal utility functions
+// ***************************************************************************
+
+
+// ---------------------------------------------------------------------------
+// CMemScanServSession::PrepareDataGroupsL()
+//
+// ---------------------------------------------------------------------------
+void CMemScanServSession::PrepareDataGroupsL(const RMessage2& aMessage)
+    {
+    // Create scan engine if it does not exist
+    if(!iMseng)
+        {
+        iMseng = CMseng::NewL(*this);
+        }
+    
+    // Get data group name array
+    CDesCArray* dataGroupArray = iMseng->DataGroupsL();
+    CleanupStack::PushL(dataGroupArray);
+   
+   
+    // *** Start externalizing the data group array to transfer buffer
+
+    // Clear the buffer
+    iTransferBuffer->Reset();
+
+    // Set buffer for the stream
+    RBufWriteStream stream(*iTransferBuffer);
+    CleanupClosePushL(stream);
+    
+    // Write number of fields in array to stream 
+    TInt count = dataGroupArray->MdcaCount();
+    stream.WriteInt32L(count);
+    
+    // Write each field in array to stream
+    for(TInt i=0; i<count; i++)
+        {
+        TInt length = dataGroupArray->MdcaPoint(i).Length();
+        stream.WriteInt32L(length); // writes datagroup name length to stream
+        const TPtrC group = dataGroupArray->MdcaPoint(i);
+        stream << group; // writes one datagroup to stream
+        }
+    
+    stream.CommitL();
+    CleanupStack::PopAndDestroy(&stream);
+    CleanupStack::PopAndDestroy(dataGroupArray);
+    
+    // *** externalizing done
+    
+    
+    // Write the size of transfer buffer back to client
+    TPckgBuf<TInt> size(iTransferBuffer->Size());
+    aMessage.WriteL(0, size);
+    
+    // complete the message
+    aMessage.Complete( KErrNone );
+    }
+
+
+// ---------------------------------------------------------------------------
+// CMemScanServSession::GetDataGroupsL()
+//
+// ---------------------------------------------------------------------------
+void CMemScanServSession::GetDataGroupsL(const RMessage2& aMessage)
+    {
+    // Get the prepared data groups
+    aMessage.WriteL( KMesArg0, iTransferBuffer->Ptr(0)); 
+        
+    aMessage.Complete( KErrNone );
+    }
+    
+// ---------------------------------------------------------------------------
+// CMemScanServSession::PrepareScanResultsL()
+//
+// ---------------------------------------------------------------------------
+void CMemScanServSession::PrepareScanResultsL(const RMessage2& aMessage)
+    {
+    // Get scan results from server
+    CArrayFix<TInt64>* resultArray = iMseng->ScanResultL();
+    CleanupStack::PushL(resultArray);
+
+    // *** Start externalizing the result array to transfer buffer
+    
+    // Clear the buffer
+    iTransferBuffer->Reset();
+        
+    // Set buffer for the stream
+    RBufWriteStream stream(*iTransferBuffer);
+    CleanupClosePushL(stream);
+    
+    // Write number of fields in array to stream 
+    TInt count = resultArray->Count();
+    stream.WriteInt32L(count);    
+    
+    // Write each field in array to stream
+    for(TInt i=0; i<count; i++)
+        {
+        const TInt64 result = resultArray->At(i);
+        stream << result; // writes one data result to stream
+        }
+    
+    stream.CommitL();
+    CleanupStack::PopAndDestroy(&stream);
+    CleanupStack::PopAndDestroy(resultArray);
+    
+    // *** externalizing done
+    
+    
+    // Write the size of transfer buffer back to client
+    TPckgBuf<TInt> size(iTransferBuffer->Size());
+    aMessage.WriteL(0, size);    
+    
+    
+    aMessage.Complete( KErrNone );    
+    }
+
+
+// ---------------------------------------------------------------------------
+// CMemScanServSession::GetScanResultsL()
+//
+// ---------------------------------------------------------------------------
+void CMemScanServSession::GetScanResultsL(const RMessage2& aMessage)
+    {
+    // Get the prepared scan results
+    aMessage.WriteL( KMesArg0, iTransferBuffer->Ptr(0));    
+    
+    aMessage.Complete( KErrNone ); 
+    }
+
+
+// ---------------------------------------------------------------------------
+// CMemScanServSession::MemScanL()
+//
+// ---------------------------------------------------------------------------
+void CMemScanServSession::MemScanL(const RMessage2& aMessage)
+    {
+    TRACES( RDebug::Print(_L("MemScanServ: CMemScanServSession::ScanL")); )
+    
+     // Get the first integer parameter of message     
+    TDriveNumber drive = TDriveNumber(aMessage.Int0()); 
+        
+    iMseng->ScanL( drive );
+    aMessage.Complete( KErrNone );
+    }
+
+
+// ---------------------------------------------------------------------------
+// CMemScanServSession::RequestScanEventsL()
+//
+// ---------------------------------------------------------------------------
+void CMemScanServSession::RequestScanEventsL(const RMessage2& aMessage)
+    {
+    if  ( iScanEventMessage.IsNull() ) 
+        {
+        // We want check that the client hasn't requested scan events
+        // twice in a row. The client is only allowed to have one 
+        // scan event request outstanding at any given time.
+        //
+        // Since the iScanEventMessage was null (i.e. its not been
+        // initialised) then its safe to store the client's message
+        // for completion later on when the scan engine has a real event.
+        
+        // Save the clients message for later until we receive an
+        // event callback from the scan engine.
+        iScanEventMessage = aMessage;
+
+        // If we have at least one event ready to send to the client, then
+        // we deliver it to the client immediately. This could be possible
+        // if the client is slow to process an earlier event.
+        const TBool haveAtLeastOneEventPending = IsEventReady();
+        if  ( haveAtLeastOneEventPending )
+            {
+            // We must deliver the oldest event to the client.
+            DeliverOldestEventToClientL(); // this will complete aMessage immediately.
+            }
+        }
+    else
+        {
+        // The client has already asked for scan events as we still
+        // have an existing (valid) iScanEventMessage object.
+        //
+        // This would imply a programming error in the client code
+        // so we punish the client by panicking it.
+        aMessage.Panic( KMemScanServerPanicCategory, EMemScanServerPanicRequestedScanEventsTwice );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CMemScanServSession::RequestScanEventsCancel()
+//
+// ---------------------------------------------------------------------------
+void CMemScanServSession::RequestScanEventsCancel(const RMessage2& aMessage)
+    {
+    // We only are able to cancel a client request if the client actually
+    // requested something.
+    // We can check whether a request is pending by using the IsNull method
+    // on our outstanding request object ("iScanEventMessage").
+    if  ( iScanEventMessage.IsNull() == EFalse ) 
+        {
+        // The client has made a request, and we need to cancel it.
+        iScanEventMessage.Complete( KErrCancel );
+        }
+        
+        
+    // If the client wants to cancel events, we should also empty
+    // the event buffer.
+    iEventBuffer.Reset();
+    
+    aMessage.Complete( KErrNone );
+    }
+
+
+// ---------------------------------------------------------------------------
+// CMemScanServSession::ScanInProgress()
+//
+// ---------------------------------------------------------------------------
+void CMemScanServSession::ScanInProgress(const RMessage2& aMessage)
+    {
+    TBool scanInProgress = iMseng->ScanInProgress();
+    aMessage.Complete(static_cast<TInt> (scanInProgress));
+    }
+
+
+
+// From MMsengUIHandler:
+// ===========================================================================
+
+// ---------------------------------------------------------------------------
+// CMemScanServSession::StartL()
+// ---------------------------------------------------------------------------
+void CMemScanServSession::StartL()
+    {
+    SendEventToClientL( EMemScanEventScanningStarted );
+    }
+
+// ---------------------------------------------------------------------------
+// CMemScanServSession::QuitL()
+// ---------------------------------------------------------------------------
+void CMemScanServSession::QuitL(TInt aReason)
+    {
+    SendEventToClientL( EMemScanEventScanningFinished, aReason );
+    }
+
+// ---------------------------------------------------------------------------
+// CMemScanServSession::Error()
+// ---------------------------------------------------------------------------
+void CMemScanServSession::ErrorL(TInt aError)
+    {
+    SendEventToClientL( EMemScanEventScanningError, aError );
+    }
+
+// ===========================================================================
+
+
+
+    
+// ---------------------------------------------------------------------------
+// CMemScanServSession::SendEventToClientL()
+//
+// ---------------------------------------------------------------------------
+void CMemScanServSession::SendEventToClientL( TMemScanEvent aEventType,
+                                              TInt aError )
+    {
+    // We need to tell the client about the event that has taken place. 
+    // The client event API expects to receive the event type, i.e. what 
+    // kind of "thing" just happened, and also any associated error value 
+    // (e.g. "Nothing went wrong" or, "we ran out of memory").
+    
+    AddNewEventToBufferL( aEventType, aError );
+    DeliverOldestEventToClientL();
+    }
+
+// ---------------------------------------------------------------------------
+// CMemScanServSession::AddNewEventToBufferL()
+//
+// ---------------------------------------------------------------------------
+void CMemScanServSession::AddNewEventToBufferL( TMemScanEvent aEventType,
+                                                TInt aError )
+    {
+    TMemScanEventPackage event;
+    event.iEvent = aEventType;
+    event.iError = aError;
+    
+    // Add the event to the event buffer. We will send this event to the 
+    // client when the client is ready to accept it.
+    iEventBuffer.AppendL( event );
+    }
+
+// ---------------------------------------------------------------------------
+// CMemScanServSession::IsEventReady()
+//
+// ---------------------------------------------------------------------------
+TBool CMemScanServSession::IsEventReady() const
+    {
+    // Returns whether we have at least one event in the buffer ready to send
+    // to the client.
+    const TInt count = iEventBuffer.Count();
+    return ( count > 0 );
+    }
+
+
+// ---------------------------------------------------------------------------
+// CMemScanServSession::DeliverOldestEventToClientL()
+//
+// ---------------------------------------------------------------------------
+void CMemScanServSession::DeliverOldestEventToClientL()
+    {
+    // Fetch the oldest event from the buffer and deliver it
+    // to the client.
+    if  ( iScanEventMessage.IsNull() == EFalse && IsEventReady() )
+        {
+        // This next block of code converts the error number to look like
+        // a descriptor, since this is the only way of writing to the
+        // client's address space. 
+        //
+        // We check that the client actually requested scan events before
+        // we try and write to its address space. If we don't do this
+        // then the kernel will panic our code with KERN-SVR 0
+        // ("you're trying to use a null message object")
+        const TMemScanEventPackage& event = iEventBuffer[ 0 ];
+        
+        TPckgC<TInt> associatedErrorAsDescriptor( event.iError );
+        iScanEventMessage.WriteL( 0, associatedErrorAsDescriptor );
+        
+        // Now that we have written the error value, its safe to complete
+        // the clients asynchronous request which will end up calling
+        // the client's RunL method.
+        iScanEventMessage.Complete( event.iEvent );
+
+        // We've delivered the oldest event to the client, so now 
+        // its safe to discard it.
+        iEventBuffer.Remove( 0 );
+        }
+    }
+ 
+
+// End of File