memspy/Engine/Source/ThreadAndProcess/MemSpyEngineObjectProcess.cpp
changeset 0 a03f92240627
child 20 a71a3e32a2ae
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/memspy/Engine/Source/ThreadAndProcess/MemSpyEngineObjectProcess.cpp	Tue Feb 02 01:57:15 2010 +0200
@@ -0,0 +1,632 @@
+/*
+* 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 <memspy/engine/memspyengineobjectprocess.h>
+
+// System includes
+#include <e32svr.h>
+#include <u32std.h>
+
+// Driver includes
+#include <memspy/driver/memspydriverclient.h>
+#include <memspy/driver/memspydriverpanics.h> // for terminate
+
+// User includes
+#include <memspy/engine/memspyengine.h>
+#include <memspy/engine/memspyengineutils.h>
+#include <memspy/engine/memspyengineobjectthread.h>
+
+// Literal constants
+_LIT( KMemSpyUnknownProcessName, "Unknown" );
+_LIT( KMemSpyUnknownExitCategory, "Unknown ExitCat" );
+_LIT( KMemSpyStandardProcessExtension, ".exe" );
+
+
+CMemSpyProcess::CMemSpyProcess( TProcessId aId, CMemSpyEngine& aEngine  )
+:   iId( aId ), iEngine( aEngine )
+    {
+    }
+
+
+CMemSpyProcess::~CMemSpyProcess()
+    {
+#ifdef _DEBUG
+    if  ( iName != NULL )
+        {
+        RDebug::Print(_L( "MEMSPY - dtor - CMemSpyProcess() - this: 0x%08x, name: %S"), this, iName);
+        }
+    else
+        {
+        RDebug::Printf( "MEMSPY - dtor - CMemSpyProcess() - this: 0x%08x", this );
+        }
+#endif
+
+    CloseAllThreads();
+    iThreads.Close();
+    delete iName;
+    delete iInfo;
+    }
+
+
+void CMemSpyProcess::ConstructL()
+    {
+    iInfo = new(ELeave) TMemSpyDriverProcessInfo();
+
+    RMemSpyDriverClient& driver = iEngine.Driver();
+    RProcess process;
+    User::LeaveIfError( driver.OpenProcess( iId, process ) );
+    CleanupClosePushL( process );
+
+    // Find the threads before we start tinkering with the process
+    // name
+    LocateThreadsL( process );
+
+    // Now build the process name
+    RefreshL( process );
+
+    CleanupStack::PopAndDestroy( &process );
+
+    
+#ifdef _DEBUG
+    if  ( iName != NULL )
+        {
+        RDebug::Print(_L( "MEMSPY - ctor - CMemSpyProcess() - this: 0x%08x, name: %S"), this, iName);
+        }
+    else
+        {
+        RDebug::Printf( "MEMSPY - ctor - CMemSpyProcess() - this: 0x%08x", this );
+        }
+#endif
+    }
+
+
+EXPORT_C CMemSpyProcess* CMemSpyProcess::NewL( const CMemSpyProcess& aCopyMe )
+    {
+    CMemSpyProcess* self = NewL( aCopyMe.Id(), aCopyMe.iEngine );
+    return self;
+    }
+
+
+CMemSpyProcess* CMemSpyProcess::NewL( TProcessId aId, CMemSpyEngine& aEngine )
+    {
+    CMemSpyProcess* self = CMemSpyProcess::NewL( aId, aEngine );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+
+CMemSpyProcess* CMemSpyProcess::NewLC( TProcessId aId, CMemSpyEngine& aEngine )
+    {
+    CMemSpyProcess* self = new(ELeave) CMemSpyProcess( aId, aEngine );
+    CleanupClosePushL( *self );
+    self->ConstructL();
+    return self;
+    }
+
+
+EXPORT_C void CMemSpyProcess::Close()
+    {
+    if  ( !OpenOrCloseInProgress() )
+        {
+        const TInt ac = AccessCount();
+        SetOpenOrCloseInProgress( ETrue );
+
+        // Calling close can do a "delete this" so make sure
+        // we don't try to access the object again in that situation...
+        CMemSpyEngineObject::Close();
+        if  ( ac - 1 > 0 )
+            {
+            SetOpenOrCloseInProgress( EFalse );
+            }
+        else
+            {
+            // We don't care - we've just been deleted!
+            }
+        }
+    }
+
+
+EXPORT_C void CMemSpyProcess::Open()
+    {
+    if  ( !OpenOrCloseInProgress() )
+        {
+        SetOpenOrCloseInProgress( ETrue );
+        CMemSpyEngineObject::Open();
+        SetOpenOrCloseInProgress( EFalse );
+        }
+    }
+
+
+EXPORT_C TInt CMemSpyProcess::MdcaCount() const
+    {
+    return iThreads.Count();
+    }
+
+
+EXPORT_C TPtrC CMemSpyProcess::MdcaPoint(TInt aIndex) const
+    {
+    const CMemSpyThread* thread = iThreads[ aIndex ];
+    return TPtrC( thread->NameForListBox() );
+    }
+
+
+EXPORT_C TInt CMemSpyProcess::ThreadIndexById( TThreadId aId ) const
+    {
+    TInt index = KErrNotFound;
+    //
+    const TInt count = iThreads.Count();
+    for( TInt i=0; i<count; i++ )
+        {
+        const CMemSpyThread* thread = iThreads[ i ];
+        if  ( thread->Id() == aId )
+            {
+            index = i;
+            break;
+            }
+        }
+    //
+    return index;
+    }
+
+
+EXPORT_C CMemSpyThread& CMemSpyProcess::ThreadByIdL( TThreadId aId ) const
+    {
+    CMemSpyThread* ret = NULL;
+    //
+    const TInt count = iThreads.Count();
+    for( TInt i=0; i<count; i++ )
+        {
+        CMemSpyThread* thread = iThreads[ i ];
+        if  ( thread->Id() == aId )
+            {
+            ret = thread;
+            break;
+            }
+        }
+    //
+    if  ( ret == NULL )
+        {
+        User::Leave( KErrNotFound );
+        }
+    //
+    return *ret;
+    }
+
+
+
+EXPORT_C TPtrC CMemSpyProcess::Name() const
+    {
+    // Just return the pure name, minus the leading tab
+    TPtrC pRet( iName->Mid(2) );
+    
+    // Find the last tab position
+    TInt pos = pRet.Locate(TChar('\t'));
+    if  ( pos > 0 )
+        {
+        pRet.Set( pRet.Left( pos ) );
+        }
+    //    
+    return pRet;
+    }
+
+
+EXPORT_C CMemSpyThread& CMemSpyProcess::At( TInt aIndex ) const
+    {
+    CMemSpyThread* ret = iThreads[ aIndex ];
+    return *ret;
+    }
+
+
+EXPORT_C void CMemSpyProcess::TerminateL()
+    {
+    RMemSpyDriverClient& driver = iEngine.Driver();
+    RProcess process;
+    User::LeaveIfError( driver.OpenProcess( iId, process ) );
+    process.Terminate( EPanicForcedTerminate );
+    process.Close();
+    //
+    RefreshL();
+    }
+
+
+EXPORT_C void CMemSpyProcess::KillL()
+    {
+    RMemSpyDriverClient& driver = iEngine.Driver();
+    RProcess process;
+    User::LeaveIfError( driver.OpenProcess( iId, process ) );
+    process.Kill( EPanicForcedKill );
+    process.Close();
+    //
+    RefreshL();
+    }
+
+
+EXPORT_C void CMemSpyProcess::PanicL()
+    {
+    RMemSpyDriverClient& driver = iEngine.Driver();
+    RProcess process;
+    User::LeaveIfError( driver.OpenProcess( iId, process ) );
+    process.Panic( KMemSpyClientPanic, EPanicForcedPanic );
+    process.Close();
+    //
+    RefreshL();
+    }
+
+
+EXPORT_C TBool CMemSpyProcess::IsSystemPermanent() const
+    {
+    const TBool ret = ( iInfo->iFlags & KProcessFlagSystemPermanent );
+    return ret;
+    }
+
+
+EXPORT_C TBool CMemSpyProcess::IsSystemCritical() const
+    {
+    const TBool ret = ( iInfo->iFlags & KProcessFlagSystemCritical );
+    return ret;
+    }
+
+
+void CMemSpyProcess::LocateThreadsL( RProcess& aProcess )
+    {
+    __ASSERT_ALWAYS( aProcess.Handle() != KNullHandle, MemSpyEngineUtils::Panic( EMemSpyEnginePanicProcessHandleNullWhenAttemptingToIdentifyThreads ) );
+
+#ifdef _DEBUG
+    RDebug::Printf("CMemSpyProcess::LocateThreadsL() - START - this: 0x%08x, pid: %d (0x%04x)", this, (TUint) aProcess.Id(), (TUint) aProcess.Id() );
+#endif
+
+    RArray<TThreadId> threadIds;
+    CleanupClosePushL( threadIds );
+
+    // Get list of child threads from driver.
+    iEngine.Driver().GetThreadsL( aProcess.Id(), threadIds );
+
+    // Create therad object for each thread the driver returned to us...
+    const TInt count = threadIds.Count();
+#ifdef _DEBUG
+    RDebug::Printf("CMemSpyProcess::LocateThreadsL() - got %d threads", count );
+#endif
+
+    for( TInt i=0; i<count; i++ )
+        {
+        const TThreadId threadId( threadIds[ i ] );
+#ifdef _DEBUG
+        RDebug::Printf("CMemSpyProcess::LocateThreadsL() - thread id: %d (0x%04d)", (TUint) threadId, (TUint) threadId );
+#endif
+        //
+        TRAP_IGNORE( 
+            CMemSpyThread* threadObj = CMemSpyThread::NewLC( threadId, *this );
+            iThreads.AppendL( threadObj );
+            CleanupStack::Pop( threadObj );
+            );
+        }
+
+    // Tidy up
+    CleanupStack::PopAndDestroy( &threadIds );
+    
+#ifdef _DEBUG
+    RDebug::Printf("CMemSpyProcess::LocateThreadsL() - END - this: 0x%08x, pid: %d (0x%04x), thread count: %d", this, (TUint) aProcess.Id(), (TUint) aProcess.Id(), iThreads.Count() );
+#endif
+    }
+
+
+void CMemSpyProcess::AppendPriority( TDes& aDes, TProcessPriority aPriority )
+    {
+    switch( aPriority )
+        {
+    case EPriorityLow:
+        aDes += _L("[L]");
+        break;
+    case EPriorityBackground:
+        aDes += _L("[B]");
+        break;
+    case EPriorityForeground:
+        aDes += _L("[F]");
+        break;
+    case EPriorityHigh:
+        aDes += _L("[H]");
+        break;
+    case EPriorityWindowServer:
+        aDes += _L("[WS]");
+        break;
+    case EPriorityFileServer:
+        aDes += _L("[FS]");
+        break;
+    case EPriorityRealTimeServer:
+        aDes += _L("[RTS]");
+        break;
+    case EPrioritySupervisor:
+        aDes += _L("[SUP]");
+        break;
+    default:
+        aDes += _L("[?]");
+        break;
+        }
+    }
+
+
+void CMemSpyProcess::GetFileName( TFileName& aFileName )
+    {
+    // Fallback
+    const TPtrC pNameCleaned( Name() );
+    aFileName.Zero();
+    aFileName.AppendFormat( _L("%S.exe"), &pNameCleaned );
+
+    // Try to get the proper name
+    RProcess process;
+    RMemSpyDriverClient& driver = iEngine.Driver();
+    if  ( driver.OpenProcess( iId, process ) == KErrNone )
+        {
+        aFileName = process.FileName();
+        process.Close();
+        }
+    }
+
+void CMemSpyProcess::RefreshL()
+    {
+    RMemSpyDriverClient& driver = iEngine.Driver();
+    RProcess process;
+
+    // Deliberately ignore error - the other overload of RefreshL can cope with
+    // a null handle.
+    driver.OpenProcess( iId, process );
+    CleanupClosePushL( process );
+
+    RefreshL( process );
+
+    CleanupStack::PopAndDestroy( &process );
+    }
+
+
+void CMemSpyProcess::RefreshL( const RProcess& aProcess )
+    {
+    const TBool handleValid = aProcess.Handle() != KNullHandle;
+    if  ( handleValid )
+        {
+        RMemSpyDriverClient& driver = iEngine.Driver();
+        User::LeaveIfError( driver.GetProcessInfo( iId, *iInfo ) );
+        }
+
+    // Get priority, exit info etc
+    iExitType = handleValid ? aProcess.ExitType() : EExitKill;
+    iPriority = handleValid ? aProcess.Priority() : EPriorityForeground;
+
+    // If the process is dead then we may not be able to get some attributes
+    // (it depends on whether the thread handle is valid anymore).
+    iExitReason = 0;
+    iExitCategory.Zero();
+
+    if  ( IsDead() )
+        {
+        if  ( handleValid )
+            {
+            iExitReason = aProcess.ExitReason();
+            iExitCategory = aProcess.ExitCategory(); 
+            }
+        else
+            {
+            iExitCategory = KMemSpyUnknownExitCategory;
+            }
+        }
+    else
+        {
+        // We only reset the flags if the process is still alive.
+        // If it is dead (i.e. 'if' branch) then we do not reset because
+        // we have no way to fetch them any more.
+        iFlags = EFlagsNone;
+        }
+
+    // Get raw process name and check whether it includes .exe suffix
+    TBool includesExecutableSuffix = EFalse;
+    HBufC* rawProcessName = GetProcessNameLC( aProcess, includesExecutableSuffix );
+    if ( includesExecutableSuffix )
+        {
+        iFlags |= EFlagsIncludedExecutableWithinName;
+        }
+
+    // Format priority as string
+    TBuf<10> priority;
+    AppendPriority( priority, iPriority );
+
+    // Convert the full name to the format we want in the UI
+    TBuf<KMaxFullName + 60> name;
+    TMemSpyTruncateOverflow overflow;
+
+    // FOR ALIVE PROCESSES:
+    //
+    // 1] Space, followed by tab
+    // 2] Process name (minus .exe)
+    // 3] Tab, Tab
+    // 4] Process uid
+    // 5] Thread count
+    // 6] Process priority
+    //
+    // FOR DEAD PROCESSES:
+    //
+    // 1] Space, followed by tab
+    // 2] Process name (minus .exe)
+    // 3] Tab, Tab
+    // 4] Process uid
+    // 5] Exit info
+
+    // Common
+    _LIT( KMemSpyProcessNameFormatSpecBasicName, " \t%S\t\t%8x, " );
+    name.AppendFormat( KMemSpyProcessNameFormatSpecBasicName, &overflow, rawProcessName, iInfo->SID() );
+    CleanupStack::PopAndDestroy( rawProcessName );
+
+    if  ( IsDead() )
+        {
+        CMemSpyThread::AppendExitInfo( name, iExitType, iExitReason, iExitCategory );
+        }
+    else
+        {
+        _LIT( KMemSpyProcessNameFormatSpecAlive, "%2d thr, %S" );
+        name.AppendFormat( KMemSpyProcessNameFormatSpecAlive, &overflow, iThreads.Count(), &priority );
+        }
+
+    // Save end result
+    HBufC* finalName = name.AllocL();
+    delete iName;
+    iName = finalName;
+    }
+
+
+void CMemSpyProcess::SetDeadL()
+    {
+    RefreshL();
+    }
+
+
+void CMemSpyProcess::SetDeadL( const RProcess& aProcess )
+    {
+    RefreshL( aProcess );
+    }
+
+
+EXPORT_C TBool CMemSpyProcess::IsDead() const
+    {
+    const TBool isDead = ( iExitType != EExitPending );
+    return  isDead;
+    }
+
+
+EXPORT_C TUint32 CMemSpyProcess::SID() const
+    {
+    return iInfo->SID();
+    }
+
+
+EXPORT_C TUint32 CMemSpyProcess::VID() const
+    {
+    return iInfo->VID();
+    }
+
+
+EXPORT_C TUidType CMemSpyProcess::UIDs() const
+    {
+    return iInfo->iUids;
+    }
+
+
+EXPORT_C SCapabilitySet CMemSpyProcess::Capabilities() const
+    {
+    return iInfo->iSecurityInfo.iCaps;
+    }
+
+void CMemSpyProcess::FullName( TDes& aFullName ) const
+    {
+    // c32exe.exe[101f7989]0001
+    aFullName.Zero();
+    aFullName.Append( Name() );
+    if ( iFlags & EFlagsIncludedExecutableWithinName )
+        {
+        // Add .exe
+        aFullName.Append( KMemSpyStandardProcessExtension );
+        }
+
+    aFullName.Append( '[' );
+	aFullName.AppendNumFixedWidth( iInfo->iUids[ 2 ].iUid, EHex, 8 );
+    aFullName.Append( ']' );
+	aFullName.AppendNumFixedWidth( iInfo->iGeneration, EDecimal, 4 );
+    }
+
+
+void CMemSpyProcess::HandleThreadIsBornL( const TThreadId& aId )
+    {
+    // A new thread has been created in this process. Just in case, we'll
+    // check there isn't already an existing thread with the same id...
+    const TInt index = ThreadIndexById( aId );
+    if  ( index < 0 )
+        {
+        TRAP_IGNORE( 
+            CMemSpyThread* threadObj = CMemSpyThread::NewLC( aId, *this );
+            iThreads.AppendL( threadObj );
+            CleanupStack::Pop( threadObj );
+            );
+        }
+    }
+
+
+HBufC* CMemSpyProcess::GetProcessNameLC( const RProcess& aProcessOrNull, TBool& aProcessNameIncludesExeSuffix ) const
+    {
+    _LIT( KMemSpySquareBraceOpen, "[" );
+    //
+    TFullName processName;
+    
+    // Assume the flags have already been set once previously in order to form default response
+    aProcessNameIncludesExeSuffix = ( iFlags & EFlagsIncludedExecutableWithinName );
+
+    const TBool handleValid = aProcessOrNull.Handle() != KNullHandle;
+    if  ( handleValid )
+        {
+        // Easy case - we have a valid thread handle...
+        //
+        // Get full name, e.g.:
+        //
+        // c32exe.exe[101f7989]0001
+        aProcessOrNull.FullName( processName );
+
+        // ... but we need to clean up the name so that it
+        // doesn't include the process UID, and neither does it
+        // include the extension (.exe).
+        TInt pos = processName.FindF( KMemSpySquareBraceOpen );
+        if  ( pos > 0 )
+            {
+            processName.SetLength( pos );
+            }
+        
+        // Discard '.exe'
+        pos = processName.FindF( KMemSpyStandardProcessExtension );
+        if  ( pos > 0 )
+            {
+            aProcessNameIncludesExeSuffix = ETrue;
+            processName.SetLength( pos );
+            }
+        }
+    else
+        {
+        // Since we don't have the possibility to enquire after the process's name
+        // we'll assume that it used to be alive and therefore at some point we did
+        // manage to grep it's name...
+        if  ( iName )
+            {
+            const TPtrC pOriginalName( Name() );
+            processName.Append( pOriginalName );
+            }
+        else
+            {
+            // Don't have a process handle, don't have any possibility to get the
+            // name from a prior cached version. Must use "unknown"
+            processName.Append( KMemSpyUnknownProcessName );
+            }
+        }
+    //
+    HBufC* ret = processName.AllocLC();
+    return ret;
+    }
+
+
+void CMemSpyProcess::CloseAllThreads()
+    {
+    const TInt count = iThreads.Count();
+    for(TInt i=count-1; i>=0; i--)
+        {
+        CMemSpyThread* thread = iThreads[ i ];
+        thread->Close();
+        }
+    }
+