memspy/Driver/Kernel/Source/MemSpyDriverSuspensionManager.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 13 Oct 2010 16:17:58 +0300
branchRCL_3
changeset 59 8ad140f3dd41
parent 49 7fdc9a71d314
permissions -rw-r--r--
Revision: 201039 Kit: 201041

/*
* 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 "MemSpyDriverSuspensionManager.h"

// System includes
#include <memspy/driver/memspydriverobjectsshared.h>

// Shared includes
#include "MemSpyDriverUtils.h"
#include "MemSpyDriverDevice.h"
#include "MemSpyDriverOSAdaption.h"

// Constants
const TInt KSuspendResumeCount = 1;



DMemSpySuspensionManager::DMemSpySuspensionManager( DMemSpyDriverDevice& aDevice )
:   iDevice( aDevice )
    {
    }


DMemSpySuspensionManager::~DMemSpySuspensionManager()
	{
	TRACE( Kern::Printf("DMemSpySuspensionManager::~DMemSpySuspensionManager() - START"));

    if  ( iAlreadySuspended )
        {
        TRACE( Kern::Printf("DMemSpySuspensionManager::~DMemSpySuspensionManager() - resuming threads in process with id: %d", iSuspendedProcessId ));
        DoResumeAllThreadsInProcess( iSuspendedProcessId );
        }
    if  ( iTempObj != NULL )
        {
    	Kern::SafeClose( iTempObj, NULL );
        }

    TRACE( Kern::Printf("DMemSpySuspensionManager::~DMemSpySuspensionManager() - END"));
    }


TInt DMemSpySuspensionManager::Construct()
    {
    return KErrNone;
    }







 



TBool DMemSpySuspensionManager::IsSuspended( TUint aPid ) const
    {
    TBool ret = iAlreadySuspended;
    //
    if  ( ret )
        {
        ret = ( aPid == iSuspendedProcessId );
        }
    //
    TRACE( Kern::Printf("DMemSpySuspensionManager::IsSuspended() - iAlreadySuspended: %d, iSuspendedProcessId: %d, aPid: %d, ret: %d", iAlreadySuspended, iSuspendedProcessId, aPid, ret ) );
    return ret;
    }


TBool DMemSpySuspensionManager::IsSuspended( DThread& aThread ) const
    {
    TBool ret = EFalse;
    //
    const TUint tid = iDevice.OSAdaption().DThread().GetId( aThread );
    DProcess* process = iDevice.OSAdaption().DThread().GetOwningProcess( aThread );
    TRACE( Kern::Printf("DMemSpySuspensionManager::IsSuspended() - START - iSuspendedProcessId: %d, aThread: (%d) %O, process: 0x%08x", iSuspendedProcessId, tid, &aThread, process ) );
    //
    if ( process )
        {
        ret = IsSuspended( *process );
        }
    //
    TRACE( Kern::Printf("DMemSpySuspensionManager::IsSuspended() - END - ret: %d", ret ) );
    return ret;
    }


TBool DMemSpySuspensionManager::IsSuspended( DProcess& aProcess ) const
    {
    const TUint pid = iDevice.OSAdaption().DProcess().GetId( aProcess );
    TRACE( Kern::Printf("DMemSpySuspensionManager::IsSuspended() - START - iSuspendedProcessId: %d, aProcess: (%d / %d) %O", iSuspendedProcessId, pid, aProcess.iId, &aProcess ) );
    //
    const TBool ret = IsSuspended( pid );
    //
    TRACE( Kern::Printf("DMemSpySuspensionManager::IsSuspended() - END - ret: %d", ret ) );
    return ret;
    }
















TInt DMemSpySuspensionManager::SuspendAllThreadsInProcess( TUint aPid, DThread& aClientThread )
    {
	// Suspend all threads in the process
	TRACE( Kern::Printf("DMemSpySuspensionManager::SuspendAllThreadsInProcess() - START - id: %8d, iSuspendedProcessId: %8d, iAlreadySuspended: %d", aPid, iSuspendedProcessId, iAlreadySuspended ));
    if  ( iAlreadySuspended && aPid != iSuspendedProcessId )
        {
		Kern::Printf("DMemSpySuspensionManager::SuspendAllThreadsInProcess() - END - trying to suspend multiple processes!");
        MemSpyDriverUtils::PanicThread( aClientThread, EPanicAttemptingToSuspendMultipleProcesses );
        return KErrNone;
        }
    else if ( IsProcessTheClientThread( aPid, aClientThread ) )
        {
		Kern::Printf("DMemSpySuspensionManager::SuspendAllThreadsInProcess() - END - trying to suspend client thread! - request ignored");
        return KErrLocked;
        }
    
	TInt r = KErrNone;
	TRACE( Kern::Printf("DMemSpySuspensionManager::SuspendAllThreadsInProcess - iAlreadySuspended: %d", iAlreadySuspended));
	if  ( !iAlreadySuspended ) 
    	{
    	r = DoSuspendAllThreadsInProcess( aPid, &aClientThread );
    	if (r != KErrNone)
    		{
    		TRACE( Kern::Printf("DMemSpySuspensionManager::SuspendAllThreadsInProcess() - END - process not found") );
    		return r;
    		}

        // To ensure we clean up in case of user-side problem...
        iSuspendedProcessId = aPid;	
        iAlreadySuspended = ETrue;
    	iSuspendCount = 1;
    	}
	else
    	{
    	// Just increment the count
    	++iSuspendCount;
    	}

    TRACE( Kern::Printf("DMemSpySuspensionManager::SuspendAllThreadsInProcess() - END - iSuspendCount: %d, iSuspendedProcessId: %d", iSuspendCount, iSuspendedProcessId ));
	return iSuspendCount;
    }


TInt DMemSpySuspensionManager::ResumeAllThreadsInProcess( TUint aPid, DThread& aClientThread )
    {
	TRACE( Kern::Printf("DMemSpySuspensionManager::ResumeAllThreadsInProcess() - START - id: %8d, iSuspendedProcessId: %8d, iAlreadySuspended: %d", aPid, iSuspendedProcessId, iAlreadySuspended));
	if  ( !iAlreadySuspended )
    	{
    	// Nothing suspended - don't panic
     	TRACE( Kern::Printf("DMemSpySuspensionManager::ResumeAllThreadsInProcess() - END - nothing suspended, ignoring client request"));
       	return KErrNone;
    	}
    else if  ( iAlreadySuspended && aPid != iSuspendedProcessId )
        {
		Kern::Printf("DMemSpySuspensionManager::ResumeAllThreadsInProcess() - END - trying to resume incorrect process!");
        MemSpyDriverUtils::PanicThread( aClientThread, EPanicAttemptingToResumeNonSuspendedProcess );
        return KErrNone;
        }
    else if  ( IsProcessTheClientThread( aPid, aClientThread ) )
        {
		Kern::Printf("DMemSpySuspensionManager::ResumeAllThreadsInProcess() - END - trying to resume client thread! - request ignored");
        return KErrLocked;
        }
    
    TRACE( Kern::Printf("DMemSpySuspensionManager::ResumeAllThreadsInProcess"));

    TInt r = KErrNone;
    if  ( --iSuspendCount <= 0 )
        {
    	r = DoResumeAllThreadsInProcess( aPid, &aClientThread );
    	if (r != KErrNone)
    		{
    		Kern::Printf("DMemSpySuspensionManager::ResumeAllThreadsInProcess() - END - process not found");
    		return r;
    		}

        // No longer need to clean up
        iAlreadySuspended = EFalse;
        iSuspendedProcessId = 0;
        iSuspendCount = 0;
        }
    else
        {
    	// No action needed - we've already decremented the counter
    	}

	TRACE( Kern::Printf("DMemSpySuspensionManager::ResumeAllThreadsInProcess() - END - iSuspendCount: %d", iSuspendCount));
	return iSuspendCount;
    }




























TInt DMemSpySuspensionManager::DoSuspendAllThreadsInProcess( TUint aPid, DThread* /*aClientThread*/ )
    {
	TRACE( Kern::Printf("DMemSpySuspensionManager::DoSuspendAllThreadsInProcess() - START - aPid: %d", aPid));
    TInt r = OpenTempObject( aPid, EProcess );
    if  (r == KErrNone)
    	{
        DProcess* process = (DProcess*) iTempObj;
        TFullName processName;
        process->FullName( processName );
        processName.Append('*');
    
        DObjectCon* container = Kern::Containers()[EThread];
        NKern::ThreadEnterCS();
        container->Wait();
        //
        TFullName result;
#ifdef MCL_FIND_HANDLES
        TFindHandle findHandle;
#else
        TInt findHandle = 0;
#endif
        r = container->FindByFullName( findHandle, processName, result );
        while( r == KErrNone )
            {
            DThread* thread = (DThread*) container->At( findHandle );
            if  ( thread )
                {
                const TUint tid = iDevice.OSAdaption().DThread().GetId( *thread );
                TRACE( Kern::Printf("DMemSpySuspensionManager::DoSuspendAllThreadsInProcess - suspending thread: (%d), %O", tid, thread ));
                //
                Kern::ThreadSuspend( *thread, KSuspendResumeCount );
                }
            //
            r = container->FindByFullName( findHandle, processName, result );
            }
        //
        container->Signal();
        NKern::ThreadLeaveCS();
    
        CloseTempObject();
        r = KErrNone;
    	}

    TRACE( Kern::Printf("DMemSpySuspensionManager::DoSuspendAllThreadsInProcess() - END - ret: %d", r));
    return r;
    }


