diff -r 000000000000 -r ba25891c3a9e ncdengine/engine/src/catalogsengineimpl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ncdengine/engine/src/catalogsengineimpl.cpp Thu Dec 17 08:51:10 2009 +0200 @@ -0,0 +1,719 @@ +/* +* Copyright (c) 2006 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: Contains CCatalogsEngineImpl class implementation +* +*/ + + +#include +#include +#include +#include + +#include "catalogspanics.h" +#include "catalogsengineimpl.h" +#include "ncdproviderproxy.h" +#include "catalogsdebug.h" +#include "catalogsengineobserver.h" +#include "catalogsconstants.h" +#include "catalogsuids.h" +#include "catalogsconnectionobserver.h" + + +class CCatalogsProviderCreator : public CActive + { +public: + + static CCatalogsProviderCreator* NewL( + RCatalogsClientServerClientSession& aEngine, + TInt aUid, + MCatalogsBase*& aProvider, + TRequestStatus& aStatus, + TUint32 aOptions ); + + MCatalogsBase* Provider() const; + + ~CCatalogsProviderCreator(); + +protected: + + CCatalogsProviderCreator( + RCatalogsClientServerClientSession& aEngine, + MCatalogsBase*& aProvider, + TRequestStatus& aStatus ); + + void ConstructL( TInt aUid, TUint32 aOptions ); + + void RunL(); + void DoCancel(); + TInt RunError( TInt aError ); + + /** + * Provider handle + */ + TInt iHandle; + + /** + * Proxy provider. + * Own. + */ + CNcdProviderProxy* iProviderProxy; + + /** + * Engine. + */ + RCatalogsClientServerClientSession& iEngine; + + /** + * Proxy provider result. + */ + MCatalogsBase*& iResultProvider; + + /** + * Proxy provider request status. + */ + TRequestStatus* iResultStatus; + + }; + +CCatalogsProviderCreator* CCatalogsProviderCreator::NewL( + RCatalogsClientServerClientSession& aEngine, + TInt aUid, + MCatalogsBase*& aProvider, + TRequestStatus& aStatus, + TUint32 aOptions ) + { + DLTRACEIN(( "aEngine=%08x, aUid=%08x, aProvider=%08x, aStatus=%08x, aOptions=%u", + &aEngine, aUid, &aProvider, &aStatus, aOptions )); + + CCatalogsProviderCreator* self = new (ELeave) CCatalogsProviderCreator( + aEngine, aProvider, aStatus ); + CleanupStack::PushL( self ); + self->ConstructL( aUid, aOptions ); + CleanupStack::Pop( self ); + + DLTRACEOUT(( "%08x", self )); + return self; + } + +void CCatalogsProviderCreator::ConstructL( TInt aUid, TUint32 aOptions ) + { + DLTRACEIN(("aUid=%08x", aUid )); + + switch( aUid ) + { + // Instantiate a provider based on UID information + case 0: + default: + { + iEngine.CreateProvider( aUid, iStatus, iHandle, aOptions ); + SetActive(); + DASSERT( iStatus.Int() == KRequestPending ); + } + break; + } + + DLTRACEOUT(("")); + } + +CCatalogsProviderCreator::~CCatalogsProviderCreator() + { + DLTRACEIN(("")); + + // Never hurts to call this in destructor of active objects + Cancel(); + + if( iProviderProxy ) + { + DLTRACE(("Release providerproxy internally")); + iProviderProxy->InternalRelease(); + } + + DLTRACEOUT(("")); + } + +MCatalogsBase* CCatalogsProviderCreator::Provider() const + { + return iProviderProxy; + } + +CCatalogsProviderCreator::CCatalogsProviderCreator( + RCatalogsClientServerClientSession& aEngine, MCatalogsBase*& aProvider, TRequestStatus& aStatus ) + : CActive( EPriorityNormal ), iEngine( aEngine ), iResultProvider( aProvider ), iResultStatus( &aStatus ) + { + CActiveScheduler::Add( this ); + *iResultStatus = KRequestPending; + } + +void CCatalogsProviderCreator::RunL() + { + DLTRACEIN(( "iStatus=%08x, iHandle=%08x", iStatus.Int(), iHandle )); + // Provider creation can succeed with positive codes + if ( iStatus.Int() >= KErrNone ) + { + DLINFO(( "Creating provider proxy" )); + // If the provider was successfully created, instantiate a + // client-side provider object + iProviderProxy = CNcdProviderProxy::NewL( iEngine, iHandle ); + DLTRACE(("Provider proxy inc ref count")); + // Increase both reference counters + iProviderProxy->InternalAddRef(); + iProviderProxy->AddRef(); + DLINFO(( "Provider proxy %08x created", iProviderProxy )); + + // We will probably never end up here if the request has been + // completed already, but checking just to be sure. + if ( iResultStatus ) + { + DLINFO(( "Completing CreateProvider request" )); + iResultProvider = iProviderProxy; + + // iResultStatus is nullified by the RequestComplete + User::RequestComplete( iResultStatus, iStatus.Int() ); + } + } + else + { + // We will probably never end up here if the request has been + // completed already, but checking just to be sure. + if ( iResultStatus ) + { + User::RequestComplete( iResultStatus, iStatus.Int() ); + } + } + DLTRACEOUT(("")); + } + +void CCatalogsProviderCreator::DoCancel() + { + DLTRACEIN(("")); + // Going down now, so pending message sent by provider creator + // should be completed immediately by client server + //(or it is completed by the framework if the message is already + // completed but creator is not yet notified of it) + iEngine.AsyncMessageSenderDown( iStatus ); + + // Pending request is completed. + // We should never end up here if the request is already + // completed, but just checking to be sure. + if ( iResultStatus ) + { + // iResultStatus is nullified by the RequestComplete + User::RequestComplete( iResultStatus, KErrCancel ); + } + + DLTRACEOUT(("")); + } + +TInt CCatalogsProviderCreator::RunError( TInt aError ) + { + DLTRACEIN(("")); + + User::RequestComplete( iResultStatus, aError ); + + DLTRACEOUT(("")); + return KErrNone; + } + + +/** Catalogs shutdown observer, subscribes to maintenance lock P&S */ + +class CCatalogsShutdownObserver : public CActive + { +public: + + static CCatalogsShutdownObserver* NewL( MCatalogsEngineObserver& aObserver ); + virtual ~CCatalogsShutdownObserver(); + +protected: + + CCatalogsShutdownObserver( MCatalogsEngineObserver& aObserver ); + void ConstructL(); + +protected: // from CActive + + void RunL(); + void DoCancel(); + +private: + + RProperty iMaintenanceLockProperty; + MCatalogsEngineObserver& iObserver; + }; + + +CCatalogsShutdownObserver* CCatalogsShutdownObserver::NewL( MCatalogsEngineObserver& aObserver ) + { + DLTRACEIN(( "aObserver=%08x", &aObserver )); + CCatalogsShutdownObserver* self = new (ELeave) CCatalogsShutdownObserver( aObserver ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + +CCatalogsShutdownObserver::~CCatalogsShutdownObserver() + { + DLTRACEIN(("this=%08x", this)); + Cancel(); + iMaintenanceLockProperty.Close(); + + DLTRACEOUT(("")); + } + +CCatalogsShutdownObserver::CCatalogsShutdownObserver( MCatalogsEngineObserver& aObserver ) + : CActive( EPriorityNormal ), iObserver( aObserver ) + { + CActiveScheduler::Add( this ); + } + +void CCatalogsShutdownObserver::ConstructL() + { + DLTRACEIN(("")); + + // Subscribe to maintenance notify property. + User::LeaveIfError( iMaintenanceLockProperty.Attach( + KCatalogsEnginePropertyCategory, + KCatalogsEnginePropertyKeyMaintenanceLock ) ); + + iMaintenanceLockProperty.Subscribe( iStatus ); + SetActive(); + + DLTRACEOUT(("")); + } + +void CCatalogsShutdownObserver::RunL() + { + DLTRACEIN(( "iStatus=%d", iStatus.Int() )); + + if( iStatus.Int() == KErrNone ) + { + // Read the property value. + TInt value; + TInt err = iMaintenanceLockProperty.Get( value ); + if( err == KErrNone && value != 0 ) + { + DLINFO(( "Calling shutdown observer %08x", &iObserver )); + iObserver.CatalogsEngineShutdown(); + } + + if( err != KErrNone ) + { + DLERROR(( "Failed to read maintenance lock property value, error %d", err )); + } + else + { + DLINFO(( "Maintenance lock value was %d", value )); + } + } + + DLTRACEOUT(("")); + } + +void CCatalogsShutdownObserver::DoCancel() + { + DLTRACEIN(("")); + iMaintenanceLockProperty.Cancel(); + DLTRACEOUT(("")); + } + + +/** Catalogs OTA update observer, subscribes to update information P&S */ + +class CCatalogsUpdateObserver : public CActive + { +public: + + static CCatalogsUpdateObserver* NewL( MCatalogsEngineObserver& aObserver ); + virtual ~CCatalogsUpdateObserver(); + +protected: + + CCatalogsUpdateObserver( MCatalogsEngineObserver& aObserver ); + void ConstructL(); + +protected: // from CActive + + void RunL(); + void DoCancel(); + +private: + + RMsgQueueBase iUpdateMessageQueue; + MCatalogsEngineObserver& iObserver; + }; + + +CCatalogsUpdateObserver* CCatalogsUpdateObserver::NewL( MCatalogsEngineObserver& aObserver ) + { + DLTRACEIN(( "aObserver=%08x", &aObserver )); + CCatalogsUpdateObserver* self = new (ELeave) CCatalogsUpdateObserver( aObserver ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + +CCatalogsUpdateObserver::~CCatalogsUpdateObserver() + { + DLTRACEIN(("this=%08x", this)); + Cancel(); + iUpdateMessageQueue.Close(); + DLTRACEOUT(("")); + } + +CCatalogsUpdateObserver::CCatalogsUpdateObserver( MCatalogsEngineObserver& aObserver ) + : CActive( EPriorityNormal ), iObserver( aObserver ) + { + CActiveScheduler::Add( this ); + } + +void CCatalogsUpdateObserver::ConstructL() + { + DLTRACEIN(("")); + + // Create the update information message queue for receiving update messages. + RProcess process; + DLINFO(( "Client SSID %08x", process.SecureId().iId )); + + HBufC* msgQueueName = HBufC::NewLC( KCatalogsUpdateQueueNameFormat().Length() + 8 ); + msgQueueName->Des().Format( KCatalogsUpdateQueueNameFormat, process.SecureId().iId ); + + DLINFO(( _L("Creating client's update message queue: %S"), msgQueueName )); + TInt err = iUpdateMessageQueue.CreateGlobal( + *msgQueueName, + KCatalogsUpdateQueueSlotCount, + KCatalogsUpdateQueueMessageSize, + EOwnerProcess ); + + if( err == KErrAlreadyExists ) + { + err = iUpdateMessageQueue.OpenGlobal( *msgQueueName ); + } + + if( err != KErrNone ) + { + DLERROR(( "Failed to create update message queue, error %d", err )); + } + else + { + THandleInfo info; + iUpdateMessageQueue.HandleInfo( &info ); + + DLINFO(( "Processes for notify data available: %d", info.iNumProcesses )); + DLINFO(( "Threads for notify data available: %d", info.iNumThreads )); + DLINFO(( "Open in process for notify data available: %d", info.iNumOpenInProcess )); + DLINFO(( "Open in thread for notify data available: %d", info.iNumOpenInThread )); + + // Only one request allowed per messagequeue + // This causes problem in STIF tests at least when they are executed + // in the emulator because the handles of crashed processes are not + // always freed so testers won't get notifications about the data + // and engine will eventually freeze because the queue gets full + if ( info.iNumProcesses == 1 ) + { + DLINFO(( "Requesting notification of update messages" )); + // A thread can have only one data available notification request outstanding + // on the message queue. If a second request is made before the first request + // completes, then the calling thread is panicked (KERN-EXEC 47). + iUpdateMessageQueue.NotifyDataAvailable( iStatus ); + SetActive(); + } + } + + CleanupStack::PopAndDestroy( msgQueueName ); + + DLTRACEOUT(("")); + } + +void CCatalogsUpdateObserver::RunL() + { + DLTRACEIN(( "iStatus=%d", iStatus.Int() )); + + if( iStatus.Int() == KErrNone ) + { + // Renew notification request. + iUpdateMessageQueue.NotifyDataAvailable( iStatus ); + SetActive(); + + CBufFlat* buffer = CBufFlat::NewL( KCatalogsUpdateInformationMaxSize + KCatalogsUpdateQueueMessageSize ); + CleanupStack::PushL( buffer ); + + buffer->ResizeL( KCatalogsUpdateInformationMaxSize + KCatalogsUpdateQueueMessageSize ); + TUint8* msgPtr = const_cast< TUint8* >( buffer->Ptr( 0 ).Ptr() ); + + while( iUpdateMessageQueue.Receive( msgPtr, KCatalogsUpdateQueueMessageSize ) == KErrNone ) + { + msgPtr += KCatalogsUpdateQueueMessageSize; + + // Make a stream for reading the buffer. + RBufReadStream stream( *buffer ); + CleanupClosePushL( stream ); + + // Read total data size. + TInt32 total; + stream >> total; + DLINFO(( "%d bytes of data incoming", total )); + + for( TInt bytesLeft = total + sizeof( TInt32 ) - KCatalogsUpdateQueueMessageSize; + bytesLeft > 0; + bytesLeft -= KCatalogsUpdateQueueMessageSize ) + { + DLINFO(( "Reading more data, %d bytes to go", bytesLeft )); + iUpdateMessageQueue.ReceiveBlocking( msgPtr, KCatalogsUpdateQueueMessageSize ); + msgPtr += KCatalogsUpdateQueueMessageSize; + } + + // Read target string. + HBufC* target = HBufC::NewLC( stream, KCatalogsUpdateTargetMaxSize ); + DLINFO(( _L("Update target: %S"), target )); + + // Read ID string. + HBufC* id = HBufC::NewLC( stream, KCatalogsUpdateIdMaxSize ); + DLINFO(( _L("Update target ID: %S"), id )); + + // Read version string. + HBufC* version = HBufC::NewLC( stream, KCatalogsUpdateVersionMaxSize ); + DLINFO(( _L("Update version: %S"), version )); + + // Read URI string. + HBufC* uri = HBufC::NewLC( stream, KCatalogsUpdateUriMaxSize ); + DLINFO(( _L("Update URI: %S"), uri )); + + // Read force boolean + TInt32 force; + stream >> force; + DLINFO(( "Update forced: %d", force )); + + DLINFO(( "Calling update observer %08x", &iObserver )); + iObserver.CatalogsUpdateNotification( *target, *id, *version, *uri, force ); + + CleanupStack::PopAndDestroy( 5 ); // uri, version, id, target, stream-close + + // Reset to start position for next round (if any). + msgPtr = const_cast< TUint8* >( buffer->Ptr( 0 ).Ptr() ); + } + + CleanupStack::PopAndDestroy( buffer ); + } + + DLTRACEOUT(("")); + } + +void CCatalogsUpdateObserver::DoCancel() + { + DLTRACEIN(("")); + iUpdateMessageQueue.CancelDataAvailable(); + DLTRACEOUT(("")); + } + + +// ======== MEMBER FUNCTIONS ======== + +TInt CCatalogsEngineImpl::AddRef() const + { + DLTRACEIN(( "" )); + return ++iRefCount; + } + +TInt CCatalogsEngineImpl::Release() const + { + DLTRACEIN(( "" )); + // NOTE: engine object is deleted by client separately, do not self-destruct here. + return --iRefCount; + } + +const TAny* CCatalogsEngineImpl::QueryInterfaceL( TInt aInterfaceType ) const + { + DLTRACEIN(( "" )); + const MCatalogsBase* result = NULL; + + switch( aInterfaceType ) + { + case MCatalogsBase::KInterfaceUid: + result = static_cast< const MCatalogsBase* >( this ); + result->AddRef(); + break; + + case MCatalogsEngine::KInterfaceUid: + result = static_cast< const MCatalogsEngine* >( this ); + result->AddRef(); + break; + } + + if( result ) + { + iRefCount++; + } + + return result; + } + +CCatalogsEngineImpl::CCatalogsEngineImpl( MCatalogsEngineObserver& aObserver ) + : iObserver( &aObserver ) + { + AddRef(); // Reference count is set to one + } + +CCatalogsEngineImpl::~CCatalogsEngineImpl() + { + DLTRACEIN(("")); + + DLTRACE(( "Deleting shutdown observer" )); + delete iShutdownObserver; + + DLTRACE(( "Deleting update observer %08x", iUpdateObserver )); + delete iUpdateObserver; + + delete iConnectionObserver; + + DLTRACE(( "Closing catalogs engine mutex" )); + iCatalogsMutex.Close(); + + DLTRACEOUT(("")); + } + +void CCatalogsEngineImpl::ConstructL() + { + DLTRACEIN(( "" )); + + // Mutex open should succeed, it is already open in CCatalogsEngine::NewLC(). + User::LeaveIfError( iCatalogsMutex.OpenGlobal( KCatalogsEngineMutex ) ); + + // Create observer for maintenance lock mutex changes -> engine shutdown callback + DLINFO(( "Creating shutdown observer" )); + iShutdownObserver = CCatalogsShutdownObserver::NewL( *iObserver ); + + // For the Catalogs UI client, create update observer for receiving OTA update + // notifications. + DLINFO(( "Checking for Catalogs UI client SID" )); + RProcess process; + static _LIT_SECURITY_POLICY_PASS( catalogsUiSecurityPolicy ); + if( catalogsUiSecurityPolicy().CheckPolicy( process ) ) + { + DLINFO(( "Passed Catalogs UI security check, SID %08x", process.SecureId().iId )); + DLINFO(( "Creating update observer" )); + iUpdateObserver = CCatalogsUpdateObserver::NewL( *iObserver ); + } + process.Close(); + + iConnectionObserver = CCatalogsConnectionObserver::NewL( *iObserver ); + DLTRACEOUT(("")); + } + +CCatalogsEngineImpl* CCatalogsEngineImpl::NewL( TAny* aInitParams ) + { + DLTRACEIN(( "aInitParams=%08x" )); + + // Engine observer was passed as init param pointer. + MCatalogsEngineObserver* observer = static_cast< MCatalogsEngineObserver* >( aInitParams ); + + CCatalogsEngineImpl* self = new( ELeave ) CCatalogsEngineImpl( *observer ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + DLTRACEOUT(( "%08x", self )); + return self; + } + +TInt CCatalogsEngineImpl::Connect( TUid aClientUid ) + { + DLTRACEIN(("%d",aClientUid.iUid)); + iClientUid = aClientUid; + return iCatalogsEngine.Connect( aClientUid ); + } + +void CCatalogsEngineImpl::Close() + { + DLTRACEIN(("")); + + // Provider creator has to be deleted before disconnect is said because + // the provider creator owns the provider (internal addref called) + // and when the provider is deleted it connects to server. + DLTRACE(( "Deleting provider creator %08x", iProviderCreator )); + delete iProviderCreator; + iProviderCreator = NULL; + + // Disconnect is enough for the iCatalogsEngine. Don't call Close for + // the iCatalogsEngine as it does it in the Disconnect. + DLTRACE(( "Disconnect" )); + iCatalogsEngine.Disconnect(); + + DLTRACEOUT(("")); + } + + +void CCatalogsEngineImpl::CreateProviderL( + TInt aUid, + MCatalogsBase*& aProvider, + TRequestStatus& aStatus, + TUint32 aProviderOptions ) + { + DLTRACEIN(("%X, %u", aUid, aProviderOptions )); + // add UID mapping + + // If a provider has already been created, return that one + if ( iProviderCreator != NULL ) + { + MCatalogsBase* provider = iProviderCreator->Provider(); + if( provider != NULL ) + { + DLINFO(("Provider already created")); + + // Increase reference count and pass to provider + provider->AddRef(); + DLINFO(( "Writing CreateProvider result" )); + aProvider = provider; + + aStatus = KRequestPending; + TRequestStatus* statusPtr = &aStatus; + User::RequestComplete( statusPtr, KErrNone ); + return; + } + else + { + DLINFO(("Provider is not created")); + delete iProviderCreator; + iProviderCreator = NULL; + } + } + + DLINFO(( "Starting provider creation" )); + iProviderCreator = CCatalogsProviderCreator::NewL( + iCatalogsEngine, aUid, aProvider, aStatus, aProviderOptions ); + + DLTRACEOUT(("")); + } + +void CCatalogsEngineImpl::CancelProviderCreation() + { + DLTRACEIN(("")); + + // If iProviderCreator is active then the provider has not been properly + // constructed. + if ( iProviderCreator->IsActive() ) + { + // iProviderCreator is deleted. This enables calling of + // CreateProviderL again after this function call. In + // that case the outcome of CreateProviderL would be as + // if the function had been called normally before any + // CancelProviderCreation. + // Deletion is also a proper solution here as the creation of + // iProviderCreator is mainly about creating the provider. + // Construction of the iProviderCreator is simple and can be + // done again with quite a little effort. + delete iProviderCreator; + iProviderCreator = NULL; + } + }