os/persistentdata/traceservices/commsdebugutility/SSVR/comsdbgaux.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
// Implements flogger utility classes
sl@0
    15
// 
sl@0
    16
//
sl@0
    17
sl@0
    18
/**
sl@0
    19
 @file
sl@0
    20
 @internalComponent
sl@0
    21
*/
sl@0
    22
sl@0
    23
#include "comsdbgaux.h"
sl@0
    24
#include "comsdbgsvr.h"
sl@0
    25
#include "comsdbgmessages.h"
sl@0
    26
sl@0
    27
_LIT8(KSubsystemWildCard, "*");
sl@0
    28
sl@0
    29
_LIT8(KLogKeyword, "Log");
sl@0
    30
_LIT8(KMediaKeyword, "Media");
sl@0
    31
_LIT8(KWin32DbgPortKeyword, "Win32Debug");
sl@0
    32
_LIT8(KLogPathKeyword, "LogPath");
sl@0
    33
_LIT8(KCommentKeyword, "//");
sl@0
    34
_LIT8(KForceFlushKeyword, "Synchronous");
sl@0
    35
const TUint8 KCarriageReturn = 0x000D;
sl@0
    36
const TUint8 KLineFeed = 0x000A;
sl@0
    37
sl@0
    38
sl@0
    39
sl@0
    40
CIniFileWatcher* CIniFileWatcher::NewL(RFs& aFs, CFileLoggerServer& aServer, const TDesC& aIniFile)
sl@0
    41
	{
sl@0
    42
	CIniFileWatcher* self = new(ELeave) CIniFileWatcher(aFs, aServer, aIniFile);
sl@0
    43
	self->Initialize();
sl@0
    44
	return self;
sl@0
    45
	}
sl@0
    46
sl@0
    47
CIniFileWatcher::CIniFileWatcher(RFs& aFs, CFileLoggerServer& aServer, const TDesC& aIniFile)
sl@0
    48
: CActive(EPriorityStandard), iFs(aFs), iServer(aServer), iWatchedIniFile(aIniFile)
sl@0
    49
{}
sl@0
    50
sl@0
    51
void CIniFileWatcher::Initialize()
sl@0
    52
  	{
sl@0
    53
  	CActiveScheduler::Add(this);
sl@0
    54
  	NotifyChange();
sl@0
    55
  	}
sl@0
    56
sl@0
    57
void CIniFileWatcher::NotifyChange()
sl@0
    58
/* Listen for change on the CDU ini file. */
sl@0
    59
    {
sl@0
    60
    iFs.NotifyChange(ENotifyAll, iStatus, iWatchedIniFile);
sl@0
    61
  	SetActive();
sl@0
    62
  	}
sl@0
    63
sl@0
    64
void CIniFileWatcher::RunL()
sl@0
    65
	{
sl@0
    66
	iStatus=KRequestPending;
sl@0
    67
   NotifyChange();
sl@0
    68
	iServer.IniFileChanged(iWatchedIniFile);
sl@0
    69
	}
sl@0
    70
sl@0
    71
void CIniFileWatcher::DoCancel()
sl@0
    72
	{
sl@0
    73
	iFs.NotifyChangeCancel();
sl@0
    74
	}
sl@0
    75
sl@0
    76
sl@0
    77
CIniFileWatcher::~CIniFileWatcher()
sl@0
    78
	{
sl@0
    79
	Cancel();
sl@0
    80
	}
sl@0
    81
sl@0
    82
///////////////CIniFileParser//////////////////////////////////////////////
sl@0
    83
sl@0
    84
TInt CIniFileParser::ParseIniFile(TDesC& aIniFile)
sl@0
    85
/*
sl@0
    86
 * Returns: KErrNotFound if file not found or KErrPathNotFound if path not found.
sl@0
    87
 */
sl@0
    88
	{
sl@0
    89
	TRAPD(err, DoParseIniFileL(aIniFile));
sl@0
    90
	return err;
sl@0
    91
	}
sl@0
    92
sl@0
    93
TInt CIniFileParser::GetNextTokenAndCheck(TLex8& lex, TPtr8& tempPtr)
sl@0
    94