TInt DMemSpySuspensionManager::DoResumeAllThreadsInProcess( TUint aPid, DThread* aClientThread )
    {
	TRACE( Kern::Printf("DMemSpySuspensionManager::DoResumeAllThreadsInProcess() - START - aPid: %d", aPid));
    TInt r = OpenTempObject( aPid, EProcess );
    if  (r == KErrNone)
    	{
        // Check that this process is suspended
        DProcess* process = (DProcess*) iTempObj;
        const TUint pid = iDevice.OSAdaption().DProcess().GetId( *process );
        if  ( !aClientThread  || ( aClientThread && CheckProcessSuspended( pid, *aClientThread ) ) )
            {
            // Resume all threads in the process
            TFullName processName;
            process->FullName( processName );
            processName.Append('*');
    
            DObjectCon* container = Kern::Containers()[EThread];
            NKern::ThreadEnterCS();
            container->Wait();
            //
            TFullName result;
    #ifdef MCL_FIND_HANDLES
            TFindHandle findHandle;
    #else
            TInt findHandle = 0;
    #endif
            r = container->FindByFullName( findHandle, processName, result );
            while( r == KErrNone )
                {
                DThread* thread = (DThread*) container->At( findHandle );
                TRACE( Kern::Printf("DMemSpySuspensionManager::DoResumeAllThreadsInProcess - resuming thread: %lS", &result));
                //
                Kern::ThreadResume(*thread);
                r = container->FindByFullName( findHandle, processName, result );
                }
            //
            container->Signal();
            NKern::ThreadLeaveCS();
    
            r = KErrNone;
            }
        else
            {
            TRACE( Kern::Printf("DMemSpySuspensionManager::DoResumeAllThreadsInProcess - parent process not suspended => KErrAccessDenied"));
            r = KErrAccessDenied;
            }

        CloseTempObject();
        }

    TRACE( Kern::Printf("DMemSpySuspensionManager::DoResumeAllThreadsInProcess() - END - ret: %d", r));
    return r;
    }

















