diff -r 000000000000 -r 2e3d3ce01487 commonappservices/alarmserver/Server/Source/ASSrvAlarmStore.cpp --- /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__