memspy/Console/Source/ConsoleMenu.cpp
changeset 0 a03f92240627
child 20 a71a3e32a2ae
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/memspy/Console/Source/ConsoleMenu.cpp	Tue Feb 02 01:57:15 2010 +0200
@@ -0,0 +1,675 @@
+/*
+* Copyright (c) 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 "ConsoleMenu.h"
+
+// System includes
+#include <e32debug.h>
+
+// Engine includes
+#include <memspyengineclientinterface.h>
+#include <memspy/engine/memspyengine.h>
+#include <memspy/engine/memspyenginehelperheap.h>
+#include <memspy/engine/memspyengineoutputsink.h>
+#include <memspy/engine/memspyenginehelperstack.h>
+#include <memspy/engine/memspyengineobjectthread.h>
+#include <memspy/engine/memspyengineobjectprocess.h>
+#include <memspy/engine/memspydevicewideoperations.h>
+#include <memspy/engine/memspyengineobjectcontainer.h>
+#include <memspy/engine/memspyenginehelperkernelcontainers.h>
+#include <memspy/engine/memspyengineobjectthreadinfoobjects.h>
+#include <memspy/engine/memspyengineobjectthreadinfocontainer.h>
+
+// User includes
+#include "ConsoleConstants.h"
+#include "ConsoleDWOperation.h"
+
+
+CMemSpyConsoleMenu::CMemSpyConsoleMenu( CMemSpyEngine& aEngine, CConsoleBase& aConsole )
+:   CActive( EPriorityHigh ), iEngine( aEngine ), iConsole( aConsole )
+    {
+    CActiveScheduler::Add( this );
+    iEngine.SetObserver( this );
+    }
+
+
+CMemSpyConsoleMenu::~CMemSpyConsoleMenu()
+    {
+    Cancel();
+    iEngine.SetObserver( NULL );
+    }
+
+
+void CMemSpyConsoleMenu::ConstructL()
+    {
+    DrawMenuL();
+    WaitForInput();
+    }
+
+
+CMemSpyConsoleMenu* CMemSpyConsoleMenu::NewLC( CMemSpyEngine& aEngine, CConsoleBase& aConsole )
+    {
+    CMemSpyConsoleMenu* self = new(ELeave) CMemSpyConsoleMenu( aEngine, aConsole );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    return self;
+    }
+
+
+void CMemSpyConsoleMenu::DrawMenuL()
+    {
+    iConsole.ClearScreen();
+   
+    // First line - sink type (defaults to file)
+    _LIT( KLine1, "1 or T. Toggle output mode between file or trace [%S]" );
+    if  ( iEngine.SinkType() == ESinkTypeDebug )
+        {
+        _LIT( KLine1Trace, "Trace" );
+        iConsole.Printf( KLine1, &KLine1Trace );
+        }
+    else
+        {
+        _LIT( KLine1File, "File" );
+        iConsole.Printf( KLine1, &KLine1File );
+        }
+    iConsole.Write( KMemSpyConsoleNewLine );
+
+    // Kernel heap dump
+    _LIT( KLine2, "2 or K. Dump kernel heap data" );
+    iConsole.Write( KLine2 );
+    iConsole.Write( KMemSpyConsoleNewLine );
+
+    // Kernel heap dump
+    _LIT( KLine3, "3 or O. Dump kernel object listing" );
+    iConsole.Write( KLine3 );
+    iConsole.Write( KMemSpyConsoleNewLine );
+
+    // Heap (CSV) listing
+    _LIT( KLine4, "4 or H. Heap CSV-information (for all threads)" );
+    iConsole.Write( KLine4 );
+    iConsole.Write( KMemSpyConsoleNewLine );
+
+    // Stack (CSV) listing
+    _LIT( KLine5, "5 or S. Stack CSV-information (for all threads)" );
+    iConsole.Write( KLine5 );
+    iConsole.Write( KMemSpyConsoleNewLine );
+
+    // Heap data
+    _LIT( KLine6, "6 or D. Get heap data for a user-thread" );
+    iConsole.Write( KLine6 );
+    iConsole.Write( KMemSpyConsoleNewLine );
+
+    // Heap cell listing
+    _LIT( KLine7, "7 or L. Get heap cell list for a user-thread" );
+    iConsole.Write( KLine7 );
+    iConsole.Write( KMemSpyConsoleNewLine );
+
+    // Exit key
+    _LIT( KLine8, "8 or X. Exit" );
+    iConsole.Write( KLine8 );
+    iConsole.Write( KMemSpyConsoleNewLine );
+
+    // Spacer
+    iConsole.Write( KMemSpyConsoleNewLine );
+    iConsole.Write( KMemSpyConsoleNewLine );
+
+    // Status message
+    iStatusMessagePos = iConsole.CursorPos();
+    RedrawStatusMessage();
+
+    // Spacer
+    iConsole.Write( KMemSpyConsoleNewLine );
+
+    // Show input prompt.
+    iCommandPromptPos = iConsole.CursorPos();
+    RedrawInputPrompt();
+    }
+
+
+void CMemSpyConsoleMenu::WaitForInput()
+    {
+    ASSERT( !IsActive() );
+    iConsole.Read( iStatus );
+    SetActive();
+    }
+
+
+void CMemSpyConsoleMenu::RunL()
+    {
+    TKeyCode key = iConsole.KeyCode();
+    //
+#ifdef _DEBUG
+    RDebug::Printf( "[MCon] CMemSpyConsoleMenu::RunL() - START - key = %d", key );
+#endif
+    //
+    if  ( key == EKeyEnter || key == KMemSpyUiS60KeyCodeButtonOk || key == KMemSpyUiS60KeyCodeRockerEnter )
+        {
+        TRAP_IGNORE( ProcessCommandBufferL() );
+        }
+    else if ( key == EKeyEscape || key == KMemSpyUiS60KeyCodeButtonCancel )
+        {
+        ClearCommandBuffer();
+        RedrawInputPrompt();
+        }   
+    else if ( key == EKeyBackspace )
+        {
+        const TInt cmdBufLength = iCommandBuffer.Length();
+        if  ( cmdBufLength > 0 )
+            {
+            iCommandBuffer.SetLength( cmdBufLength - 1 );
+            RedrawInputPrompt();
+            }
+        }
+    else
+        {
+        TChar character( key );
+        if  ( character.IsPrint() )
+            {
+            if  ( iCommandBuffer.Length() < iCommandBuffer.MaxLength() )
+                {
+                iCommandBuffer.Append( TChar( key ) );
+                }
+
+            RedrawInputPrompt();
+            }
+        }
+
+    WaitForInput();
+
+#ifdef _DEBUG
+    RDebug::Printf( "[MCon] CMemSpyConsoleMenu::RunL() - END" );
+#endif
+    }
+
+
+void CMemSpyConsoleMenu::DoCancel()
+    {
+    iConsole.ReadCancel();
+    }
+
+
+void CMemSpyConsoleMenu::OnCmdSinkTypeToggleL()
+    {
+    if  ( iEngine.SinkType() == ESinkTypeDebug )
+        {
+        iEngine.InstallSinkL( ESinkTypeFile );
+        }
+    else
+        {
+        iEngine.InstallSinkL( ESinkTypeDebug );
+        }
+    }
+
+
+void CMemSpyConsoleMenu::OnCmdHeapDataKernelL()
+    {
+#ifdef _DEBUG
+    RDebug::Printf( "[MCon] CMemSpyConsoleMenu::OnCmdHeapDataKernelL() - START" );
+#endif
+
+    _LIT( KMsg, "Ouputting Kernel data..." );
+    RedrawStatusMessage( KMsg );
+
+    iEngine.HelperHeap().OutputHeapDataKernelL();
+
+    RedrawStatusMessage( KNullDesC );
+    }
+
+
+void CMemSpyConsoleMenu::OnCmdKernelObjectListingL()
+    {
+#ifdef _DEBUG
+    RDebug::Printf( "[MCon] CMemSpyConsoleMenu::OnCmdKernelObjectListingL() - START" );
+#endif
+
+    _LIT( KMsg, "Ouputting Kernel Object listing..." );
+    RedrawStatusMessage( KMsg );
+    //
+    CMemSpyEngineHelperKernelContainers& kernelContainerManager = iEngine.HelperKernelContainers();
+    CMemSpyEngineGenericKernelObjectContainer* model = kernelContainerManager.ObjectsAllL();
+    CleanupStack::PushL( model );
+    //
+    CMemSpyEngineOutputSink& sink = iEngine.Sink();
+    model->OutputL( sink );
+    //
+    CleanupStack::PopAndDestroy( model );
+
+    RedrawStatusMessage( KNullDesC );
+    }
+
+
+void CMemSpyConsoleMenu::OnCmdCSVListingStackL()
+    {
+#ifdef _DEBUG
+    RDebug::Printf( "[MCon] CMemSpyConsoleMenu::OnCmdCSVListingStackL() - START" );
+#endif
+
+    iEngine.HelperStack().OutputStackInfoForDeviceL();
+    }
+
+
+void CMemSpyConsoleMenu::OnCmdCSVListingHeapL()
+    {
+#ifdef _DEBUG
+    RDebug::Printf( "[MCon] CMemSpyConsoleMenu::OnCmdCSVListingHeapL() - START" );
+#endif
+
+    iEngine.HelperHeap().OutputHeapInfoForDeviceL();
+    }
+
+
+void CMemSpyConsoleMenu::OnCmdHeapDataUserL()
+    {
+#ifdef _DEBUG
+    RDebug::Printf( "[MCon] CMemSpyConsoleMenu::OnCmdHeapDataUserL() - START" );
+#endif
+
+    GetProcessName();
+
+    // Work out what to do.
+    iCommandBuffer.Trim();
+
+#ifdef _DEBUG
+    RDebug::Print( _L("[MCon] CMemSpyConsoleMenu::OnCmdHeapDataUserL() - requested dump heap for proc: %S"), &iCommandBuffer );
+#endif
+
+    if  ( iCommandBuffer.Length() > 0 )
+        {
+        iConsole.Write( KMemSpyConsoleNewLine );
+        iConsole.Write( KMemSpyConsoleNewLine );
+        //
+        HBufC* cmdBuf = HBufC::NewLC( KMemSpyMaxInputBufferLength + 10 );
+        TPtr pCmdBuf( cmdBuf->Des() );
+        pCmdBuf.Copy( iCommandBuffer );
+        pCmdBuf.Append( KMemSpyConsoleWildcardCharacter );
+        //
+        CMemSpyEngineObjectContainer& container = iEngine.Container();
+        const TInt count = container.Count();
+        TFullName fullThreadName;
+        //
+        TInt index = 0;
+#ifdef _DEBUG
+        RDebug::Printf( "[MCon] CMemSpyConsoleMenu::OnCmdHeapDataUserL() - procCount: %d", count );
+#endif
+
+        while( index < count )
+            {
+            CMemSpyProcess& process = container.At( index );
+            const TPtrC processName( process.Name() );
+#ifdef _DEBUG
+            RDebug::Print( _L("[MCon] CMemSpyConsoleMenu::OnCmdHeapDataUserL() - procName: 0x%08x %S"), &process, &processName );
+#endif
+
+            //
+            if  ( processName.MatchF( pCmdBuf ) >= 0 )
+                {
+                _LIT( KProcessingRequest, "** Dumping Heap Data for thread: %S" );
+                const TInt threadCount = process.Count();
+                for( TInt i=0; i<threadCount; i++ )
+                    {
+                    CMemSpyThread& thread = process.At( i );
+                    //
+                    fullThreadName = thread.FullName();
+                    iConsole.Printf( KProcessingRequest, &fullThreadName );
+                    iConsole.Write( KMemSpyConsoleNewLine );
+                    //
+                    TRAP_IGNORE( iEngine.HelperHeap().OutputHeapDataUserL( thread ) );
+                    }
+
+                break;
+                }
+            
+            ++index;
+            }
+
+        CleanupStack::PopAndDestroy( cmdBuf );
+        DrawMenuL();
+        }
+    else
+        {
+        // Bad user data entry
+        DrawMenuL();
+        _LIT( KInvalidEntry, "*** ERROR - Invalid Command ***" );
+        RedrawStatusMessage( KInvalidEntry );
+        RedrawInputPrompt();
+        }
+    }
+
+
+void CMemSpyConsoleMenu::OnCmdHeapCellListUserL()
+    {
+#ifdef _DEBUG
+    RDebug::Printf( "[MCon] CMemSpyConsoleMenu::OnCmdHeapCellListUserL() - START" );
+#endif
+
+    GetProcessName();
+
+    // Work out what to do.
+    iCommandBuffer.Trim();
+    if  ( iCommandBuffer.Length() > 0 )
+        {
+        iConsole.Write( KMemSpyConsoleNewLine );
+        iConsole.Write( KMemSpyConsoleNewLine );
+        //
+        HBufC* cmdBuf = HBufC::NewLC( KMemSpyMaxInputBufferLength + 10 );
+        TPtr pCmdBuf( cmdBuf->Des() );
+        pCmdBuf.Copy( iCommandBuffer );
+        pCmdBuf.Append( KMemSpyConsoleWildcardCharacter );
+        //
+        CMemSpyEngineObjectContainer& container = iEngine.Container();
+        const TInt count = container.Count();
+        TFullName fullThreadName;
+        //
+        TInt index = 0;
+        while( index < count )
+            {
+            CMemSpyProcess& process = container.At( index );
+            const TPtrC processName( process.Name() );
+            //
+            if  ( processName.MatchF( pCmdBuf ) >= 0 )
+                {
+                _LIT( KProcessingRequest, "** Dumping Heap Cell List for thread: %S" );
+                const TInt threadCount = process.Count();
+                for( TInt i=0; i<threadCount; i++ )
+                    {
+                    CMemSpyThread& thread = process.At( i );
+                    //
+                    fullThreadName = thread.FullName();
+                    iConsole.Printf( KProcessingRequest, &fullThreadName );
+                    iConsole.Write( KMemSpyConsoleNewLine );
+                    //
+                    TRAP_IGNORE( iEngine.HelperHeap().OutputCellListingUserL( thread ) );
+                    }
+
+                break;
+                }
+            
+            ++index;
+            }
+
+        CleanupStack::PopAndDestroy( cmdBuf );
+        DrawMenuL();
+        }
+    else
+        {
+        // Bad user data entry
+        DrawMenuL();
+        _LIT( KInvalidEntry, "*** ERROR - Invalid Command ***" );
+        RedrawStatusMessage( KInvalidEntry );
+        RedrawInputPrompt();
+        }
+    }
+
+
+void CMemSpyConsoleMenu::ClearCommandBuffer()
+    {
+    iCommandBuffer.Zero();
+    }
+
+
+void CMemSpyConsoleMenu::ProcessCommandBufferL()
+    {
+    iCommandBuffer.Trim();
+    //
+#ifdef _DEBUG
+    RDebug::Print( _L("[MCon] CMemSpyConsoleMenu::ProcessCommandBufferL() - cmd: [%S]"), &iCommandBuffer );
+#endif
+    //
+    TBool validCommand = EFalse;
+    if  ( iCommandBuffer.Length() == 1 )
+        {
+        // Reset if not recognised...
+        validCommand = ETrue;
+
+        const TChar cmd = iCommandBuffer[ 0 ]; 
+        switch( cmd )
+            {
+        case '1':
+        case 't':
+        case 'T':
+            OnCmdSinkTypeToggleL();
+            break;
+        case '2':
+        case 'k':
+        case 'K':
+            OnCmdHeapDataKernelL();
+            break;
+        case '3':
+        case 'o':
+        case 'O':
+            OnCmdKernelObjectListingL();
+            break;
+        case '4':
+        case 'h':
+        case 'H':
+            OnCmdCSVListingHeapL();
+            break;
+        case '5':
+        case 's':
+        case 'S':
+            OnCmdCSVListingStackL();
+            break;
+        case '6':
+        case 'd':
+        case 'D':
+            OnCmdHeapDataUserL();
+            break;
+        case '7':
+        case 'l':
+        case 'L':
+            OnCmdHeapCellListUserL();
+            break;
+        case '8':
+        case 'x':
+        case 'X':
+            CActiveScheduler::Stop();
+            return; // NB: avoid redrawing menu when exiting
+
+        default:
+            validCommand = EFalse;
+            break;
+            }
+        }
+    //
+    ClearCommandBuffer();
+    //
+    if  ( !validCommand )
+        {
+        _LIT( KInvalidEntry, "*** ERROR - Invalid Command ***" );
+        RedrawStatusMessage( KInvalidEntry );
+        RedrawInputPrompt();
+        }
+    else
+        {
+        DrawMenuL();
+        }
+
+#ifdef _DEBUG
+    RDebug::Printf( "[MCon] CMemSpyConsoleMenu::ProcessCommandBufferL() - END" );
+#endif
+    }
+
+
+void CMemSpyConsoleMenu::RedrawInputPrompt()
+    {
+    iConsole.SetCursorPosAbs( iCommandPromptPos );
+    iConsole.ClearToEndOfLine();
+    iConsole.Printf( KMemSpyConsoleInputPrompt, &iCommandBuffer );
+    }
+
+
+void CMemSpyConsoleMenu::RedrawStatusMessage()
+    {
+    RedrawStatusMessage( KNullDesC );
+    }
+
+
+void CMemSpyConsoleMenu::RedrawStatusMessage( const TDesC& aMessage )
+    {
+    iConsole.SetCursorPosAbs( iStatusMessagePos );
+    iConsole.ClearToEndOfLine();
+    iConsole.Write( aMessage );
+    iConsole.Write( KMemSpyConsoleNewLine );
+    }
+
+
+void CMemSpyConsoleMenu::GetProcessName()
+    {
+    iConsole.ClearScreen();
+
+    _LIT( KPromptMessage1, "Enter the full or partial process name" );
+    iConsole.Write( KPromptMessage1 );
+    iConsole.Write( KMemSpyConsoleNewLine );
+    _LIT( KPromptMessage2, "of the process that you are interested in." );
+    iConsole.Write( KPromptMessage2 );
+    iConsole.Write( KMemSpyConsoleNewLine );
+    _LIT( KPromptMessage3, "Press \'enter\' when done." );
+    iConsole.Write( KPromptMessage3 );
+    iConsole.Write( KMemSpyConsoleNewLine );
+    //
+    ClearCommandBuffer();
+    iConsole.Write( KMemSpyConsoleNewLine );
+    iCommandPromptPos = iConsole.CursorPos();
+    RedrawInputPrompt();
+    //
+    TBool done = EFalse;
+    while( !done )
+        {
+        // Get a key
+        const TKeyCode key = iConsole.Getch();
+
+        // Process it
+#ifdef _DEBUG
+        RDebug::Printf( "[MCon] CMemSpyConsoleMenu::OnCmdHeapDataUserL() - START - key = %d", key );
+#endif
+        //
+        if  ( key == EKeyEnter || key == KMemSpyUiS60KeyCodeButtonOk || key == KMemSpyUiS60KeyCodeRockerEnter )
+            {
+            done = ETrue;
+            }
+        else if ( key == EKeyEscape || key == KMemSpyUiS60KeyCodeButtonCancel )
+            {
+            ClearCommandBuffer();
+            done = ETrue;
+            }   
+        else if ( key == EKeyBackspace )
+            {
+            const TInt cmdBufLength = iCommandBuffer.Length();
+            if  ( cmdBufLength > 0 )
+                {
+                iCommandBuffer.SetLength( cmdBufLength - 1 );
+                RedrawInputPrompt();
+                }
+            }
+        else
+            {
+            TChar character( key );
+            if  ( character.IsPrint() )
+                {
+                if  ( iCommandBuffer.Length() < iCommandBuffer.MaxLength() )
+                    {
+                    iCommandBuffer.Append( TChar( key ) );
+                    }
+
+                RedrawInputPrompt();
+                }
+            }
+        }
+    }
+
+
+void CMemSpyConsoleMenu::HandleMemSpyEngineEventL( MMemSpyEngineObserver::TEvent aEvent, TAny* aContext )
+    {
+    if  ( aEvent == MMemSpyEngineObserver::EHandleClientServerOperationRequest )
+        {
+        const TInt function = reinterpret_cast< TInt >( aContext );
+        InitiateMemSpyClientServerOperationL( function );
+        }
+    }
+
+
+void CMemSpyConsoleMenu::InitiateMemSpyClientServerOperationL( TInt aOpCode )
+    {
+#ifdef _DEBUG
+    RDebug::Printf( "[MCon] CMemSpyConsoleMenu::InitiateMemSpyClientServerOperationL() - START - aOpCode: %d, iRunningDeviceWideOperation: %d", aOpCode, iRunningDeviceWideOperation );
+#endif
+    //
+    if ( aOpCode == EMemSpyClientServerOpExit )
+        {
+        // Exit console app UI
+        CActiveScheduler::Stop();
+        }
+    else
+        {
+        CMemSpyDeviceWideOperations::TOperation op = CMemSpyDeviceWideOperations::EPerEntityGeneralSummary;
+        switch( aOpCode )
+            {
+        case EMemSpyClientServerOpSummaryInfo:
+            op = CMemSpyDeviceWideOperations::EPerEntityGeneralSummary;
+            break;
+        case EMemSpyClientServerOpSummaryInfoDetailed:
+            op = CMemSpyDeviceWideOperations::EPerEntityGeneralDetailed;
+            break;
+        //
+        case EMemSpyClientServerOpHeapInfo:
+            op = CMemSpyDeviceWideOperations::EPerEntityHeapInfo;
+            break;
+        case EMemSpyClientServerOpHeapCellListing:
+            op = CMemSpyDeviceWideOperations::EPerEntityHeapCellListing;
+            break;
+        case EMemSpyClientServerOpHeapData:
+            op = CMemSpyDeviceWideOperations::EPerEntityHeapData;
+            break;
+        //
+        case EMemSpyClientServerOpStackInfo:
+            op = CMemSpyDeviceWideOperations::EPerEntityStackInfo;
+            break;
+        case EMemSpyClientServerOpStackDataUser:
+            op = CMemSpyDeviceWideOperations::EPerEntityStackDataUser;
+            break;
+        case EMemSpyClientServerOpStackDataKernel:
+            op = CMemSpyDeviceWideOperations::EPerEntityStackDataKernel;
+            break;
+        
+        // These are not supported by the console UI
+        default:
+        case EMemSpyClientServerOpBitmapsSave:
+        case EMemSpyClientServerOpSendToBackground:
+        case EMemSpyClientServerOpBringToForeground:
+            User::Leave( KErrNotSupported );
+            break;
+            }
+
+        if  ( iRunningDeviceWideOperation )
+            {
+            User::Leave( KErrInUse );
+            }
+        else
+            {
+            iRunningDeviceWideOperation = ETrue;
+            TRAP_IGNORE( CMemSpyDeviceWideOperationWaiter::ExecuteLD( iEngine, op ) );
+            iRunningDeviceWideOperation = EFalse;
+            }
+        }
+
+#ifdef _DEBUG
+    RDebug::Printf( "[MCon] CMemSpyConsoleMenu::InitiateMemSpyClientServerOperationL() - END - aOpCode: %d", aOpCode );
+#endif
+    }
+
+
+