commonappservices/alarmserver/Server/Source/ASSrvAlarmStore.cpp
changeset 0 2e3d3ce01487
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/commonappservices/alarmserver/Server/Source/ASSrvAlarmStore.cpp	Tue Feb 02 10:12:00 2010 +0200
@@ -0,0 +1,670 @@
+// Copyright (c) 1999-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 "ASSrvAlarmStore.h"
+
+// User includes
+#include "ASSrvDefs.h"
+#include "ASSrvDataPool.h"
+#include "ASSrvAlarmQueue.h"
+#include "ASSrvStaticUtils.h"
+#include "ASSrvSoundSettings.h"
+#include "ASSrvServerWideData.h"
+#include "ASSrvAlarmQueue.h"
+
+// Type definitions
+#define UNUSED_VAR(a) a = a
+
+// Constants
+const TInt KDelayInMicrosecondsBetweenFileOperations = 2000000; // 2 seconds
+const TInt KDelayInMicrosecondsBetweenFileOperationsLongDelay = 10 * 60 * 1000000; // 10 minutes, allow user time to clear disk space?
+const TInt KNumberOfAttemptsAtExternalizingFile = 5; // 5 * 2 seconds => 10 seconds
+const TInt KDelayPeriodBeforeAttemptingAnExternalize = 1000; // 1 seconds
+
+// Enumerations
+
+// Definitions
+#define __START_WITH_RESTORED_QUEUE__
+
+// Classes referenced
+
+//#define VERBOSE_DEBUG
+
+#if defined(VERBOSE_DEBUG)
+#define DEBUG_PRINT1(A)			{ RDebug::Print(A); }
+#define DEBUG_PRINT2(A,B)		{ RDebug::Print(A,B); }
+#define DEBUG_PRINT3(A,B,C)		{ RDebug::Print(A,B,C); }
+#else
+#define DEBUG_PRINT1(A)
+#define DEBUG_PRINT2(A,B)
+#define DEBUG_PRINT3(A,B,C)
+#endif
+
+
+
+//
+// ----> CASSrvAlarmStore (source)
+//
+
+//*************************************************************************************
+CASSrvAlarmStore::CASSrvAlarmStore(CASSrvServerWideData& aServerWideData)
+:	CTimer(CActive::EPriorityIdle), iServerWideData(aServerWideData)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+
+//*************************************************************************************
+CASSrvAlarmStore::~CASSrvAlarmStore()
+	{
+#ifndef __WINC__
+	delete iBackupNotification;	
+#endif
+
+	ServerWideData().Queue().NotificationPoolChangeCancel(*this);
+
+	DEBUG_PRINT1(_L("-- -- Alarm Store destructor"));
+
+	// is an externalize request still waiting?
+	if (iFlags.IsSet(ERequestExternalize))
+		{
+		Cancel();
+		// Flush current alarm queue
+		// (if this fails now there is nothing we can do about it)
+		Externalize();
+		}
+
+	// no longer interested in these events
+	ServerWideData().AnyEventManager().MASAnyEventManagerObserverRemove(*this);
+	}
+
+
+//*************************************************************************************
+void CASSrvAlarmStore::ConstructL()
+	{
+	CTimer::ConstructL();
+
+	DEBUG_PRINT1(_L("++ ++ Alarm Store ConstructL"));
+
+	TFileName name;
+	RFs& fsSession = ServerWideData().FsSession();
+	ASSrvStaticUtils::GetPrivateDirL(fsSession, name);
+
+	//Check INI file directory exists
+	TUint attribs;	//Not used dummy parameter
+	TInt error = fsSession.Att(name,attribs);
+	if (error == KErrNotFound || error == KErrPathNotFound)
+		{
+		error = fsSession.MkDirAll(name);
+		}
+	User::LeaveIfError(error);
+
+	ASSrvStaticUtils::GetServerPathL(fsSession, name);
+
+#ifndef __WINC__
+	iBackupNotification = CBackupRestoreNotification::NewL(name, *this);
+#endif
+
+	// Internalize any previously persisted data
+	error = Internalize(CASSrvAlarmQueue::EStoreInternalizeStartup);
+	if	(error != KErrNone)
+		{
+		error = fsSession.Delete(name);
+		if	(error != KErrNotFound)
+			User::LeaveIfError(error);
+		}
+
+	// Ready to watch for "Alarm Added" and other Alarm Queue events
+	ServerWideData().Queue().NotificationPoolChangeL(*this);
+
+	// Ready to watch for Alarm Sound Intervals changing
+	ServerWideData().AnyEventManager().MASAnyEventManagerObserverAddL(*this);
+	}
+
+
+//*************************************************************************************
+CASSrvAlarmStore* CASSrvAlarmStore::NewL(CASSrvServerWideData& aServerWideData)
+	{
+	CASSrvAlarmStore* self = new(ELeave) CASSrvAlarmStore(aServerWideData);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+
+//
+//
+//
+
+
+
+
+//*************************************************************************************
+/**
+ * @see MASSrvAlarmQueueObserver
+ */
+void CASSrvAlarmStore::MAlarmQueueObserverHandleEvent(TASSrvAlarmQueueEvent aEvent, TAlarmId /*aAlarmId*/)
+	{
+	switch(aEvent)
+		{
+	case EASSrvAlarmQueueEventHeadItemChanged:
+	case EASSrvAlarmQueueEventAlarmAdded:
+	case EASSrvAlarmQueueEventAlarmChanged:
+	case EASSrvAlarmQueueEventAlarmDeleted:
+		// RunL will Externalize all changes in 100ms
+		ScheduleExternalizeWithRetry(100);
+		break;
+
+	default:
+		break;
+		}
+	}
+
+
+//
+//
+//
+
+
+//*************************************************************************************
+/**
+ * @see MASSrvAnyEventObserver
+ *
+ * Facade interface that notifies observer about event. No real processing done
+ * by this object.
+ */
+void CASSrvAlarmStore::MASSrvAnyEventHandleChange(TAlarmChangeEvent aEvent, TAlarmId /*aAlarmId*/)
+	{
+	switch(aEvent)
+		{
+	case EAlarmChangeEventPlayIntervalsChanged:
+		// The sound intervals associated with sound timing have changed.
+		// RunL will Externalize all changes in 100ms
+		ScheduleExternalizeWithRetry(100);
+		break;
+
+	default:
+		break;
+		}
+	}
+
+
+//
+//
+//
+
+
+//*************************************************************************************
+/**
+ * Internalize (non-leaving) the contents of the Alarm Server backup
+ * from the backup file.
+ */
+TInt CASSrvAlarmStore::Internalize(CASSrvAlarmQueue::TStoreOperation aInternalizeOperation)
+	{
+	TInt error = KErrNone;
+
+	DEBUG_PRINT1(_L("> Alarm Store Internalize ()"));
+
+	// tell Alarm Queue what type of Internalize to perform
+	error = ServerWideData().Queue().StartAlarmStoreOperation(aInternalizeOperation);
+
+	if (!error)
+		{
+		// don't watch for change notifications during Internalize
+		iFlags.Set(EIsInternalizing);
+
+		TRAP(error, InternalizeL());
+
+		// tell alarm queue that Internalize is complete
+		ServerWideData().Queue().EndAlarmStoreOperation(error);
+
+		// Finished Internalize, Look for notifications again, etc...
+		iFlags.Clear(EIsInternalizing);
+		}
+
+	DEBUG_PRINT2(_L("< Alarm Store Internalize - error %i"), error);
+
+	return error;
+	}
+
+
+//*************************************************************************************
+/**
+ * Internalize the contents of the Alarm Server backup
+ * from the backup file.
+ */
+void CASSrvAlarmStore::InternalizeL()
+	{
+	RStoreReadStream stream;
+	CDirectFileStore* store = OpenStoreLC(EFileRead);
+	CStreamDictionary* dictionary = OpenDictionaryLC(*store);
+
+	// Open the alarm queue stream & internalize
+#ifdef __START_WITH_RESTORED_QUEUE__
+	OpenStreamLC(*store, *dictionary, KAlarmStoreStreamUidQueue, stream);
+	stream >> ServerWideData().Queue();
+	CleanupStack::PopAndDestroy(&stream);
+
+	// Open the alarm data stream & internalize
+	OpenStreamLC(*store, *dictionary, KAlarmStoreStreamUidData, stream);
+	stream >> ServerWideData().DataPool();
+	CleanupStack::PopAndDestroy(&stream);
+#endif
+
+	// Open the sound settings stream & internalize
+	OpenStreamLC(*store, *dictionary, KAlarmStoreStreamUidSoundSettings, stream);
+	stream >> ServerWideData().SoundSettings();
+	CleanupStack::PopAndDestroy(&stream);
+
+#ifdef SYMBIAN_SKIPPED_CALENDAR_ALARMS
+	// Open the missed alarm data stream & internalize
+	OpenStreamLC(*store, *dictionary, KAlarmStoreStreamUidEnvironmentChangeData, stream);
+	ServerWideData().Queue().InternalizeLastAlarmedInstanceParamsL(stream);
+	CleanupStack::PopAndDestroy(&stream);
+#endif
+	
+	// Tidy up
+	CleanupStack::PopAndDestroy(2, store);
+	}
+	
+//*************************************************************************************
+/**
+ * Externalize (non-leaving) the contents of the Alarm Server backup
+ * to the backup file.
+ */
+TInt CASSrvAlarmStore::ExternalizeIfRequested()
+	{
+	TInt error = KErrNone;
+
+	DEBUG_PRINT2(_L("= Alarm Store Externalize If Requested (%u)"), iFlags.IsSet(ERequestExternalize));
+
+	if (iFlags.IsSet(ERequestExternalize))
+		{
+		// Don't RunL
+		Cancel();
+
+		error = Externalize();
+		}
+
+	return error;
+	}
+
+
+//*************************************************************************************
+/**
+ * Externalize (non-leaving) the contents of the Alarm Server backup
+ * to the backup file.
+ */
+TInt CASSrvAlarmStore::Externalize()
+	{
+	TInt error = KErrNone;
+	
+#ifdef SYMBIAN_SYSTEM_STATE_MANAGEMENT
+	if (!iServerWideData.ServerIsReadOnly())
+		{
+#endif
+		DEBUG_PRINT1(_L("> Alarm Store Externalize"));
+	
+		// tell Alarm Queue what type of Store operation we want to perform
+		error = ServerWideData().Queue().StartAlarmStoreOperation(CASSrvAlarmQueue::EStoreExternalize);
+	
+		if (!error)
+			{
+			TRAP(error, ExternalizeL());
+	
+			// tell alarm queue that Externalize is complete
+			ServerWideData().Queue().EndAlarmStoreOperation(error);
+			}
+	
+		DEBUG_PRINT2(_L("< Alarm Store Externalize - error %i"), error);
+#ifdef SYMBIAN_SYSTEM_STATE_MANAGEMENT
+		}
+#endif
+	
+	return error;
+	}
+
+
+//*************************************************************************************
+/**
+ * Externalize the contents of the Alarm Server backup
+ * to the backup file.
+ */
+void CASSrvAlarmStore::ExternalizeL()
+	{
+	TStreamId streamId;
+	RStoreWriteStream stream;
+	CStreamDictionary* dictionary = CStreamDictionary::NewLC();
+
+	CDirectFileStore* store = OpenStoreLC(EFileWrite | EFileShareExclusive);
+
+	// Create the alarm queue stream & externalize
+	streamId = stream.CreateLC(*store);
+	stream << ServerWideData().Queue();
+	stream.CommitL();
+	CleanupStack::PopAndDestroy(&stream);
+	dictionary->AssignL(KAlarmStoreStreamUidQueue, streamId);
+
+	// Create the alarm data queue & externalize
+	streamId = stream.CreateLC(*store);
+	stream << ServerWideData().DataPool();
+	stream.CommitL();
+	CleanupStack::PopAndDestroy(&stream);
+	dictionary->AssignL(KAlarmStoreStreamUidData, streamId);
+
+	// Create the alarm data queue & externalize
+	streamId = stream.CreateLC(*store);
+	stream << ServerWideData().SoundSettings();
+	stream.CommitL();
+	CleanupStack::PopAndDestroy(&stream);
+	dictionary->AssignL(KAlarmStoreStreamUidSoundSettings, streamId);
+
+#ifdef SYMBIAN_SKIPPED_CALENDAR_ALARMS
+	// Create the missed alarm data stream & externalize
+	streamId = stream.CreateLC(*store);
+	ServerWideData().Queue().ExternalizeLastAlarmedInstanceParamsL(stream);
+	stream.CommitL();
+	CleanupStack::PopAndDestroy(&stream);
+	dictionary->AssignL(KAlarmStoreStreamUidEnvironmentChangeData, streamId);	
+#endif
+	
+	// Create root stream
+	streamId = stream.CreateLC(*store);
+	stream << *dictionary;
+	stream.CommitL();
+	CleanupStack::PopAndDestroy(&stream);
+	store->SetRootL(streamId);
+	store->CommitL();
+
+	// clear Externalize request flag now, so another can be requested
+	iFlags.Clear(ERequestExternalize);
+
+	// Tidy up
+	CleanupStack::PopAndDestroy(2, dictionary);
+	}
+
+
+//*************************************************************************************
+/**
+ * Open the backup store (AlarmServer.ini) using the specified
+ * file mode.
+ *
+ * @return A file store object which encapsulates the backup store.
+ */
+CDirectFileStore* CASSrvAlarmStore::OpenStoreLC(TUint aMode) const
+	{
+	CDirectFileStore* store = OpenStoreL(aMode);
+
+	CleanupStack::PushL(store);
+	//
+	return store;
+	}
+
+
+/**
+ * Open the backup store (AlarmServer.ini) using the specified
+ * file mode.
+ *
+ * @return A file store object which encapsulates the backup store.
+ */
+CDirectFileStore* CASSrvAlarmStore::OpenStoreL(TUint aMode) const
+	{
+	RFs& fsSession = ServerWideData().FsSession();
+	TFileName fileName;
+	ASSrvStaticUtils::GetServerPathL(fsSession, fileName);
+
+	CDirectFileStore* store = NULL;
+	TInt error = KErrNone;
+	//
+	if	(aMode == EFileRead)
+		{
+		// First try to open the store. If opening fails, then we
+		// replace the store with a blank one.
+		TRAP(error, store = CDirectFileStore::OpenL(fsSession, fileName, aMode));
+		}
+	//
+	if	(!store || error != KErrNone)
+		{
+		store = CDirectFileStore::ReplaceLC(fsSession, fileName, aMode);
+		//
+		const TUidType type(KDirectFileStoreLayoutUid, KAlarmStoreUid, KNullUid);
+		store->SetTypeL(type);
+		//
+		CleanupStack::Pop(store);
+		}
+	//
+	return store;
+	}
+
+
+//*************************************************************************************
+/**
+ * Restore the root stream dictionary from the specified store
+ *
+ * @return A stream dictionary object on the cleanup stack
+ */
+CStreamDictionary* CASSrvAlarmStore::OpenDictionaryLC(CPersistentStore& aStore) const
+	{
+	const TStreamId rootId = aStore.Root();
+	//
+	CStreamDictionary* dictionary = CStreamDictionary::NewLC();
+	RStoreReadStream stream;
+	stream.OpenLC(aStore, rootId);
+	stream >> *dictionary;
+	CleanupStack::PopAndDestroy(&stream);
+	//
+	return dictionary;
+	}
+
+
+//*************************************************************************************
+/**
+ * Open the specified stream in the store
+ */
+void CASSrvAlarmStore::OpenStreamLC(CPersistentStore& aStore, CStreamDictionary& aDictionary, TUid aStreamUid, RStoreReadStream& aStream) const
+	{
+	const TStreamId streamId = aDictionary.At(aStreamUid);
+	aStream.OpenLC(aStore, streamId);
+	}
+
+
+//*************************************************************************************
+/**
+ * Retry a previously requested backup operation
+ */
+void CASSrvAlarmStore::RetryStoreOperation()
+	{
+	if (iFlags.IsSet(ERequestExternalize) && !IsActive())
+		{
+		// can RunL now
+		After(0);
+		}
+	}
+
+
+//
+//
+//
+
+
+//*************************************************************************************
+/**
+ * @see CActive
+ */
+void CASSrvAlarmStore::RunL()
+	{
+	TInt error = iStatus.Int();
+
+	// operation isn't cancelled
+	if	(error == KErrNone)
+		{
+		// task : Externalize
+		if (iFlags.IsSet(ERequestExternalize))
+			{
+			// Try to Externalize
+			error = Externalize();
+
+			if (error < KErrNone)
+				{
+				++iNumberOfAttemptedRetries;
+
+				// check retries, and reschedule
+				if (iNumberOfAttemptedRetries == KNumberOfAttemptsAtExternalizingFile)
+					{
+					// Try one last time. Wait for 10 mins and then attempt operation again.
+					// After that, give up.
+					//
+					// Possible reasons for entering this state:
+					//
+					// Low disk space, low memory, corrupt file system, etc etc. Don't think
+					// its acceptable to panic - operation should be failed gracefully. 
+					After(KDelayInMicrosecondsBetweenFileOperationsLongDelay);
+					}
+				else if (iNumberOfAttemptedRetries < KNumberOfAttemptsAtExternalizingFile)
+					{
+					// Try again after the delay
+					After(KDelayInMicrosecondsBetweenFileOperations);
+					}
+				else
+					{
+					// Tried max number of times already. Give up.
+					iFlags.Clear(ERequestExternalize);
+					}
+				}
+
+			}
+		}
+	}
+
+
+//*************************************************************************************
+
+#ifndef __WINC__
+void CASSrvAlarmStore::ScheduleExternalizeWithRetry(TUint aTimeMS)
+#else
+void CASSrvAlarmStore::ScheduleExternalizeWithRetry(TUint /*aTimeMS*/)
+#endif
+	{
+	// make sure change isn't due to Internalize
+	if (iFlags.IsClear(EIsInternalizing))
+		{
+		DEBUG_PRINT2(_L("*** Schedule Externalize - IsActive() = %u"), IsActive());
+
+		iFlags.Set(ERequestExternalize);
+		iNumberOfAttemptedRetries = 0;
+
+#ifndef __WINC__
+		// set the time to RunL iff not already set to run
+		//   check that no Backup or Restore is in progress, 
+		if (!iBackupNotification->BackupInProgress() && 
+			!iBackupNotification->RestoreInProgress()&& !IsActive())
+			{
+			// schedule the actual Externalize 
+			After(aTimeMS * 1000);
+			}
+#endif
+		}
+	}
+
+
+//*************************************************************************************
+/**
+ * @see CActive
+ */
+TInt CASSrvAlarmStore::RunError(TInt /*aError*/)
+	{
+	return KErrNone;
+	}
+
+
+//*************************************************************************************
+#ifndef __WINC__
+
+/**
+ * @see MBackupRestoreNotificationObserver
+ */
+
+void CASSrvAlarmStore::BackupBeginningL()
+	{
+	DEBUG_PRINT1(_L("-> Alarm Store => Backup Beginning"));
+	StartOfBackupOrRestoreL(CASSrvAlarmQueue::EStoreBackup);
+	}
+
+void CASSrvAlarmStore::BackupCompletedL()
+	{
+	// End of Backup
+	DEBUG_PRINT1(_L("-> Alarm Store => Backup Ended"));
+
+	// Backup server was reading from the alarm file so
+	// tell alarm queue that Backup is complete
+	ServerWideData().Queue().EndAlarmStoreOperation(KErrNone);
+
+	// In case Store has been waiting for backup to finish. Now
+	// attempt to perform deferred operation.
+	RetryStoreOperation();
+	}
+
+void CASSrvAlarmStore::RestoreBeginningL()
+	{
+	// Restore is starting
+	DEBUG_PRINT1(_L("-> Alarm Store => Restore Beginning"));
+	StartOfBackupOrRestoreL(CASSrvAlarmQueue::EStoreRestore);
+}
+
+void CASSrvAlarmStore::RestoreCompletedL(TInt aRestoreResult)
+	{
+	DEBUG_PRINT1(_L("-> Alarm Store => Restore Ended"));
+
+	// If the Backup server successfully wrote to the alarm file, then we should 
+	// read its contents and restore all alarm data based upon it.
+	if (aRestoreResult == KErrNone)
+		{
+		DEBUG_PRINT1(_L("-- End of Restore ... EEnd"));
+		// Any error during Internalize must be pretty severe so catch it and leave.
+		// NB Internalize calls ServerWideData().Queue().EndAlarmStoreOperation();
+		User::LeaveIfError(Internalize(CASSrvAlarmQueue::EStoreInternalizeRestore));
+		}
+	else
+		{
+		DEBUG_PRINT1(_L("-- end of Restore ... EAbort"));
+	
+        ServerWideData().Queue().EndAlarmStoreOperation(KErrGeneral);
+        
+		// we don't know what state the AlarmServer.Ini file is in
+		// so want an Externalize() to happen soon
+		ScheduleExternalizeWithRetry(KDelayPeriodBeforeAttemptingAnExternalize);
+		}
+	}
+
+#ifdef SYMBIAN_SYSTEM_STATE_MANAGEMENT
+void CASSrvAlarmStore::MHandleSystemStateChange(TState aState)
+	{
+	if (aState == EShutdown)
+		{
+		ExternalizeIfRequested();
+		}
+	}
+#endif
+
+void CASSrvAlarmStore::StartOfBackupOrRestoreL(CASSrvAlarmQueue::TStoreOperation aStoreOperation)
+	{
+	// Flush any 'scheduled' Externalize before Restore
+	ExternalizeIfRequested();
+
+	// tell Alarm Queue what type of Store is wanted
+	User::LeaveIfError(ServerWideData().Queue().StartAlarmStoreOperation(aStoreOperation));
+	}
+#endif // #ifndef __WINC__