|
||
TaskSchedulerExample
: Using Task Scheduler for
Creating and Executing Tasks
This example application demonstrates the usage of the Task Scheduler
API. It is located in the folder
examples\SysLibs\TaskSchedulerExample
.
The overview contains the following sections:
The scheduler example has two applications; one to schedule the tasks, and the other to run the scheduled tasks. The scheduler application launches the application that runs the scheduled tasks, when the tasks are due to be completed.
The scheduler application is the client of the scheduler server. It
connects and registers itself with the scheduler server using the
RScheduler::Connect()
and
RScheduler::Register()
methods, respectively. While
registering itself with the scheduler server, the scheduler application
provides the name of the application that runs the scheduled tasks, along with
its complete path and its priority relative to other clients.
When a session with the scheduler server is started, the scheduler
creates a persistent time-based schedule using the
RScheduler::CreatePersistentSchedule()
method. Then, it
adds a task to the persistent schedule using the
RScheduler::ScheduleTask()
method.
The scheduler application also creates a transient time-based schedule
using the RScheduler::ScheduleTask()
method. The
application passes the schedule information to the method using the
TScheduleEntryInfo2
and TTaskInfo
objects. It also edits the transient schedule entry to change its validity
using RScheduler::EditSchedule()
.
The scheduler application launches the executor application, which runs
the scheduled tasks when they are due to be completed. The executor checks
whether it has the necessary capability to run the scheduled tasks using the
CScheduledTask::SecurityInfo()
method. The executor
application also checks whether the Secure ID (SID) is the same as that of the
task requester, to be able to run the tasks. If these security checks pass, the
executor prints the details of the scheduled task to the console.
Finally, the scheduled tasks are deleted using the
RScheduler::DeleteSchedule()
and
RScheduler::DeleteTask()
methods, respectively.
RScheduler
Client side interface to the Task Scheduler. CScheduledTask
The representation of a scheduled task that is passed to registered programs.TScheduleEntryInfo2
Contains detailed information for a single schedule entry.TTaskInfo
Contains detailed information for a single task.TSchedulerItemRef
Defines, and uniquely identifies a schedule.TSecurityInfo
Class representing all security attributes of a process or DLL. These comprise a...The Symbian OS build process describes how to build an application.
The TaskSchedulerExample
builds executables called
taskscheduler.exe
and Taskexecutor.exe
in the
standard location
(\epoc32\release\winscw\
<build_variant>
for CodeWarrior). After launching the executable, depending on the emulator you
are using, you may need to navigate using the application launcher or the
eshell screen to view the console.
// BLD.INF
//
//
// Copyright (c) Symbian Software Ltd 2007. All rights reserved.
//
PRJ_MMPFILES
taskscheduler.mmp
taskexecutor.mmp
// taskscheduler.mmp
//
// Copyright (c) Symbian Software Ltd 2007. All rights reserved.
//
TARGET taskscheduler.exe
TARGETTYPE exe
UID 0 0xE80000B5
CAPABILITY ReadUserData WriteUserData WriteDeviceData
SOURCEPATH .
SOURCE taskscheduler.cpp
USERINCLUDE .
SYSTEMINCLUDE \epoc32\include
LIBRARY euser.lib
LIBRARY schsvr.lib
// taskexecutor.mmp
//
// Copyright (c) Symbian Software Ltd 2007. All rights reserved.
//
TARGET Taskexecutor.exe
TARGETTYPE exe
SOURCEPATH .
USERINCLUDE .
SYSTEMINCLUDE \epoc32\include
SOURCE taskexecutor.cpp
LIBRARY EUSER.LIB
LIBRARY EFSRV.LIB
LIBRARY ESTOR.LIB
LIBRARY SCHSVR.LIB
// taskscheduler.h
//
// Copyright (c) Symbian Software Ltd 2007. All rights reserved.
//
/**
@file
Contains the CTaskSchedule class.
*/
#ifndef __TASKSCHEDULER_H__
#define __TASKSCHEDULER_H__
// Symbian OS includes
#include <csch_cli.h>
/**
CTaskSchedule is a class that publicly inherits from CBase class
The class demonstrates how to connect and register with the task scheduler server,
create persistent and transient schedules and to delete the persistent tasks
and schedules.
*/
class CTaskSchedule: public CBase
{
public:
static CTaskSchedule* NewLC();
~CTaskSchedule();
void ConnectAndRegisterL();
void PersistentScheduleL();
void CreatePersistentScheduleL(TSchedulerItemRef& aRef, const TTsTime& aStartTime);
void CreateTransientScheduleL();
void DoesScheduledItemExistL(TSchedulerItemRef &aRef, TBool& aExists);
void DeleteSchedulesL(TSchedulerItemRef &aRef, TScheduleFilter aFilter);
private:
CTaskSchedule();
void ConstructL();
private:
/** Pointer to the console interface */
CConsoleBase* iConsole;
/** Handle to task scheduler interface*/
RScheduler iScheduler;
};
#endif //__TASKSCHEDULER_H__
// taskscheduler.cpp
//
// Copyright (c) Symbian Software Ltd 2007. All rights reserved.
//
/**
@file
This is simple example code that demonstrates the use of task scheduler.
The code demonstrates how to,
1) Connect and register with the task scheduler
2) Create a persistent schedule
3) Add tasks to it
4) Execute the schedule
5) Delete the schedules and the tasks associated with them after
verifying that they are the schedules created by us.
6) Create a transient schedule
7) Add task to the transient schedule, edit the schedule and execute it
*/
#include "taskscheduler.h"
#include <e32std.h>
#include <schinfo.h>
#include <e32base.h>
_LIT(KTaskName,"MyTaskName\n");
_LIT(KTitle, "Task Scheduler example");
_LIT(KTextPressAKey, "\nPress any key to step through the example\n");
_LIT(KExit,"\nPress any key to exit the application");
_LIT(KPressAKey,"\nPress any key to continue\n");
_LIT(KConnect, "\nConnecting the client to the task scheduler server");
_LIT(KRegisterClient,"\nRegistering the client\n");
_LIT(KCreateSchedule,"Creating a persistent schedule\n");
_LIT(KCreateTask,"Creating task for the schedule\n");
_LIT(KPersistentWait,"Waiting for the persistent task to complete. This will take 20 seconds\n");
_LIT(KDone,"Task complete \n");
_LIT(KTransientSchedule,"A transient schedule");
_LIT(KTransientWait,"Waiting for the transient task to complete. This will take 20 seconds\n");
_LIT(KCreateTransient,"\nCreating a transient schedule with non-repeating task\n");
_LIT(KDeleteAllTasks,"\nDeleting all the persistent tasks scheduled by this exe");
_LIT(KDeleteAllSchedules,"\nDeleting all schedules created by this exe\n");
_LIT(KTask, "Number of task(s) scheduled by us is(are) %d\n");
_LIT(KExists, "The tasks scheduled exist\n");
_LIT(KOtherTask,"Error! Unexpected schedules not scheduled by this exe exist\n");
/**
Allocates and constructs a CTaskSchedule object using two phase construction
Initialises all member data to their default values.
*/
CTaskSchedule* CTaskSchedule::NewLC()
{
CTaskSchedule* schedule = new(ELeave) CTaskSchedule();
CleanupStack::PushL(schedule);
schedule->ConstructL();
return schedule;
}
/**
Constructor
*/
CTaskSchedule::CTaskSchedule()
{
}
void CTaskSchedule::ConstructL()
{
iConsole = Console::NewL(KTitle,TSize(KConsFullScreen,KConsFullScreen));
iConsole->Printf (KTextPressAKey);
iConsole->Getch ();
}
/**
Destructor
*/
CTaskSchedule::~CTaskSchedule()
{
iScheduler.Close();
iConsole->Printf(KExit);
iConsole->Getch();
delete iConsole;
}
/**
Connects a client to the task scheduler server by
creating a session with that server and registers the client
with the scheduler.
@leave system-wide error codes.
*/
void CTaskSchedule::ConnectAndRegisterL()
{
// Connect to the scheduler server
iConsole->Printf(KConnect);
User::LeaveIfError(iScheduler.Connect());
_LIT(KTaskExec,"Taskexecutor");
TFileName filename;
filename.Append(KTaskExec);
// Register with the scheduler
iConsole->Printf(KRegisterClient);
// A priority value
const TInt priority = 3;
User::LeaveIfError(iScheduler.Register(filename, priority));
}
/**
Creates a persistent schedule task by calling CreatePersistentScheduleL().
Launches the task executor after adding and scheduling the task.
@leave KErrArgument
@leave system-wide error codes.
*/
void CTaskSchedule::PersistentScheduleL()
{
iConsole->Printf(KCreateSchedule);
TSchedulerItemRef scheduleHandle;
TTime time;
time.UniversalTime();
// Assign an offset of 20 seconds. TTimeIntervalMinutes,
// TTimeIntervalHours etc can be used for longer offsets.
time += TTimeIntervalSeconds(20);// 20 secs in future
TTsTime time2 (time, ETrue);
iConsole->Printf(KCreateTask);
CreatePersistentScheduleL(scheduleHandle,time2);
// Create the task to be scheduled
TTaskInfo taskInfo;
const TInt priority = 2;
const TInt numberOfRepeats = 2;
// Name of the task
taskInfo.iName = KTaskName;
// Task priority set by the client.
// If the client has two tasks with different priorities,
// the task with the higher priority will be executed first.
taskInfo.iPriority = priority;
// Task repeats twice
taskInfo.iRepeat = numberOfRepeats;
_LIT(KScheduleType," persistent schedule");
const TDesC* persistent = &KScheduleType;
HBufC* data = persistent->AllocLC();
// Add the task
User::LeaveIfError(iScheduler.ScheduleTask(taskInfo, *data, scheduleHandle.iHandle));
// Wait for the entry to fire
iConsole->Printf(KPersistentWait);
const TInt twentySecs = 20000000;
User::After(twentySecs); // pause for 20 seconds
// Delete all the persistent schedules created
DeleteSchedulesL(scheduleHandle, EAllSchedules);
CleanupStack::PopAndDestroy(1); // data
}
/**
Creates a persistent time based schedule with no tasks associated
with it but merely contains start and end time information.
A persistent schedule is a schedule whose lifetime is not limited
to the lifetime of the tasks associated with it.
Persistent schedules have their information persisted to disk.
On device reboot, this data is read back into memory by the
task scheduler server.
@param aRef Reference to TSchedulerItemRef for unique identification of the schedule
@param aStartTime Reference to TTsTime class
@leave KErrArgument
@leave system-wide error codes.
*/
void CTaskSchedule::CreatePersistentScheduleL(TSchedulerItemRef& aRef, const TTsTime& aStartTime)
{
CArrayFixFlat<TScheduleEntryInfo2>* cSchEntryInfoArray;
cSchEntryInfoArray = new CArrayFixFlat<TScheduleEntryInfo2>(1);
CleanupStack::PushL(cSchEntryInfoArray);
// Create an hourly schedule with StartTime of aStartTime
TScheduleEntryInfo2 entry1;
// Set the first instance when the entry will
// cause the execution of tasks.
entry1.SetStartTime(aStartTime);
// Set the type of interval used between due times
// for the scheduled entry
entry1.SetIntervalType(TIntervalType(EHourly));
// Set the period for which the entry is valid. After 8 hours the
// tasks associated with the entry will not be eligible for execution.
const TInt eightHours = 480; // in minutes
entry1.SetValidityPeriod(TTimeIntervalMinutes (eightHours));
// Set the interval between execution of tasks
// Here the interval is 1 hour because the interval type is hourly.
const TInt interval = 1;
entry1.SetInterval(interval);
cSchEntryInfoArray->AppendL(entry1);
User::LeaveIfError(iScheduler.CreatePersistentSchedule(aRef, *cSchEntryInfoArray));
CleanupStack::PopAndDestroy(cSchEntryInfoArray);
}
/**
Creates a new, transient, time based schedule, adds a task to it and then
edits the schedule and executes the edited schedule.
Launches the task executor after scheduling the task.
A transient schedule is destroyed when the task is destroyed or power is lost.
@leave KErrArgument
@leave system-wide error codes.
*/
void CTaskSchedule::CreateTransientScheduleL()
{
iConsole->ClearScreen();
TSchedulerItemRef ref;
CArrayFixFlat<TScheduleEntryInfo2>* cSchEntryInfoArray;
cSchEntryInfoArray = new CArrayFixFlat<TScheduleEntryInfo2>(1);
CleanupStack::PushL(cSchEntryInfoArray);
ref.iName = KTransientSchedule;
iConsole->Printf(KCreateTransient);
// Create a schedule entry
TScheduleEntryInfo2 entry;
TTime now;
// Set the date and time of this TTime to the universal time.
now.UniversalTime();
// Assign an offset of 15 seconds. TTimeIntervalMinutes,
// TTimeIntervalHours etc can be used for longer offsets.
TInt offset = 15;
now += TTimeIntervalSeconds(offset);
// Constructs a TTsTime with a TTime object.
// ETrue indicates that TTsTime is UTC based time
TTsTime time (now, ETrue);
// Set the above time as the first time at which
// the entry will cause execution of tasks.
entry.SetStartTime(time);
// Set the type of interval used between due times for scheduled entry
entry.SetIntervalType(TIntervalType(EHourly));
// Set the period for which the entry is valid.
// After 2 hours the tasks associated with the entry will not be eligible for execution
TInt validity = 120;
entry.SetValidityPeriod(TTimeIntervalMinutes (validity));
// Set the interval between execution of tasks
// Here the interval is 1 hour because the interval type is hourly.
entry.SetInterval(1);
cSchEntryInfoArray->AppendL(entry);
// Create a transient task to be scheduled
TTaskInfo taskInfo;
// Name of the task
taskInfo.iName = KTransientSchedule;
// Task id
const TInt tId = 0;
taskInfo.iTaskId = tId;
// The task repeats just once
const TInt numberOfRepeats = 1;
taskInfo.iRepeat = numberOfRepeats;
// Task priority set by the client.
// Where a client has two tasks with different priorities,
// the task with the higher priority will be executed first.
const TInt priority = 2;
taskInfo.iPriority = priority;
_LIT(KScheduleType," transient schedule");
const TDesC* transient = &KScheduleType;
HBufC* data = transient->AllocLC();
// Schedule the item
User::LeaveIfError(iScheduler.ScheduleTask(taskInfo, *data, ref, *cSchEntryInfoArray));
// Change the start time and validity duration for the schedule
offset = 19; // 19 seconds in future
now += TTimeIntervalSeconds(offset);
TTsTime newTime (now, ETrue);
entry.SetStartTime(newTime);
validity = 300;
entry.SetValidityPeriod(TTimeIntervalMinutes (validity));
cSchEntryInfoArray->AppendL(entry);
// Change the transient time based schedule
User::LeaveIfError(iScheduler.EditSchedule(ref.iHandle, *cSchEntryInfoArray));
CleanupStack::PopAndDestroy(2); // data, CSchEntryInfoArray
// Check if the tasks scheduled exist
TBool exists;
DoesScheduledItemExistL(ref, exists);
if(!exists)
{
User::Leave(KErrNotFound);
}
// Wait for the task to fire and complete
iConsole->Printf(KTransientWait);
const TInt twentySecs = 20000000;
User::After(twentySecs); // pause for 20 seconds
iConsole->Printf(KDone);
// Transient schedules are deleted automatically once they are executed
// i.e check for count to be zero in the function being called
DoesScheduledItemExistL(ref, exists);
if(exists)
{
User::Leave(KErrGeneral);
}
}
/**
Checks if a schedule exists
@param aRef Reference to TSchedulerItemRef for unique identification of the schedule
@param aExists TBool value, ETrue if the schedule exists, EFalse otherwise
@leave system wide error codes
*/
void CTaskSchedule::DoesScheduledItemExistL(TSchedulerItemRef &aRef, TBool& aExists)
// Extract schedule references from the schedule server based on a filter.
{
aExists = EFalse;
CArrayFixFlat<TSchedulerItemRef>* CSchItemRefArray;
CSchItemRefArray = new CArrayFixFlat<TSchedulerItemRef>(3);
CleanupStack::PushL(CSchItemRefArray);
User::LeaveIfError(iScheduler.GetScheduleRefsL(*CSchItemRefArray, EAllSchedules));
TInt count = CSchItemRefArray->Count();
for(TInt i = 0; i < count; i++)
{
// Get a list of schedules created by this executable
if(aRef.iHandle == (*CSchItemRefArray)[i].iHandle)
{
aExists = ETrue;
iConsole->Printf(KExists);
iConsole->Printf(KTask, count);
}
else
{
iConsole->Printf(KOtherTask);
}
}
CleanupStack::PopAndDestroy(); // CSchItemRefArray
}
/**
Delete all tasks and schedules created by this exe before program exit
@param TSchedulerItemRef Reference to TSchedulerItemRef for unique identification of the schedule
@param TScheduleFilter Reference to a filter when listing the schedules
@leave KErrNotFound
@leave KErrAbort
@leave KErrPermissionDenied,
@leave KErrArgument
@leave system-wide error codes.
*/
void CTaskSchedule::DeleteSchedulesL(TSchedulerItemRef &aRef, TScheduleFilter aFilter)
{
CArrayFixFlat<TSchedulerItemRef>* CSchItemRefArray;
CSchItemRefArray = new CArrayFixFlat<TSchedulerItemRef>(3);
CleanupStack::PushL(CSchItemRefArray);
User::LeaveIfError(iScheduler.GetScheduleRefsL(*CSchItemRefArray, aFilter));
TInt count = CSchItemRefArray->Count();
iConsole->Printf(KTask, count);
for(TInt i = 0; i < count; i++)
{
// Check if the schedules are created by this exe or
// some other exe
if(aRef.iHandle == (*CSchItemRefArray)[i].iHandle)
{
// Delete the tasks scheduled by us (this exe)
iConsole->Printf(KDeleteAllTasks);
User::LeaveIfError(iScheduler.DeleteTask(aRef.iHandle));
// Delete the schedules created by us (this exe)
iConsole->Printf(KDeleteAllSchedules);
User::LeaveIfError(iScheduler.DeleteSchedule(aRef.iHandle));
iConsole->Printf(KPressAKey);
iConsole->Getch();
}
else
{
// Not deleting the tasks or schedules as,
// they are not created by this exe
iConsole->Printf(KOtherTask);
}
}
CleanupStack::PopAndDestroy(); // CSchItemRefArray
}
void MainL()
{
// Create an Active Scheduler to handle asychronous calls
CActiveScheduler* scheduler = new (ELeave) CActiveScheduler;
CleanupStack::PushL(scheduler);
// Install the active scheduler
CActiveScheduler::Install( scheduler );
CTaskSchedule* app = CTaskSchedule::NewLC();
// Connect and register with the task scheduler
app->ConnectAndRegisterL();
// Create a persistent schedule and add tasks to it
app->PersistentScheduleL();
// Create a transient schedule and add tasks to it
app->CreateTransientScheduleL();
CleanupStack::PopAndDestroy(2); // app, scheduler
}
TInt E32Main()
{
__UHEAP_MARK;
CTrapCleanup* cleanup = CTrapCleanup::New();
if(cleanup == NULL)
{
return KErrNoMemory;
}
TRAPD(err, MainL());
if(err != KErrNone)
{
User::Panic(_L("Failed to complete"),err);
}
delete cleanup;
__UHEAP_MARKEND;
return KErrNone;
}
// taskexecutor.cpp
//
// Copyright (c) Symbian Software Ltd 2007. All rights reserved.
//
/**
@file
This is simple code that executes the task scheduled by the task scheduler.
The code also checks if the task requester has the required capability.
This window belongs to the task scheduled to execute by the main program.
It shows the details of the task information passed by the Task Scheduler
to the executed program.
*/
#include <schtask.h>
#include <e32cons.h>
_LIT(KTaskConsoleName, "TaskExecutor");
_LIT(KContent,"\nContents of task file:\n");
_LIT(KTask,"\nRunning task: %S");
_LIT(KTaskData,"\nThis is the task data for a");
_LIT(KTaskId,"\nThe task Id is: %d\n");
_LIT(KValidity,"Task is valid until %S\n");
_LIT(KDateString,"%H%:1%T %*E%*D%X%*N%Y %1 %2 %3");
_LIT(KPressAnyKey,"Press any key to continue \n");
_LIT(KAbort,"\nCapabilities of the task scheduler and the executor do not match. Task aborted\n");
_LIT(KSidMismatch,"SID of the task executor is not same as that of the scheduler. Task aborted\n");
// Uid of the task requester
const TUint32 KTaskSchedulerSid = 0xE80000B5;
const TCapability KTaskCapability = ECapabilityWriteDeviceData;
/**
Extracts task data, and puts up a message on the console.
Validates the security of the task requester by
a) Checking the secure ID; and
b) Capabilities of the task requester.
*/
void TaskExecuteL(RFile& aTaskFile)
{
// Construct console
CConsoleBase* console = Console::NewL(KTaskConsoleName, TSize(KConsFullScreen, KConsFullScreen));
CleanupStack::PushL(console);
console->Printf(KContent);
// Open the filestore
CFileStore* store = CDirectFileStore::FromLC(aTaskFile);//pushes store onto CleanupStack
RStoreReadStream instream;
// Open the file containing the store
instream.OpenLC(*store,store->Root());//pushes instream onto CleanupStack
// Get task count
TInt count = instream.ReadInt32L();
for (TInt i=0;i<count;i++)
{
CScheduledTask* task = CScheduledTask::NewLC(instream); //pushes task onto CleanupStack
// Check if this is the SID of task requester
if(task->SecurityInfo().iSecureId == KTaskSchedulerSid)
{
// Check if the requester has the necessary capability to run
// the scheduled tasks.
if(task->SecurityInfo().iCaps.HasCapability(KTaskCapability))
{
TBuf<50> buf;
buf.Format(KTask, &task->Info().iName);
console->Printf(buf);
HBufC* data = const_cast<HBufC*>(&(task->Data()));
console->Printf(KTaskData);
console->Printf(*data);
console->Printf(KTaskId,task->Info().iTaskId);
// Get the time when the task stops being valid
TTsTime tstime = task->ValidUntil();
const TTime time = tstime.GetLocalTime();
TBuf<30> dateString;
time.FormatL(dateString,(KDateString));
console->Printf(KValidity, &dateString);
}
else
{
console->Printf(KAbort);
}
}
else
{
console->Printf(KSidMismatch);
}
console->Printf(KPressAnyKey);
console->Getch();
CleanupStack::PopAndDestroy(task);
}
CleanupStack::PopAndDestroy(3); // instream, store, console
}
TInt Execute()
{
TInt err = KErrNoMemory;
CTrapCleanup* cleanup = CTrapCleanup::New();
if (cleanup)
{
RFile file;
// Needs to be called early-on to allow the task scheduler server
// to adopt the already open task file from the task scheduler
err = file.AdoptFromCreator(TScheduledTaskFile::FsHandleIndex(),
TScheduledTaskFile::FileHandleIndex());
if (err != KErrNone)
{
return err;
}
// Execute
TRAPD(err,TaskExecuteL(file));
if(err != KErrNone)
{
User::Panic(_L("Failed to complete"),err);
}
// Close the file
file.Close();
delete cleanup;
}
return err;
}
GLDEF_C TInt E32Main()
{
return Execute();
}