Symbian
Symbian Developer Library

SYMBIAN OS V9.4

Feedback

[Index] [Previous] [Next]


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:

[Top]


Description

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.

[Top]


Class summary

Related APIs

[Top]


Build

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.

[Top]


Example code


bld.inf

// BLD.INF
// 
// 
// Copyright (c) Symbian Software Ltd 2007. All rights reserved.
//

PRJ_MMPFILES
taskscheduler.mmp
taskexecutor.mmp

taskscheduler.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

// 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

// 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

// 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

// 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();
    }