appfw/apparchitecture/apserv/APSSERV.CPP
changeset 0 2e3d3ce01487
child 19 924385140d98
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/appfw/apparchitecture/apserv/APSSERV.CPP	Tue Feb 02 10:12:00 2010 +0200
@@ -0,0 +1,1080 @@
+// Copyright (c) 2005-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:
+// apsserv.cpp
+//
+
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#if !defined(__APA_INTERNAL_H__)
+#include "apainternal.h"
+#endif
+#include "apaidpartner.h"
+#endif //SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <e32svr.h>
+#include <u32hal.h>
+#include "apsserv.h"
+#include "APFREC.H"
+#include "APSSES.H"
+#include "APSSTD.H"
+#include "../aplist/aplappregfinder.h"
+#include "../aplist/aplapplistitem.h"
+#include "APSSCAN.H"
+#include "APSSTD.H"
+#include "APASVST.H"
+#include <datastor.h>
+#include "APSRECCACHE.h"
+#include "apsnnapps.h"
+#include "../apfile/apinstallationmonitor.h"
+#include "../apgrfx/apprivate.h"
+#include "apgnotif.h"
+
+_LIT(KAppArcServerSemaphore,"AppArcServerSemaphore");
+_LIT(KAppArcServerThread,"AppArcServerThread");
+_LIT(KAppRegistrationFileImportLocation, "?:\\private\\10003a3f\\import\\apps\\");
+_LIT(KAppResourceAppsLocation, "?:\\resource\\apps\\");
+_LIT(KNonNativeApplicationTypeRegistry, ":\\private\\10003a3f\\NonNativeTypes.dat");
+
+/*
+ * patchable const data values defined in ApsConstData.cpp
+ */
+
+IMPORT_C extern const TInt KApaLoadDataRecognizersOnDemand;
+IMPORT_C extern const TInt KApaUnloadRecognizersTimeout;
+IMPORT_C extern const TInt KApaDrivesToMonitor;
+IMPORT_C extern const TInt KApaLoadMbmIconsOnDemand;
+
+const TUint8 KPolicyElementWriteDeviceData = 0;
+
+//To monitor all drives.
+const TInt KApaMonitorAllDrives = 0x3FFFFFF;
+
+const TUint KRangeCount = 3; 
+
+const TInt KAppListServRanges[KRangeCount] = 
+	{	
+	EFirstUnrestrictedOpcodeInAppListServ,
+	EFirstOpcodeNeedingWriteDeviceDataInAppListServ, 
+	EAppListFirstUnusedOpcode,
+	};
+
+const TUint8 KElementsIndex[KRangeCount] =
+	{
+	CPolicyServer::EAlwaysPass,			//Always passing no capability required [0-99]
+	KPolicyElementWriteDeviceData,		//Requires WriteDeviceData				 [100-(EAppListFirstUnusedOpcode-1)]
+	CPolicyServer::ENotSupported, 		//Not Supported		[EAppListFirstUnusedOpcode-End]
+	};
+
+const CPolicyServer::TPolicyElement KPolicyElements[] = 
+	{ 
+	{_INIT_SECURITY_POLICY_C1(ECapabilityWriteDeviceData), CPolicyServer::EFailClient} 
+	};
+
+const CPolicyServer::TPolicy KApaServPolicy =
+	{
+	CPolicyServer::EAlwaysPass, 
+	KRangeCount,
+	KAppListServRanges,
+	KElementsIndex, 	
+	KPolicyElements 	
+	};
+ 	
+
+
+//
+// CApaAppArcServer
+//
+
+const TInt KAppListServerPriority=CActive::EPriorityStandard;
+/**
+NameApaServStartSemaphore
+
+@internalTechnology
+@released
+*/
+EXPORT_C TPtrC NameApaServStartSemaphore()
+	{
+	TPtrC nameApaServStartSemaphore(KAppArcServerSemaphore);
+	return nameApaServStartSemaphore;
+	}
+
+/**
+NameApaServServerThread
+
+@internalTechnology
+@released
+*/
+EXPORT_C TPtrC NameApaServServerThread()
+	{
+	TPtrC nameApaServServerThread(KAppArcServerThread);
+	return nameApaServServerThread;
+	}
+
+EXPORT_C CApaAppArcServer* CApaAppArcServer::Self()
+	{ // static
+	return static_cast<CApaAppArcServer*>(Dll::Tls());
+	}
+
+EXPORT_C CApaAppArcServer* CApaAppArcServer::NewL()
+// Create a new CApaAppArcServer which owns it's own resources
+	{
+	CApaAppArcServer* self=new(ELeave) CApaAppArcServer(KAppListServerPriority);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;
+	}
+
+CApaAppArcServer::CApaAppArcServer(TInt aPriority)
+	: CPolicyServer(aPriority,KApaServPolicy),
+	iAppList(0),
+	iTypeStoreModified(0),
+	iLoadRecognizersOnDemand(KApaLoadDataRecognizersOnDemand),
+	iLoadMbmIconsOnDemand(KApaLoadMbmIconsOnDemand),
+	iForceRegistrationStatus(EForceRegistrationNone)
+	{
+	
+#ifdef __WINS__
+	// KApaLoadDataRecognizersOnDemand and KApaloadIconsOnDemand are Rom patchable constants,
+	// so need an emulator equivalent
+	// if WINS then read value from epoc.ini
+	// requires licencees to set property in epoc.ini
+
+	TInt halValue = 0;
+	if (UserSvr::HalFunction(EHalGroupEmulator, EEmulatorHalIntProperty, (TAny*)"patchdata_apserv_dll_KApaLoadDataRecognizersOnDemand", &halValue) == KErrNone)
+		iLoadRecognizersOnDemand = halValue;
+
+	if (UserSvr::HalFunction(EHalGroupEmulator, EEmulatorHalIntProperty, (TAny*)"patchdata_apserv_dll_KApaLoadMbmIconsOnDemand", &halValue) == KErrNone)
+		iLoadMbmIconsOnDemand = halValue;
+#endif
+	}
+
+void CApaAppArcServer::ConstructL()
+	{
+	StartL(KAppListServerName);
+	User::LeaveIfError(Dll::SetTls(this));
+	User::LeaveIfError(iFs.Connect());
+		
+	// Get the idle timeout delay from the commandline if specified. The default is 50000ms
+	const TInt cmdLineLen = User::CommandLineLength();
+	TInt idlePeriodicDelay=50000; //default value
+	if(cmdLineLen)
+		{
+		_LIT(KIdleTimeout,"IDLE_TIMEOUT_PERIODIC_DELAY_");
+		
+		// Extract the command line into a buffer
+		HBufC* cmdLine = HBufC::NewLC(cmdLineLen);
+		TPtr cmdLinePtr = cmdLine->Des();
+		User::CommandLine(cmdLinePtr);
+		cmdLinePtr.UpperCase();
+				
+		// Check if there is an idle timeout value given
+		TInt idleTimeOutArgPos = cmdLinePtr.Find(KIdleTimeout);
+		if(KErrNotFound != idleTimeOutArgPos)
+			{
+			// Extract the value out of the command line argument
+			const TInt idleTimeOutValuePos = idleTimeOutArgPos + KIdleTimeout().Length();
+			TInt i = idleTimeOutValuePos;
+			while (i < cmdLineLen)
+				{
+				TChar c(cmdLinePtr[i]);
+				if (!c.IsDigit())
+					{
+					break;
+					}
+				i++;
+				}
+			TLex idleTimeOutParser(cmdLinePtr.Mid(idleTimeOutValuePos, (i-idleTimeOutValuePos)));
+		  	User::LeaveIfError(idleTimeOutParser.Val(idlePeriodicDelay));	  					  	
+			}
+							
+		// Check if the recognition cache should be used or not. By default the cache is used
+		iRecognitionCache = 0;
+		_LIT(KWithoutRecognitionCache,"WITHOUT_RECOGNITION_CACHE");
+		if(KErrNotFound == cmdLinePtr.Find(KWithoutRecognitionCache))
+			{
+			iRecognitionCache = new (ELeave) CApsRecognitionCache(iFs);
+			}
+			
+		_LIT(KTextShellMode,"TEXT_SHELL_MODE");
+		if (KErrNotFound == cmdLinePtr.Find(KTextShellMode))
+			{
+			// We are NOT running in text shell mode so connect to wserv session
+			User::LeaveIfError(iWsSession.Connect());
+			iRuleBasedPlugIns = CApaScanningRuleBasedPlugIns::NewL();
+			}
+
+		CleanupStack::PopAndDestroy(cmdLine);		
+		}
+	else
+		{
+		// no arguments so cache is used
+		iRecognitionCache = new (ELeave) CApsRecognitionCache(iFs);
+		// and rule based plugins are enabled
+		User::LeaveIfError(iWsSession.Connect());
+		iRuleBasedPlugIns = CApaScanningRuleBasedPlugIns::NewL();
+		}
+	
+	iAppList=CApaAppList::NewL(iFs, iLoadMbmIconsOnDemand, idlePeriodicDelay); // takes ownership of scanner
+
+	// If the phone rebooted halfway through processing updates, there will be a log file left
+	// look for one and recover if neccessary
+	CApsNonNativeApplicationsManager::RecoverFromUpdateLogL(iFs);
+
+	iMimeTypeRecognizer=CApaScanningDataRecognizer::NewL(iFs, !iLoadRecognizersOnDemand);
+
+	ConstructPathsToMonitorL();	
+
+	if ( iAppFsMonitor )
+		{
+		iAppFsMonitor->Start(ENotifyFile);
+		iAppFsMonitor->SetBlocked(ETrue);			
+		}
+	TRAP_IGNORE(iAppList->InitListL(this));
+	
+	//
+	iRecEcomMonitor=CApaEComMonitor::NewL(TCallBack(&PlugInNotifyCallBack,this));
+	iRecEcomMonitor->Start();
+
+	// Create the EMIME type store manager (part of the app-framework_emime component)
+	iMimeTypeToAppMappingsManager=CTypeStoreManager::NewL(iFs);
+	TRAPD(err,iMimeTypeToAppMappingsManager->RestoreL());
+	if(!err)
+		User::LeaveIfError(iFs.Modified(iMimeTypeToAppMappingsManager->IniFileName(),iTypeStoreModified));
+
+	// Create the EMIME type store monitor
+	iTypeStoreMonitor = CApaFsMonitor::NewL(iFs,iMimeTypeToAppMappingsManager->IniFileName(),TCallBack(&TypeStoreNotifyCallback,this));
+	iTypeStoreMonitor->Start(ENotifyWrite); // this presumably needs to be ENotifyWrite rather than ENotifyFile (the latter being used or the other CApaFsMonitor objects) because CTypeStoreManager internally uses CDictionaryFileStore::OpenL, which presumably itself uses RFile::Open, which isn't covered by ENotifyFile according to its documentation
+	TypeStoreNotifyCallback(this);
+
+	//
+	iBaBackupSessionWrapper=CBaBackupSessionWrapper::NewL();
+	iBaBackupSessionWrapper->RegisterBackupOperationObserverL(*((MBackupOperationObserver*)this));
+
+	//
+	TChar sysDrive = RFs::GetSystemDriveChar();
+	TInt maxSizeofFileName = KNonNativeApplicationTypeRegistry().Length() + 1;
+	iNonNativeApplicationTypeRegistry.CreateL(maxSizeofFileName);
+	iNonNativeApplicationTypeRegistry.Append(sysDrive);
+	iNonNativeApplicationTypeRegistry.Append(KNonNativeApplicationTypeRegistry());
+
+	TRAP_IGNORE(InternalizeNonNativeApplicationTypeArrayL());	// We don't want a corrupt file to prevent from starting
+	if(iLoadRecognizersOnDemand)
+		iRecognizerUnloadTimer=CPeriodic::NewL(EPriorityNormal);
+
+	//
+	iAppInstallationMonitor = CApaAppInstallationMonitor::NewL(this);
+	iAppInstallationMonitor->Start();
+	}
+	
+void CApaAppArcServer::ConstructPathsToMonitorL()
+	{
+	TInt drivesToMonitor = KApaDrivesToMonitor;
+	#ifdef __WINS__
+	// KApaDrivesToMonitor is a Rom patchable constant, so need an emulator equivalent
+	// if WINS then read value from epoc.ini requires licencees to set property in epoc.ini
+	// Usage: In epoc.ini patchdata_apserv_dll_KApaDrivesToMonitor 4
+	
+	TInt valueOfKApaDrivesToMonitor = 0;
+	if (UserSvr::HalFunction(EHalGroupEmulator,EEmulatorHalIntProperty,(TAny*)"patchdata_apserv_dll_KApaDrivesToMonitor",&valueOfKApaDrivesToMonitor) == KErrNone)
+		{
+		drivesToMonitor = valueOfKApaDrivesToMonitor;
+		}
+	#endif
+	
+	if ( drivesToMonitor != KApaMonitorAllDrives )
+		{
+		// 1. Create and add CApaFsNotifier for all locations belonging to a drive if the drive is set to monitor.
+		// 2. Do this for all the drives which are required to monitor.
+		TInt maskBit = 1;
+		TChar driveLetter;
+		//Only bits from 0(EDriveA)- 25(EDriveZ) are valid other bits are ignored from 32-bit KApaDrivesToMonitor.
+		for ( TInt i = EDriveA; i <= EDriveZ; i++ )
+			{
+			if ( drivesToMonitor & maskBit )
+				{
+				RFs::DriveToChar(i,driveLetter);
+				RBuf pathToBeMonitored;
+				TBuf<1> drive;
+				drive.Append(driveLetter);
+				
+				//Creating or Adding <driveLetter>:\private\10003a3f\import\apps\ path to monitor.
+				pathToBeMonitored.CreateL(KAppRegistrationFileImportLocation());				
+				CleanupClosePushL(pathToBeMonitored);
+				pathToBeMonitored.Replace(0,1,drive);				
+				if ( iAppFsMonitor == NULL )
+					{
+					iAppFsMonitor=CApaFsMonitor::NewL(iFs, pathToBeMonitored, TCallBack(&AppFsNotifyCallBack, this));
+					}
+				else
+					{
+					iAppFsMonitor->AddLocationL(pathToBeMonitored);		
+					}
+				CleanupStack::PopAndDestroy(&pathToBeMonitored);
+			
+				//Adding <driveLetter>:\resource\apps\ path to monitor.
+				pathToBeMonitored.CreateL(KAppResourceAppsLocation());
+				CleanupClosePushL(pathToBeMonitored);
+				pathToBeMonitored.Replace(0,1,drive);			
+				iAppFsMonitor->AddLocationL(pathToBeMonitored);
+				CleanupStack::PopAndDestroy(&pathToBeMonitored);
+				}
+			maskBit = maskBit << 1;
+			}	
+		}
+	else
+		{
+		iAppFsMonitor=CApaFsMonitor::NewL(iFs, KAppRegistrationFileImportLocation, TCallBack(&AppFsNotifyCallBack, this));
+		iAppFsMonitor->AddLocationL(KAppResourceAppsLocation);
+		}	
+	}
+	
+EXPORT_C CApaAppArcServer::~CApaAppArcServer()
+	{
+	if(iBaBackupSessionWrapper)
+		iBaBackupSessionWrapper->DeRegisterBackupOperationObserver(*this);
+	delete iAppInstallationMonitor;
+	delete iAppList; // deletes scanners
+	delete iMimeTypeRecognizer;
+	delete iMimeTypeToAppMappingsManager;
+	delete iAppFsMonitor;	
+	delete iTypeStoreMonitor;
+	delete iBaBackupSessionWrapper;
+	delete iRecognitionCache;
+	delete iRecEcomMonitor;
+
+	iFs.Close();
+	iWsSession.Close();	
+	delete 	iRuleBasedPlugIns;
+	for (TInt i = iNonNativeApplicationTypeArray.Count()-1; i >= 0; --i)
+		delete iNonNativeApplicationTypeArray[i].iNativeExecutable;
+
+	iNonNativeApplicationTypeArray.Close();
+
+	delete iRecognizerUnloadTimer;
+	iNonNativeApplicationTypeRegistry.Close();
+	}
+
+EXPORT_C void CApaAppArcServer::HandleInstallationStartEvent()
+	{
+	if ( iAppFsMonitor )
+		{
+		iAppFsMonitor->SetBlocked(ETrue);	
+		}
+	AppList().StopScan();
+	}
+
+EXPORT_C void CApaAppArcServer::HandleInstallationEndEventL()
+	{
+	if ( iAppFsMonitor )
+		{
+		iAppFsMonitor->SetBlocked(EFalse);	
+		}
+	AppList().RestartScanL();
+	}
+
+CSession2* CApaAppArcServer::NewSessionL(const TVersion& aVersion,const RMessage2&/* aMessage*/) const
+// Create a new server session.
+	{
+	// check we're the right version
+	TVersion v(KAppListServMajorVersionNumber, KAppListServMinorVersionNumber, KAppListServBuildVersionNumber);
+	if (!User::QueryVersionSupported(v,aVersion))
+		User::Leave(KErrNotSupported);
+	// make new session
+	return CApaAppArcServSession::NewL(const_cast<CApaAppArcServer&>(*this), const_cast<RFs&>(iFs));
+	}
+
+//
+// scanning code here
+//
+
+EXPORT_C TCallBack CApaAppArcServer::RescanCallBack()
+	{
+	return TCallBack(&AppFsNotifyWithForcedRegistrationsResetCallBack,this);
+	}
+
+TInt CApaAppArcServer::AppFsNotifyWithForcedRegistrationsResetCallBack(TAny* aPtr)
+	{
+	ASSERT(aPtr);
+	reinterpret_cast<CApaAppArcServer*>(aPtr)->AppList().ResetForcedRegistrations();
+	return AppFsNotifyCallBack(aPtr);
+	}
+
+TInt CApaAppArcServer::AppFsNotifyCallBack(TAny* aObject)
+	{
+	ASSERT(aObject);
+	reinterpret_cast<CApaAppArcServer*>(aObject)->UpdateApps();
+	return KErrNone;
+	}
+
+TInt CApaAppArcServer::PlugInNotifyCallBack(TAny* aObject)
+	{
+	//update the pre-Platform-security style  recognizers and rule-based plug-ins
+	ASSERT(aObject);
+	reinterpret_cast<CApaAppArcServer*>(aObject)->UpdatePlugIns();
+	return KErrNone;
+	}
+
+TInt CApaAppArcServer::TypeStoreNotifyCallback(TAny* aObject)
+	{
+	ASSERT(aObject);
+	reinterpret_cast<CApaAppArcServer*>(aObject)->UpdateTypeStore();
+	return KErrNone;
+	}
+
+void CApaAppArcServer::UpdateApps()
+// update the list
+	{
+	// File system change, rescan
+	TRAP_IGNORE(iAppList->StartIdleUpdateL (this));
+	}
+
+/*
+Updates application list with force registered applications.
+*/
+ 
+void CApaAppArcServer::UpdateAppsByForceRegistration()
+    {
+    iForceRegistrationStatus|=EForceRegistrationRequested;
+    UpdateApps();
+    }
+
+void CApaAppArcServer::NotifyUpdate(TInt aReason)
+// tell all sessions to update their clients
+	{
+	// Updates the applist with the icon caption details from the Central Repository.
+	TRAP_IGNORE(iAppList->UpdateAppListByIconCaptionOverridesL());
+	// The short caption value sets through the API has got the highest precedence over the
+	// values found in either central repository or resource file.
+	TRAP_IGNORE(iAppList->UpdateAppListByShortCaptionL());
+
+    //Delete any data mappings in service registry related to uninstalled applications.
+    CArrayFixFlat<TUid>* uninstalledApps=iAppList->UninstalledAppArray();
+    TBool modificationStatus=EFalse;
+    TBool modified;
+    
+    if(uninstalledApps)
+        {
+        TInt count=uninstalledApps->Count();
+        for(int index=0;index<count;index++)
+            {
+            modified=iMimeTypeToAppMappingsManager->DeleteApplicationDataMappings((*uninstalledApps)[index]);
+        
+            //Set modificationStatus if any data mapping is removed from the service registry
+            if(modified)
+                modificationStatus=ETrue;
+            }
+        
+        delete uninstalledApps;
+        
+        //If service registry is modified, store it to a file
+        if(modificationStatus)
+            TRAP_IGNORE(iMimeTypeToAppMappingsManager->StoreL());
+        }
+    
+	// iterate through sessions
+	iSessionIter.SetToFirst();
+	CApaAppArcServSession* ses=static_cast<CApaAppArcServSession*>(&(*iSessionIter++));
+	while (ses!=NULL)
+		{
+		if(iForceRegistrationStatus & EForceRegistrationRequested)
+            {
+             //Notify clients about completion of force registration. 
+            ses->NotifyScanComplete();
+            }
+		else
+            {
+            ses->NotifyClients(aReason);
+            }
+		ses=static_cast<CApaAppArcServSession*>(&(*iSessionIter++));
+		}
+	
+     if(iForceRegistrationStatus & EForceRegistrationRequested)
+         {
+         //If this function is called because of force registration, clear force registration request status and
+        //set force registration applist change status
+        iForceRegistrationStatus &= (~EForceRegistrationRequested);
+         iForceRegistrationStatus |= EForceRegistrationAppListChanged;
+         }
+     else
+         {
+         //If this function is called not because of force registration, clear force registration applist change status. 
+        iForceRegistrationStatus &= (~EForceRegistrationAppListChanged);        
+         }
+	}
+
+void CApaAppArcServer::UpdatePlugIns()
+// update the pre-Platform-security style, ecom style recognizers and rule-based plug-ins
+	{
+	//we want the recognizers to be loaded either if:
+	// 1) they are not loaded on demand
+	// 2) they are loaded on demand and actively used
+	// 3) they are loaded on demand but waiting for the timer to be unloaded
+	if(!iLoadRecognizersOnDemand || iRecognizerUsageCount > 0 || (iRecognizerUnloadTimer && iRecognizerUnloadTimer->IsActive()))
+		{
+		TRAP_IGNORE(iMimeTypeRecognizer->LoadRecognizersL());
+		}
+	if (iRecognitionCache)
+		{	// RecognitionCache is flushed if there are any changes in plugins, i.e.,if:
+			// 1. New ECom Plugin is installed.
+			// 2. Existing ECom Plugin is uninstalled.
+		iRecognitionCache->Flush();
+		}
+
+	TRAP_IGNORE(iRuleBasedPlugIns->ScanForRuleBasedPlugInsL());
+	}
+
+void CApaAppArcServer::UpdateTypeStore()
+// Update the internal type store if things have changed
+	{
+	TRAP_IGNORE(DoUpdateTypeStoreL());
+	}
+
+void CApaAppArcServer::DoUpdateTypeStoreL()
+	{
+	TTime modified;
+	TInt err=iFs.Modified(iMimeTypeToAppMappingsManager->IniFileName(),modified);
+	// check the time stamp to see if we are interested in an update
+	if (modified>iTypeStoreModified && err==KErrNone)
+		{
+		CTypeStoreManager* manager=CTypeStoreManager::NewL(iFs);
+		CleanupStack::PushL(manager);
+		manager->RestoreL();
+		iTypeStoreModified=modified;
+		delete iMimeTypeToAppMappingsManager;
+		iMimeTypeToAppMappingsManager=manager;
+		CleanupStack::Pop(manager); 
+		}
+		
+	for (iSessionIter.SetToFirst(); ; iSessionIter++) //lint !e1757 prefix operator not defined for TDblQueIter
+		{
+     	CSession2* const session=iSessionIter;
+     	if (!session)
+  			break;
+
+     	static_cast<CApaAppArcServSession*>(session)->NotifyClientOfDataMappingChange();
+		}
+	}
+
+void CApaAppArcServer::HandleBackupOperationEventL(const TBackupOperationAttributes& aBackupOperationAttributes)
+//
+// Handle a signal from the backup server to indicate that a backup has started or finished.
+//
+	{
+	switch(aBackupOperationAttributes.iOperation)
+		{
+	case MBackupOperationObserver::ENone:
+	case MBackupOperationObserver::EAbort:
+		break;
+	case MBackupOperationObserver::EStart:
+		if ( iAppFsMonitor )
+			{
+			iAppFsMonitor->SetBlocked(ETrue);	
+			}
+		break;
+	case MBackupOperationObserver::EEnd:
+		if ( iAppFsMonitor )
+			{
+			iAppFsMonitor->SetBlocked(EFalse);	
+			}
+		break;
+	default:
+		Panic(EEventFromBackupObserverError);
+		break;
+		}
+	}
+
+void CApaAppArcServer::InitialListPopulationComplete()
+	{
+	if ( iAppFsMonitor )
+		{
+		iAppFsMonitor->SetBlocked(EFalse);	
+		}
+	
+	// notify clients (whoever is interested) that initial population of list is completed
+	iSessionIter.SetToFirst();
+	CApaAppArcServSession* ses=static_cast<CApaAppArcServSession*>(&(*iSessionIter++));
+	// iterate through sessions
+	while (ses!=NULL)
+		{
+		ses->NotifyClientForCompletionOfListPopulation();	
+		ses=static_cast<CApaAppArcServSession*>(&(*iSessionIter++));
+		}
+	}
+
+void CApaAppArcServer::RegisterNonNativeApplicationTypeL(TUid aApplicationType, const TDesC& aNativeExecutable)
+	{
+	for (TInt i=iNonNativeApplicationTypeArray.Count()-1; i>=0; --i)
+		{
+		if (iNonNativeApplicationTypeArray[i].iTypeUid.iUid==aApplicationType.iUid)
+			User::Leave(KErrAlreadyExists);
+		}
+		
+	SNonNativeApplicationType nonNativeApplicationType;
+	nonNativeApplicationType.iTypeUid.iUid=aApplicationType.iUid;
+	nonNativeApplicationType.iNativeExecutable=aNativeExecutable.AllocLC();
+	iNonNativeApplicationTypeArray.AppendL(nonNativeApplicationType);
+	CleanupStack::Pop(nonNativeApplicationType.iNativeExecutable);
+	CleanupStack::PushL(TCleanupItem(DeleteLastNonNativeApplicationType, this));
+	ExternalizeNonNativeApplicationTypeArrayL();
+	CleanupStack::Pop(this); // the TCleanupItem
+	}
+
+void CApaAppArcServer::DeregisterNonNativeApplicationTypeL(TUid aApplicationType)
+	{
+	TInt i;
+	for (i=iNonNativeApplicationTypeArray.Count()-1; i>=0; --i)
+		{
+		if (iNonNativeApplicationTypeArray[i].iTypeUid.iUid==aApplicationType.iUid)
+			break;
+		}
+		
+	if (i>=0)
+		{
+		ExternalizeNonNativeApplicationTypeArrayL(i);
+		delete iNonNativeApplicationTypeArray[i].iNativeExecutable;
+		iNonNativeApplicationTypeArray[i].iNativeExecutable = NULL;
+		iNonNativeApplicationTypeArray.Remove(i);
+		}
+	}
+
+void CApaAppArcServer::InternalizeNonNativeApplicationTypeArrayL()
+	{
+	RFile file;
+	CleanupClosePushL(file);
+	const TInt error=file.Open(iFs, iNonNativeApplicationTypeRegistry, EFileShareReadersOnly|EFileStream|EFileRead);
+	if (error==KErrNone) // don't leave if the file can't be opened (because it doesn't exist, or because the directory we're looking for it in doesn't exist)
+		{
+		RFileReadStream sourceStream;
+		sourceStream.Attach(file); // file gets closed by this call, but that's okay, we don't need it any more (sourceStream has its own copy of this RFile object that it owns)
+		CleanupClosePushL(sourceStream);
+		TCardinality arrayCount;
+		arrayCount.InternalizeL(sourceStream);
+		for (TInt i=0; i<TInt(arrayCount); ++i)
+			{
+			SNonNativeApplicationType nonNativeApplicationType;
+			nonNativeApplicationType.iTypeUid.iUid=sourceStream.ReadUint32L();
+			nonNativeApplicationType.iNativeExecutable=HBufC::NewLC(sourceStream, KMaxFileName);
+			iNonNativeApplicationTypeArray.AppendL(nonNativeApplicationType);
+			CleanupStack::Pop(nonNativeApplicationType.iNativeExecutable);
+			}
+		CleanupStack::PopAndDestroy(&sourceStream);
+		}
+		
+	CleanupStack::PopAndDestroy(&file);
+	}
+
+void CApaAppArcServer::ExternalizeNonNativeApplicationTypeArrayL(TInt aIndexToIgnore/*=-1*/) const
+	{
+	RFs& fs=const_cast<RFs&>(iFs);
+	fs.MkDirAll(iNonNativeApplicationTypeRegistry); // ignore any error
+	RFile file;
+	CleanupClosePushL(file);
+	User::LeaveIfError(file.Replace(fs, iNonNativeApplicationTypeRegistry, EFileShareExclusive|EFileStream|EFileWrite));
+	RFileWriteStream targetStream;
+	targetStream.Attach(file); // file gets closed by this call, but that's okay, we don't need it any more (targetStream has its own copy of this RFile object that it owns)
+	CleanupClosePushL(targetStream);
+	const TInt arrayCount(iNonNativeApplicationTypeArray.Count());
+	TInt arrayCountToExternalize=arrayCount;
+	if (aIndexToIgnore>=0)
+		--arrayCountToExternalize;
+
+	TCardinality(arrayCountToExternalize).ExternalizeL(targetStream);
+	for (TInt i=0; i<arrayCount; ++i)
+		{
+		if (i!=aIndexToIgnore)
+			{
+			const SNonNativeApplicationType& nonNativeApplicationType=iNonNativeApplicationTypeArray[i];
+			targetStream.WriteUint32L(nonNativeApplicationType.iTypeUid.iUid);
+			targetStream << *nonNativeApplicationType.iNativeExecutable;
+			}
+		}
+		
+	targetStream.CommitL();
+	CleanupStack::PopAndDestroy(2, &file);
+	}
+
+TPtrC CApaAppArcServer::NativeExecutableL(TUid aNonNativeApplicationType) const
+	{
+	for (TInt i=iNonNativeApplicationTypeArray.Count()-1; i>=0; --i)
+		{
+		const SNonNativeApplicationType& nonNativeApplicationType=iNonNativeApplicationTypeArray[i];
+		if (nonNativeApplicationType.iTypeUid.iUid==aNonNativeApplicationType.iUid)
+			return *nonNativeApplicationType.iNativeExecutable;
+		}
+		
+	User::Leave(KErrNotSupported); // not KErrNotFound
+	return KNullDesC();
+	}
+
+void CApaAppArcServer::DeleteLastNonNativeApplicationType(TAny* aThis)
+	{ // static
+	CApaAppArcServer& self=*static_cast<CApaAppArcServer*>(aThis);
+	const TInt arrayIndex=self.iNonNativeApplicationTypeArray.Count()-1;
+	delete self.iNonNativeApplicationTypeArray[arrayIndex].iNativeExecutable;
+	self.iNonNativeApplicationTypeArray[arrayIndex].iNativeExecutable = NULL;
+	self.iNonNativeApplicationTypeArray.Remove(arrayIndex);
+	}
+
+void CApaAppArcServer::NotifyScanComplete()
+	{
+	// Updates the applist with the icon caption details from the Central Repository.
+	TRAP_IGNORE(iAppList->UpdateAppListByIconCaptionOverridesL());
+	// The short caption value sets through the API has got the highest precedence over the
+	// values found in either central repository or resource file.		
+	TRAP_IGNORE(iAppList->UpdateAppListByShortCaptionL());
+
+	// iterate through sessions
+	iSessionIter.SetToFirst();
+	CApaAppArcServSession* ses=static_cast<CApaAppArcServSession*>(&(*iSessionIter++));
+	while (ses)
+		{
+		if((iForceRegistrationStatus & EForceRegistrationRequested) ||
+	            !(iForceRegistrationStatus & EForceRegistrationAppListChanged))
+		    {
+		    //Notify clients about completion of force registration or scan completion		
+		    ses->NotifyScanComplete();
+		    }
+		else
+		    {
+		    //If force registration changes applicaiton list,
+		    // then notify applist change to clients.
+		    ses->NotifyClients(MApaAppListServObserver::EAppListChanged);
+		    }		
+		ses=static_cast<CApaAppArcServSession*>(&(*iSessionIter++));
+		}
+	if(!(iForceRegistrationStatus & EForceRegistrationRequested))
+	    {
+	    //If this function is called not because of force registration, 
+	    //clear force registration applist change status. 
+            iForceRegistrationStatus &= (~EForceRegistrationAppListChanged);	        
+	    }
+	//Clear force registration request status
+        iForceRegistrationStatus &= (~EForceRegistrationRequested);
+	}
+
+/*
+ * Data Recognizer calls
+ */
+ 
+TBool CApaAppArcServer::CachedRecognitionResult(const TParseBase& aParser, TDataRecognitionResult& aResult) const
+	{
+	if(iRecognitionCache && aParser.PathPresent() && aParser.NamePresent())
+		return iRecognitionCache->Get(aParser.DriveAndPath(), aParser.NameAndExt(), aResult);
+
+	return EFalse;
+	}
+
+/**
+N.B. The @c CRecognitionResult object is reference counted so it must be closed!
+*/
+CRecognitionResult* CApaAppArcServer::CachedRecognitionResult(const RFile& aFile, const TParseBase& aParser) const
+	{
+	if(iRecognitionCache && aParser.PathPresent() && aParser.NamePresent())
+		return iRecognitionCache->Get(aFile, aParser.DriveAndPath(), aParser.NameAndExt());
+
+	return NULL;
+	}
+
+void CApaAppArcServer::CacheRecognitionResultL(const TParseBase& aParser, const TDataRecognitionResult& aResult)
+	{
+	if(iRecognitionCache && aParser.PathPresent() && aParser.NamePresent())
+		iRecognitionCache->AddL(aParser.DriveAndPath(), aParser.NameAndExt(), aResult);
+	}
+
+void CApaAppArcServer::CacheRecognitionResultL(const RFile& aFile, const TParseBase& aParser, const TDataRecognitionResult& aResult)
+	{
+	if(iRecognitionCache && aParser.PathPresent() && aParser.NamePresent())
+		{
+		iRecognitionCache->AddL(aFile, aParser.DriveAndPath(), aParser.NameAndExt(), aResult);
+		}
+	}
+
+TDataRecognitionResult CApaAppArcServer::RecognizeDataL(const TDesC& aName, const TDesC8& aBuffer)
+	{
+	TParsePtrC parser(iFs.IsValidName(aName) ? aName : KNullDesC);
+	TDataRecognitionResult result;
+	
+	// check cache	
+	if(!CachedRecognitionResult(parser, result))
+		{
+		// recognize
+		if(iLoadRecognizersOnDemand)
+			LoadRecognizersLC();
+
+		result = iMimeTypeRecognizer->RecognizeL(aName, aBuffer);
+		if(iLoadRecognizersOnDemand)
+			CleanupStack::PopAndDestroy();
+
+		// add to cache
+		CacheRecognitionResultL(parser, result);
+		}
+	
+	return result;	
+	}
+
+TDataRecognitionResult CApaAppArcServer::RecognizeDataL(RFile& aFile, TInt aPreferredBufSize)
+	{
+	CRecognitionResult* result = RecognizeDataAsCRecognitionResultL(aFile, aPreferredBufSize);
+	TDataRecognitionResult ret;
+	result->Get(ret);
+	result->Close();
+	return ret;
+	}
+
+/**
+Same as @c RecognizeDataL(RFile&, TInt) but returns a @c CRecognitionResult 
+instead of a @c TDataRecognitionResult.
+
+N.B. The @c CRecognitionResult object is reference counted so it must be closed!
+*/
+CRecognitionResult* CApaAppArcServer::RecognizeDataAsCRecognitionResultL(RFile& aFile, TInt aPreferredBufSize)
+	{
+	CRecognitionResult* result = NULL;
+	
+	TFileName fileName;
+	User::LeaveIfError(aFile.FullName(fileName));
+	TParsePtrC parser(fileName); //fileName is valid since it comes from RFile
+
+	//check cache
+	result = CachedRecognitionResult(aFile,parser);
+	if(!result)
+		{
+		// recognize
+		if(iLoadRecognizersOnDemand)
+			LoadRecognizersLC();
+
+		const TDataRecognitionResult recResult = iMimeTypeRecognizer->RecognizeL(aFile, aPreferredBufSize);
+		if(iLoadRecognizersOnDemand)
+			CleanupStack::PopAndDestroy();
+	
+		//add to cache
+		CacheRecognitionResultL(aFile, parser, recResult);
+
+		result = CRecognitionResult::NewL(parser.NameAndExt(), recResult);
+		}
+	
+	return result;
+	}
+
+TBool CApaAppArcServer::RecognizeDataL(const TDesC& aName, const TDesC8& aBuffer, const TDataType& aDataType)
+	{
+	if(iLoadRecognizersOnDemand)
+		LoadRecognizersLC();
+
+	const TBool ret = iMimeTypeRecognizer->RecognizeL(aName,aBuffer,aDataType);
+	if(iLoadRecognizersOnDemand)
+		CleanupStack::PopAndDestroy();
+
+	return ret;
+	}
+
+TBool CApaAppArcServer::RecognizeDataL(RFile& aFile, TInt aPreferredBufSize, const TDataType& aDataType)
+	{
+	if(iLoadRecognizersOnDemand)
+		LoadRecognizersLC();
+
+	const TBool ret = iMimeTypeRecognizer->RecognizeL(aFile,aPreferredBufSize,aDataType);
+	if(iLoadRecognizersOnDemand)
+		CleanupStack::PopAndDestroy();
+
+	return ret;
+	}
+
+TInt CApaAppArcServer::DataRecognizerPreferredBufSizeL()
+	{
+	if(iLoadRecognizersOnDemand)
+		LoadRecognizersLC();
+
+	const TInt ret = iMimeTypeRecognizer->PreferredBufSize();
+	if(iLoadRecognizersOnDemand)
+		CleanupStack::PopAndDestroy();
+
+	return ret;
+	}
+
+void CApaAppArcServer::DataTypeL(CDataTypeArray& aArray)
+	{
+	if(iLoadRecognizersOnDemand)
+		LoadRecognizersLC();
+
+	iMimeTypeRecognizer->DataTypeL(aArray);
+	if(iLoadRecognizersOnDemand)
+		CleanupStack::PopAndDestroy();
+	}
+
+/*
+ * Recognizer loading/unloading code
+ */
+
+void CApaAppArcServer::LoadRecognizersLC()
+	{
+	ASSERT(iLoadRecognizersOnDemand);
+
+	LoadRecognizersL();
+	TCleanupItem cleanup(CApaAppArcServer::RecognizerCleanup, this);
+	CleanupStack::PushL(cleanup);
+	}
+
+void CApaAppArcServer::RecognizerCleanup(TAny* aSelf)
+	{
+	if (aSelf)
+		{
+		static_cast<CApaAppArcServer*>(aSelf)->UnloadRecognizers();
+		}
+	}
+
+void CApaAppArcServer::LoadRecognizersL()
+	{
+	ASSERT(iLoadRecognizersOnDemand);
+
+	if(iRecognizerUnloadTimer->IsActive())
+		{
+		__ASSERT_DEBUG(iRecognizerUsageCount==0,Panic(EReferenceCountingError1));
+		iRecognizerUnloadTimer->Cancel();
+		}
+	else if(iRecognizerUsageCount==0)
+		{
+		iMimeTypeRecognizer->LoadRecognizersL();
+		}
+
+	++iRecognizerUsageCount;
+	}
+
+TInt CApaAppArcServer::UnloadRecognizers()
+	{
+	ASSERT(iLoadRecognizersOnDemand);
+
+	--iRecognizerUsageCount;
+	__ASSERT_DEBUG(iRecognizerUsageCount>=0,Panic(EReferenceCountingError2));
+	if (iRecognizerUsageCount==0)
+		{
+		iRecognizerUnloadTimer->Start(KApaUnloadRecognizersTimeout,0,TCallBack(CApaAppArcServer::DoUnloadRecognizersCallback,this));
+		}
+	return KErrNone;
+	}
+	
+TInt CApaAppArcServer::DoUnloadRecognizersCallback(TAny* aSelf)
+	{
+	TInt ret=KErrNone;
+	if (aSelf)
+		{
+		ret = static_cast<CApaAppArcServer*>(aSelf)->DoUnloadRecognizers();
+		}
+	return ret;
+	}
+
+TInt CApaAppArcServer::DoUnloadRecognizers()
+	{
+	ASSERT(iLoadRecognizersOnDemand);
+
+	// need to cancel the periodic timer since we only want a oneshot timer
+	iRecognizerUnloadTimer->Cancel();
+	iMimeTypeRecognizer->UnloadRecognizers();
+	return KErrNone;
+	}
+	
+void CApaAppArcServer::GetAppForMimeType(const TDataType& aDataType, TUid& aUid) const
+	{
+	iMimeTypeToAppMappingsManager->GetAppByDataType(aDataType, aUid);
+	}
+	
+void CApaAppArcServer::GetAppForMimeType(const TDataType& aDataType, TUid aServiceUid, TUid& aUid) const
+	{
+	iMimeTypeToAppMappingsManager->GetAppByDataType(aDataType, aServiceUid, aUid);
+	}
+	
+TBool CApaAppArcServer::InsertAndStoreIfHigherL(const TDataType& aDataType, TDataTypePriority aPriority, TUid aUid)
+	{
+	return iMimeTypeToAppMappingsManager->InsertAndStoreIfHigherL(aDataType, aPriority, aUid);
+	}
+	
+void CApaAppArcServer::InsertAndStoreDataMappingL(const TDataType& aDataType, TDataTypePriority aPriority, TUid aUid, TUid aServiceUid)
+	{
+	iMimeTypeToAppMappingsManager->InsertAndStoreDataMappingL(aDataType, aPriority, aUid, aServiceUid);
+	}
+	
+void CApaAppArcServer::DeleteAndStoreDataMappingL(const TDataType& aDataType, TUid aServiceUid)
+	{
+	iMimeTypeToAppMappingsManager->DeleteAndStoreDataMappingL(aDataType, aServiceUid);
+	}
+
+TBool CApaAppArcServer::LoadMbmIconsOnDemand() const
+	{
+	return iLoadMbmIconsOnDemand;
+	}
+
+#ifdef _DEBUG
+
+/**
+Flushes the recognition cache.
+
+Useful for debugging.
+*/
+void CApaAppArcServer::FlushRecognitionCache()
+	{
+	if(iRecognitionCache)
+		iRecognitionCache->Flush();
+	}
+
+/**
+Sets whether or not recognizers should be loaded when they are needed.
+
+Useful for debugging.
+*/	
+void CApaAppArcServer::SetLoadRecognizersOnDemandL(TBool aLoadRecognizersOnDemand)
+	{
+	if(iLoadRecognizersOnDemand == aLoadRecognizersOnDemand)
+		return;
+	
+	CPeriodic* newUnloadTimer;
+	if(aLoadRecognizersOnDemand)
+		{
+		ASSERT(!iRecognizerUnloadTimer);
+		newUnloadTimer = CPeriodic::NewL(EPriorityNormal);
+		}
+	else
+		{
+		ASSERT(iRecognizerUnloadTimer);
+		newUnloadTimer = NULL;
+		}
+	CleanupStack::PushL(newUnloadTimer);
+	
+	CApaScanningDataRecognizer* newMimeTypeRecognizer = CApaScanningDataRecognizer::NewL(iFs,!aLoadRecognizersOnDemand);
+	delete iMimeTypeRecognizer;
+	iMimeTypeRecognizer = newMimeTypeRecognizer;
+	
+	delete iRecognizerUnloadTimer;
+	iRecognizerUnloadTimer = newUnloadTimer;
+	CleanupStack::Pop(newUnloadTimer);
+	
+	iRecognizerUsageCount = 0;
+	iLoadRecognizersOnDemand = aLoadRecognizersOnDemand;	
+	}
+
+/**
+If recognizers are set to be loaded on demand this method can be used to perform
+the unloading synchronously, instead of waiting for the unloading timer to go off.
+
+Useful for debugging.
+*/
+void CApaAppArcServer::PerformOutstandingRecognizerUnloading()
+	{
+	if(iLoadRecognizersOnDemand && iRecognizerUnloadTimer->IsActive())
+		{
+		__ASSERT_DEBUG(iRecognizerUsageCount==0,Panic(EReferenceCountingError3));
+		DoUnloadRecognizers();
+		}
+	}
+
+#endif //_DEBUG
+