analyzetool/dynamicmemoryhook/src/customuser.cpp
branchRCL_3
changeset 13 da2cedce4920
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/analyzetool/dynamicmemoryhook/src/customuser.cpp	Tue May 25 14:22:58 2010 +0300
@@ -0,0 +1,518 @@
+/*
+* 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:  Definitions for the class CustomUser.
+*
+*/
+
+#include <f32file.h>
+#include <utf.h>
+#include "customuser.h"
+#include "analyzetoolmainallocator.h"
+#include "analyzetoolallocator.h"
+#include "atlog.h"
+#include "analyzetoolmemoryallocator.h"
+#include "analyzetoolpanics.pan"
+#include "atstorageservercommon.h"
+#include "atdriveinfo.h"
+#include <analyzetool/analyzetooltraceconstants.h>
+
+#ifdef USE_CLEANER_DLL
+// Global variable to detect dll attach & detach in process.
+// Note! This is initialized after SetupThreadHeap so its not usable there.
+// This is used to store the main thread id and track when the process ends
+// to load the cleaner dll with call back feature to cleanup allocator at the
+// last possible phase.
+#include <analyzetool/analyzetoolcleaner.h>
+
+// CONSTANTS
+const TInt KAToolCleanerOrdinal = 1;
+
+class TAnalyzeToolGlobalTracker : public TAnalyzeToolCleanerBase
+    {
+public:
+    /* Main thread id */
+    TThreadId iMainId;
+    
+    /* Inform if panic occured */
+    TBool iPanic;
+    
+    // -----------------------------------------------------------------------------
+    // TAnalyzeToolGlobalTracker::TAnalyzeToolGlobalTracker()
+    // C++ default constructor 
+    // -----------------------------------------------------------------------------
+    //
+    TAnalyzeToolGlobalTracker()
+        {
+        LOGSTR1( "ATMH TAnalyzeToolGlobalTracker::TAnalyzeToolGlobalTracker()" );
+        
+        iPanic = EFalse; // no panic occured
+        iMainId = RThread().Id(); // set main thread id
+        LOGSTR2( "ATMH TAnalyzeToolGlobalTracker() > Main id set: %d", 
+                iMainId.operator TUint() );
+        }
+    
+    // -----------------------------------------------------------------------------
+    // TAnalyzeToolGlobalTracker::~TAnalyzeToolGlobalTracker()
+    // Destructor.
+    // -----------------------------------------------------------------------------
+    //
+    ~TAnalyzeToolGlobalTracker()
+        {
+        LOGSTR1( "ATMH TAnalyzeToolGlobalTracker::~TAnalyzeToolGlobalTracker()" );
+        
+        // We dont load dll if panic has happened (uninstallation has been done).
+        if ( iPanic )
+            {
+            LOGSTR1( "ATMH ~TAnalyzeToolGlobalTracker > Panic set not loading cleaner dll." );
+            return;
+            }
+        
+        LOGSTR1( "ATMH ~TAnalyzeToolGlobalTracker > about to load cleaner dll" );
+        // Load cleaner library and set a call back to our cleanup
+        RLibrary lib;
+        TInt error( lib.Load( KATCleanerDllName ) );
+        if ( error == KErrNone )
+            {
+            // Set address to point to ourself
+            TLibraryFunction func = lib.Lookup( KAToolCleanerOrdinal ); // Ordinal 1 of the dll
+            ATCLEANERTABLE* cleaner = (ATCLEANERTABLE*) func(); // Use function to get address
+            cleaner->At( 0 ) = (TUint32) this; // Set address
+            LOGSTR1( "ATMH ~TAnalyzeToolGlobalTracker() > cleaner dll loaded and call back set" );
+            }
+        else
+            {
+            // Error loading cleanup dll
+            LOGSTR2( "ATMH ~TAnalyzeToolGlobalTracker() > cleaner dll load error(%i) uninstalling allocator now!", 
+                    error );
+            Cleanup();
+            }
+        }
+    
+    // -----------------------------------------------------------------------------
+    // TAnalyzeToolGlobalTracker::Cleanup()
+    // 
+    // -----------------------------------------------------------------------------
+    //
+    void Cleanup()
+        {
+        LOGSTR1( "ATMH TAnalyzeToolGlobalTracker::Cleanup() - allocator uninstall" );
+        
+        // Uninstall allocator
+        ( (RAnalyzeToolMemoryAllocator&) User::Allocator() ).Uninstall();
+        }
+    
+    };
+
+// Global variable definition.
+TAnalyzeToolGlobalTracker gGlobalTracker;
+#endif
+
+// CONSTANTS
+// When needed, update the version number directly inside _LIT macro.
+// Constant for the atool API(staticlib) version.
+_LIT( KAtoolApiVersion, "1.7.5" );
+
+// Version number buffer length
+const TInt KAtoolVersionNumberLength = 10;
+
+// Wrong version error code
+const TInt KAtoolVersionError = -1999;
+
+// Version number separator
+_LIT( KVersionSeparator, ";" );
+
+// Incorrect version error strings 
+_LIT( KIncorrectText, "ERROR_OCCURED INCORRECT_ATOOL_VERSION [API v.%S][ATOOL v.%S]" );
+_LIT( KIncorrectTextTrace, "PCSS " );
+
+// -----------------------------------------------------------------------------
+// CustomUser::Panic()
+// Overloaded User::Panic() function
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CustomUser::Panic( const TDesC& aCategory, TInt aReason )
+    {
+    LOGSTR3( "ATMH CustomUser::Panic() %S %i", &aCategory, aReason );
+    
+#ifdef USE_CLEANER_DLL
+    // Set global tracker that panic has happened.
+    gGlobalTracker.iPanic = ETrue;
+#endif
+    
+    // Uninstall thread's RAllocator
+    ( (RAnalyzeToolMemoryAllocator&) User::Allocator() ).Uninstall();
+       
+    // Call the "real" User::Panic()
+    User::Panic( aCategory, aReason );
+    }
+
+// -----------------------------------------------------------------------------
+// CustomUser::Exit()
+// Overloaded User::Exit() function
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CustomUser::Exit( TInt aReason )
+    {
+    LOGSTR3( "ATMH CustomUser::Exit() %i %i", aReason, RThread().Id().Id() );
+    
+    if ( aReason != KAtoolVersionError )
+    	{
+#ifdef USE_CLEANER_DLL
+        // Only uninstall allocator if its not the process main/first thread.
+        LOGSTR3( "ATMH CustomUser::Exit() - Thread id: %d - Main Id: %d",
+                RThread().Id().operator TUint(), gGlobalTracker.iMainId.operator TUint() );
+        
+        if ( RThread().Id() != gGlobalTracker.iMainId )
+            {
+            LOGSTR2("ATMH CustomUser::Exit() - Calling allocator uninstall in thread: %d" , RThread().Id().operator TUint() );
+            ( (RAnalyzeToolMemoryAllocator&) User::Allocator() ).Uninstall();
+            }
+#else
+    	// Uninstall thread's RAllocator
+    	( (RAnalyzeToolMemoryAllocator&) User::Allocator() ).Uninstall();
+    	LOGSTR1( "ATMH CustomUser::Exit() - about to User::Exit" );
+#endif
+    	}
+    
+    // Call the "real" User::Exit()
+    User::Exit( aReason );
+    }
+
+// -----------------------------------------------------------------------------
+// CustomUser::SetCritical()
+// Overloaded User::SetCritical() function which returns
+// KErrNone, if successful; KErrArgument, if EAllThreadsCritical is 
+// passed - this is a state associated with a process, and you use 
+// User::SetProcessCritical() to set it.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CustomUser::SetCritical( User::TCritical aCritical )
+    {
+    LOGSTR1( "ATMH CustomUser::SetCritical()" );
+    // Check the given User::TCritical type
+    if ( aCritical == User::EAllThreadsCritical )
+        {
+        return KErrArgument;
+        }
+    else
+        {
+        return KErrNone;
+        }
+    }
+  
+// -----------------------------------------------------------------------------
+// CustomUser::SetProcessCritical()
+// Overloaded User::SetProcessCritical() function
+// KErrNone, if successful; KErrArgument, if either EProcessCritical or 
+// EProcessPermanent is passed - these are states associated with a 
+// thread, and you use User::SetCritical() to set them.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CustomUser::SetProcessCritical( User::TCritical aCritical )
+    {
+    LOGSTR1( "ATMH CustomUser::SetProcessCritical()" );
+     // Check the given User::TCritical type 
+    if ( aCritical == User::EProcessCritical || 
+         User::EProcessPermanent == aCritical )
+        {
+        return KErrArgument;
+        }
+    else
+        {
+        return KErrNone;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CustomUser::SetupThreadHeap()
+// Overloaded UserHeap::SetupThreadHeap function
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CustomUser::SetupThreadHeap( TBool aNotFirst, 
+    SStdEpocThreadCreateInfo& aInfo, const TFileName& aFileName,
+    TUint32 aLogOption, TUint32 aIsDebug, const TATVersion& aVersion,
+    TUint32 aAllocCallStackSize, TUint32 aFreeCallStackSize,
+    TRefByValue<const TDesC> aFmt, ... )
+    {
+    LOGSTR1( "ATMH CustomUser::SetupThreadHeap()" );
+    LOGSTR2( "ATMH > Thread id(%d)", RThread().Id().operator TUint() );
+    
+    // Add handling of the argument list here.
+        
+    TInt ret( KErrNone );    
+    // Check version number
+    TBuf<KAtoolVersionNumberLength> atoolVer;
+    if ( CheckVersion( aVersion, atoolVer ) != KErrNone )
+    	{
+    	LOGSTR1( "ATMH > Wrong API version > Inform user and Exit." );
+    	ReportIncorrectVersion( aLogOption, aFileName, atoolVer );
+    	return KAtoolVersionError;
+    	}
+    
+    // Check is this shared heap
+    if ( aInfo.iAllocator == NULL )
+        {
+        LOGSTR1( "ATMH creating a new heap" );
+        // RAllocator is NULL so heap is not shared, creating a new heap
+        ret = UserHeap::SetupThreadHeap( aNotFirst, aInfo );
+        __ASSERT_ALWAYS( KErrNone == ret, AssertPanic( EFailedToCreateHeap ) );
+        
+#if ( SYMBIAN_VERSION_SUPPORT >= SYMBIAN_3 )
+    #ifndef __WINS__
+        // Set dummy Tls value
+        TAny* dummyPtr( NULL );
+        TInt setErr( UserSvr::DllSetTls( KDummyHandle, dummyPtr ) );
+        LOGSTR2( "ATMH > Set Tls err(%i)", setErr );
+    #endif
+#endif
+        // Install the RAllocator
+        aInfo.iAllocator = &InstallAllocator( aNotFirst, aFileName, aLogOption, aIsDebug,
+                aAllocCallStackSize, aFreeCallStackSize );
+        }
+    else
+        {
+        LOGSTR1( "ATMH sharing the heap" );
+        // The heap is shared. Acquire pointer to the original heap
+        RAnalyzeToolMemoryAllocator* allocator = 
+			(RAnalyzeToolMemoryAllocator*) aInfo.iAllocator;
+        // Share the heap
+        allocator->ShareHeap();
+        // Switch thread heap 
+        User::SwitchAllocator( allocator );
+        }
+    return ret;
+    }
+
+// -----------------------------------------------------------------------------
+// CustomUser::InstallAllocator
+// Installs the RAllocator
+// -----------------------------------------------------------------------------
+//
+//lint -e{429} suppress "Custodial pointer 'allocator' has not been freed or returned"
+EXPORT_C RAllocator& CustomUser::InstallAllocator( TBool aNotFirst, 
+	const TFileName& aFileName, TUint32 aLogOption, TUint32 aIsDebug,
+	TUint32 aAllocCallStackSize, TUint32 aFreeCallStackSize )
+    {
+    LOGSTR1( "ATMH CustomUser::InstallAllocator()" );
+    
+    // Open handle to the device driver
+    RAnalyzeTool analyzetool;
+    TInt error = analyzetool.Open();
+    
+    // Check if the device driver has already loaded
+    if ( KErrNone == error )
+        {
+        LOGSTR1( "ATMH CustomUser::InstallAllocator() - analyzetool.Open() returned KErrNone" );
+        // The device driver has already loaded
+        // Get pointer to the main thread allocator
+        TMainThreadParamsBuf params;
+        params().iProcessId = RProcess().Id().operator TUint();
+        error = analyzetool.MainThreadAlloctor( params );
+
+        __ASSERT_ALWAYS( KErrNone == error, AssertPanic( ECantOpenHandle ) );
+        
+        // Close handle to the device driver
+        analyzetool.Close();
+        
+        // Is this the first thread of the program
+        if ( params().iAlone )
+            {
+            LOGSTR1( "ATMH CustomUser::InstallAllocator() - first thread of the program" );
+            // Only one thread in the program. Must be main thread
+            RAnalyzeToolMainAllocator* allocator = 
+				new RAnalyzeToolMainAllocator( aNotFirst, aFileName, aLogOption,
+				                               aIsDebug, aAllocCallStackSize, aFreeCallStackSize );
+            
+            __ASSERT_ALWAYS( allocator != NULL, AssertPanic( ENoMemory ) );
+            
+            // Change threads allocator
+            User::SwitchAllocator( allocator );
+            
+            // Return reference to the RAllocator
+            return *allocator;
+            }
+        // This is not the first thread. A new thread with a new heap created
+        else
+            {
+            LOGSTR1( "ATMH CustomUser::InstallAllocator() - create a new allocator for the new thread" );
+            // Create new RAllocator with handles from the main thread
+            RAnalyzeToolAllocator* allocator = new RAnalyzeToolAllocator( 
+                    aNotFirst,
+                    ((RAnalyzeToolMainAllocator*)params().iAllocator)->StorageServer(), 
+                    ((RAnalyzeToolMainAllocator*)params().iAllocator)->Codeblocks(), 
+                    ((RAnalyzeToolMainAllocator*)params().iAllocator)->Mutex(), 
+                    ((RAnalyzeToolMainAllocator*)params().iAllocator)->ProcessId(), 
+                    ((RAnalyzeToolMainAllocator*)params().iAllocator)->AnalyzeTool(),
+                    ((RAnalyzeToolMainAllocator*)params().iAllocator)->StorageServerOpen(),
+                    ((RAnalyzeToolMainAllocator*)params().iAllocator)->LogOption(),
+                    ((RAnalyzeToolMainAllocator*)params().iAllocator)->AllocMaxCallStack(),
+                    ((RAnalyzeToolMainAllocator*)params().iAllocator)->FreeMaxCallStack() );
+
+            __ASSERT_ALWAYS( allocator != NULL, AssertPanic( ENoMemory ) );
+            
+            // Change threads allocator
+            User::SwitchAllocator( allocator );
+            
+            // Return reference to the RAllocator
+            return *allocator;
+            }
+        }
+    // The device driver does not exists so this must be the first thread
+    else
+        {
+        LOGSTR1( "ATMH CustomUser::InstallAllocator() - analyzetool.Open() returned error, creating DD" );
+        RAnalyzeToolMainAllocator* allocator = 
+			new RAnalyzeToolMainAllocator( aNotFirst, aFileName, aLogOption, aIsDebug,
+			        aAllocCallStackSize, aFreeCallStackSize );
+        
+        __ASSERT_ALWAYS( allocator != NULL, AssertPanic( ENoMemory ) );
+        
+        // Change threads allocator
+        User::SwitchAllocator( allocator );
+
+        // Return reference to the RAllocator
+        return *allocator;
+        }
+    } 
+    
+// -----------------------------------------------------------------------------
+// CustomUser::CheckVersion
+// Check atool version
+// -----------------------------------------------------------------------------
+//
+TInt CustomUser::CheckVersion( const TATVersion& aVersion, TDes& aToolVersion )
+    { 
+    LOGSTR2( "ATMH CustomUser::CheckVersion(), aVersion( %S )", &aVersion );
+    
+    TFileName version;
+    version.Copy( aVersion );
+    TBuf<KAtoolVersionNumberLength> apiVer;
+    	
+    // Find separator place
+    TInt findplace( version.Find( KVersionSeparator() ) );
+    // Parse API version first [x.x.x;x.x.x]
+    if ( findplace >= 0 && findplace <= apiVer.MaxLength() )
+		{
+		apiVer.Copy( version.Mid( 0, findplace ) ); 
+		version.Delete( 0, findplace + KVersionSeparator().Length() );
+		}
+ 
+    if ( version.Length() <= aToolVersion.MaxLength() )
+    	{
+    	aToolVersion.Copy( version );
+    	if ( aToolVersion.Compare( KAtoolApiVersion ) == KErrNone &&
+    		 apiVer.Length() == 0 )
+    		{
+    		// Support 1.5.0 version (Version info: [1.5.0])
+    		apiVer.Copy( version );
+    		}
+    	}
+    
+    LOGSTR3( "ATMH > API version( %S ), ATOOL version( %S )", 
+    		&apiVer, &aToolVersion );
+        
+    // Check version numbers 
+    if ( apiVer.Compare( KAtoolApiVersion ) == KErrNone )
+    	{
+    	return KErrNone;
+    	}
+    return KErrCancel;    
+    }
+
+// -----------------------------------------------------------------------------
+// CustomUser::ReportIncorrectVersion
+// Function for showing incorrect version information
+// -----------------------------------------------------------------------------
+//
+void CustomUser::ReportIncorrectVersion( const TUint32 aLogOption,
+	const TFileName& aFileName, const TDes& aToolVersion )
+	{
+	LOGSTR2( "ATMH CustomUser::ReportIncorrectVersion(), aFileName( %S )", 
+			&aFileName );
+	
+	switch ( aLogOption )
+		{
+		case EATLogToFile:
+			{
+			LOGSTR1( "ATMH ReportIncorrectVersion > EATLogToFile" );			
+			
+			// A handle to a file server session.
+			RFs fs;
+			// Creates and opens a file, 
+			// and performs all operations on a single open file.
+			RFile file;	
+			// Create full path buffer
+			TBuf<KMaxFileName> logFileBuf;
+			// Connects a client to the file server.
+			TInt err( fs.Connect() );
+			
+			if ( !err )
+				{				
+                err = TATDriveInfo::CreatePath( logFileBuf, aFileName, fs );
+			    
+				// Replace file if exists
+				if ( err && err != KErrAlreadyExists )
+					{
+					LOGSTR2( "ATMH > TATDriveInfo::CreatePath() err( %i )", err );
+					return;
+					}
+				
+				// Replace file if exists (drive C)
+				err = file.Replace( fs, logFileBuf, EFileWrite );
+										
+				// Write to file
+				if ( !err )
+					{
+					err = file.Write( KDataFileVersion );
+					// Error msg buffer
+					TBuf8<KMaxFileName> msg;				     
+					// Write the error code to the buffer  
+					logFileBuf.Format( KIncorrectText, &KAtoolApiVersion, &aToolVersion );	
+					CnvUtfConverter::ConvertFromUnicodeToUtf8( msg, logFileBuf );
+					err = file.Write( msg );
+					}
+				// Closes the file.
+				file.Close();
+				}
+			
+			LOGSTR2( "ATMH > File err( %i )", err );			
+			// Closes the handle.
+			fs.Close();
+			}
+			break;
+			
+		case EATUseDefault:
+		case EATLogToTrace:
+			{
+			LOGSTR1( "ATMH > ReportIncorrectVersion > EATLogToTrace" );
+			// Error msg buffer
+			TBuf<KMaxFileName> msg;	
+			msg.Copy( KIncorrectTextTrace );
+			msg.Append( KIncorrectText );
+			TBuf<KMaxFileName> traceMsg;	
+			// Write the error code to the buffer  
+			traceMsg.Format( msg, &KAtoolApiVersion, &aToolVersion );
+			RDebug::Print( traceMsg );
+			}
+			break;
+		
+		default:
+			{
+			LOGSTR1( "ATMH > ReportIncorrectVersion > default" );
+			}
+			break;
+		}	
+	}
+
+// End of File