TBool DMemSpySuspensionManager::IsProcessTheClientThread( TUint aPid, DThread& aClientThread ) const
    {
    TBool ret = EFalse;
    DProcess& clientProcess = *iDevice.OSAdaption().DThread().GetOwningProcess( aClientThread );
    const TUint pid = iDevice.OSAdaption().DProcess().GetId( clientProcess );
    if  ( pid == aPid )
        {
        ret = ETrue;
        }
    //
    return ret;
    }
    

TBool DMemSpySuspensionManager::CheckProcessSuspended( TUint aExpectedPid, DThread& aClientThread ) const
    {
    TBool suspended = ETrue;
    //
    if  ( !iAlreadySuspended )
        {
        MemSpyDriverUtils::PanicThread( aClientThread, EPanicThreadsInProcessNotSuspended );
        }
    else if ( aExpectedPid != iSuspendedProcessId )
        {
        MemSpyDriverUtils::PanicThread( aClientThread, EPanicWrongProcessSuspended );
        }
    //
    return suspended;
    }



















TInt DMemSpySuspensionManager::OpenTempObject(TUint aId, TObjectType aType)
	{
	__ASSERT_DEBUG( aType == EProcess || aType == EThread, MemSpyDriverUtils::Fault( __LINE__ ) );
	__ASSERT_DEBUG( !iTempObj, MemSpyDriverUtils::Fault( __LINE__ ) );

	TRACE( Kern::Printf("DMemSpySuspensionManager::OpenTempObject() - START - aId: %d, aType: %d", aId, aType ));
	DObjectCon* pC = Kern::Containers()[aType];
	NKern::ThreadEnterCS();
	pC->Wait();
	iTempObj = (aType == EProcess) ? (DObject*)Kern::ProcessFromId(aId) : (DObject*)Kern::ThreadFromId(aId);
	TRACE( Kern::Printf("DMemSpySuspensionManager::OpenTempObject() - kernel obj from id returned: 0x%08x %O", iTempObj, iTempObj ));
    //
    TBool openedOkay = EFalse;
    TInt r = KErrNone;
    //
	if ( iTempObj )
        {
		NKern::LockSystem();
		r = iTempObj->Open();
	    TRACE( Kern::Printf("DMemSpySuspensionManager::OpenTempObject() - open returned: %d", r ));
		NKern::UnlockSystem();
		//
        if  ( r == KErrNone )
            {
            openedOkay = ETrue;
            if  ( aType == EProcess )
                {
                // Check the process is still alive
                DProcess* process = (DProcess*) iTempObj;
                const TExitType exitType = iDevice.OSAdaption().DProcess().GetExitType( *process );
                if  ( exitType != EExitPending )
					{
                    r = KErrDied;
	                TRACE( Kern::Printf("DMemSpySuspensionManager::OpenTempObject() - PROCESS IS DEAD!" ));
					}
                }
            else if (aType == EThread )
                {
                // Check the thread is still alive
                DThread* thread = (DThread*) iTempObj;
                const TExitType exitType = iDevice.OSAdaption().DThread().GetExitType( *thread );
                if  ( exitType != EExitPending )
                    {
                    r = KErrDied;
	                TRACE( Kern::Printf("DMemSpySuspensionManager::OpenTempObject() - THREAD IS DEAD!" ));
                    }
                }
            }

        }
    else if ( ! iTempObj )
        {
        r = KErrNotFound;
	    TRACE( Kern::Printf("DMemSpySuspensionManager::OpenTempObject() - ENTITY NOT FOUND!" ));
        }
    //
	pC->Signal();
	TRACE( Kern::Printf("DMemSpySuspensionManager::OpenTempObject() - signalled container..." ));
	NKern::ThreadLeaveCS();
	TRACE( Kern::Printf("DMemSpySuspensionManager::OpenTempObject() - left CS..." ));
    //
    if  ( r != KErrNone && iTempObj )
        {
	    TRACE( Kern::Printf("DMemSpySuspensionManager::OpenTempObject() - ERROR CASE - closing temp object (r: %d, openedOkay: %d)...", r, openedOkay ));
        //
        if ( openedOkay )
            {
            CloseTempObject();
            }
        else
            {
            NKern::SafeSwap( NULL, (TAny*&) iTempObj );
            }
        //
	    TRACE( Kern::Printf("DMemSpySuspensionManager::OpenTempObject() - ERROR CASE - closed temp object" ));
        }
    //
	TRACE( Kern::Printf("DMemSpySuspensionManager::OpenTempObject() - END - r: %d", r ));
	return r;
	}


void DMemSpySuspensionManager::CloseTempObject()
	{
	TRACE( Kern::Printf("DMemSpySuspensionManager::CloseTempObject() - START - iTempObj: 0x%08x %O", iTempObj, iTempObj ));

	__ASSERT_DEBUG( iTempObj, MemSpyDriverUtils::Fault( __LINE__ ) );
    if  ( iTempObj )
        {
	    NKern::ThreadEnterCS();
        
        TRACE( Kern::Printf("DMemSpySuspensionManager::CloseTempObject() - in CS..." ));
	    Kern::SafeClose( iTempObj, NULL );
        TRACE( Kern::Printf("DMemSpySuspensionManager::CloseTempObject() - done safe close..." ));
	    NKern::ThreadLeaveCS();

        TRACE( Kern::Printf("DMemSpySuspensionManager::CloseTempObject() - left CS" ));
        }

    TRACE( Kern::Printf("DMemSpySuspensionManager::CloseTempObject() - END" ));
	}