/*
sl@0
    95
Gets next token and ensures the token is simply not the EOF or a linefeed.
sl@0
    96
lex is the lexical string to get the next token from.
sl@0
    97
tempPtr points to the next token
sl@0
    98
Returns KErrGeneral if token is bad or if we've already read past the end.
sl@0
    99
*/
sl@0
   100
	{
sl@0
   101
	TUint8 ch;
sl@0
   102
	TInt len;
sl@0
   103
sl@0
   104
	if (lex.Eos())
sl@0
   105
		{
sl@0
   106
		return KErrGeneral;
sl@0
   107
		}
sl@0
   108
	
sl@0
   109
	tempPtr = lex.NextToken();
sl@0
   110
sl@0
   111
	len = tempPtr.Length();
sl@0
   112
	if (len == 0)
sl@0
   113
		{
sl@0
   114
		// lex has figured out what is left is just the EOF
sl@0
   115
		return KErrGeneral;
sl@0
   116
		}
sl@0
   117
sl@0
   118
	// this next part may be superfluous but we've had so much strife with
sl@0
   119
	// the parser thus far that for now we're leaving it in
sl@0
   120
sl@0
   121
	ch = tempPtr[0];
sl@0
   122
	if (ch == KCarriageReturn || ch == KLineFeed)
sl@0
   123
		{
sl@0
   124
		return KErrGeneral;
sl@0
   125
		}
sl@0
   126
sl@0
   127
	if (tempPtr.Length() < 2)
sl@0
   128
		{
sl@0
   129
		return KErrNone;
sl@0
   130
		}
sl@0
   131
	ch = tempPtr[1];
sl@0
   132
	if (ch == KCarriageReturn || ch == KLineFeed)
sl@0
   133
		{
sl@0
   134
		return KErrGeneral;
sl@0
   135
		}
sl@0
   136
sl@0
   137
	return KErrNone;
sl@0
   138
	}
sl@0
   139
	
sl@0
   140
void CIniFileParser::DoParseIniFileL(TDesC& aIniFile)
sl@0
   141
/*
sl@0
   142
 * 
sl@0
   143
 * The force flush state is only updated if it is not already set to something other
sl@0
   144
 * than ENoValue. If force flush option is not found in ini file, force flush is set
sl@0
   145
 * to off.
sl@0
   146
 */
