loggingservices/eventlogger/LogServ/src/LogServBackupManager.cpp
changeset 0 08ec8eefde2f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/loggingservices/eventlogger/LogServ/src/LogServBackupManager.cpp	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,350 @@
+// Copyright (c) 2002-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 "LogServBackupManager.h"
+
+// User includes
+#include <logcli.h>
+#include "logservpanic.h"
+
+// Constants
+const TInt KTimerDelay = 10000000; // 10 seconds
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// -----> CLogServBackupManager (source)
+/////////////////////////////////////////////////////////////////////////////////////////
+
+CLogServBackupManager::CLogServBackupManager(TInt aPriority)
+:	CTimer(aPriority)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+CLogServBackupManager::~CLogServBackupManager()
+	{
+	__ASSERT_DEBUG(iObservers.Count() == 0, Panic(ELogBackupObserversStillRegistered));
+	Cancel();
+
+	// Unregister ourselves with backup server
+	if (iBackup)
+		{
+		if	(iDatabaseName)
+			iBackup->DeregisterFile(*iDatabaseName);
+		delete iBackup;
+		}
+	delete iDatabaseName;
+	iObservers.Close();
+	}
+
+void CLogServBackupManager::ConstructL()
+	{
+	CTimer::ConstructL();
+	}
+
+CLogServBackupManager* CLogServBackupManager::NewL(TInt aPriority)
+	{
+	CLogServBackupManager* self = new(ELeave) CLogServBackupManager(aPriority);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CLogServBackupManager::BIObserverAddL(MLogServBackupObserver& aObserver, TLogServBackupPriority aPriority)
+	{
+	LOGTEXT2("CLogServBackupManager::BIObserverAddL(aPriority=%d)", aPriority);
+	TLogBackupNotificationEntry entry(aObserver, aPriority);
+	
+	// Create orderer which ensures that we place the objects in priority ascending order (i.e. 
+	// higher priority gets notified first).
+	TLinearOrder<TLogBackupNotificationEntry> orderer(CompareEntries);
+	const TInt error = iObservers.InsertInOrderAllowRepeats(entry, orderer);
+	User::LeaveIfError(error);
+
+	LOGTEXT("CLogServBackupManager::BIObserverAddL() - end");
+	}
+
+void CLogServBackupManager::BIObserverRemove(MLogServBackupObserver& aObserver)
+//
+//	Removes an observer from the notification queue
+//
+	{
+	const TInt count = iObservers.Count();
+	for(TInt i=0; i<count; i++)
+		{
+		const TLogBackupNotificationEntry& entry = iObservers[i];
+		if	(&aObserver == &entry.iObserver)
+			{
+			iObservers.Remove(i);
+			return;
+			}
+		}
+	}
+
+MLogServBackupInterface::TLogServBackupState CLogServBackupManager::BIState() const
+	{
+	return iState;
+	}
+
+TInt CLogServBackupManager::BIErrorValueForCurrentState() const
+	{
+	TInt error = KErrNone;
+	switch(BIState())
+		{
+	case ELogServBackupStateIdle:
+		error = KErrNone;
+		break;
+	case ELogServBackupStateBackupInProgress:
+		error = KErrAccessDenied;
+		break;
+		}
+	//
+	LOGTEXT2("CLogServBackupManager::BIErrorValueForCurrentState() = %d", error);
+	return error;
+	}
+
+void CLogServBackupManager::BISetDatabaseNameL(const TDesC& aDatabaseName)
+	{
+#ifdef LOGGING_ENABLED
+	LOGTEXT3("CLogServBackupManager::BISetDatabaseNameL(%S, isActive: %d)", &aDatabaseName, IsActive());
+	if	(iDatabaseName)
+		{
+		LOGTEXT2("CLogServBackupManager::BISetDatabaseNameL() - currently registered database filename is: %S", iDatabaseName);
+		}
+	else
+		{
+		LOGTEXT("CLogServBackupManager::BISetDatabaseNameL() - no file registered with backup interface yet");
+		}
+#endif
+
+	Cancel();
+
+	HBufC* databaseName = aDatabaseName.AllocLC();
+
+	// If we haven't already created a backup observer, then we need
+	// to kick the object back into life again.
+	if	(!iBackup)
+		{
+		LOGTEXT("CLogServBackupManager::BISetDatabaseNameL() - no backup session created");
+
+		// Try and create backup interface synchronously first of all, if that fails
+		// then construct as an idle operation
+		TRAPD(err, iBackup = CreateBackupL(*databaseName));
+
+		LOGTEXT2("CLogServBackupManager::BISetDatabaseNameL() - backup session creation error: %d", err);
+		if	(err != KErrNone)
+			After(0);
+		}
+	else if (iDatabaseName->Compare(aDatabaseName) != KErrNone)
+		{
+		LOGTEXT3("CLogServBackupManager::BISetDatabaseNameL() - database filename changed from %S to %S", &iDatabaseName, &aDatabaseName);
+
+		// De register the old, register the new
+		iBackup->DeregisterFile(*iDatabaseName);
+		iBackup->RegisterFileL(aDatabaseName, *this);
+
+		LOGTEXT("CLogServBackupManager::BISetDatabaseNameL() - database re-registration complete");
+		}
+
+
+	delete iDatabaseName;
+	iDatabaseName = databaseName;
+	CleanupStack::Pop(databaseName);
+
+	LOGTEXT("CLogServBackupManager::BISetDatabaseNameL() - end");
+	}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CLogServBackupManager::RunL()
+//
+// This method does two things
+//
+// 1) Keeps trying to create a backup object - which may fail on device 
+//    bootup until the ui framework starts the backup server.
+//
+// 2) Handles the case where the server fails to restart correctly after a backup - it keeps trying
+//
+	{
+	LOGTEXT2("CLogServBackupManager::RunL(%d)", iStatus.Int());
+
+	if	(!iBackup)
+		{
+		LOGTEXT("CLogServBackupManager::RunL() - trying to create backup object");
+
+		// Keep trying to create backup object
+		iBackup = CreateBackupL(*iDatabaseName);
+
+		LOGTEXT("CLogServBackupManager::RunL() - backup object created okay");
+		}
+	else
+		{
+		// This branch is executed if we failed to create the backup object on our first
+		// attempt in BISetDatabaseNameL
+		LOGTEXT("CLogServBackupManager::RunL() - notifying observers about dummy backup ended event");
+		NotifyObservers(MLogServBackupObserver::EBackupEnded);
+		}
+
+	LOGTEXT("CLogServBackupManager::RunL() - end");
+	}
+
+TInt CLogServBackupManager::RunError(TInt aError)
+	{
+	(void) aError;
+	LOGTEXT2("CLogServBackupManager::RunError(%d)", aError);
+
+	// Make sure we don't leak anything, pretend the backup started again - won't fail
+	if	(iBackup)
+		NotifyObservers(MLogServBackupObserver::EBackupStarting);
+
+	After(KTimerDelay);
+
+	LOGTEXT("CLogServBackupManager::RunError() - end");
+	return KErrNone;
+	}
+
+TInt CLogServBackupManager::NotifyObservers(MLogServBackupObserver::TLogServBackupEvent aEvent)
+//
+//	Notify observers of the event. Assumes event queue correctly ordered.
+//
+	{
+	const TInt count = iObservers.Count();
+	LOGTEXT3("CLogServBackupManager::NotifyObservers(aEvent = %d) - %d observers", aEvent, count);
+
+	// Depending on the event type, we have to reverse the order of notification.
+	// I wish it was possible to do this in a more elegant way... hmm... pointers
+	// to member functions?...
+
+	TInt error = KErrNone;
+	TRAP(error, 
+		//
+		switch(aEvent)
+			{
+		case MLogServBackupObserver::EBackupStarting:
+			{
+			// Update our state
+			iState = ELogServBackupStateBackupInProgress;
+
+			// Notify
+			for(TInt i=0; i<count; i++)
+				{
+				TLogBackupNotificationEntry& entry = iObservers[i];
+				entry.iObserver.BOHandleEventL(aEvent);
+				}
+			}
+			break;
+		case MLogServBackupObserver::EBackupEnded:
+			{
+			// Update our state
+			iState = ELogServBackupStateIdle;
+
+			// Notify
+			for(TInt i=count-1; i>=0; i--)
+				{
+				TLogBackupNotificationEntry& entry = iObservers[i];
+				entry.iObserver.BOHandleEventL(aEvent);
+				}
+			}
+			break;
+			}
+		);
+
+	LOGTEXT("CLogServBackupManager::NotifyObservers() - end");
+	return error;
+	}
+
+void CLogServBackupManager::ChangeFileLockL(const TDesC& aFileName, TFileLockFlags aFlags)
+	{
+	LOGTEXT3("CLogServBackupManager::ChangeFileLockL(%S, aFlags = %d)", &aFileName, aFlags);
+
+#ifdef LOGGING_ENABLED
+	if	(aFlags & (MBackupObserver::EReleaseLockReadOnly | MBackupObserver::EReleaseLockNoAccess))
+		{
+		LOGTEXT("CLogServBackupManager::ChangeFileLockL() - Backup is STARTING");
+		}
+	else
+		{
+		LOGTEXT("CLogServBackupManager::ChangeFileLockL() - Backup is ENDING");
+		}
+#endif
+
+	Cancel();
+
+	// This probably won't ever happen
+	if	(iDatabaseName->Compare(aFileName) != 0)
+		{
+		LOGTEXT("CLogServBackupManager::ChangeFileLockL() - Notification from backup server about the wrong file!");
+		User::Leave(KErrNotFound);
+		}
+
+	// Work out type of backup event
+	MLogServBackupObserver::TLogServBackupEvent event = MLogServBackupObserver::EBackupEnded;
+	if	(aFlags & (MBackupObserver::EReleaseLockReadOnly | MBackupObserver::EReleaseLockNoAccess))
+		event = MLogServBackupObserver::EBackupStarting;
+
+	// Notify observers
+	const TInt error = NotifyObservers(event);
+	LOGTEXT2("CLogServBackupManager::ChangeFileLockL() - notifying observers error: %d", error);
+
+	// Shouldn't be any problems when notifying observers
+	__ASSERT_DEBUG(!(event == MLogServBackupObserver::EBackupStarting && error != KErrNone), Panic(ELogStartBackupFailure));
+
+	// Handle failure to restart the server after a backup
+	if	(error && (event == MLogServBackupObserver::EBackupEnded))
+		{
+		LOGTEXT("CLogServBackupManager::ChangeFileLockL() - Kicking off server objects again after backup completed (and there was an error)");
+
+		// Make sure we don't leak anything, pretend the backup started again - won't fail
+		Cancel();
+		NotifyObservers(MLogServBackupObserver::EBackupStarting);
+		After(KTimerDelay);
+		}
+
+	LOGTEXT("CLogServBackupManager::ChangeFileLockL() - end");
+	}
+
+CBaBackupSessionWrapper* CLogServBackupManager::CreateBackupL(const TDesC& aLogDatabaseFileName)
+	{
+	LOGTEXT("CLogServBackupManager::CreateBackupL()");
+
+	// Create backup session
+	CBaBackupSessionWrapper* backup = CBaBackupSessionWrapper::NewL();
+	CleanupStack::PushL(backup);
+
+	// Register with the backup server
+	backup->RegisterFileL(aLogDatabaseFileName, *this);
+
+	// All done
+	CleanupStack::Pop(backup);
+
+	LOGTEXT("CLogServBackupManager::CreateBackupL() - end");
+	return backup;
+	}
+
+TInt CLogServBackupManager::CompareEntries(const TLogBackupNotificationEntry& aLeft, const TLogBackupNotificationEntry& aRight)
+	{
+	if	(aLeft.iPriority == aRight.iPriority)
+		return 0;
+	else if (aLeft.iPriority > aRight.iPriority) // Not what you might expect since higher priority must go first
+		return -1;
+	return 1;
+	}