lowlevellibsandfws/pluginfw/Framework/frame/Registrar.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 02 Feb 2010 02:01:42 +0200
changeset 0 e4d67989cc36
permissions -rw-r--r--
Revision: 201002 Kit: 201005

// 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:
// Implementation of the registrar class
// 
//

/**
 @internalComponent
 @file 
*/

#include <barsc2.h> // CResourceFile
#include <barsread2.h> // RResourceReader
#include <bautils.h>
#include <e32uid.h>
#include <startup.hrh> // for EStartupStateNonCritical

#include "ecompanics.h"
#include "EComDebug.h"
#include <ecom/ecom.h>
#include <ecom/ecomerrorcodes.h>
#include <ecom/ecomresolverparams.h>
#include "TestUtilities.h"	// For __FILE__LINE__
#include "Registrar.h"
#include "Discoverer.h"
#include "BackupNotifier.h"
#include "RegistryData.h"
#include "EComUidCodes.h"
#include "RegistrarObserver.h"
#include "DriveInfo.h"
#include "ParseImplementationData.h"
#include "EComInternalErrorCodes.h"
	
const TInt KMinBuffAllocSize = 1;


#define UNUSED_VAR(a) a = a


CRegistrar* CRegistrar::NewL(CRegistryData& aRegistry, MRegistrarObserver& aRegistrarObserver, RFs& aFs)
	{
	CRegistrar* self = new(ELeave) CRegistrar(aRegistry,aRegistrarObserver,aFs);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}

// Default d'tor

CRegistrar::~CRegistrar()
	{
	delete iBackupNotifier;
	delete iDiscoverer;
	delete iCachedDriveInfo;
	}

// Default c'tor

CRegistrar::CRegistrar(CRegistryData& aRegistry, MRegistrarObserver& aRegistrarObserver, RFs& aFs)
: CBase(), iRegistry(aRegistry), iRegistrarObserver(aRegistrarObserver), iFs(aFs), iState(EReg_Undefined)
	{
	}


void CRegistrar::ConstructL()
	{
	iCachedDriveInfo = CEComCachedDriveInfo::NewL(iFs);

	// Instantiate the discoverer
	iDiscoverer = CDiscoverer::NewL(*this, iFs);
	InitialiseEvent();
	}


TInt CRegistrar::Disable(TUid aImplementationUid)
	{
	return iRegistry.SetEnabledState(aImplementationUid, EFalse);
	}


TInt CRegistrar::Enable(TUid aImplementationUid)
	{
	return iRegistry.SetEnabledState(aImplementationUid, ETrue);
	}


TInt CRegistrar::Resume()
	{
	return iDiscoverer->Resume();
	}


TInt CRegistrar::Suspend()
	{
	return iDiscoverer->Suspend();
	}


void CRegistrar::DriveRemovedL(TDriveUnit aDrive)
	{
	iRegistry.TemporaryUninstallL(aDrive);
	}


void CRegistrar::DriveReinstatedL(TDriveUnit aDrive)
	{
	iRegistry.UndoTemporaryUninstallL(aDrive);
	}
	
TBool CRegistrar::IsAnyDllRegisteredWithDriveL(const TDriveUnit aDrive)const
	{
	return iRegistry.IsAnyDllRegisteredWithDriveL(aDrive);
	}

void CRegistrar::RegisterDiscoveryL(const TDriveName& aDrive,CPluginBase*& aDirEntry, TBool aAnyDllDiscovered)
	{
	TBool found = EFalse;
	TBool update = EFalse;
	TInt  registryDriveIndex = KErrNotFound;

	// Find the appropriate drive entry
	TChar driveLetter = User::UpperCase(aDrive[0]) - 'A';
	TDriveUnit driveUnit = EDriveA + driveLetter;
	CRegistryData::CDriveData* drive =NULL;
	
	// Get the drive data in the registry.
	registryDriveIndex = iRegistry.FindDriveL(driveUnit, drive);
	if(registryDriveIndex == KErrNotFound)
		{
		User::Leave(KEComErrDriveNotFound);
		}
		

	// Get the registry to return enough data so that the Add and Update routines
	// can be optimised to avoid rescanning the registry data.
	// This means that registryDriveIndex MUST remain valid until after
	// the ParseRegistrationDataL call below.
	
	// IsRegisteredWithDate will be called if the this drive is NOT
	// under its initial discovery. If any Dll is discovered in the drive, then
	// this drive is NOT in its initial discovery.
	
	// In read-only drive with SPI enable, aAnyDllDiscovered will be always false. 
	// If language downgrade path has been changed, IsRegisteredWithDate will be
	// called to check whether current localised file need to be updated. 
	if((aAnyDllDiscovered) || (iRegistry.HasLanguageChanged()))
		{
		found = iRegistry.IsRegisteredWithDate(aDirEntry->iDllThirdUid, aDirEntry->iDllModifiedTime, update, drive);
		}
	
	if(!found || update || iRegistry.HasLanguageChanged())
		{
		if(found && !update && iRegistry.HasLanguageChanged())
			{
			// If we got here because the language has changed
			// ensure the existing registry data is updated rather than a new entry added
			update = ETrue;
			}
		ParseRegistrationDataL(aDirEntry,driveUnit, update, registryDriveIndex, drive);
		}
	}