sl@0
   147
	{
sl@0
   148
sl@0
   149
	TInt fileLength;
sl@0
   150
	TInt ret = KErrNone;
sl@0
   151
	RFile iniFile;
sl@0
   152
sl@0
   153
	// Open file
sl@0
   154
	User::LeaveIfError(iniFile.Open(iFs, aIniFile, EFileShareAny));
sl@0
   155
		
sl@0
   156
	CleanupClosePushL(iniFile);
sl@0
   157
	
sl@0
   158
	// as we have been able to open the file, set the media to default.
sl@0
   159
	// If the ini file is parsed correctly, this then gets overwritten.
sl@0
   160
	// Otherwise the caller should pass thru a mesg to get the default enabled.
sl@0
   161
	if (iLoggingMediaString.Length() == 0)
sl@0
   162
		{
sl@0
   163
		iLoggingMediaString = KDefaultMedia;
sl@0
   164
		}
sl@0
   165
		
sl@0
   166
	
sl@0
   167
sl@0
   168
	User::LeaveIfError(iniFile.Size(fileLength));
sl@0
   169
sl@0
   170
	HBufC8* iniContents = HBufC8::NewLC(fileLength);
sl@0
   171
	TPtr8 hbufPtr = iniContents->Des();
sl@0
   172
	User::LeaveIfError(iniFile.Read(hbufPtr));
sl@0
   173
	TLex8 lex(*iniContents);
sl@0
   174
sl@0
   175
	//OK, file is open and ready for parsing. Make a tempory array and if there is a
sl@0
   176
	//problem in the ini file leave settings as they were, leave, and
sl@0
   177
	//the error will get picked up.
sl@0
   178
sl@0
   179
	delete iIniSettings;
sl@0
   180
	iIniSettings = NULL;
sl@0
   181
	CIniLoggingPairs* iniSettings = CIniLoggingPairs::NewL();
sl@0
   182
	CleanupStack::PushL(iniSettings);
sl@0
   183
	TNameTag tempTag;
sl@0
   184
	TNameTag tempTag2;
sl@0
   185
	TChar  tempChar;
sl@0
   186
sl@0
   187
	FOREVER
sl@0
   188
		{
sl@0
   189
		ret = GetNextTokenAndCheck(lex,hbufPtr);
sl@0
   190
		if (ret != KErrNone)
sl@0
   191
			{
sl@0
   192
			break;
sl@0
   193
			}
sl@0
   194
		if (hbufPtr.Find(KCommentKeyword)!=KErrNotFound)		//found a Comment
sl@0
   195
			{
sl@0
   196
			tempChar = lex.Get();
sl@0
   197
			while (!lex.Eos() && TUint(tempChar) != KCarriageReturn && TUint(tempChar) != KLineFeed)
sl@0
   198
				{
sl@0
   199
				tempChar = lex.Get();
sl@0
   200
				}
sl@0
   201
			}
sl@0
   202
		else if (hbufPtr.CompareF(KMediaKeyword)==0)		//MediaSetting
sl@0
   203
			{
sl@0
   204
			User::LeaveIfError(GetNextTokenAndCheck(lex,hbufPtr));
sl@0
   205
			if (hbufPtr.Length()>KMaxMediaStringLength)
sl@0
   206
				{
sl@0
   207
				User::Leave(KErrGeneral);
sl@0
   208
				}
sl@0
   209
			iLoggingMediaString = hbufPtr;
sl@0
   210
			}
sl@0
   211
		else if (hbufPtr.CompareF(KLogKeyword)==0)		//LOG
sl@0
   212
			{
sl@0
   213
			User::LeaveIfError(GetNextTokenAndCheck(lex,hbufPtr));
sl@0
   214
sl@0
   215
			if (hbufPtr.Length()>KMaxTagLength)
sl@0
   216
				{
sl@0
   217
				tempTag = hbufPtr.Left(KMaxTagLength);
sl@0
   218
				}
sl@0
   219
			else
sl@0
   220
				{
sl@0
   221
				tempTag = hbufPtr;
sl@0
   222
				}
sl@0
   223
			User::LeaveIfError(GetNextTokenAndCheck(lex,hbufPtr));
sl@0
   224
			if (hbufPtr.Length()>KMaxTagLength)
sl@0
   225
				{
sl@0
   226
				tempTag2 = hbufPtr.Left(KMaxTagLength);
sl@0
   227
				}
sl@0
   228
			else
sl@0
   229
				{
sl@0
   230
				tempTag2 = hbufPtr;
sl@0
   231
				}
sl@0
   232
			iniSettings->AddSettingL(tempTag, tempTag2);
sl@0
   233
			}
sl@0
   234
		else if (hbufPtr.CompareF(KForceFlushKeyword)==0)		//ForceFlush
sl@0
   235
			{
sl@0
   236
			if (iForceFlushState == ENoValue)
sl@0
   237
				{
sl@0
   238
				iForceFlushState = EFlushOn;
sl@0
   239
				}
sl@0
   240
			}
sl@0
   241
		else if (hbufPtr.CompareF(KLogPathKeyword) == 0)		//LogPath
sl@0
   242
			{
sl@0
   243
			User::LeaveIfError(GetNextTokenAndCheck(lex,hbufPtr));
sl@0
   244
			if (hbufPtr.Length()>KMaxName)
sl@0
   245
				{
sl@0
   246
				User::Leave(KErrOverflow);
sl@0
   247
				}
sl@0
   248
			iLoggingPathString.Copy(hbufPtr);
sl@0
   249
			}
sl@0
   250
		else if (hbufPtr.CompareF(KWin32DbgPortKeyword)==0)		//Win32DebugPort
sl@0
   251
			{
sl@0
   252
			iWin32DebugEnabled = ETrue;
sl@0
   253
			}
sl@0
   254
		else
sl@0
   255
			User::Leave(KErrBadName);
sl@0
   256
sl@0
   257
		if (lex.Eos())
sl@0
   258
			{
sl@0
   259
			break;
sl@0
   260
			}
sl@0
   261
		}
sl@0
   262
	iIniSettings = iniSettings;
sl@0
   263
	CleanupStack::Pop(iniSettings);
sl@0
   264
	CleanupStack::PopAndDestroy();	//iniContents
sl@0
   265
	CleanupStack::PopAndDestroy();	//iniFile
sl@0
   266
sl@0
   267
	if (iForceFlushState == ENoValue)
sl@0
   268
		{
sl@0
   269
		iForceFlushState = EFlushOff;
sl@0
   270
		}
sl@0
   271
	}
sl@0
   272
