--- /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 <e32base.h>
+#include <e32property.h>
+#include <e32msgqueue.h>
+#include <s32mem.h>
+
+#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;
+ }
+ }