devicediagnosticsfw/diagresultsdb/server/src/diagresultsdbsession.cpp
branchRCL_3
changeset 26 19bba8228ff0
parent 0 b497e44ab2fc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/devicediagnosticsfw/diagresultsdb/server/src/diagresultsdbsession.cpp	Wed Sep 01 12:27:42 2010 +0100
@@ -0,0 +1,1042 @@
+/*
+* Copyright (c) 2007 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:  Class definition of CDiagResultsDbSession
+*
+*/
+
+
+#include "diagresultsdatabasecommon.h"
+#include "diagresultsdbsession.h"
+#include "diagresultsdbserver.h"
+#include "diagresultsdbtestrecordsubsession.h"
+#include "diagresultsdatabasetestrecordinfo.h"
+#include "diagresultsdbtestrecordhandle.h"
+#include "diagresultsdbtestrecord.h"
+#include "diagresultsdatabaseitem.h"
+#include "diagresultsdbrecordinfoarraypacked.h"
+#include "diagresultsdbcrdc.h"
+#include "diagresultsdbrecordengineparam.h"
+
+//System includes
+#include <s32mem.h>
+
+const TInt KArrayGranuality = 50;
+const TInt KResultsDatabaseBufferLength=0x700;
+
+// ---------------------------------------------------------------------------
+// constructor - must pass client to CSession
+// ---------------------------------------------------------------------------
+// 
+CDiagResultsDbSession::CDiagResultsDbSession(CDiagResultsDbServer * aServer): 
+       iServer(aServer), iSubsessionContainer( NULL ), iSubsessionIndex(NULL), 
+       iLastResultCommand( 0 ),
+       iStore(NULL), iBufferedLastResults(NULL), iBufferedSingleResult(NULL),
+       iHasWrittenData(EFalse)
+	{
+	aServer->IncreaseSessionCount();
+	}
+
+// ---------------------------------------------------------------------------
+// NewL.
+// ---------------------------------------------------------------------------
+// 
+CDiagResultsDbSession* CDiagResultsDbSession::NewL(CDiagResultsDbServer * aServer)
+	{
+	CDiagResultsDbSession* pSession= new (ELeave) CDiagResultsDbSession( aServer );
+	CleanupStack::PushL( pSession );
+	pSession->ConstructL();
+	CleanupStack::Pop();
+	return pSession;
+	}
+
+// ---------------------------------------------------------------------------
+// ConstructL.
+// ---------------------------------------------------------------------------
+// 
+void CDiagResultsDbSession::ConstructL()
+	{
+	iSubsessionContainer = iServer->NewContainerL();
+	iSubsessionIndex = CObjectIx::NewL();
+	
+	// buffer for IPC. Objects are transmitted in this buffer.
+	// Size of the buffer has to be selected carefully.
+	// It should be 'large enough' but not too large.
+	// If you see too many overflows, increase the size.
+	iBuffer = CBufFlat::NewL(KArrayGranuality);
+	iBuffer->ResizeL(KResultsDatabaseBufferLength);
+	}
+
+// ---------------------------------------------------------------------------
+// Destructor.
+// ---------------------------------------------------------------------------
+// 	
+CDiagResultsDbSession::~CDiagResultsDbSession()
+	{
+    if ( iBuffer )
+        {
+        iBuffer->Reset();
+        delete iBuffer;
+        iBuffer = NULL;
+        }
+    
+	// NOTE!
+	// The deletion order is important here. You must
+	// delete object indexes first, because this zeros the
+	// number of references to any CObject type objects. Trying 
+	// to delete object container first, you get panic
+	// E32USER-CBase 33: an attempt is made to delete the CObject 
+	// when the reference count is not zero.
+	delete iSubsessionIndex;
+
+    if ( iSubsessionContainer )
+        {
+        iServer->RemoveContainer( iSubsessionContainer );
+        }
+	
+	delete iStore;
+	
+    if ( iServer )
+        {
+        iServer->DecreaseSessionCount();
+        }
+	
+	if ( iBufferedLastResults )
+	    {
+	    iBufferedLastResults->ResetAndDestroy();
+	    iBufferedLastResults->Close();
+	    delete iBufferedLastResults;
+	    iBufferedLastResults = 0;
+	    }
+	    
+    if ( iBufferedSingleResult )
+        {
+        delete iBufferedSingleResult;
+        iBufferedSingleResult = NULL;
+        }
+	}
+
+// ---------------------------------------------------------------------------
+// Service client requests.
+// ---------------------------------------------------------------------------
+// 
+void CDiagResultsDbSession::ServiceL(const RMessage2& aMessage)
+	{
+	LOGME("CDiagResultsDbSession::ServiceL");
+	TBool async = EFalse;
+	TRAPD( err, async = DispatchMessageL( aMessage ) );
+	LOGME1("CDiagResultsDbSession::ServiceL %d",err);
+	if ( !async ) 
+	    {
+	    aMessage.Complete( err );
+	    }
+	}
+
+// ---------------------------------------------------------------------------
+// service a client request; test the opcode and then do appropriate servicing
+// ---------------------------------------------------------------------------
+//     
+TBool CDiagResultsDbSession::DispatchMessageL(const RMessage2 &aMessage)
+	{
+	LOGME("CDiagResultsDbSession::DispatchMessageL");
+	iMsg = aMessage;
+	TInt function = aMessage.Function();
+	LOGME1("CDiagResultsDbSession::DispatchMessageL - %d",function);
+	TInt handle(0);
+	CObject* subsession = NULL;
+	switch( function )
+        {
+	case DiagResultsDbCommon::EConnect:
+	    {
+	    LOGME("CDiagResultsDbSession::EConnect");
+	    TPckgBuf<TUid> uidpckg;
+	    aMessage.Read(0, uidpckg);
+        iDbUid = uidpckg();
+        
+        iStore = CDiagResultsDbStore::NewL( iDbUid );
+		return EFalse;
+	    }
+        
+    case DiagResultsDbCommon::EClose:
+        {        
+        LOGME("CDiagResultsDbSession::EClose");
+        aMessage.Complete (KErrNone);
+                      
+        return ETrue;
+        }
+        
+    case DiagResultsDbCommon::EGetRecordCount:
+        {        
+        LOGME("CDiagResultsDbSession::EGetRecordCount");
+        RArray<TUid> uids;
+        CleanupClosePushL ( uids );
+        iStore->RecordUidsL( uids );
+        
+        TPckgBuf<TUint> pckg( uids.Count() );
+        aMessage.Write(0, pckg);
+        
+        CleanupStack::PopAndDestroy( &uids );
+        return EFalse;
+        }
+        
+	case DiagResultsDbCommon::EConnectSubsession:
+			LOGME("CDiagResultsDbSession::EConnectSubsession");
+	    ConnectSubsessionL( aMessage );
+		return EFalse;			
+		
+	case DiagResultsDbCommon::ESubsessionCreateNewRecord:
+			LOGME("CDiagResultsDbSession::ESubsessionCreateNewRecord");
+	    CreateNewRecordL( aMessage );
+	    HasWritten();
+		return EFalse;
+		
+	case DiagResultsDbCommon::ECloseSubsession:
+		LOGME("CDiagResultsDbSession::ECloseSubsession");
+		CloseSubsessionL();
+		return EFalse;
+		
+    case DiagResultsDbCommon::EGetLastRecord:  
+    		LOGME("CDiagResultsDbSession::EGetLastRecord");
+        GetLastRecordL( aMessage );
+        return EFalse;
+        
+    case DiagResultsDbCommon::EGetLastNotCompletedRecord:
+    		LOGME("CDiagResultsDbSession::EGetLastNotCompletedRecord");
+        GetLastNotCompletedRecordL( aMessage );
+        return EFalse;
+    
+    case DiagResultsDbCommon::EGetRecordList: //record uids 
+    		LOGME("CDiagResultsDbSession::EGetRecordList");
+        GetRecordListL( aMessage );
+        return EFalse;
+
+    case DiagResultsDbCommon::EGetRecordInfoList:
+    		LOGME("CDiagResultsDbSession::EGetRecordInfoList");
+        GetRecordInfoListL( aMessage );
+        return EFalse;
+
+    case DiagResultsDbCommon::EInitiateGetLastResults:  //Async
+        {     
+        LOGME("CDiagResultsDbSession::EInitiateGetLastResults");
+        ReadBufferL( aMessage, 0, iBuffer );
+               
+        iLastResultsMsg = iMsg;
+        	
+        iLastResultCommand = DiagResultsDbCommon::EInitiateGetLastResults;	
+        	
+        if ( iBufferedLastResults )
+	        {
+	        iBufferedLastResults->ResetAndDestroy();
+	        iBufferedLastResults->Close();
+	        delete iBufferedLastResults;
+	        iBufferedLastResults = 0;
+	        }
+	        
+        iStore->ExistingRecordsAsyncL( *this );
+        return ETrue;
+        }
+    
+    case DiagResultsDbCommon::EInitiateGetSingleLastResult: //Async
+        {           
+        LOGME("CDiagResultsDbSession::EInitiateGetSingleLastResult");     
+        iLastSingleResultsMsg = iMsg;
+        
+        iLastResultCommand = DiagResultsDbCommon::EInitiateGetSingleLastResult;	
+        
+        if ( iBufferedSingleResult )
+            {
+            delete iBufferedSingleResult;
+            iBufferedSingleResult = NULL;
+            }
+            
+        iStore->ExistingRecordsAsyncL( *this );
+        return ETrue;  
+        }
+    
+    
+    case DiagResultsDbCommon::EGetLastResults:    
+    		LOGME("CDiagResultsDbSession::EGetLastResults");     
+        GetLastResultsL( aMessage );
+        return EFalse;
+        
+    case DiagResultsDbCommon::EGetSingleLastResult: 
+    		LOGME("CDiagResultsDbSession::EGetSingleLastResult");        
+        GetSingleLastResultL( aMessage );
+        return EFalse;    
+        
+    case DiagResultsDbCommon::ECancelInitiateGetLastResults:
+        {
+        LOGME("CDiagResultsDbSession::ECancelInitiateGetLastResults");        
+        CancelLastResultsL( aMessage );
+        return EFalse;
+        }
+       
+	// Sub-session requests. See CDiagResultsDbTestRecordSubsession.
+    case DiagResultsDbCommon::ESubsessionGetTestRecordId:
+    case DiagResultsDbCommon::ESubsessionTestCompleted:
+    case DiagResultsDbCommon::ESubsessionIsTestCompleted:
+    case DiagResultsDbCommon::ESubsessionGetRecordInfo:
+    case DiagResultsDbCommon::ESubsessionGetTestUids:
+    case DiagResultsDbCommon::ESubsessionSuspend:
+    case DiagResultsDbCommon::ESubsessionIsSuspended:
+    case DiagResultsDbCommon::ESubsessionLogTestResult:
+    case DiagResultsDbCommon::ESubsessionGetTestResult:
+    case DiagResultsDbCommon::ESubsessionGetTestResults:
+    case DiagResultsDbCommon::ESubsessionGetEngineParam:
+    case DiagResultsDbCommon::ESubsessionGetStatus:
+    case DiagResultsDbCommon::ESubsessionCancelLogTestResult:
+    LOGME("CDiagResultsDbSession::ESubsessionCancelLogTestResult");        
+		handle = aMessage.Int3();
+		subsession = iSubsessionIndex->At( handle );
+		return static_cast<CDiagResultsDbTestRecordSubsession*>(subsession)
+		                                    ->DispatchMessageL( aMessage );
+	default:
+		aMessage.Panic( _L("DiagSrv panic: unknown command"), 
+		                    DiagResultsDbCommon::EBadRequest );
+		return EFalse;
+		}
+	}
+
+// ---------------------------------------------------------------------------
+// Get function.
+// ---------------------------------------------------------------------------
+// 
+TBool CDiagResultsDbSession::SessionHasWritten() const
+    {
+    return iHasWrittenData;
+    }
+            
+// ---------------------------------------------------------------------------
+// Connect to a subsession. Test record represents the connected subsession.
+// ---------------------------------------------------------------------------
+//     
+void CDiagResultsDbSession::ConnectSubsessionL( const RMessage2 &aMessage )    
+    {
+    TPckgBuf<TUid> uidpckg;
+	aMessage.Read(0, uidpckg);
+    TUid recordUid = uidpckg(); 
+    
+    TPckgBuf<TBool> readOnlyPckg;
+	aMessage.Read(1, readOnlyPckg);
+    TBool readonly = readOnlyPckg();
+    
+	CDiagResultsDbTestRecordHandle* handle = iStore->OpenExistingHandleL( 
+	                                           recordUid );
+	                                           
+    if ( readonly ) 
+        {
+        // keep the record as it is.
+        }
+    else
+        {
+        if ( handle->RecordInfo().iCompleted )
+            {
+            delete handle;
+            handle = 0;
+            User::Leave( KErrAlreadyExists );
+            }
+        
+        handle->RecordInfo().iRecordStatus = 
+                TDiagResultsDatabaseTestRecordInfo::EOpen;
+        }
+	                                           
+    CreateSubsessionL( handle, readonly );
+    }
+
+// ---------------------------------------------------------------------------
+// Create a new record. This does not write data into the db file.
+// ---------------------------------------------------------------------------
+//     
+void CDiagResultsDbSession::CreateNewRecordL ( const RMessage2 &aMessage )
+    {
+    
+    ReadBufferL( aMessage, 1, iBuffer );
+    
+    RBufReadStream stream( *iBuffer );
+    CleanupClosePushL ( stream );
+    
+    CDiagResultsDbRecordEngineParam* params = 
+                            CDiagResultsDbRecordEngineParam::NewL ( stream );
+    CleanupStack::PushL( params );                         
+
+    CDiagResultsDbTestRecordHandle* handle = iStore->CreateNewRecordL( params );
+
+    handle->RecordInfo().iRecordStatus = 
+                                TDiagResultsDatabaseTestRecordInfo::EOpen;
+
+    CleanupStack::Pop(); //params    
+    CleanupStack::PopAndDestroy( &stream );
+
+	CreateSubsessionL(handle, EFalse);
+		
+	TPckgBuf<TUid> recorduidpckg( handle->RecordInfo().iRecordId );
+		
+	aMessage.Write(0, recorduidpckg );
+    }
+    
+// ---------------------------------------------------------------------------
+// Return the database file uid.
+// ---------------------------------------------------------------------------
+//      
+TUid CDiagResultsDbSession::DbUid() const
+    {
+    return iDbUid;
+    }
+
+// ---------------------------------------------------------------------------
+// Create a new subsession.
+// ---------------------------------------------------------------------------
+//     
+void CDiagResultsDbSession::CreateSubsessionL( 
+                            CDiagResultsDbTestRecordHandle* aTestRecordHandle,
+                            TBool aReadonly )
+	{
+    TInt handle(0);
+    CObject* subsession = NULL;
+    
+	// Create sub-session object
+	subsession = CDiagResultsDbTestRecordSubsession::NewL( this, 
+	                                                    aTestRecordHandle,
+	                                                    aReadonly );
+    CleanupStack::PushL( subsession );
+    iSubsessionContainer->AddL( subsession );
+    CleanupStack::Pop();
+
+	// Create sub-session handle
+	TRAPD( err, handle = iSubsessionIndex->AddL( subsession ) );
+
+	// Remember to remove session object from object container
+	if( err != KErrNone )
+		{
+		iSubsessionContainer->Remove( subsession ); 
+		User::Leave( DiagResultsDbCommon::ESvrCreateSubsession );
+		}
+
+    // Package to pass information to the client
+    TPckgC<TInt> handlePckg(handle);
+    
+    // Send handle to the client
+    TRAP( err, iMsg.WriteL( 3, handlePckg ) );
+	if( err != KErrNone )
+		{
+		iSubsessionIndex->Remove(handle);
+		User::Leave( DiagResultsDbCommon::ESvrCreateSubsession );
+		}
+
+	return;
+	}
+
+// ---------------------------------------------------------------------------
+// Close existing subsession.
+// ---------------------------------------------------------------------------
+// 
+void CDiagResultsDbSession::CloseSubsessionL()
+	{
+	TInt handle = iMsg.Int3();
+	iSubsessionIndex->Remove(handle);
+	}
+
+// ---------------------------------------------------------------------------
+// Return store that is responsible for handling the database file.
+// ---------------------------------------------------------------------------
+// 	
+CDiagResultsDbStore& CDiagResultsDbSession::Store()
+    {
+    return *iStore;
+    }
+
+// ---------------------------------------------------------------------------
+// Service function. Searches for newest test results. 
+//    Related functions: 
+//    ExistingRecordsAsyncL (initiates async fetch of test records)
+//    CancelLastResultsL (cancel async fetch)
+//    ExistingRecordsL (retrieves test records)
+// ---------------------------------------------------------------------------
+// 
+void CDiagResultsDbSession::GetLastResultsL( const RMessage2 &aMessage )
+    {
+    if ( iBufferedLastResults == NULL )
+        {
+        User::Leave ( KErrNotFound );
+        }
+       
+    ReadBufferL( aMessage, 0, iBuffer );
+      
+    RBufWriteStream stream ( *iBuffer );
+    CleanupClosePushL( stream );
+    
+    stream.WriteInt16L( iBufferedLastResults->Count() );
+    
+    for ( TInt i = 0; i < iBufferedLastResults->Count(); ++i )
+        {    
+        CDiagResultsDatabaseItem* item = (*iBufferedLastResults)[i];
+        
+        if ( item == NULL )
+            {
+            stream.WriteUint8L(0); 
+            }
+        else 
+            {
+            stream.WriteUint8L(1);
+            (*iBufferedLastResults)[i]->ExternalizeL( stream );
+            }
+        }
+
+    if ( iBuffer->Ptr(0).Length() > aMessage.GetDesMaxLength(0) )
+        {
+        User::Leave( KErrOverflow );
+        }
+   
+    stream.CommitL();
+     
+    CleanupStack::PopAndDestroy( &stream );
+    
+    aMessage.Write( 0, iBuffer->Ptr(0) ); //write to client's address space 
+         
+    iBufferedLastResults->ResetAndDestroy();
+    iBufferedLastResults->Close();
+    delete iBufferedLastResults;
+    iBufferedLastResults = NULL;   
+    }
+
+
+// ---------------------------------------------------------------------------
+// Service function. Get single test result (the newest).
+// ---------------------------------------------------------------------------
+//   
+void CDiagResultsDbSession::GetSingleLastResultL( const RMessage2 &aMessage )
+    {
+    ReadBufferL( aMessage, 0, iBuffer );
+          
+    RBufWriteStream stream ( *iBuffer );
+    CleanupClosePushL( stream );
+    
+    if ( iBufferedSingleResult )
+        {
+        stream.WriteInt8L( 1 );
+        
+        iBufferedSingleResult->ExternalizeL( stream );
+        
+        }
+    else //NULL
+        {
+        stream.WriteInt8L( 0 );
+        }
+    
+    stream.CommitL();
+    CleanupStack::PopAndDestroy( &stream );
+    
+    aMessage.Write( 0, iBuffer->Ptr(0) );
+            
+    delete iBufferedSingleResult;
+    iBufferedSingleResult = NULL;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Service function. Cancel InitiateGetLastResults method.
+// ---------------------------------------------------------------------------
+//     
+void CDiagResultsDbSession::CancelLastResultsL( const RMessage2 & /*aMessage*/ )
+    {
+      if ( !iLastResultsMsg.IsNull() )
+        {
+        iStore->Cancel();    
+        iLastResultsMsg.Complete( KErrCancel );  
+        
+        if ( iBufferedLastResults )
+            {
+            iBufferedLastResults->ResetAndDestroy();
+            delete iBufferedLastResults;
+            iBufferedLastResults = NULL;
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Service function. Retrieve uid of the newest test record.
+// ---------------------------------------------------------------------------
+// 
+void CDiagResultsDbSession::GetLastRecordL( const RMessage2 &aMessage )
+    {
+    RArray<TUid> uids;
+    CleanupClosePushL ( uids );
+    iStore->RecordUidsL( uids );
+    
+    if ( uids.Count() == 0 )
+        {
+        User::Leave( KErrNotFound );
+        }
+    
+    TPckgBuf<TUid> pckg( uids[uids.Count() -1] ); //newest record is the last
+    aMessage.Write( 0, pckg );
+    
+    CleanupStack::PopAndDestroy( &uids );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Service function. Try to find a test record that was suspended.
+// Leave with KErrNotFound if such test record is not found.
+// ---------------------------------------------------------------------------
+// 
+void CDiagResultsDbSession::GetLastNotCompletedRecordL( const RMessage2 &aMessage )
+    {
+    RArray<TUid> uids;
+    CleanupClosePushL ( uids );
+    iStore->RecordUidsL( uids );
+    
+    TBool found = EFalse;
+    
+    // newest record are on the top.
+	for (TInt i = uids.Count() -1; i >= 0; --i)
+	    {
+	    CDiagResultsDbTestRecordHandle* handle = 
+	                                iStore->OpenExistingHandleL( uids[i] );
+	    
+	    CleanupStack::PushL (handle);
+        
+        if( handle->RecordInfo().iRecordStatus != 
+                                 TDiagResultsDatabaseTestRecordInfo::ECompleted &&
+               !handle->RecordInfo().iCompleted )
+                                 
+            {
+            TPckgBuf<TUid> pckg( handle->RecordInfo().iRecordId ); 
+            aMessage.Write( 0, pckg );
+            found = ETrue;
+            CleanupStack::PopAndDestroy( handle );
+            break;
+            }     
+        
+        CleanupStack::PopAndDestroy( handle );
+	    }
+	
+    CleanupStack::PopAndDestroy( &uids );
+	 
+    if ( !found )
+        {
+        User::Leave ( KErrNotFound );
+        }  
+    }
+
+// ---------------------------------------------------------------------------
+// Service function. Retrieve all test record uids that there are.
+// ---------------------------------------------------------------------------
+//     
+void CDiagResultsDbSession::GetRecordListL( const RMessage2 &aMessage )
+    {    
+    ReadBufferL( aMessage, 0, iBuffer );
+   
+    RArray<TUid> uids; 
+    CleanupClosePushL( uids );
+    iStore->RecordUidsL( uids );
+    
+    RBufWriteStream stream ( *iBuffer );
+    CleanupClosePushL( stream );
+    stream.WriteInt16L( uids.Count() );
+    
+    for ( TInt i = 0; i < uids.Count(); ++i )
+        {    
+        stream.WriteInt32L( uids[i].iUid );  
+        }
+
+    if ( iBuffer->Ptr(0).Length() > aMessage.GetDesMaxLength(0) )
+        {
+        User::Leave( KErrOverflow );
+        }
+    
+    aMessage.Write( 0, iBuffer->Ptr(0) ); //write to client's address space 
+   
+    CleanupStack::PopAndDestroy( &stream );
+    CleanupStack::PopAndDestroy( &uids );
+
+    }
+
+// ---------------------------------------------------------------------------
+// Service function. Return overviews of test records.
+// ---------------------------------------------------------------------------
+//     
+void CDiagResultsDbSession::GetRecordInfoListL( const RMessage2 &aMessage )
+    {
+    ReadBufferL( aMessage, 0, iBuffer );
+    
+    CArrayFixFlat<TDiagResultsDatabaseTestRecordInfo>* array = new (ELeave) 
+        CArrayFixFlat<TDiagResultsDatabaseTestRecordInfo>(KArrayGranuality);
+    CleanupStack::PushL (array);
+    
+    RArray<TUid> uids;
+    CleanupClosePushL ( uids );
+    iStore->RecordUidsL( uids );
+    
+	for (TInt i = 0; i < uids.Count(); ++i)
+	    {
+	    CDiagResultsDbTestRecordHandle* handle = 
+	                                iStore->OpenExistingHandleL( uids[i] );
+	    
+	    CleanupStack::PushL (handle);
+        array->AppendL( handle->RecordInfo() );
+        
+        CleanupStack::PopAndDestroy( handle );
+	    }
+	
+	CleanupStack::PopAndDestroy( &uids );
+	
+    TDiagResultsDbRecordInfoArrayPacked packedArray ( iBuffer );
+    packedArray.PackArrayL ( *array );
+    
+    if ( iBuffer->Ptr(0).Length() > aMessage.GetDesMaxLength(0) )
+        {
+        User::Leave( KErrOverflow );
+        }
+	
+    aMessage.Write( 0, iBuffer->Ptr(0) ); //write to client's address space 
+   
+    CleanupStack::PopAndDestroy( array );
+    
+    }
+ 
+// ---------------------------------------------------------------------------
+// Helper function to read a buffer from client side. Leaves the buffer
+// onto cleanup stack IF it has to create a new one.
+// ---------------------------------------------------------------------------
+//    
+void CDiagResultsDbSession::ReadBufferL(const RMessage2& aMessage, TInt aParam, 
+                                                            CBufFlat*& aBuffer)
+	{
+	TInt desLen = aMessage.GetDesLengthL(aParam);
+
+	if(desLen >= 0)
+		{		
+		if (aBuffer==NULL)
+			{
+			aBuffer = CBufFlat::NewL(KArrayGranuality);
+			aBuffer->ResizeL(desLen);
+			CleanupStack::PushL(aBuffer);
+			}
+		else if (desLen > aBuffer->Ptr(0).MaxLength())
+			{
+			iBuffer->Delete( 0, iBuffer->Size() ); // delete old data.
+			// we have to increase the size of aBuffer	
+			aBuffer->ResizeL(desLen);		
+			}
+
+		TPtr8 desPtr = aBuffer->Ptr(0);
+		aMessage.ReadL(aParam, desPtr);
+
+		}
+	else
+		{
+		// desLen is negative leave with an error.
+		User::Leave(KErrArgument);
+		}
+	}   
+
+// ---------------------------------------------------------------------------
+// Store observer method. This is called after store has retrieved
+// test records from the DB file.
+// ---------------------------------------------------------------------------
+// 
+void CDiagResultsDbSession::ExistingRecordsL( TInt aError, 
+                            RPointerArray<CDiagResultsDbTestRecord>* aArray )
+    {
+    CleanupStack::PushL ( aArray );
+    CleanupResetAndDestroyClosePushL( *aArray );
+
+    //Check if there were any errors during loading the test records.
+    if ( aError != KErrNone )
+        {
+        
+        if ( iLastResultCommand == 
+             DiagResultsDbCommon::EInitiateGetLastResults )
+            {
+            iLastResultsMsg.Complete ( aError );            
+            }
+        else if ( iLastResultCommand == 
+                  DiagResultsDbCommon::EInitiateGetSingleLastResult  )
+            {
+            iLastSingleResultsMsg.Complete ( aError );
+            }        
+        
+        CleanupStack::PopAndDestroy( aArray );
+        CleanupStack::PopAndDestroy( aArray ); //delete the pointer  
+        return;
+        }
+        	
+	switch( iLastResultCommand )
+        {
+	
+	//Find multiple last results
+	//buffer contains the uids to be searched.
+	//See RDiagResultsDatabase::InitiateGetLastResults.
+	case DiagResultsDbCommon::EInitiateGetLastResults:
+	    {
+        //Trap is needed so that we can complete client's request
+        //if any errors occur.
+        TRAPD(error, FindLastResultsL( *aArray ));	        
+	        	    
+	    if ( error != KErrNone )
+	        {	        
+	        iLastResultsMsg.Complete (error);	        
+	        break;
+	        }
+	    else 
+	        {
+	        iLastResultsMsg.Complete (KErrNone);    
+	        }
+	    	    	  
+	    break;
+	    }
+	    
+	  // Find single test result  
+	  // see RDiagResultsDatabase::InitiateGetLastResult.
+     case DiagResultsDbCommon::EInitiateGetSingleLastResult:
+        {        
+        TPckgBuf<TUid> uidpckg;
+	    iLastSingleResultsMsg.Read(0, uidpckg);
+        TUid resultsItemUid = uidpckg();
+                 	    	            
+        CDiagResultsDatabaseItem* item = NULL;
+        
+        // Trap any errors and complete client's request if there
+        // are any errors.
+        TRAPD(error, item = FindDatabaseItemL( resultsItemUid, aArray)) ;	                            	                           
+
+        if ( error != KErrNone )
+            {
+            delete item;
+            item = NULL;
+            
+            iLastSingleResultsMsg.Complete (error);
+            break;
+            }
+	        
+	    if ( item == NULL ) //Not found
+	        {
+	        iBufferedSingleResult = NULL;
+	        
+	        //Check also the last results buffer  
+	        CheckLastResultsBufferL( resultsItemUid, iBufferedSingleResult );
+	        }
+	    else 
+	        {	                	                
+	        iBufferedSingleResult = item;
+	        }          
+	       
+	   
+	       
+	    iLastSingleResultsMsg.Complete (KErrNone);
+	    break;
+        }  
+	  
+	  default:
+	    {
+	    User::Panic ( _L("Diag results DB"), 
+	                  DiagResultsDbCommon::EUnknownLastResultState );
+	    }	    	    
+      }
+    
+    iLastResultCommand = 0;  
+      
+    CleanupStack::PopAndDestroy( aArray ); //call reset and destroy + close
+    CleanupStack::PopAndDestroy( aArray ); //delete the pointer
+    }
+
+
+// ---------------------------------------------------------------------------
+// Read UIDs from a stream and search last results.
+// ---------------------------------------------------------------------------
+// 
+void CDiagResultsDbSession::FindLastResultsL( 
+                            RPointerArray<CDiagResultsDbTestRecord>& aArray )
+    {
+    
+	CArrayFixFlat<TUid>* uidArray = new (ELeave) 
+	                                    CArrayFixFlat<TUid>(KArrayGranuality);
+	CleanupStack::PushL( uidArray );
+	     
+    RBufReadStream stream( *iBuffer );
+    CleanupClosePushL ( stream );
+        
+    TInt8 count = stream.ReadInt8L();
+        
+    for ( TInt i = 0; i < count; ++i )
+        {
+        TInt32 uid = stream.ReadInt32L();
+            
+        uidArray->AppendL( TUid::Uid( uid ));
+        }
+	    
+    CleanupStack::PopAndDestroy( &stream );	 
+	    	    
+	iBufferedLastResults = new (ELeave) RPointerArray<CDiagResultsDatabaseItem>;
+	    	    
+	SearchLastResultsL( *uidArray, aArray, *iBufferedLastResults  );
+	
+	//last results could be also in the last results buffer.
+	CheckLastResultsBufferL( *uidArray, *iBufferedLastResults );
+	    
+	  // there must be exactly the same number of cells in both arrays. 
+	if ( uidArray->Count() != iBufferedLastResults->Count() ) 
+	    {
+	    User::Panic ( _L("Diag results DB"), 
+	                  DiagResultsDbCommon::EGetLastResultsMismatch );
+	    }
+	    
+	CleanupStack::PopAndDestroy( uidArray );   
+    }
+
+
+// ---------------------------------------------------------------------------
+// Check last result buffer for test results.
+// ---------------------------------------------------------------------------
+// 
+void CDiagResultsDbSession::CheckLastResultsBufferL( 
+                         const CArrayFixFlat<TUid>& aUidArray,                           
+                         RPointerArray<CDiagResultsDatabaseItem>& aResultsArray )
+    {        
+    CDiagResultsDbTestRecord* buffer = iStore->OpenExistingLastResultsBufferL(); 
+    CleanupStack::PushL( buffer );
+    
+    for (TInt i = 0; i < aResultsArray.Count(); ++i)
+        {        
+        if ( aResultsArray[i] == NULL )
+            {
+            TUid uid = aUidArray[i];
+            
+            CDiagResultsDatabaseItem* item = buffer->FindTestRecord( uid );
+            
+            if ( item )
+                {
+                buffer->RemoveL( uid );
+                aResultsArray[i] = item;
+                }            
+            }        
+        }
+    
+    CleanupStack::PopAndDestroy( buffer );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Check last result buffer for test result.
+// ---------------------------------------------------------------------------
+// 
+void CDiagResultsDbSession::CheckLastResultsBufferL( 
+                         TUid aTestUid,                           
+                         CDiagResultsDatabaseItem*& aResult )
+    {
+    
+    
+    CDiagResultsDbTestRecord* buffer = iStore->OpenExistingLastResultsBufferL(); 
+    CleanupStack::PushL( buffer );
+ 
+    CDiagResultsDatabaseItem* item = buffer->FindTestRecord( aTestUid );
+            
+    if ( item )
+        {
+        buffer->RemoveL( aTestUid );
+        aResult = item;                                                
+        }
+    
+    CleanupStack::PopAndDestroy( buffer );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Searches for the newest test results.
+// ---------------------------------------------------------------------------
+// 
+void CDiagResultsDbSession::SearchLastResultsL( 
+                         const CArrayFixFlat<TUid>& aUidArray, 
+                         RPointerArray<CDiagResultsDbTestRecord>& aTestRecordArray, 
+                         RPointerArray<CDiagResultsDatabaseItem>& aResultsArray )
+            
+    {   
+    //Search all records for certain uid.
+	for ( TInt i = 0; i < aUidArray.Count(); ++i )
+	    {
+	      
+	    CDiagResultsDatabaseItem* item = 
+	                            FindDatabaseItemL( aUidArray[i], &aTestRecordArray );	                            	                           
+	        
+	    if ( item == NULL ) //Not found
+	        {
+	        aResultsArray.Append(NULL);
+	        }
+	     else 
+	        {	                	                
+	        aResultsArray.Append( item );
+	        }          
+	    }
+    }
+	     
+
+// ---------------------------------------------------------------------------
+// Indicates has session written any data into the DB file. 
+// To be exact only subsession writes data into the file.
+// ---------------------------------------------------------------------------
+//     
+void CDiagResultsDbSession::HasWritten()
+    {
+    iHasWrittenData = ETrue;
+    }
+
+// ---------------------------------------------------------------------------
+// Turn off compacting.
+// ---------------------------------------------------------------------------
+//  
+void CDiagResultsDbSession::DoNotCompact()
+    {
+    iHasWrittenData = EFalse;
+    }
+
+// ---------------------------------------------------------------------------
+// Helper function to seach an item from a pointer array.
+// Starts from the newest record to search for an UID.
+// ---------------------------------------------------------------------------
+// 
+CDiagResultsDatabaseItem* CDiagResultsDbSession::FindDatabaseItemL( TUid aUid, 
+                             RPointerArray<CDiagResultsDbTestRecord>* aArray )    
+    {
+    
+    //Check that there is a test record.
+    if ( !aArray || aArray->Count() == 0 )
+        {
+        return NULL;
+        }
+    
+    // start from the newest record
+    for (TInt x = aArray->Count() -1; x >= 0 ; --x ) 
+	    {
+	    CDiagResultsDbTestRecord* record = (*aArray)[x];
+	    
+	    //Assumes that there is only MAX one specific UID in the test record.        
+	    for ( TInt y = 0; y < record->Count(); ++y )
+	        {
+	        CDiagResultsDatabaseItem* item = record->GetItem( y );
+	                 
+             //	 Search for a test result that is not skipped / cancelled.                 
+	         if (  item->TestUid() == aUid && 
+	              (item->TestResult() == CDiagResultsDatabaseItem::ESuccess ||
+	               item->TestResult() == CDiagResultsDatabaseItem::EFailed ))
+	            {
+	            //Remove the found item to speed up look up times.
+	            //This does not remove it from the DB file.
+	            record->RemoveL( y ); 
+	            return item;
+	            }
+	        }     
+	    }
+	     
+	return NULL;  
+    }