sl@0
   273
CIniFileParser* CIniFileParser::NewL(RFs& aFs)
sl@0
   274
	{
sl@0
   275
	return new(ELeave) CIniFileParser(aFs);
sl@0
   276
	}
sl@0
   277
sl@0
   278
CIniFileParser::~CIniFileParser()
sl@0
   279
	{
sl@0
   280
	delete iIniSettings;
sl@0
   281
	}
sl@0
   282
sl@0
   283
TBool CIniFileParser::LogValid(const TDesC8& aSubsystem, const TDesC8& aComponent) const
sl@0
   284
// If no memory, this operation will return EFalse so user will not get logs, nor a msg to say so.
sl@0
   285
	{
sl@0
   286
	if (iIniSettings)
sl@0
   287
		{
sl@0
   288
		TBool result = iIniSettings->SettingValid(aSubsystem, aComponent);
sl@0
   289
		return result;
sl@0
   290
		}
sl@0
   291
	else
sl@0
   292
		{
sl@0
   293
		return EFalse;
sl@0
   294
		}
sl@0
   295
	}
sl@0
   296
sl@0
   297
void CIniFileParser::LogMediaSetting(TDes8& aString) const
sl@0
   298
	{
sl@0
   299
	aString=iLoggingMediaString;
sl@0
   300
	}
sl@0
   301
sl@0
   302
void CIniFileParser::LogPathSetting(TDes8& aString) const
sl@0
   303
	{
sl@0
   304
	aString.Copy(iLoggingPathString);
sl@0
   305
	}
sl@0
   306
sl@0
   307
void CIniFileParser::FlushingOn(TBool& aFlushingOn) const
sl@0
   308
/*
sl@0
   309
 * Return whether flushing is on or off.
sl@0
   310
 */
sl@0
   311
	{
sl@0
   312
	if (iForceFlushState == EFlushOn)
sl@0
   313
		{
sl@0
   314
		aFlushingOn = ETrue;
sl@0
   315
		}
sl@0
   316
	else
sl@0
   317
		{
sl@0
   318
		aFlushingOn = EFalse;
sl@0
   319
		}
sl@0
   320
	}
sl@0
   321
sl@0
   322
void CIniFileParser::FinaliseFlushSetting()
sl@0
   323
/*
sl@0
   324
 * It is not safe to switch flush modes once we begin logging, so this is called
sl@0
   325
 * to let fileparser know that system is about to commence logging.
sl@0
   326
 * If the file parser has still not determined whether it should be logging or not,
sl@0
   327
 * then set flushing to off.
sl@0
   328
 */
sl@0
   329
	{
sl@0
   330
	if (iForceFlushState == ENoValue)
sl@0
   331
		{
sl@0
   332
		iForceFlushState = EFlushOff;
sl@0
   333
		}
sl@0
   334
	}
sl@0
   335
sl@0
   336
CIniFileParser::CIniFileParser(RFs& aFs)
sl@0
   337
: iFs(aFs)
sl@0
   338
	{
sl@0
   339
	iForceFlushState = ENoValue;
sl@0
   340
	}
sl@0
   341
sl@0
   342
/////////////////////////////////////////////
sl@0
   343
sl@0
   344
CSubsystemSettings::~CSubsystemSettings()
sl@0
   345
	{
sl@0
   346
	iComponentArray.Close();
sl@0
   347
	}
sl@0
   348
sl@0
   349
TInt CSubsystemSettings::AddComponent(const TDesC8& aComponent)
sl@0
   350
	{
sl@0
   351
	return iComponentArray.InsertInOrder(TNameTag(aComponent),
sl@0
   352
		TLinearOrder<TNameTag>(CompareTComponent));
sl@0
   353
	}
sl@0
   354
sl@0
   355
TBool CSubsystemSettings::ElementExistsInArray(const TDesC8& aComponent) const
sl@0
   356
	{
sl@0
   357
	return (iComponentArray.FindInOrder(aComponent, TLinearOrder<TNameTag>(CSubsystemSettings::CompareTComponent))!=KErrNotFound);
sl@0
   358
	}
sl@0
   359
sl@0
   360
CSubsystemSettings::CSubsystemSettings(const TDesC8& aName)
sl@0
   361
: iSubsystemName(aName)
sl@0
   362
	{}
sl@0
   363
sl@0
   364
