traceservices/commsdebugutility/SSVR/comsdbgaux.cpp
changeset 0 08ec8eefde2f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/traceservices/commsdebugutility/SSVR/comsdbgaux.cpp	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,524 @@
+// Copyright (c) 1997-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:
+// Implements flogger utility classes
+// 
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include "comsdbgaux.h"
+#include "comsdbgsvr.h"
+#include "comsdbgmessages.h"
+
+_LIT8(KSubsystemWildCard, "*");
+
+_LIT8(KLogKeyword, "Log");
+_LIT8(KMediaKeyword, "Media");
+_LIT8(KWin32DbgPortKeyword, "Win32Debug");
+_LIT8(KLogPathKeyword, "LogPath");
+_LIT8(KCommentKeyword, "//");
+_LIT8(KForceFlushKeyword, "Synchronous");
+const TUint8 KCarriageReturn = 0x000D;
+const TUint8 KLineFeed = 0x000A;
+
+
+
+CIniFileWatcher* CIniFileWatcher::NewL(RFs& aFs, CFileLoggerServer& aServer, const TDesC& aIniFile)
+	{
+	CIniFileWatcher* self = new(ELeave) CIniFileWatcher(aFs, aServer, aIniFile);
+	self->Initialize();
+	return self;
+	}
+
+CIniFileWatcher::CIniFileWatcher(RFs& aFs, CFileLoggerServer& aServer, const TDesC& aIniFile)
+: CActive(EPriorityStandard), iFs(aFs), iServer(aServer), iWatchedIniFile(aIniFile)
+{}
+
+void CIniFileWatcher::Initialize()
+  	{
+  	CActiveScheduler::Add(this);
+  	NotifyChange();
+  	}
+
+void CIniFileWatcher::NotifyChange()
+/* Listen for change on the CDU ini file. */
+    {
+    iFs.NotifyChange(ENotifyAll, iStatus, iWatchedIniFile);
+  	SetActive();
+  	}
+
+void CIniFileWatcher::RunL()
+	{
+	iStatus=KRequestPending;
+   NotifyChange();
+	iServer.IniFileChanged(iWatchedIniFile);
+	}
+
+void CIniFileWatcher::DoCancel()
+	{
+	iFs.NotifyChangeCancel();
+	}
+
+
+CIniFileWatcher::~CIniFileWatcher()
+	{
+	Cancel();
+	}
+
+///////////////CIniFileParser//////////////////////////////////////////////
+
+TInt CIniFileParser::ParseIniFile(TDesC& aIniFile)
+/*
+ * Returns: KErrNotFound if file not found or KErrPathNotFound if path not found.
+ */
+	{
+	TRAPD(err, DoParseIniFileL(aIniFile));
+	return err;
+	}
+
+TInt CIniFileParser::GetNextTokenAndCheck(TLex8& lex, TPtr8& tempPtr)
+/*
+Gets next token and ensures the token is simply not the EOF or a linefeed.
+lex is the lexical string to get the next token from.
+tempPtr points to the next token
+Returns KErrGeneral if token is bad or if we've already read past the end.
+*/
+	{
+	TUint8 ch;
+	TInt len;
+
+	if (lex.Eos())
+		{
+		return KErrGeneral;
+		}
+	
+	tempPtr = lex.NextToken();
+
+	len = tempPtr.Length();
+	if (len == 0)
+		{
+		// lex has figured out what is left is just the EOF
+		return KErrGeneral;
+		}
+
+	// this next part may be superfluous but we've had so much strife with
+	// the parser thus far that for now we're leaving it in
+
+	ch = tempPtr[0];
+	if (ch == KCarriageReturn || ch == KLineFeed)
+		{
+		return KErrGeneral;
+		}
+
+	if (tempPtr.Length() < 2)
+		{
+		return KErrNone;
+		}
+	ch = tempPtr[1];
+	if (ch == KCarriageReturn || ch == KLineFeed)
+		{
+		return KErrGeneral;
+		}
+
+	return KErrNone;
+	}
+	
+void CIniFileParser::DoParseIniFileL(TDesC& aIniFile)
+/*
+ * 
+ * The force flush state is only updated if it is not already set to something other
+ * than ENoValue. If force flush option is not found in ini file, force flush is set
+ * to off.
+ */
+	{
+
+	TInt fileLength;
+	TInt ret = KErrNone;
+	RFile iniFile;
+
+	// Open file
+	User::LeaveIfError(iniFile.Open(iFs, aIniFile, EFileShareAny));
+		
+	CleanupClosePushL(iniFile);
+	
+	// as we have been able to open the file, set the media to default.
+	// If the ini file is parsed correctly, this then gets overwritten.
+	// Otherwise the caller should pass thru a mesg to get the default enabled.
+	if (iLoggingMediaString.Length() == 0)
+		{
+		iLoggingMediaString = KDefaultMedia;
+		}
+		
+	
+
+	User::LeaveIfError(iniFile.Size(fileLength));
+
+	HBufC8* iniContents = HBufC8::NewLC(fileLength);
+	TPtr8 hbufPtr = iniContents->Des();
+	User::LeaveIfError(iniFile.Read(hbufPtr));
+	TLex8 lex(*iniContents);
+
+	//OK, file is open and ready for parsing. Make a tempory array and if there is a
+	//problem in the ini file leave settings as they were, leave, and
+	//the error will get picked up.
+
+	delete iIniSettings;
+	iIniSettings = NULL;
+	CIniLoggingPairs* iniSettings = CIniLoggingPairs::NewL();
+	CleanupStack::PushL(iniSettings);
+	TNameTag tempTag;
+	TNameTag tempTag2;
+	TChar  tempChar;
+
+	FOREVER
+		{
+		ret = GetNextTokenAndCheck(lex,hbufPtr);
+		if (ret != KErrNone)
+			{
+			break;
+			}
+		if (hbufPtr.Find(KCommentKeyword)!=KErrNotFound)		//found a Comment
+			{
+			tempChar = lex.Get();
+			while (!lex.Eos() && TUint(tempChar) != KCarriageReturn && TUint(tempChar) != KLineFeed)
+				{
+				tempChar = lex.Get();
+				}
+			}
+		else if (hbufPtr.CompareF(KMediaKeyword)==0)		//MediaSetting
+			{
+			User::LeaveIfError(GetNextTokenAndCheck(lex,hbufPtr));
+			if (hbufPtr.Length()>KMaxMediaStringLength)
+				{
+				User::Leave(KErrGeneral);
+				}
+			iLoggingMediaString = hbufPtr;
+			}
+		else if (hbufPtr.CompareF(KLogKeyword)==0)		//LOG
+			{
+			User::LeaveIfError(GetNextTokenAndCheck(lex,hbufPtr));
+
+			if (hbufPtr.Length()>KMaxTagLength)
+				{
+				tempTag = hbufPtr.Left(KMaxTagLength);
+				}
+			else
+				{
+				tempTag = hbufPtr;
+				}
+			User::LeaveIfError(GetNextTokenAndCheck(lex,hbufPtr));
+			if (hbufPtr.Length()>KMaxTagLength)
+				{
+				tempTag2 = hbufPtr.Left(KMaxTagLength);
+				}
+			else
+				{
+				tempTag2 = hbufPtr;
+				}
+			iniSettings->AddSettingL(tempTag, tempTag2);
+			}
+		else if (hbufPtr.CompareF(KForceFlushKeyword)==0)		//ForceFlush
+			{
+			if (iForceFlushState == ENoValue)
+				{
+				iForceFlushState = EFlushOn;
+				}
+			}
+		else if (hbufPtr.CompareF(KLogPathKeyword) == 0)		//LogPath
+			{
+			User::LeaveIfError(GetNextTokenAndCheck(lex,hbufPtr));
+			if (hbufPtr.Length()>KMaxName)
+				{
+				User::Leave(KErrOverflow);
+				}
+			iLoggingPathString.Copy(hbufPtr);
+			}
+		else if (hbufPtr.CompareF(KWin32DbgPortKeyword)==0)		//Win32DebugPort
+			{
+			iWin32DebugEnabled = ETrue;
+			}
+		else
+			User::Leave(KErrBadName);
+
+		if (lex.Eos())
+			{
+			break;
+			}
+		}
+	iIniSettings = iniSettings;
+	CleanupStack::Pop(iniSettings);
+	CleanupStack::PopAndDestroy();	//iniContents
+	CleanupStack::PopAndDestroy();	//iniFile
+
+	if (iForceFlushState == ENoValue)
+		{
+		iForceFlushState = EFlushOff;
+		}
+	}
+
+CIniFileParser* CIniFileParser::NewL(RFs& aFs)
+	{
+	return new(ELeave) CIniFileParser(aFs);
+	}
+
+CIniFileParser::~CIniFileParser()
+	{
+	delete iIniSettings;
+	}
+
+TBool CIniFileParser::LogValid(const TDesC8& aSubsystem, const TDesC8& aComponent) const
+// If no memory, this operation will return EFalse so user will not get logs, nor a msg to say so.
+	{
+	if (iIniSettings)
+		{
+		TBool result = iIniSettings->SettingValid(aSubsystem, aComponent);
+		return result;
+		}
+	else
+		{
+		return EFalse;
+		}
+	}
+
+void CIniFileParser::LogMediaSetting(TDes8& aString) const
+	{
+	aString=iLoggingMediaString;
+	}
+
+void CIniFileParser::LogPathSetting(TDes8& aString) const
+	{
+	aString.Copy(iLoggingPathString);
+	}
+
+void CIniFileParser::FlushingOn(TBool& aFlushingOn) const
+/*
+ * Return whether flushing is on or off.
+ */
+	{
+	if (iForceFlushState == EFlushOn)
+		{
+		aFlushingOn = ETrue;
+		}
+	else
+		{
+		aFlushingOn = EFalse;
+		}
+	}
+
+void CIniFileParser::FinaliseFlushSetting()
+/*
+ * It is not safe to switch flush modes once we begin logging, so this is called
+ * to let fileparser know that system is about to commence logging.
+ * If the file parser has still not determined whether it should be logging or not,
+ * then set flushing to off.
+ */
+	{
+	if (iForceFlushState == ENoValue)
+		{
+		iForceFlushState = EFlushOff;
+		}
+	}
+
+CIniFileParser::CIniFileParser(RFs& aFs)
+: iFs(aFs)
+	{
+	iForceFlushState = ENoValue;
+	}
+
+/////////////////////////////////////////////
+
+CSubsystemSettings::~CSubsystemSettings()
+	{
+	iComponentArray.Close();
+	}
+
+TInt CSubsystemSettings::AddComponent(const TDesC8& aComponent)
+	{
+	return iComponentArray.InsertInOrder(TNameTag(aComponent),
+		TLinearOrder<TNameTag>(CompareTComponent));
+	}
+
+TBool CSubsystemSettings::ElementExistsInArray(const TDesC8& aComponent) const
+	{
+	return (iComponentArray.FindInOrder(aComponent, TLinearOrder<TNameTag>(CSubsystemSettings::CompareTComponent))!=KErrNotFound);
+	}
+
+CSubsystemSettings::CSubsystemSettings(const TDesC8& aName)
+: iSubsystemName(aName)
+	{}
+
+void CSubsystemSettings::SetSubsystemName(const TDesC8& aName)
+	{
+	iSubsystemName = aName;
+	}
+TInt CSubsystemSettings::CompareCSubsystemSettings(const CSubsystemSettings& aFirst, const CSubsystemSettings& aSecond)
+	{
+	return aFirst.iSubsystemName.CompareF(aSecond.iSubsystemName);
+	}
+
+TInt CSubsystemSettings::CompareTComponent(const TNameTag& aFirst, const TNameTag& aSecond)
+	{
+	return aFirst.CompareF(aSecond);
+	}
+
+void CSubsystemSettings::SetWildCarded(TBool aWildCarded)
+	{
+	iSubsystemWildcarded = aWildCarded;
+	}
+
+CIniLoggingPairs* CIniLoggingPairs::NewL()
+	{
+	CIniLoggingPairs* self = new(ELeave) CIniLoggingPairs;
+	if((self->iProbeSubsystem = new CSubsystemSettings(KNullDesC8)) == NULL)
+		{
+		delete self;
+		User::Leave(KErrNoMemory);
+		}
+	return self;
+	}
+	
+CIniLoggingPairs::~CIniLoggingPairs()
+	{
+	iSubsystems.ResetAndDestroy();
+	delete iProbeSubsystem;
+	}
+
+void CIniLoggingPairs::AddSettingL(const TDesC8& aSubsystem, const TDesC8& aComponent)
+	{
+	TBool subsystemIsNewInList(EFalse);
+	CSubsystemSettings* subsystemSetting;
+	iProbeSubsystem->SetSubsystemName(aSubsystem);
+	TInt subsysPos = iSubsystems.FindInOrder(iProbeSubsystem, TLinearOrder<CSubsystemSettings>(CSubsystemSettings::CompareCSubsystemSettings));
+	if (subsysPos == KErrNotFound)
+		{
+		subsystemSetting = new(ELeave) CSubsystemSettings(aSubsystem);
+		CleanupStack::PushL(subsystemSetting);
+		iSubsystems.InsertInOrderL(subsystemSetting, TLinearOrder<CSubsystemSettings>(CSubsystemSettings::CompareCSubsystemSettings));
+		subsystemIsNewInList = ETrue;
+		CleanupStack::Pop(subsystemSetting);
+		}
+	else 
+		{
+		ASSERT(subsysPos >= KErrNone);
+		subsystemSetting = iSubsystems[subsysPos];
+		}
+	//subsystemSetting is now owned in the array, so we don't need to worry about any leaves from here on.
+	if (aComponent.CompareF(KSubsystemWildCard)==0)
+		{
+		subsystemSetting->SetWildCarded(ETrue);
+		return;
+		}
+	TInt err;
+	if ((err = subsystemSetting->AddComponent(aComponent))!=KErrNone)
+		{
+		if (subsystemIsNewInList)
+			{
+			delete subsystemSetting;
+			iSubsystems.Remove(subsysPos);
+			User::Leave(err);
+			}
+		}
+	}
+
+TBool CIniLoggingPairs::SettingValid(const TDesC8& aSubsystem, const TDesC8& aComponent) const
+	{
+	iProbeSubsystem->SetSubsystemName(aSubsystem);
+	TBool settingValid;
+	TInt positionInArray;
+	if (iSubsystems.FindInOrder(iProbeSubsystem, positionInArray, TLinearOrder<CSubsystemSettings>(CSubsystemSettings::CompareCSubsystemSettings))==KErrNotFound)
+		{
+		settingValid = EFalse;
+		}
+	else if (iSubsystems[positionInArray]->IsWildCarded())
+		{
+		settingValid = ETrue;
+		}
+	else
+		{
+		settingValid = iSubsystems[positionInArray]->ElementExistsInArray(aComponent);
+		}
+	return settingValid;
+	}
+
+/////////////////////////////////////////////
+
+CTimeManager* CTimeManager::NewL(MLogArrayAccess& aArrayAccess)
+	{
+	CTimeManager* self = new(ELeave) CTimeManager(aArrayAccess);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+void CTimeManager::Beat()
+/*
+ * Called by kernel every second if we're synchronised.
+ * Updates the variable recording the current time, and sends it to the log queue.
+ */
+	{
+	iTime+=TTimeIntervalSeconds(1);
+	SendTimeUpdate();
+	}
+
+void CTimeManager::Synchronize()
+/*
+ * Called by kernel when it finds synchronisation is lost (a heartbeat was missed - maybe
+ * device has been off for a while).
+ * Updates the variable recording the current time, and sends it to the log queue.
+ */
+	{
+	iTime.HomeTime();
+	SendTimeUpdate();
+	}
+
+CTimeManager::CTimeManager(MLogArrayAccess& aArrayAccess)
+: iArrayAccess(aArrayAccess)
+{}
+
+void CTimeManager::SendTimeUpdate()
+/*
+ * append to queue a time update message
+ */
+	{
+	CTimeUpdateMessage* timeMessage = new CTimeUpdateMessage(iTime);
+	if (timeMessage)
+		{
+		if (iArrayAccess.AppendAndGiveOwnership(timeMessage)!=KErrNone)
+			{
+			delete timeMessage;	//We failed to get a time update in. Ahh well. 
+			}
+		}
+	}
+
+void CTimeManager::ConstructL()
+/*
+ * Start heartbeat active object to trigger every second, passing in this class
+ * for kernel to callback to.
+ */
+	{
+	iTime.HomeTime();
+	iHeartbeat = CHeartbeat::NewL(EPriorityHigh);
+	iHeartbeat->Start(ETwelveOClock, this); // 12 1/12th intervals
+	SendTimeUpdate();
+	}
+
+CTimeManager::~CTimeManager()
+	{
+	delete iHeartbeat;
+	}
+