--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/commonuisupport/uikon/srvsrc/EIKBAKSV.CPP Tue Feb 02 01:00:49 2010 +0200
@@ -0,0 +1,849 @@
+// Copyright (c) 1997-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 "EIKBAKSV.H"
+#include <babackup.h>
+#include <basched.h>
+
+#include <e32base.h>
+#include <w32std.h>
+#include <apaid.h>
+#include <apacmdln.h>
+#include <apgcli.h>
+#include <apgtask.h>
+#include <apgwgnam.h>
+#include <coemain.h> // for TActivePriority only
+#include <uikon/patchdata.h>
+
+class RFindLib : public RLibrary
+ {
+public:
+ inline TInt Open(const TFindLibrary& aFind,TOwnerType aType=EOwnerProcess);
+ };
+
+inline TInt RFindLib::Open(const TFindLibrary& aFind,TOwnerType aType)
+ {return(RHandleBase::Open(aFind,aType));}
+
+
+//
+// class CEikServBackupServer
+//
+
+
+/**
+Creates a CEikServBackupServer.
+Static factory function.
+Does not call ConstructL (BUT ConstructL is not EXPORTed !?!?)
+@return Instantiated object
+@publishedAll
+@released
+*/
+EXPORT_C CEikServBackupServer* CEikServBackupServer::NewL()
+ { // static
+ CEikServBackupServer* self=new(ELeave) CEikServBackupServer(EActivePriorityIpcEventsHigh);
+ return self;
+ }
+
+/**
+Constructor
+@internalComponent
+*/
+CEikServBackupServer::CEikServBackupServer(TInt aPriority)
+ : CBaBackupServer(aPriority)
+ {}
+
+/**
+2nd phase constructor. Opens connection to Window Server
+Framework function
+@see CBaBackupServer::ConstructL()
+*/
+void CEikServBackupServer::ConstructL()
+ {
+ CBaBackupServer::ConstructL();
+ }
+
+/**
+Destructor
+*/
+CEikServBackupServer::~CEikServBackupServer()
+ {
+ delete iAppStarter;
+ }
+
+
+/**
+Framework function
+@see CBaBackupServer::IsOtherClientBusy(TUint32 aUniqueClientId)
+*/
+TBool CEikServBackupServer::IsOtherClientBusy(TUint32 aUniqueClientId) const
+ {
+ return (iAppStarter || CBaBackupServer::IsOtherClientBusy(aUniqueClientId));
+ }
+
+/**
+Framework function
+@see CBaBackupServer::CompleteClosingFiles(CArrayFix<CBaServBackupSession::TClosedFile>* aClosedFiles)
+*/
+void CEikServBackupServer::CompleteClosingFiles(CArrayFix<CBaServBackupSession::TClosedFile>* aClosedFiles)
+ {
+ delete iAppStarter;
+ iAppStarter=NULL;
+ TRAPD(err,iAppStarter=CAppStarter::NewL(*this,aClosedFiles));
+ if (err!=KErrNone)
+ {
+ SetBusy(0);
+ }
+ }
+
+/**
+Framework function
+@see CServer2:;::NewSessionL(const TVersion &aVersion, const RMessage2&)
+*/
+CSession2* CEikServBackupServer::NewSessionL(const TVersion &aVersion, const RMessage2&) const
+ {
+ const TVersion version(KBakServMajorVN,KBakServMinorVN,KBakServBuildVN);
+ if (!User::QueryVersionSupported(version,aVersion))
+ {
+ User::Leave(KErrNotSupported);
+ }
+ return CEikServBackupSession::NewL();
+ }
+
+/**
+Framework Function
+@see MAppStarterObserver::HandleAppsStarted()
+*/
+void CEikServBackupServer::HandleAppsStarted()
+ {
+ SetBusy(0);
+ delete iAppStarter;
+ iAppStarter=NULL;
+ }
+
+
+
+//
+// class CAppWatcher
+//
+
+
+/**
+Static factory function
+@param aThreadId - Of application to watch
+@param aAppShutter - Called when watcher (this) sees app close.
+@param aClosedFile - file that will need restarting
+@return Instantiated and constructed object
+@internalTechnology
+*/
+CAppWatcher* CAppWatcher::NewL(TThreadId aThreadId,CAppShutter& aAppShutter,
+ const CEikServBackupSession::TClosedFile& aClosedFile)
+ { // static
+ CAppWatcher* self=new(ELeave) CAppWatcher(aAppShutter,aClosedFile);
+ CleanupStack::PushL(self);
+ self->ConstructL(aThreadId);
+ CleanupStack::Pop(); // self
+ return self;
+ }
+
+/**
+Destructor
+*/
+CAppWatcher::~CAppWatcher()
+ {
+ Cancel();
+ iThread.Close();
+ }
+
+/**
+@return Copy of the closed file
+@internalTechnology
+@see CEikServBackupSession::TClosedFile
+*/
+const CEikServBackupSession::TClosedFile& CAppWatcher::Info() const
+ {
+ return iClosedFile;
+ }
+
+/**
+Private constructor
+@param aAppShutter - called when watcher (this) sees app close.
+@param aClosedFile- the file that will need restarting
+@internalComponent
+*/
+CAppWatcher::CAppWatcher(CAppShutter& aAppShutter,const CEikServBackupSession::TClosedFile& aClosedFile)
+ : CActive(CActive::EPriorityStandard), iAppShutter(aAppShutter), iClosedFile(aClosedFile)
+ {}
+
+
+/**
+Second phase constructor
+Logs on to thread to wait for application to close.
+@param aThreadId
+@internalComponent
+*/
+void CAppWatcher::ConstructL(TThreadId aThreadId)
+ {
+ CActiveScheduler::Add(this);
+ iStatus=KRequestPending;
+ SetActive();
+ User::LeaveIfError(iThread.Open(aThreadId));
+ iThread.Logon(iStatus);
+ }
+
+/**
+CActive framework function
+Cancels thread logon
+*/
+void CAppWatcher::DoCancel()
+ {
+ if (iThread.Id() && iStatus==KRequestPending)
+ {
+ iThread.LogonCancel(iStatus);
+ }
+ }
+
+/**
+CActive framework function
+Handles application closure. Calls App shutter
+*/
+void CAppWatcher::RunL()
+ {
+ iAppShutter.HandleAppClosedL(iClosedFile);
+ }
+
+/**
+CActive framework function
+*/
+TInt CAppWatcher::RunError(TInt /*aError*/)
+ {
+ delete this;
+ return KErrNone;
+ }
+
+//
+// class CAppShutter
+//
+
+/**
+@internalComponent
+*/
+CAppShutter::CShutterTimer* CAppShutter::CShutterTimer::NewL(TInt aPriority)
+ { // static
+ CShutterTimer* self=new(ELeave) CShutterTimer(aPriority);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(); // self
+ CActiveScheduler::Add(self);
+ return self;
+ }
+/**
+@internalComponent
+*/
+TInt CAppShutter::CShutterTimer::RunError(TInt aError)
+ {
+ if (aError==KLeaveWithoutAlert)
+ {
+ return KErrNone;
+ }
+ return aError;
+ }
+
+/**
+@internalComponent
+*/
+CAppShutter::CShutterTimer::CShutterTimer(TInt aPriority)
+ : CPeriodic(aPriority)
+ {}
+
+/**
+@internalTechnology
+*/
+CAppShutter* CAppShutter::StartL(MAppShutterObserver& aObserver,
+ CArrayFix<CEikServBackupSession::TClosedFile>& aClosedFiles,
+ CBaBackupServer& aBackupServer)
+ { // static
+ CAppShutter* self=new(ELeave) CAppShutter(aObserver,aClosedFiles, aBackupServer);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(); // self
+ return self;
+ }
+
+/**
+@internalComponent
+*/
+CAppShutter::~CAppShutter()
+ {
+ if (iAppWatchers)
+ {
+ iAppWatchers->ResetAndDestroy();
+ delete iAppWatchers;
+ }
+ delete iTimer;
+ delete iWgIds;
+ iWsSession.Close();
+ }
+
+
+/**
+@internalComponent
+*/
+CAppShutter::CAppShutter(MAppShutterObserver& aObserver,
+ CArrayFix<CEikServBackupSession::TClosedFile>& aClosedFiles,
+ CBaBackupServer& aBackupServer)
+ : iObserver(aObserver),iClosedFiles(aClosedFiles), iBackupServer(aBackupServer)
+
+
+ {}
+
+/**
+@internalComponent
+*/
+void CAppShutter::ConstructL()
+ {
+ iTimer=CShutterTimer::NewL(CActive::EPriorityStandard);
+ iTimer->Start(0,1,TCallBack(TimerCallBackL,this));
+ iAppWatchers=new(ELeave) CArrayPtrFlat<CAppWatcher>(1);
+ User::LeaveIfError(iWsSession.Connect());
+ const TInt wgCount=iWsSession.NumWindowGroups(0);
+ iWgIds=new(ELeave) RArray<RWsSession::TWindowGroupChainInfo>(wgCount);
+ User::LeaveIfError(iWsSession.WindowGroupList(0,iWgIds));
+ }
+
+/**
+@internalTechnology
+*/
+void CAppShutter::HandleAppClosedL(const CEikServBackupSession::TClosedFile& aClosedFile)
+ {
+ const TInt count=iAppWatchers->Count();
+ for (TInt ii=0;ii<count;ii++)
+ {
+ CAppWatcher* watcher=(*iAppWatchers)[ii];
+ if (watcher->Info()==aClosedFile)
+ {
+ iAppWatchers->Delete(ii);
+ NextL();
+ delete watcher;
+ break;
+ }
+ }
+ }
+
+/**
+@internalComponent
+*/
+TInt CAppShutter::TimerCallBackL(TAny* aPtr)
+ { // static
+ REINTERPRET_CAST(CAppShutter*,aPtr)->HandleTimerCallBackL();
+ return 0;
+ }
+
+/**
+@internalComponent
+*/
+void CAppShutter::HandleTimerCallBackL()
+ {
+ NextL();
+ }
+
+/**
+@internalComponent
+*/
+void CAppShutter::NextL()
+ {
+ if (iNextWgIndex==iWgIds->Count())
+ {
+ CheckCompleteL();
+ }
+ else
+ {
+ const RWsSession::TWindowGroupChainInfo wgId=(*iWgIds)[iNextWgIndex++];
+ CApaWindowGroupName* wgName=CApaWindowGroupName::NewLC(iWsSession,wgId.iId);
+ if (!IsWgIdValid(wgId.iId) || wgName->IsSystem() || wgName->Hidden())
+ {
+ NextL();
+ }
+ else
+ {
+ TPtrC docName=wgName->DocName();
+ CEikServBackupSession::TClosedFile data;
+ if (docName.Length())
+ {
+ data.iDocName=docName;
+ }
+ data.iUid=wgName->AppUid();
+ // We don't want to restart server apps
+ if (wgId.iParentId <= 0)
+ {
+ iClosedFiles.AppendL(data);
+ }
+ TThreadId threadId;
+ User::LeaveIfError(iWsSession.GetWindowGroupClientThreadId(wgId.iId,threadId));
+ CAppWatcher* watcher=CAppWatcher::NewL(threadId,*this,data);
+ CleanupStack::PushL(watcher);
+ iAppWatchers->AppendL(watcher);
+ CleanupStack::Pop(); // watcher
+ TApaTask task(iWsSession);
+ task.SetWgId(wgId.iId);
+ task.SendSystemEvent(EApaSystemEventShutdown);
+ if (iTimer->IsActive())
+ {
+ iTimer->Cancel();
+ }
+ // If hardware use patchable constant if not default to 5 seconds
+ iTimer->Start(KUIKONBackupCloseAllFilesTimeout,KUIKONBackupCloseAllFilesTimeout,TCallBack(TimerCallBackL,this));
+ }
+ CleanupStack::PopAndDestroy(); // wgName
+ }
+ }
+
+/**
+@internalComponent
+*/
+TBool CAppShutter::IsWgIdValid(TInt aWgId)
+ {
+ TBuf<600> name;
+ const TInt r=iWsSession.GetWindowGroupNameFromIdentifier(aWgId,name);
+ return r==KErrNone;
+ }
+
+/**
+@internalComponent
+*/
+void CAppShutter::CheckCompleteL()
+ {
+ // see if any new window groups exist. If they do, add them to the end of iWgIds and go back to NextL
+ const TInt wgCount=iWsSession.NumWindowGroups(0);
+ RArray<RWsSession::TWindowGroupChainInfo>* wgIds=new(ELeave) RArray<RWsSession::TWindowGroupChainInfo>(wgCount);
+ CleanupStack::PushL(wgIds);
+ User::LeaveIfError(iWsSession.WindowGroupList(0,wgIds));
+ TBool foundNewWg=EFalse;
+ for (TInt ii=0;ii<wgCount;ii++)
+ {
+ if (iWgIds->Find((*wgIds)[ii])<0)
+ {
+ iWgIds->AppendL((*wgIds)[ii]);
+ foundNewWg=ETrue;
+ }
+ }
+ CleanupStack::PopAndDestroy(); // wgIds
+ if (foundNewWg)
+ {
+ NextL();
+ }
+ else // if iAppWatchers is non-empty then some tasks are still closing. Give them up to 5 seconds to terminate
+ {
+ // Check all files that have been registered for file lock notifications have been updated
+ TBool filesAllLocked = iBackupServer.HaveAllCloseAllFilesClientsReRegistered();
+
+ // If all registered files are locked and all app watchers are done we can proceed
+ if ((filesAllLocked && (iAppWatchers->Count() == 0)) || (iCheckCount == 3))
+ {
+ const TBool allAppsClosed=(iAppWatchers->Count()==0);
+ iObserver.HandleAppsClosedL(allAppsClosed);
+ }
+ else
+ {
+ iCheckCount++;
+ if (iTimer->IsActive())
+ {
+ iTimer->Cancel();
+ }
+ // If hardware use patchable constant if not default to 5 seconds
+ iTimer->Start(KUIKONBackupCloseAllFilesTimeout,KUIKONBackupCloseAllFilesTimeout,TCallBack(TimerCallBackL,this));
+
+ }
+ }
+ }
+
+//
+// class CEikServAppShutter
+//
+
+/**
+@internalTechnology
+*/
+CEikServAppShutter::CEikServAppShutter(const RMessage2& aMessage)
+ : iMessage(aMessage)
+ {}
+
+/**
+@internalTechnology
+*/
+void CEikServAppShutter::ConstructL(MAppShutterObserver& aObserver,
+ CArrayFix<CEikServBackupSession::TClosedFile>& aClosedFiles,
+ CBaBackupServer* aBackupServer)
+ {
+ iShutter=CAppShutter::StartL(aObserver,aClosedFiles, *aBackupServer);
+ }
+/**
+@internalTechnology
+*/
+CEikServAppShutter::~CEikServAppShutter()
+ {
+ delete iShutter;
+ }
+
+/**
+@internalTechnology
+*/
+const RMessage2& CEikServAppShutter::Message() const
+ {
+ return iMessage;
+ }
+
+
+//
+// class CEikServBackupSession
+//
+
+
+/**
+Static factory function
+@return Instantiated and constructed object.
+@internalTechnology
+*/
+CEikServBackupSession* CEikServBackupSession::NewL()
+ { // static
+ CEikServBackupSession* self=new(ELeave) CEikServBackupSession();
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+/**
+@internalTechnology
+*/
+CEikServBackupSession::~CEikServBackupSession()
+ {
+ }
+
+/**
+Framework function
+@see CBaBackupServerSession::HandleError( Tint aError )
+*/
+void CEikServBackupSession::HandleError(TInt aError)
+ {
+ if (iAppShutter)
+ {
+ BackupServer()->SetCloseAllOperationRunningState(EFalse);
+ iAppShutter->Message().Complete(aError);
+ delete iAppShutter;
+ iAppShutter=NULL;
+ CBaServBackupScheduler::Current()->SetErrorHandler(NULL);
+ }
+ else
+ {
+ CBaServBackupSession::HandleError(aError);
+ }
+ }
+
+/**
+@internalComponent
+*/
+void CEikServBackupSession::ServiceL(const RMessage2& aMessage)
+ {
+ CBaServBackupSession::ServiceL(aMessage);
+ }
+
+/**
+@internalComponent
+*/
+void CEikServBackupSession::ServiceError(const RMessage2& aMessage,TInt aError)
+ {
+ if (!aMessage.IsNull())
+ {
+ aMessage.Complete(aError);
+ }
+ }
+
+/**
+Framework function
+@see MAppShutterObserver::HandleAppsClosedL(TBool aAllAppsClosed)
+*/
+void CEikServBackupSession::HandleAppsClosedL(TBool aAllAppsClosed)
+ {
+ if (iAppShutter)
+ {
+ // End the CloseAll period
+ BackupServer()->SetCloseAllOperationRunningState(EFalse);
+ const TInt err=(aAllAppsClosed? KErrNone : KErrInUse);
+ iAppShutter->Message().Complete(err);
+ delete iAppShutter;
+ iAppShutter=NULL;
+ }
+ }
+
+/**
+Used as TCleanupItem.
+@internalComponent
+*/
+void CEikServBackupSession::CleanupCloseAllFiles(TAny* aPtr)
+ { // static
+ CEikServBackupSession* self=REINTERPRET_CAST(CEikServBackupSession*,aPtr);
+ delete self->iAppShutter;
+ self->iAppShutter=NULL;
+ }
+
+
+/**
+Framework function
+@see CBaBackupServerSession::CloseAllFilesL(const RMessage2& aMessage)
+*/
+TCompletionType CEikServBackupSession::CloseAllFilesL(const RMessage2& aMessage)
+ {
+ CBaServBackupSession::DoCloseAllFilesL(aMessage);
+ CEikServBackupServer* server=static_cast<CEikServBackupServer*>(BackupServer());
+ CleanupStack::PushL(TCleanupItem(CleanupCloseAllFiles,this));
+ __ASSERT_DEBUG(iAppShutter == NULL, PanicClientL(aMessage,EBadInternalState));
+ iAppShutter=new(ELeave) CEikServAppShutter(aMessage);
+ if(!ClosedFiles())
+ {
+ CArrayFixSeg<CBaServBackupSession::TClosedFile>* closedFiles=new(ELeave) CArrayFixSeg<CBaServBackupSession::TClosedFile>(1);
+ SetClosedFiles(closedFiles);
+ }
+ iAppShutter->ConstructL(*this,*ClosedFiles(), (CBaBackupServer*)BackupServer() );
+ CleanupStack::Pop(); // CleanupCloseAllFiles
+ return ECompleteAsync;
+ }
+
+/**
+Framework function
+@see CBaBackupServerSession::RestartAll()
+*/
+void CEikServBackupSession::RestartAll()
+ {
+ CBaBackupServer* server=BackupServer();
+ if (server->IsClientBusy(UniqueClientId()))
+ {
+ if (iAppShutter)
+ {
+ BackupServer()->SetCloseAllOperationRunningState(EFalse);
+ iAppShutter->Message().Complete(KErrCancel);
+ delete iAppShutter;
+ iAppShutter=NULL;
+ }
+ CBaServBackupSession::RestartAll();
+ }
+ }
+
+
+/**
+@internalComponent
+*/
+void CEikServBackupSession::PanicClientL(const RMessage2& aMessage, TEikBackupServPanic aCode)
+ {
+ _LIT(KPanicCat,"BackupSrv");
+ aMessage.Panic(KPanicCat,aCode);
+ User::Leave(KLeaveWithoutAlert);
+ }
+
+
+
+//
+// class CAppStarter
+//
+
+const TInt KAppStarterTimerGranularity=100000; // 0.1s
+_LIT(KThreadName,"AppStarterThread");
+
+/**
+Static factory function
+@param aObserver Applications starter observer
+@param aClosedFiles A list of the files closed for backing up (i.e. which need re-starting)
+@return instantiated and constructed App Starter
+@internalTechnology
+*/
+CAppStarter* CAppStarter::NewL(MAppStarterObserver& aObserver,CArrayFix<CEikServBackupSession::TClosedFile>* aClosedFiles)
+ { // static
+ CleanupStack::PushL(aClosedFiles);
+ CAppStarter* self=new(ELeave) CAppStarter(aObserver,aClosedFiles);
+ CleanupStack::Pop(); // aClosedFiles
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(); // self
+ return self;
+ }
+
+/**
+destructor
+*/
+CAppStarter::~CAppStarter()
+ {// Cancel any outstanding request before cleanup
+ Cancel(); // Calls DoCancel()
+ delete iClosedFiles;
+ }
+
+/**
+Constructor
+@param aObserver Startup observer
+@param aClosedFiles A list of the files closed for backing up (i.e. which need re-starting)
+@internalComponent
+*/
+CAppStarter::CAppStarter(MAppStarterObserver& aObserver, CArrayFix<CEikServBackupSession::TClosedFile>* aClosedFiles)
+ : CActive(EPriorityStandard), iObserver(aObserver), iClosedFiles(aClosedFiles)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+/**
+2nd phase constructor.
+This function creates a separate thread which is used to run StartAppsL() synchronously.
+A static fuction - ThreadEntryPoint() - is called to call StartAppsL() on 'this'.
+@internalComponent
+*/
+void CAppStarter::ConstructL()
+ {
+ if (IsActive())
+ {
+ return;
+ }
+
+ TInt res = iThread.Create(KThreadName,
+ ThreadEntryPoint,
+ KDefaultStackSize,
+ NULL,
+ this);
+
+ if(KErrNone==res)
+ {// set ourselves to KRequestPending, set active, resume new thread (to make synchronous call)
+ iStatus = KRequestPending;
+ SetActive();
+ iThread.Logon(iStatus); // Request notification when thread dies
+ iThread.Resume(); // Start the thread
+ }
+ }
+
+/**
+This function is excuted synchronously in a separate thread
+Each of the closed files passed in during construction is restarted.
+@internalComponent
+*/
+void CAppStarter::StartAppsL()
+ {// synchronous call executed in thread
+
+ RApaLsSession apaSession;
+ User::LeaveIfError(apaSession.Connect());
+ CleanupClosePushL(apaSession);
+ RWsSession wsSession;
+ User::LeaveIfError(wsSession.Connect());
+ CleanupClosePushL(wsSession);
+
+
+ do {
+ const TInt count=iClosedFiles->Count();
+ if (count!=0)
+ {
+ CEikServBackupSession::TClosedFile& item=(*iClosedFiles)[count-1];
+ TInt wgId=0;
+ CApaCommandLine* cmdLine=CApaCommandLine::NewLC();
+ if (item.iDocName.Length()>0)
+ {
+ CApaWindowGroupName::FindByDocName(item.iDocName,wsSession,wgId);
+ cmdLine->SetDocumentNameL(item.iDocName);
+ }
+ else
+ {
+ CApaWindowGroupName::FindByAppUid(item.iUid,wsSession,wgId);
+ }
+
+ if (wgId==KErrNotFound)
+ {
+ cmdLine->SetCommandL(EApaCommandBackground);
+ TApaAppInfo info;
+ User::LeaveIfError(apaSession.GetAppInfo(info, item.iUid));
+ cmdLine->SetExecutableNameL(info.iFullName);
+ apaSession.StartApp(*cmdLine); // ignore the error, we can't do anything useful in response
+ }
+ CleanupStack::PopAndDestroy(1); // cmdLine
+ }
+
+ if (count<=1)
+ {
+ break;//loop termination condition
+ }
+ else
+ {
+ iClosedFiles->Delete(count-1);
+ User::After(KAppStarterTimerGranularity);// force thread to sleep
+ }
+
+ } while(1);
+
+ CleanupStack::PopAndDestroy(2); // apaSession & wsSession
+ }
+
+/**
+Static function used to run StartAppsL() in separate thread.
+Thread is terminated on completion
+@param aParams 'this' pointer to CAppStarter
+@return Is ignored
+*/
+TInt CAppStarter::ThreadEntryPoint(TAny* aParams)
+ {// perform apps startup
+
+ //CleanupStack for this thread
+ CTrapCleanup* theCleanupStack = CTrapCleanup::New();
+ CAppStarter* appStarter = NULL;
+ appStarter = static_cast<CAppStarter*>(aParams);
+ TInt err = KErrNone;
+ if(appStarter)
+ {
+ TRAP(err, appStarter->StartAppsL());//synchronous call
+ }
+ delete theCleanupStack;
+
+ // Task complete so end this thread
+ RThread().Kill(err);// err value can be retrieved via 'ExitReason()' in CAppStarter::RunL()
+ return (KErrNone); //value discarded
+ }
+
+/**
+Kills (other) thread if necessary
+CActive framework function
+*/
+void CAppStarter::DoCancel()
+ {
+ TExitType threadExitType = iThread.ExitType();
+ if(EExitPending==threadExitType)
+ {//thread still running
+ iThread.LogonCancel(iStatus);//cancel outstanding notification request
+ iThread.Kill(KErrCancel);
+ iThread.Close();
+ }
+ }
+
+/**
+Closes (other) thread. Kills it if necessary.
+Signals to observer that task is complete.
+CActive framework function.
+*/
+void CAppStarter::RunL()
+ {// check in case thread is still running e.g. if Logon() failed
+ TExitType threadExitType = iThread.ExitType();
+ if(EExitPending==threadExitType) // Thread still running - kill it
+ {
+ iThread.Kill(KErrNone);
+ }
+
+ iThread.Close();// close thread handle
+ iObserver.HandleAppsStarted();// calls delete on this active object
+ }
+
+//
+// Main
+//
+