diff -r d27dfa8884ad -r da2cedce4920 analyzetool/dynamicmemoryhook/src/customuser.cpp --- /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 +#include +#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 + +#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 + +// 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 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 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 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 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 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 msg; + msg.Copy( KIncorrectTextTrace ); + msg.Append( KIncorrectText ); + TBuf 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