void CSubsystemSettings::SetSubsystemName(const TDesC8& aName)
sl@0
   365
	{
sl@0
   366
	iSubsystemName = aName;
sl@0
   367
	}
sl@0
   368
TInt CSubsystemSettings::CompareCSubsystemSettings(const CSubsystemSettings& aFirst, const CSubsystemSettings& aSecond)
sl@0
   369
	{
sl@0
   370
	return aFirst.iSubsystemName.CompareF(aSecond.iSubsystemName);
sl@0
   371
	}
sl@0
   372
sl@0
   373
TInt CSubsystemSettings::CompareTComponent(const TNameTag& aFirst, const TNameTag& aSecond)
sl@0
   374
	{
sl@0
   375
	return aFirst.CompareF(aSecond);
sl@0
   376
	}
sl@0
   377
sl@0
   378
void CSubsystemSettings::SetWildCarded(TBool aWildCarded)
sl@0
   379
	{
sl@0
   380
	iSubsystemWildcarded = aWildCarded;
sl@0
   381
	}
sl@0
   382
sl@0
   383
CIniLoggingPairs* CIniLoggingPairs::NewL()
sl@0
   384
	{
sl@0
   385
	CIniLoggingPairs* self = new(ELeave) CIniLoggingPairs;
sl@0
   386
	if((self->iProbeSubsystem = new CSubsystemSettings(KNullDesC8)) == NULL)
sl@0
   387
		{
sl@0
   388
		delete self;
sl@0
   389
		User::Leave(KErrNoMemory);
sl@0
   390
		}
sl@0
   391
	return self;
sl@0
   392
	}
sl@0
   393
	
sl@0
   394
CIniLoggingPairs::~CIniLoggingPairs()
sl@0
   395
	{
sl@0
   396
	iSubsystems.ResetAndDestroy();
sl@0
   397
	delete iProbeSubsystem;
sl@0
   398
	}
sl@0
   399
sl@0
   400
void CIniLoggingPairs::AddSettingL(const TDesC8& aSubsystem, const TDesC8& aComponent)
sl@0
   401
	{
sl@0
   402
	TBool subsystemIsNewInList(EFalse);
sl@0
   403
	CSubsystemSettings* subsystemSetting;
sl@0
   404
	iProbeSubsystem->SetSubsystemName(aSubsystem);
sl@0
   405
	TInt subsysPos = iSubsystems.FindInOrder(iProbeSubsystem, TLinearOrder<CSubsystemSettings>(CSubsystemSettings::CompareCSubsystemSettings));
sl@0
   406
	if (subsysPos == KErrNotFound)
sl@0
   407
		{
sl@0
   408
		subsystemSetting = new(ELeave) CSubsystemSettings(aSubsystem);
sl@0
   409
		CleanupStack::PushL(subsystemSetting);
sl@0
   410
		iSubsystems.InsertInOrderL(subsystemSetting, TLinearOrder<CSubsystemSettings>(CSubsystemSettings::CompareCSubsystemSettings));
sl@0
   411
		subsystemIsNewInList = ETrue;
sl@0
   412
		CleanupStack::Pop(subsystemSetting);
sl@0
   413
		}
sl@0
   414
	else 
sl@0
   415
		{
sl@0
   416
		ASSERT(subsysPos >= KErrNone);
sl@0
   417
		subsystemSetting = iSubsystems[subsysPos];
sl@0
   418
		}
sl@0
   419
	//subsystemSetting is now owned in the array, so we don't need to worry about any leaves from here on.
sl@0
   420
	if (aComponent.CompareF(KSubsystemWildCard)==0)
sl@0
   421
		{
sl@0
   422
		subsystemSetting->SetWildCarded(ETrue);
sl@0
   423
		return;
sl@0
   424
		}
sl@0
   425
	TInt err;
sl@0
   426
	if ((err = subsystemSetting->AddComponent(aComponent))!=KErrNone)
sl@0
   427
		{
sl@0
   428
		if (subsystemIsNewInList)
sl@0
   429
			{
sl@0
   430
			delete subsystemSetting;
sl@0
   431
			iSubsystems.Remove(subsysPos);
sl@0
   432
			User::Leave(err);
sl@0
   433
			}
sl@0
   434
		}
sl@0
   435
	}
sl@0
   436
sl@0
   437