void CRegistrar::DiscoveriesBegin()
	{
	// We are about to receive registrations so inform the registry that its index
	// is about to be invalid
	iRegistry.DiscoveriesBeginning();
	}


void CRegistrar::DiscoveriesComplete(TBool aSuccessful, TPluginProcessingTypeIdentifier aProcessingType)
	{
	
	TBool doesRegChanged = EFalse;

	// Successfully completed, if registry data has been changed, update 
	TRAPD(error,iRegistry.DiscoveriesCompleteL(aSuccessful, aProcessingType,doesRegChanged));
    UNUSED_VAR(error);
	// Notify if the registry data has been changed.
	if(doesRegChanged)
		{
	// Notify that we have updated the registry
		iRegistrarObserver.Notification(KErrNone);
		}
	}

void CRegistrar::SetDiscoveryFlagL(const TDriveUnit& aDriveUnit)
	{
	//set the drive flag to indicate it has changes.
	iRegistry.SetDiscoveryFlagL(aDriveUnit);
	}
	
TBool CRegistrar::NotifiedWithErrorCode(TInt aError)
	{
	// Test the safe error codes
	return (aError == KErrNotReady ||		// Drive removed?
			aError == KErrPathNotFound);	// Directory deleted?
	}

void CRegistrar::ParseRegistrationDataL(CPluginBase*& aEntry,
										const TDriveUnit& aDrive, 
										TBool aUpdate, 
										TInt aRegistryDriveIndex,
										CRegistryData::CDriveData* aDriveData)
	{
	// Ok we intend installing this item so 
	// create the Interface Implementation Collection entry first
	CRegistryData::CDllData* dll = CRegistryData::CDllData::NewLC(*(aEntry->iDllName),aEntry->iDllModifiedTime,aEntry->iDllSecondUid,aEntry->iDllThirdUid,aDriveData);

#ifdef ECOM_TRACE
	static int counter = 0; counter++;
	TFileName fullFileName(aDrive.Name());
	fullFileName.Append(_L("\\sys\\bin\\"));
	fullFileName.Append(*(aEntry->iDllName));
	__ECOM_TRACE2("ECOM: Plugin discovered (%04d) %S", counter, &fullFileName);
#endif

	// update resource ext info
	HBufC* resourceExt = aEntry->RscFileExt();
	if(resourceExt)
		dll->SetResourceExtL(*resourceExt);
	
	// Don't automatically leave during the parse of the implementation
	// collection's registration data.
	// If we did then there would be a cascade of leaves which stop the 
	// entire registration process for all discoveries remaining on the list.
	// Check to see if there is a problem specifically with the registration data
	// OR if its a general problem. In the latter case leave.
	TInt error=KErrNone;
			
	TRAP(error, ParseL(aEntry,*dll));
	if (error==KErrNoMemory)
		User::LeaveNoMemory();
	if(error == KErrNone)
		{
		if(aUpdate)
			{	
			iRegistry.UpdateDllDataL(aDrive, aRegistryDriveIndex, dll);
			}
		else
			{	
			iRegistry.AddDllDataL(aDrive, aRegistryDriveIndex, dll);
			}
		// Remove dll from CleanupStack as ownership has been passed in one of
		// the two functions above
		CleanupStack::Pop(dll);
		}
	else
		{
		// This interface implementation collection 
		// cannot be registered correctly.
		CleanupStack::PopAndDestroy(dll);
		}
	}

void CRegistrar::GetResourceFormatVersionL(RResourceReader& aReader, TInt& aResourceFormatVersion)
	{
	aResourceFormatVersion = 1;
	TUid dllUid(KNullUid);
	TUid uid = {aReader.ReadInt32L()};
	if(uid==KUidEComResourceFormatV2)
		{
		aResourceFormatVersion = 2;
		dllUid.iUid = aReader.ReadInt32L();
		}
	else if(uid==KUidEComResourceFormatV3)
		{
		aResourceFormatVersion = 3;
		dllUid.iUid = aReader.ReadInt32L();
		}		
	else
		dllUid = uid;
	}

	
