genericservices/taskscheduler/SCHSVR/SCHMAN.CPP
changeset 0 e4d67989cc36
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/genericservices/taskscheduler/SCHSVR/SCHMAN.CPP	Tue Feb 02 02:01:42 2010 +0200
@@ -0,0 +1,912 @@
+// Copyright (c) 2004-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:
+//
+
+// System includes
+#include <bacntf.h>
+
+// User includes
+#include "SCHMAN.H"
+#include "SchTimer.h"
+#include "SchLogger.h"
+#include "SCHEDULE.H"
+#include "SCHCLI.H"
+#include "SCHSTORE.H"
+#include <schtask.h>
+#include "SCHLOG.h"
+
+// Constants
+const TInt KMinScheduleId = 0;
+const TInt KMaxSchedules = 25000;
+
+//Command line argument  
+_LIT(KCommandLine, "SYSSTARTSCHEXE");
+
+//SID of SysStart
+const TInt KSysStartSID = 0x10205C44; 
+
+
+#define UNUSED_VAR(a) a = a
+
+//
+// Construction/Destruction functions
+//
+
+CTaskScheduler::CTaskScheduler()
+:	iSchedules(CSchedule::Offset()), 
+	iClients(CClientProxy::Offset()),
+	iStartupStatePassNonCritical(EFalse)
+	{
+	}
+
+CTaskScheduler::~CTaskScheduler()
+	{
+	if (iBackupNotification)
+		{
+		iBackupNotification->DeRegisterBackupOperationObserver(*this);
+		}
+	delete iBackupNotification;
+	delete iBackupManager;
+	delete iNotifier;
+	delete iScheduleCriteriaManager;
+	delete iSchLogManager;
+	
+	//remove clients and schedules as well!!
+	TDblQueIter<CClientProxy> clientIter(iClients);
+	
+	clientIter.SetToFirst();
+	CClientProxy* client=NULL;
+	while ((client=clientIter++)!=NULL)
+		{
+			client->Remove();
+			delete client;
+		}
+	
+	TSglQueIter<CSchedule> schedIter(iSchedules);
+	
+	schedIter.SetToFirst();
+	CSchedule* schedule=NULL;
+	while ((schedule=schedIter++)!=NULL)
+		{
+			iSchedules.Remove(*schedule);
+			delete schedule;
+		}	
+	}
+
+void CTaskScheduler::ConstructL()
+	{
+	LOGSTRING("CTaskScheduler::ConstructL - Creating new schedule server log entry");
+
+	User::LeaveIfError(iFsSession.Connect());
+	iBackupManager = new(ELeave) CSchBackupManager(iFsSession);
+	iBackupManager->ConstructL();
+
+	iNotifier = CEnvironmentChangeNotifier::NewL(CActive::EPriorityHigh, TCallBack(EnvironmentChanged, this));
+	iNotifier->Start();
+
+	iScheduleCriteriaManager = CScheduleCriteriaManager::NewL(*this);
+
+	iSchLogManager = CSchLogManager::NewL(iFsSession);
+
+	LOGSTRING("CTaskScheduler::ConstructL - Restoring clients and schedules");
+	TRAPD(err, iBackupManager->RestoreL(iClients, iSchedules,*iSchLogManager));
+	if	(err != KErrNone) // the file's corrupt or something...
+		{
+		LOGSTRING2("CTaskScheduler::ConstructL - had to create new store because of error: %d", err);
+		iBackupManager->CreateEmptyBackupL();
+		}
+		
+	//checking the SID of the process which started the Task scheduler	
+ 	if (User::CreatorSecureId() == KSysStartSID)
+	 	{
+	    TInt argLen = User::CommandLineLength();
+     	if (argLen)
+	         {
+	         HBufC* arg = HBufC::NewLC(argLen);
+	         TPtr argPtr = arg->Des();
+	         User::CommandLine(argPtr);
+	         argPtr.UpperCase();
+	         
+	 		 //Checking Comman dLine arg passed to it is same as in SSCForStartupMode0.rss
+	 		 //and checking for persisted schedules
+	         if((argPtr.Compare(KCommandLine) == 0) && iSchedules.IsEmpty())
+	             {
+	             //if no schedule leave
+				 User::Leave(KErrNone);
+	             }
+	 	      CleanupStack::PopAndDestroy(arg);
+	 	      }
+         }
+
+	// Each client now contains a list of associated tasks. We need
+	// to now associate those tasks with specific schedules
+	CClientProxy* client;
+	TDblQueIter<CClientProxy> clientIter(iClients);
+	clientIter.SetToFirst();
+	while ((client = clientIter++) != NULL)
+		{
+		// Fetch an iterator for each task owned by this client
+		CScheduledTask* task;
+		TDblQueIter<CScheduledTask> taskIterator = client->TaskIterator();
+		taskIterator.SetToFirst();
+
+		// Iterate through all the tasks owned by this client, trying to find
+		// the corresponding schedules.
+		while ((task = taskIterator++) != NULL)
+			{
+			CSchedule* schedule = NULL;
+			schedule = Find(task->ScheduleId());
+			if (schedule)
+				{
+				TScheduledTask* taskRef = new(ELeave) TScheduledTask(*task,*client);
+				schedule->AddTask(*taskRef);
+				}
+			}
+		}
+	iBackupNotification = CBaBackupSessionWrapper::NewL();
+	iBackupNotification->RegisterBackupOperationObserverL(*this);
+	}
+
+CTaskScheduler* CTaskScheduler::NewL()
+	{
+	CTaskScheduler* self = CTaskScheduler::NewLC();
+	CleanupStack::Pop();
+	return self;	
+	}
+
+CTaskScheduler* CTaskScheduler::NewLC()
+	{
+	CTaskScheduler* self = new(ELeave) CTaskScheduler();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;
+	}
+
+//
+// Client, Schedule and Task functions
+//
+
+CClientProxy* CTaskScheduler::AddClientL(const TDesC& aFilename, TInt aPriority)
+	{
+	//check we don't already have a client that will do...
+	TDblQueIter<CClientProxy> clientIter(iClients);
+	clientIter.SetToFirst();
+	CClientProxy* client=NULL;
+	while ((client=clientIter++)!=NULL)
+		{
+		if	(client->IsEqual(aFilename, aPriority))
+			return client;
+		}
+	client = CClientProxy::NewL(iFsSession, aFilename, aPriority,*iSchLogManager); 
+	iClients.Add(*client);
+	return client;
+	}
+
+void CTaskScheduler::AddScheduleL(CSchedule& aSchedule)
+	{
+	LOGSTRING3("CTaskScheduler::AddScheduleL - schedule: %S, %d", &aSchedule.Name(), aSchedule.Id());
+	iBackupManager->PerformStoreOperationL(CSchBackupManager::ESchBackupOperationAdd, aSchedule);
+	iSchedules.AddLast(aSchedule);
+	LOGSTRING("CTaskScheduler::AddScheduleL - schedule added");
+	}
+
+void CTaskScheduler::EditScheduleL(TInt aScheduleHandle, CArrayFixFlat<TScheduleEntryInfo2>& aEntryList)
+	{
+	CSchedule* schedule = FindL(aScheduleHandle);
+
+	// remove schedule from condition manager before replacing entries to ensure 
+	// its deleted properly.
+	iScheduleCriteriaManager->RemoveSchedule(schedule->Id());
+	schedule->ReplaceEntriesL(aEntryList);
+
+	TRAPD(err, iBackupManager->PerformStoreOperationL(CSchBackupManager::ESchBackupOperationEdit, *schedule));
+	if(err)
+		{
+		schedule->RemoveEntries();
+		User::Leave(err);
+		}
+	// recalculate due time only if schedule is enabled and has tasks to run	
+	if (IsScheduleReadyForUpdate(*schedule))
+		{
+		iScheduleCriteriaManager->ReplaceScheduleL(*schedule);
+		}
+	}
+
+void CTaskScheduler::DoEditScheduleL(CSchedule& aSchedule, 
+							CArrayFixFlat<TTaskSchedulerCondition>& aConditionList,
+							const TTsTime& aDefaultTime)
+	{
+	aSchedule.ReplaceConditionsL(aConditionList);
+	
+	//Default Time is represented by a single entry class
+	CArrayFixFlat<TScheduleEntryInfo2>* entries 
+		= new(ELeave) CArrayFixFlat<TScheduleEntryInfo2>(1);
+	CleanupStack::PushL(entries);
+	TScheduleEntryInfo2 info;
+	info.SetStartTime(aDefaultTime);
+	info.SetInterval(1);
+	info.SetIntervalType(EDaily);
+	//validityperiod of 24 hours will ensure task is always run
+	info.SetValidityPeriod(60*24); 
+	entries->AppendL(info);
+	aSchedule.ReplaceEntriesL(*entries);
+	CleanupStack::Pop(entries);
+	
+	iBackupManager->PerformStoreOperationL(CSchBackupManager::ESchBackupOperationEdit, aSchedule);
+	}
+
+void CTaskScheduler::EditScheduleL(TInt aScheduleHandle, 
+							CArrayFixFlat<TTaskSchedulerCondition>& aConditionList,
+							const TTsTime& aDefaultTime)
+	{
+	CSchedule* schedule = FindL(aScheduleHandle);
+
+	// remove schedule from condition manager before replacing entries to ensure 
+	// its deleted properly.
+	iScheduleCriteriaManager->RemoveSchedule(schedule->Id());
+
+	TRAPD(err, DoEditScheduleL(*schedule, aConditionList, aDefaultTime));
+	if(err)
+		{
+		schedule->RemoveEntries();
+		schedule->RemoveConditions();
+		User::Leave(err);
+		}
+
+	// recalculate due time only if schedule is enabled and has tasks to run	
+	if (IsScheduleReadyForUpdate(*schedule))
+		{
+		iScheduleCriteriaManager->ReplaceScheduleL(*schedule);
+		}
+	}	
+
+void CTaskScheduler::RemoveScheduleL(TInt aHandle)
+	{
+	CSchedule* schedule = FindL(aHandle);
+	LOGSTRING3("CTaskScheduler::RemoveScheduleL - schedule: %S, %d", &schedule->Name(), schedule->Id());
+	if (!schedule->HasTasks())
+		{
+		LOGSTRING("CTaskScheduler::RemoveScheduleL - schedule doesn't have any tasks, removing");
+		//remove schedule from timer
+		iScheduleCriteriaManager->RemoveSchedule(schedule->Id());
+		DoRemoveL(schedule);
+		}
+	else
+		{
+		// Can't delete a schedule which has tasks
+		LOGSTRING("CTaskScheduler::RemoveScheduleL - schedule has tasks, can't delete");
+		User::Leave(KErrArgument);
+		}
+	}
+
+void CTaskScheduler::DisableScheduleL(TInt aHandle)
+	{
+	CSchedule* schedule = FindL(aHandle);
+	schedule->SetEnabled(EFalse);
+	iBackupManager->PerformStoreOperationL(CSchBackupManager::ESchBackupOperationEdit, *schedule);
+	//remove schedule from timer as its disabled
+	iScheduleCriteriaManager->RemoveSchedule(schedule->Id());
+	}
+
+void CTaskScheduler::EnableScheduleL(TInt aHandle)
+	{
+	CSchedule* schedule = FindL(aHandle);
+	schedule->SetEnabled(ETrue);
+	iBackupManager->PerformStoreOperationL(CSchBackupManager::ESchBackupOperationEdit, *schedule);
+
+	// recalculate due time only if schedule has tasks to run	
+	if ( IsScheduleReadyForUpdate(*schedule))
+		{
+		iScheduleCriteriaManager->ReplaceScheduleL(*schedule);
+		}
+	}
+
+void CTaskScheduler::ScheduleTaskL(CSchedule& aSchedule, CClientProxy& aClient)
+	{
+	// Backup the task
+	if	(aSchedule.Persists())
+		{
+		iBackupManager->PerformStoreOperationL(CSchBackupManager::ESchBackupOperationEdit, aClient);
+		}
+	// if schedule is enabled then add schedule to timer.
+	if (aSchedule.Enabled() && IsStartupStateNonCritical())
+		{
+		iScheduleCriteriaManager->ReplaceScheduleL(aSchedule);
+		}		
+	}
+
+void CTaskScheduler::DeleteTaskL(TInt aScheduleHandle, TInt aTaskHandle)
+	{
+	CSchedule* schedule = FindL(aScheduleHandle);
+
+	TScheduledTask* task = schedule->Task(aTaskHandle);
+	if (!task)
+		{
+		LOGSTRING("CTaskScheduler::DeleteTaskL - task wasn't found");
+		User::Leave(KErrNotFound);
+		}
+
+	const CClientProxy& clientForTask = task->Client();
+	
+	// This deletes the task and removes the CScheduledTask
+	// from the CClientProxy's queue of tasks
+	task->RemoveInfo();
+
+	// This deletes the TScheduledTask defined above and removes it
+	// from CSchedule's queue of TScheduledTask's.
+	schedule->RemoveTask(task);
+	if (!schedule->HasTasks())	//i.e. it was the last task 
+		{
+		LOGSTRING("CTaskScheduler::DeleteTaskL - schedule doesn't have any more tasks left");
+		//remove scheule from timer as there are no more tasks
+		iScheduleCriteriaManager->RemoveSchedule(schedule->Id());
+		// If the schedule isn't persistent then we delete it (transient schedules only
+		// have one task).
+		if (!schedule->Persists())
+			DoRemoveL(schedule);
+		else
+			iBackupManager->PerformStoreOperationL(CSchBackupManager::ESchBackupOperationEdit, clientForTask);		
+		}
+	else
+		{
+		// Backup the changes to the tasks. Although we are deleting a task, we are not actually
+		// deleting the client, so this is actually an edit operation.
+		if (schedule->Persists())
+			iBackupManager->PerformStoreOperationL(CSchBackupManager::ESchBackupOperationEdit, clientForTask);
+		}
+	}
+
+//
+// Utility Functions
+//
+
+TInt CTaskScheduler::GenerateId()
+	{
+	TInt id = KMinScheduleId;
+	CSchedule* schedule = Find(id);
+	while (schedule!=NULL) 
+		{
+		id+=KScheduleIdDifferential;//=10 000
+		if ((id/KScheduleIdDifferential) > KMaxSchedules)
+			return KErrOverflow;
+		schedule = Find(id);
+		}
+	return id;
+	}
+
+void CTaskScheduler::DoRemoveL(CSchedule* aSchedule)
+	{
+	TRAPD(err, iBackupManager->PerformStoreOperationL(CSchBackupManager::ESchBackupOperationDelete, *aSchedule));
+	if	(err < KErrNone && err != KErrNotFound)
+		User::Leave(err);
+	iSchedules.Remove(*aSchedule);
+	delete aSchedule;
+	aSchedule = NULL;
+	}
+
+CSchedule* CTaskScheduler::FindL(TInt aHandle)
+	{
+	CSchedule* schedule = Find(aHandle);
+	if (!schedule)
+		User::Leave(KErrNotFound);
+	return schedule;
+	}
+
+CSchedule* CTaskScheduler::Find(TInt aHandle)
+	{
+	TSglQueIter<CSchedule> scheduleIter(iSchedules);
+	scheduleIter.SetToFirst();
+	CSchedule* schedule;
+	while ((schedule = scheduleIter++)!=NULL)
+		{
+		if (schedule->Id() == aHandle)
+			return schedule;
+		}
+	return NULL;
+	}
+
+// If aRefArray is NULL then only count it returned.
+TInt CTaskScheduler::GetScheduleRefsL(CArrayFixFlat<TSchedulerItemRef>* aRefArray, 
+									TScheduleFilter aFilter,
+									const RMessagePtr2& aMessage)
+	{
+	TInt count = 0;
+	TSglQueIter<CSchedule> iter(iSchedules);
+	iter.SetToFirst();
+	CSchedule* schedule = NULL;
+	while ((schedule = iter++) != NULL)
+		{
+		if(aFilter == EAllSchedules || (schedule->Enabled() && schedule->HasTasks()))
+			{
+			//only add information for schedules that the client has permission to alter
+			if(schedule->IsAccessAllowed(aMessage))
+				{
+				if(aRefArray)
+					{
+					TSchedulerItemRef ref;
+					ref.iHandle = schedule->Id();
+					ref.iName = schedule->Name();
+					aRefArray->AppendL(ref);	
+					}
+				count++;		
+				}
+			}
+		}
+	return count;				
+	}
+
+// If aRefArray is NULL then only count it returned.
+TInt CTaskScheduler::GetTaskRefsL(CArrayFixFlat<TSchedulerItemRef>* aRefArray, 
+									TScheduleFilter aScheduleFilter,
+									TTaskFilter aTaskFilter,
+									CClientProxy* aClient,
+									const RMessagePtr2& aMessage)
+	{
+	TInt count = 0;
+	TSglQueIter<CSchedule> iter(iSchedules);
+	iter.SetToFirst();
+	CSchedule* schedule = NULL;
+	while ((schedule = iter++) != NULL)
+		{
+		if(aScheduleFilter == EAllSchedules || (schedule->Enabled() && schedule->HasTasks()))
+			{
+			//only add information for schedules that the client has permission to alter
+			if(schedule->IsAccessAllowed(aMessage))
+				{
+				TSglQueIter<TScheduledTask> taskIter(*(schedule->Tasks()));
+				taskIter.SetToFirst();
+				TScheduledTask* task;
+				while ((task=taskIter++)!=NULL)
+					{
+					if (aTaskFilter==EAllTasks||&task->Client() == aClient) // This pointer comparison is a bit rubbish.  Change?
+						{
+						if(aRefArray)
+							{
+							TTaskInfo info = task->Info();
+							TSchedulerItemRef ref;
+							ref.iHandle = info.iTaskId;
+							ref.iName = info.iName;
+							aRefArray->AppendL(ref);
+							}
+						count++;
+						}
+					}
+				}
+			}
+		}
+	return count;				
+	}
+	
+
+//
+// Schedule Execution functions
+//
+
+// A schedule is ready to be run
+void CTaskScheduler::DueTaskNotifyL(TInt aScheduleHandle)
+	{
+	CSchedule* schedule = FindL(aScheduleHandle);
+	//NotifyTasks() also removes tasks from the schedule if there are no 
+	//repeats left.
+	schedule->NotifyTasks(); 
+
+	if (!schedule->HasTasks())
+		{
+		// remove schedule.
+		TRAPD(ignore, DoRemoveL(schedule));
+		//??error only occurs in relation to persistence!! Do something.  
+        UNUSED_VAR(ignore);
+		}
+	else
+		{
+		__ASSERT_ALWAYS(IsStartupStateNonCritical(), User::Invariant());
+		iScheduleCriteriaManager->ReplaceScheduleL(*schedule,EConditionAndTime,ETrue);
+		}
+
+	// Execute all clients.  This method doesn't leave as all errors are either
+	// logged in the log engine or handled elsewhere.
+	ExecuteClients();
+	}
+
+//	Go through all clients, executing their tasks
+void CTaskScheduler::ExecuteClients(TBool aUpdateClient)
+	{
+	if ((BUROperationInProgress() == EBUROperationNoActivity) || !aUpdateClient)
+		{
+		TDblQueIter<CClientProxy> clientIter(iClients);
+		clientIter.SetToFirst();
+		CClientProxy* client;
+		while( (client = clientIter++) != NULL)
+			{
+			// Does this client have anything ready to run?
+			if	(client->IsReadyToExecute())
+				{
+				client->ExecuteTasks();
+				// Clears the 'IsReadyToExecute' flag...
+				client->RemoveDueTasks();
+				}
+			}
+		if (aUpdateClient)	
+			{
+			// Update the store file now
+			UpdateClients();	
+			}
+		}
+	else
+		{
+		// Sets the flag to trigger delayed store operation when BUR ends
+		iTaskExecutedDuringBUR = ETrue;
+		}
+	}
+
+//	Go through all clients, update the store file with modified client info
+void CTaskScheduler::UpdateClients()
+	{
+	// iterate the client list to perform delayed update of the store file
+	TDblQueIter<CClientProxy> clientIter(iClients);
+	clientIter.SetToFirst();
+	CClientProxy* client;
+	while( (client = clientIter++) != NULL)
+		{
+		if	(!client->Users())
+			{
+			// Remove from store
+			TRAPD(ignore, iBackupManager->PerformStoreOperationL(CSchBackupManager::ESchBackupOperationDelete, *client));
+			//?? if ignore is not KErrNone then there is a problem with the store
+            UNUSED_VAR(ignore);
+			// Remove client & delete it
+			client->Remove();
+			delete client;
+			}
+		else
+			{
+			// Update this clients data in the store...
+			TRAPD(ignore, iBackupManager->PerformStoreOperationL(CSchBackupManager::ESchBackupOperationEdit, *client));
+
+			//?? if ignore is not KErrNone then there is a problem with the store
+            UNUSED_VAR(ignore);
+			}
+		}
+	}
+	
+//
+// Environment change functions
+//
+
+TInt CTaskScheduler::EnvironmentChanged(TAny* aScheduler)
+	{
+	CTaskScheduler* self = reinterpret_cast<CTaskScheduler*>(aScheduler);
+	self->HandleEnvironmentChange();
+	return KErrNone;
+	}
+
+void CTaskScheduler::HandleEnvironmentChange()
+	{
+	// If staged startup still in critical region, can safely
+	// ignore system time change.
+	if (!IsStartupStateNonCritical())
+		{
+		return;
+		}
+
+	TInt changes=iNotifier->Change();
+	if	(changes & EChangesSystemTime)
+		{
+#ifdef __SCHLOGGING__
+		{
+		TTime time;
+		time.HomeTime();
+		TDateTime due(time.DateTime());
+		LOGSTRING7("CTaskScheduler::HandleEnvironmentChangeL - system time is now: [%02d/%02d/%d] @ %02d:%02d:%02d", due.Day(), (TInt) due.Month() + 1, due.Year(), due.Hour(), due.Minute(), due.Second());
+		}
+#endif
+
+
+		// Cannot use AddSchedulesToTimerL() because this method
+		// uses the non-condition version of ReplaceScheduleL.
+		TSglQueIter<CSchedule> scheduleIter(iSchedules);
+		scheduleIter.SetToFirst();
+		CSchedule* schedule = NULL;
+		while ((schedule=scheduleIter++)!=NULL)
+			{
+			if(IsScheduleReadyForUpdate(*schedule))
+				{
+				TRAPD(err, iScheduleCriteriaManager->ReplaceScheduleL(*schedule, EOnlyTime));
+                UNUSED_VAR(err);
+				}
+			}
+		}
+	}
+
+void CTaskScheduler::AddSchedulesToTimerL()
+	{
+	if (!IsStartupStateNonCritical())
+		{
+		return; // not ready
+		}
+
+	TInt ret = KErrNone;
+
+	TSglQueIter<CSchedule> scheduleIter(iSchedules);
+	scheduleIter.SetToFirst();
+	CSchedule* schedule = NULL;
+	while ((schedule=scheduleIter++)!=NULL)
+		{
+		if(IsScheduleReadyForUpdate(*schedule))
+			{
+			TRAPD(err, iScheduleCriteriaManager->ReplaceScheduleL(*schedule));
+			if (err != KErrNone)
+				{
+				ret = err;
+				}
+			}
+		}
+	User::LeaveIfError(ret);
+	}
+	
+void CTaskScheduler::CleanupScheduledTasksL()
+	{
+	RFs fs;
+	_LIT(KTempFilePath, "_:\\private\\10005399\\*.tmp");
+	TBuf<32> filePath(KTempFilePath);
+
+	filePath[0] = RFs::GetSystemDriveChar();	
+	
+	fs.Connect();
+	CleanupClosePushL(fs);
+	
+	CFileMan* fileMan = CFileMan::NewL(fs);
+	CleanupStack::PushL(fileMan);
+
+	//Delete all temporary files in the private folder	
+	fileMan->Delete(filePath,0);
+	
+	//Pop and destroy fs and fileMan  
+	//This will call fs.Close() so no need to call it explicitly
+	CleanupStack::PopAndDestroy(2); 
+	}
+
+/**
+CSchStartupStateMgr calls this to notify startup state changes of
+interest.
+
+@internalComponent
+*/
+void CTaskScheduler::ProcessSSAEventL(TStartupStateIdentifier aKnownState)
+	{
+	LOGSTRING2("ProcessSSAEventL receive SS 0x%x", aKnownState);
+
+	if (! IsStartupStateNonCritical() &&
+		(aKnownState >= KSchFinalStartupState))
+		{
+		iStartupStatePassNonCritical = ETrue;
+		CleanupScheduledTasksL();
+		AddSchedulesToTimerL();
+		}
+	}
+
+/**
+Returns ETrue if Start-up State is NonCritical
+*/
+TBool CTaskScheduler::IsStartupStateNonCritical()
+	{
+	return iStartupStatePassNonCritical;
+	}
+
+/**
+Check schedule is valid
+*/
+TBool CTaskScheduler::IsScheduleReadyForUpdate(CSchedule& aSchedule)
+	{
+	if(aSchedule.IsUpdatable() && IsStartupStateNonCritical())
+		return 	ETrue;		
+	else
+		return EFalse;
+	}
+
+/**
+babackup server calls this to notify backup operations. The attributes are read and translated to determine
+which operation is actually in progress.  
+@internalComponent
+*/
+void CTaskScheduler::HandleBackupOperationEventL(const TBackupOperationAttributes& aBackupOperationAttributes)
+	{
+	TBUROperation type;
+
+	// determine the operation type (backup or restore)
+	switch(aBackupOperationAttributes.iFileFlag)	
+		{
+		case MBackupObserver::EReleaseLockReadOnly:
+			type = EBUROperationBackup;
+			break;
+		case MBackupObserver::EReleaseLockNoAccess:
+			type = EBUROperationRestore;
+			break;
+		case MBackupObserver::ETakeLock:
+			// No information is passed from babackup server, so we need to depend on our own memory
+			type = iBUROperationInProgress;
+			break;
+		default:
+			type = EBUROperationNoActivity;
+			break;
+		}
+		
+	// determine the operation status (e.g. starting, ending)
+	switch(aBackupOperationAttributes.iOperation)
+		{
+		case EStart:
+			BURBeginningL(type);
+			break;
+		case EEnd:
+			BURCompleteL(type, EBUROperationSuccess);
+			break;
+		case EAbort:
+			BURCompleteL(type, EBUROperationAbort);
+			break;
+		default:
+			break;
+		}
+	}
+
+
+/**
+This function is called to notify when a Backup or Restore operation is commencing.
+
+@internalComponent
+*/
+void CTaskScheduler::BURBeginningL(TBUROperation aOperationType)
+{
+	// This will stop the API calls that directly modify the store file
+	iBUROperationInProgress	= aOperationType;
+	
+	//cancel background compaction of store during backup/restore	
+	iBackupManager->Cancel();
+}
+
+
+/**
+This function is called to notify when a Backup or Restore operation is finished.
+
+@internalComponent
+*/
+void CTaskScheduler::BURCompleteL(TBUROperation aOperationType, TBUROperationResult aBURResult)
+{
+	// If there is a successful restore, this means that we have a different store file then we were using 
+	// so we have to internalize and use that file. In any other case, we can proceed with the delayed 
+	// updates to the old file
+	if ((aOperationType == EBUROperationRestore)&&(aBURResult == EBUROperationSuccess))
+		{
+		LOGSTRING("CTaskScheduler::BURCompleteL - Restoring clients and schedules after successful restore");
+
+		//First check whether any task expires during the restore process now that this is completed
+		if (iTaskExecutedDuringBUR)	
+			{
+			// performed the delayed task execution but with no externalizing as we dont want to modify
+			// the just restored file as after the delayed execution, all persistent schedule will be removed
+			ExecuteClients(EFalse);
+			iTaskExecutedDuringBUR=EFalse;			
+			}
+		
+		// Now remove existing persistent schedules, tasks and clients
+		TSglQueIter<CSchedule> scheduleIter(iSchedules);
+		scheduleIter.SetToFirst();
+		CSchedule* schedule;
+		while ((schedule = scheduleIter++)!=NULL)
+			{
+			if (schedule->Persists())
+				{
+				iSchedules.Remove(*schedule);
+				schedule->RemoveTasks(ETrue);
+				delete schedule; 
+				}
+			}
+
+		CClientProxy* client;
+		TDblQueIter<CClientProxy> clientIter(iClients);
+		
+		// remove clients which don't have any associated tasks left (tasks in persistent schedules are
+		// already removed, but the client might have transient schedules as well)
+		clientIter.SetToFirst();
+		while ((client = clientIter++) != NULL)
+			{
+			TDblQueIter<CScheduledTask> taskIter = client->TaskIterator();
+			taskIter.SetToFirst();
+			
+			// remove client if no more tasks
+			if (taskIter++ == NULL)
+				{
+				client->Remove();
+				delete client; // removes associated tasks
+				}
+			else
+				{
+				//remove any persisted task and if the client only has persisted task, remove client as well
+				taskIter.SetToFirst();
+				CScheduledTask* task;
+				TInt taskCount=0;
+				TInt persistCount=0;
+				while ((task = taskIter++) != NULL)
+					{
+					taskCount++;
+					if (task->Persists())
+						{
+						persistCount++;
+						client->RemoveTask(task);
+						}
+					}
+				//if after removing the persist tasks, there are no more other tasks, we can remove the client too						
+				if (taskCount==persistCount)
+					{
+					client->Remove();
+					delete client;
+					}					
+				}
+			}
+		
+		// now re-read the clients and schedules from the restored store file
+		TRAPD(err, iBackupManager->RestoreL(iClients, iSchedules,*iSchLogManager,ETrue));
+
+		if	(err != KErrNone) // the file's corrupt or something...
+			{
+			LOGSTRING2("CTaskScheduler::BURCompleteL - had to create new store because of error: %d", err);
+			iBackupManager->CreateEmptyBackupL();
+			}
+
+			
+		// Each client now contains a list of associated tasks. We need
+		// to now associate those tasks with specific schedules
+		clientIter.SetToFirst();
+		while ((client = clientIter++) != NULL)
+			{
+			// Fetch an iterator for each task owned by this client
+			CScheduledTask* task;
+			TDblQueIter<CScheduledTask> taskIterator = client->TaskIterator();
+			taskIterator.SetToFirst();
+
+			// Iterate through all the tasks owned by this client, trying to find
+			// the corresponding schedules.
+			while ((task = taskIterator++) != NULL)
+				{
+				TSglQueIter<CSchedule> persScheduleIter(iSchedules);
+				persScheduleIter.SetToFirst();
+				CSchedule* persSchedule;
+				while ((persSchedule = persScheduleIter++)!=NULL)
+					{
+					if ((persSchedule->Persists())&&(persSchedule->Id() == task->ScheduleId()))
+						{
+						TScheduledTask* taskRef = new(ELeave) TScheduledTask(*task,*client);
+						persSchedule->AddTask(*taskRef);
+						}
+					}
+				}
+			}
+		
+		// Activate the scheduler with the new schedules
+		AddSchedulesToTimerL();	
+		}
+	else
+		{
+		if (iTaskExecutedDuringBUR)	
+			{
+			iBUROperationInProgress	= EBUROperationNoActivity;		
+			iTaskExecutedDuringBUR = EFalse;
+			// performed the delayed task execution
+			ExecuteClients();
+			}	
+		}	
+	
+	// BUR operation is completed
+	iBUROperationInProgress	= EBUROperationNoActivity;		
+	iTaskExecutedDuringBUR = EFalse;
+}