TBool CIniLoggingPairs::SettingValid(const TDesC8& aSubsystem, const TDesC8& aComponent) const
sl@0
   438
	{
sl@0
   439
	iProbeSubsystem->SetSubsystemName(aSubsystem);
sl@0
   440
	TBool settingValid;
sl@0
   441
	TInt positionInArray;
sl@0
   442
	if (iSubsystems.FindInOrder(iProbeSubsystem, positionInArray, TLinearOrder<CSubsystemSettings>(CSubsystemSettings::CompareCSubsystemSettings))==KErrNotFound)
sl@0
   443
		{
sl@0
   444
		settingValid = EFalse;
sl@0
   445
		}
sl@0
   446
	else if (iSubsystems[positionInArray]->IsWildCarded())
sl@0
   447
		{
sl@0
   448
		settingValid = ETrue;
sl@0
   449
		}
sl@0
   450
	else
sl@0
   451
		{
sl@0
   452
		settingValid = iSubsystems[positionInArray]->ElementExistsInArray(aComponent);
sl@0
   453
		}
sl@0
   454
	return settingValid;
sl@0
   455
	}
sl@0
   456
sl@0
   457
/////////////////////////////////////////////
sl@0
   458
sl@0
   459
CTimeManager* CTimeManager::NewL(MLogArrayAccess& aArrayAccess)
sl@0
   460
	{
sl@0
   461
	CTimeManager* self = new(ELeave) CTimeManager(aArrayAccess);
sl@0
   462
	CleanupStack::PushL(self);
sl@0
   463
	self->ConstructL();
sl@0
   464
	CleanupStack::Pop(self);
sl@0
   465
	return self;
sl@0
   466
	}
sl@0
   467
sl@0
   468
void CTimeManager::Beat()
sl@0
   469
/*
sl@0
   470
 * Called by kernel every second if we're synchronised.
sl@0
   471
 * Updates the variable recording the current time, and sends it to the log queue.
sl@0
   472
 */
sl@0
   473
	{
sl@0
   474
	iTime+=TTimeIntervalSeconds(1);
sl@0
   475
	SendTimeUpdate();
sl@0
   476
	}
sl@0
   477
sl@0
   478
void CTimeManager::Synchronize()
sl@0
   479
/*
sl@0
   480
 * Called by kernel when it finds synchronisation is lost (a heartbeat was missed - maybe
sl@0
   481
 * device has been off for a while).
sl@0
   482
 * Updates the variable recording the current time, and sends it to the log queue.
sl@0
   483
 */
sl@0
   484
	{
sl@0
   485
	iTime.HomeTime();
sl@0
   486
	SendTimeUpdate();
sl@0
   487
	}
sl@0
   488
sl@0
   489
CTimeManager::CTimeManager(MLogArrayAccess& aArrayAccess)
sl@0
   490
: iArrayAccess(aArrayAccess)
sl@0
   491
{}
sl@0
   492
sl@0
   493
void CTimeManager::SendTimeUpdate()
sl@0
   494
/*
sl@0
   495
 * append to queue a time update message
sl@0
   496
 */
sl@0
   497
	{
sl@0
   498
	CTimeUpdateMessage* timeMessage = new CTimeUpdateMessage(iTime);
sl@0
   499
	if (timeMessage)
sl@0
   500
		{
sl@0
   501
		if (iArrayAccess.AppendAndGiveOwnership(timeMessage)!=KErrNone)
sl@0
   502
			{
sl@0
   503
			delete timeMessage;	//We failed to get a time update in. Ahh well. 
sl@0
   504
			}
sl@0
   505
		}
sl@0
   506
	}
sl@0
   507
sl@0
   508
void CTimeManager::ConstructL()
sl@0
   509
/*
sl@0
   510
 * Start heartbeat active object to trigger every second, passing in this class
sl@0
   511
 * for kernel to callback to.
sl@0
   512
 */
sl@0
   513
	{
sl@0
   514
	iTime.HomeTime();
sl@0
   515
	iHeartbeat = CHeartbeat::NewL(EPriorityHigh);
sl@0
   516
	iHeartbeat->Start(ETwelveOClock, this); // 12 1/12th intervals
sl@0
   517
	SendTimeUpdate();
sl@0
   518
	}
sl@0
   519
sl@0
   520
CTimeManager::~CTimeManager()
sl@0
   521
	{
sl@0
   522
	delete iHeartbeat;
sl@0
   523
	}
sl@0
   524