void CRegistrar::ParseL(CPluginBase*& aEntry,CRegistryData::CDllData& aDll)
	{
// Read the resource file starting at offset:0 section size:0
	CResourceFile* regFile =aEntry->RscFile();
//	Note : There may be an issue here with resource reading when the 
//  file is not in the ROM. The solution would be to call
//	regFile.ConfirmSignatureL(regFile.SignatureL());
//	However for 6.2 interface implementation collections will ALL
//	be within the ROM. and future development will move to an
//	XML parsed solution @ build time.
//	IF this situation changes, place the fix here.
 	RResourceReader theReader;
 	theReader.OpenLC(regFile, KMinBuffAllocSize);
	TInt resourceFormatVersion = 0;
	GetResourceFormatVersionL(theReader,resourceFormatVersion);
	
	TDriveUnit drive(aDll.iParent->iDrive);
	TBool romBased = iCachedDriveInfo->DriveIsReadOnlyInternalL(drive);
	const TInt numInterfaces = theReader.ReadInt16L();
	if (resourceFormatVersion == 3 && numInterfaces > KMaxInterfacesInResV3)
		{
		User::Leave(KErrNotSupported);
		}
	for(TInt iface = 0; iface < numInterfaces; ++iface)
		{
		// Read the interface uid
		const TUid interfaceUid = {theReader.ReadInt32L()};
		CRegistryData::CInterfaceData* interfaceList = CRegistryData::CInterfaceData::NewLC(interfaceUid,&aDll);
		aDll.AddL(interfaceList);
		CleanupStack::Pop(interfaceList);		// Now owned by aDll
		const TInt numImplementations = theReader.ReadInt16L();
		if (resourceFormatVersion == 3 && numImplementations > KMaxImplementationsForEachInterfacesInResV3)
			{
			User::Leave(KErrNotSupported);
			}
		for(TInt index = 0; index < numImplementations; ++index)
			{
			TUid implementationUid;
			TInt versionNo;
			TInt infoFormat;
			TBool romOnly;
			RExtendedInterfacesArray* extendedInterfaces = NULL;
			HBufC* name = NULL;
			HBufC8* defaultData = NULL;
			HBufC8* opaqueData = NULL;
			CParseImplementationData* parseImplementationData = CParseImplementationData::NewLC(resourceFormatVersion);
			parseImplementationData->ParseL(theReader,
											infoFormat,
											implementationUid,
											versionNo,
									   	  	name,
									      	defaultData,
									      	opaqueData,
									      	extendedInterfaces,
									      	romOnly);
			CleanupStack::PopAndDestroy(parseImplementationData);									      	
			
			CleanupStack::PushL(TCleanupItem(CloseAndDeleteArray, extendedInterfaces));
			CleanupStack::PushL(name);
			CleanupStack::PushL(defaultData);
			CleanupStack::PushL(opaqueData);
			if (romOnly && !(romBased))
				{
				// pop and destroy opaquedata, defaultdata,name and extendedInterfaces
				CleanupStack::PopAndDestroy(4,extendedInterfaces); 
				}
			else
				{
				CRegistryData::CImplementationData* implData = CRegistryData::CImplementationData::NewL(interfaceList,
																										implementationUid, 
																				 						versionNo, 
																				 						name, 
																						 				defaultData,
																										opaqueData,
																					 					drive,
																					 					romOnly,
																				 						romBased,
																				 						extendedInterfaces);
				CleanupStack::Pop(4,extendedInterfaces); // opaqueData,defaultData,name,extendedInterfaces owned by implData
				CleanupStack::PushL(implData);
				interfaceList->AddL(implData);	// Now owned by interfaceList	
				CleanupStack::Pop(implData);
				}
			}
		}
	CleanupStack::PopAndDestroy(&theReader);		
	}

	
CRegistrar::TRegistrarState CRegistrar::State()const
	{
	return iState;
	}

void CRegistrar::ProcessSSAEventL(TStartupStateIdentifier aKnownState)
	{
	iDiscoverer->ProcessSSAEventL(aKnownState); 
	if(aKnownState == EStartupStateNonCritical && iState == EReg_StartupInProgess)
		{
		__ECOM_TRACE("ECOM: CRegistrar::ProcessSSAEventL(): EStartupStateNonCritical is reached.");

		iState = EReg_StartupComplete;
		iBackupNotifier = CBackupNotifier::NewL(*this);
		}
	}
void CRegistrar::InitialiseEvent()
	{
	iState = EReg_StartupInProgess;
	}

void CRegistrar::LanguageChangedL(TBool& aLanguageChanged)
	{
	iRegistry.LanguageChangedL(aLanguageChanged);
	}

void CRegistrar::InstallSwiEventCallBack(const TCallBackWithArg& aCallBack)
	{
	iDiscoverer->SetSwiChangeCallBack(aCallBack);
	}

void CRegistrar::InstallBurEventCallBack(const TCallBackWithArg& aCallBack)
	{
	iDiscoverer->SetBurChangeCallBack(aCallBack);
	}