diff -r 000000000000 -r 4e1aa6a622a0 sensorservices/sensorserver/src/server/sensrvpluginproxy.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sensorservices/sensorserver/src/server/sensrvpluginproxy.cpp Tue Feb 02 00:53:00 2010 +0200 @@ -0,0 +1,1567 @@ +/* +* Copyright (c) 2006-2008 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: Sensor server plugin proxy implementation +* +*/ + + +#include +#include "sensrvdefines.h" +#include "sensrvpluginproxy.h" +#include "sensrvproxymanager.h" +#include "sensrvtransaction.h" +#include "sensrvtransactionqueue.h" +#include "sensrvtransactionmonitor.h" +#include "senserverchannel.h" +#include "sensrvssymediator.h" +#include "sensrvservermediator.h" +#include "sensrvssyactivescheduler.h" +#include "sensrvclientserver.h" +#include "sensrvthreadmonitor.h" +#include "sensrvchanneldatareader.h" + +// --------------------------------------------------------------------------- +// 2-phase constructor +// --------------------------------------------------------------------------- +// +CSensrvPluginProxy* CSensrvPluginProxy::NewL(CSensrvProxyManager& aParent, + TUid aImplementationUid) + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::NewL(, aImplementationUid: 0x%x)" ), aImplementationUid.iUid ) ); + + CSensrvPluginProxy* self = new( ELeave ) CSensrvPluginProxy(aParent, aImplementationUid); + + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::NewL - return 0x%x" ), self ) ); + + return self; + } + +// --------------------------------------------------------------------------- +// C++ constructor +// --------------------------------------------------------------------------- +// +CSensrvPluginProxy::CSensrvPluginProxy(CSensrvProxyManager& aParent, + TUid aImplementationUid) + : iPluginState( EPluginStateUninitialized ), + iProxyManager(aParent), + iImplementationUid(aImplementationUid) + { + // Nothing to do + } + +// --------------------------------------------------------------------------- +// 2nd phase of construction +// --------------------------------------------------------------------------- +// +void CSensrvPluginProxy::ConstructL() + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::ConstructL()" ) ) ); + + // Init mutex + User::LeaveIfError(iMutex.CreateLocal()); + + iMutex.Wait(); + + iLoadWaitQueue = CSensrvTransactionQueue::NewL(ETrue); + + iTransactionMonitor = CSensrvTransactionMonitor::NewL(*this); + + // Note: Slight memory savings are possible if iThreadMonitor and iUnloadTimer + // are created and deleted alongside SSY thread. However, since the timer events + // in these classes initiate cleanup, it is not trivial. Maybe server mediator + // could be utilized for delayed cleanup of these classes? + + iThreadMonitor = CSensrvThreadMonitor::NewL(*this); + + iUnloadTimer = CSensrvTimer::NewL(*this, + iProxyManager.SsyInactivityPeriod(), + CSensrvTimer::ETimerIdSsyInactivityTimer); + + iMutex.Signal(); + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::ConstructL - return" ) ) ); + } + +// --------------------------------------------------------------------------- +// Destructor +// --------------------------------------------------------------------------- +// +CSensrvPluginProxy::~CSensrvPluginProxy() + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::~CSensrvPluginProxy()" ) ) ); + + iMutex.Wait(); + + delete iThreadMonitor; + delete iTransactionMonitor; + + delete iServerMediator; + delete iSsyMediator; + + // Cleanup channels + TInt count = iChannelList.Count(); + for(TInt i = 0; i < count; i ++) + { + delete iChannelList[i]; + } + + iChannelList.Reset(); + iChannelInfoList.Reset(); + iRemovedChannelsInfoList.Reset(); + iDynamicChannelInfoList.Reset(); + + delete iLoadWaitQueue; + delete iUnloadTimer; + + iMutex.Signal(); + + iMutex.Close(); + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::~CSensrvPluginProxy - return" ) ) ); + } + + + +// --------------------------------------------------------------------------- +// Completes the transaction and calls handling for next one in queue. +// --------------------------------------------------------------------------- +// +void CSensrvPluginProxy::TransactionHandledAtSsy(CSensrvTransaction* aTransaction) + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::TransactionHandledAtSsy(aTransaction: 0x%x)" ), aTransaction ) ); + + // Handle transaction according to transaction type + if (aTransaction) + { + // Route transaction finalization according to transaction type + switch(aTransaction->Type()) + { + // Proxy level transactions handled here + case CSensrvTransaction::ETransTypeLoadSsy: + case CSensrvTransaction::ETransTypeMediatorChannelsChanged: + { + CompleteTransaction(aTransaction); + } + break; + + // Channel level transactions handled in corresponding channel object. + case CSensrvTransaction::ETransTypeOpenChannel: + case CSensrvTransaction::ETransTypeCloseChannel: + case CSensrvTransaction::ETransTypeStartListening: + case CSensrvTransaction::ETransTypeStopListening: + case CSensrvTransaction::ETransTypeMediatorNewDataAvailable: + case CSensrvTransaction::ETransTypeGetProperty: + case CSensrvTransaction::ETransTypeGetAllProperties: + case CSensrvTransaction::ETransTypeSetProperty: + case CSensrvTransaction::ETransTypeStartConditionListening: + case CSensrvTransaction::ETransTypeStopConditionListening: + case CSensrvTransaction::ETransTypeMediatorPropertyChanged: + case CSensrvTransaction::ETransTypeMediatorForceChannelClose: + { + // These transactions must always have valid channel object. + __ASSERT_ALWAYS(aTransaction->Channel(), User::Panic(KSensrvPanicCategory, ESensrvPanicNullChannel)); + + aTransaction->Channel()->CompleteTransaction(aTransaction); + } + break; + + default: + // Unexpected transaction type, so we do not know what to do with it + ERROR_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::TransactionHandledAtSsy - ERROR: Invalid transaction type" ) ) ); + User::Panic(KSensrvPanicCategory, ESensrvPanicUnknownTransactionType); + break; + } + } + else + { + // NULL transaction used to trigger transaction handling. + if ( iPluginState == EPluginStateThreadInitializing ) + { + // Initial notify from SSY thread. + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::TransactionHandledAtSsy - SSY thread initialization completion detected." ) ) ); + + SetPluginState(EPluginStateThreadInitialized); + + // Start handling queued transactions + HandleNextTransaction(); + } + else if (iPluginState == EPluginStateUnloaded) + { + // SSY unloading has finished, handle next transaction if any + HandleNextTransaction(); + } + else + { + // Can get here if server mediator has been notified, + // but before its RunL is executed, the only transaction in server mediator's queue + // is deleted (because of client panic caused session termination, for example). + // Highly unlikely case, but theoretically possible. + // In that case we can just ignore the notification. + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::TransactionHandledAtSsy - NULL transaction in an unexpected plugin state: %d" ), iPluginState ) ); + } + } + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::TransactionHandledAtSsy - return" ) ) ); + } + + +// --------------------------------------------------------------------------- +// Initializes plugin mediators and thread, +// loads the plugin and queries for supported channels. +// --------------------------------------------------------------------------- +// +void CSensrvPluginProxy::InitializePluginL() + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::InitializePluginL()" ) ) ); + + iMutex.Wait(); + + iPreviousSsyLoadFailed = EFalse; // Reset SSY load fail indicator + + if (iPluginState != EPluginStateUnloading) + { + // Create mutex signaling cleanup item. + CleanupStack::PushL( + TCleanupItem( CleanupInitializePlugin, this ) ); + + // Create Ssy thread + // Use unique identifier generated by proxy manager to name thread + // so that name is guaranteed unique, yet recognizable. + HBufC* buf = HBufC::NewLC(KSensrvSsyThreadNameMaxLen); + buf->Des().Append(KSensrvSsyThreadNameBase); + + TInt err(KErrAlreadyExists); + + while (err == KErrAlreadyExists) + { + + buf->Des().AppendNum(iProxyManager.GenerateUniqueId()); + + err = iSsyThread.Create(*buf, + SsyThreadFunction, + ProxyManager().SsyStackSize(), + KSensrvSsyHeapInitialSize, + ProxyManager().SsyHeapMaxSize(), + (TAny*)this); + + if (err == KErrAlreadyExists) + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::InitializePluginL - Thread name is already in use, recreating..." ) ) ); + } + + buf->Des().Delete(KSensrvSsyThreadNameBaseLen, KSensrvSsyThreadNameMaxLen); + } + + if (err != KErrNone) + { + ERROR_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::InitializePluginL - Error creating thread." ) ) ); + User::Leave(err); + } + + CleanupStack::PopAndDestroy(buf); + + // start monitoring the thread + User::LeaveIfError(iThreadMonitor->StartMonitoring(iSsyThread)); + + // If InitializePluginL leaves, thread monitor triggered cleanup will set state again + SetPluginState(EPluginStateThreadInitializing); + + // SSY mediator is created here but initialized by SSY thread as it needs current thread handle. + iSsyMediator = CSensrvSsyMediator::NewL(this); + + // Create and initialize server mediator if not yet created + if (!iServerMediator) + { + iServerMediator = CSensrvServerMediator::NewL(this); + User::LeaveIfError(iServerMediator->Initialize()); + // Note: SSY mediator is initialized by SSY thread + } + + // Initially there are no channel change listeners concerning this proxy + iChannelChangeListenerCount = 0; + + // Create transaction for loading plugin. + CSensrvTransaction* loadTransaction = NULL; + loadTransaction = CSensrvTransaction::NewL( + NULL, + this, + NULL, + CSensrvTransaction::ETransTypeLoadSsy); + + // Add transaction to the beginning of the queue + err = QueueTransaction(loadTransaction, EFalse); + + if (err == KErrNone) + { + // Resume Ssy thread. Must be last thing to do in this method + // so that nothing else can leave after this. + iSsyThread.Resume(); + } + else + { + ERROR_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::InitializePluginL - ERROR: Failed to queue load transaction %d" ), err ) ); + // Cleanup transaction + loadTransaction->SetErrorCode(err); + loadTransaction->Complete(); + delete loadTransaction; + User::Leave(err); + } + + CleanupStack::Pop(); // CleanupInitializePlugin + } + else + { + TInt err = EnqueueDelayedInitializeTransaction(); + if (err == KErrNone) + { + // Handle delayed initialize immediately, if already fully unloaded + if (iPluginState == EPluginStateUnloaded) + { + HandleNextTransaction(); + } + } + else + { + ERROR_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::InitializePluginL - ERROR: Failed to queue delayed initialize %d" ), err ) ); + iPreviousSsyLoadFailed = ETrue; + User::Leave(err); + } + } + + iMutex.Signal(); + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::InitializePluginL - return" ) ) ); + } + +// --------------------------------------------------------------------------- +// Initializes plugin channel data. +// --------------------------------------------------------------------------- +// +TInt CSensrvPluginProxy::InitializeChannelData( const CImplementationInformation& aImplInfo ) + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::InitializeChannelDataL" ) ) ); + + TSensrvChannelDataReader reader; + TInt err = reader.ReadChannels( aImplInfo, iChannelInfoList, iDynamicChannelInfoList ); + if ( err == KErrNone ) + { + // Generate unique IDs for static channels now. IDs for dynamic channels are handled by SSY channel registration. + TInt count( iChannelInfoList.Count() ); + for( TInt i = 0; i < count; i++) + { + TSensrvChannelId newId = static_cast(ProxyManager().GenerateUniqueId()); + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::InitializeChannelDataL - plugin UID: 0x%x channel: %d" ), + aImplInfo.ImplementationUid().iUid, newId ) ); + + iChannelInfoList[i].iChannelId = newId; + } + } + iIsInitialized = ETrue; // even though thread not setup and plugin not laoded yet. + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::InitializeChannelDataL - err %d, return" ), err ) ); + + return err; + } + +// --------------------------------------------------------------------------- +// Handles client message. +// All messages coming from client to proxy target specific channel, +// so pass the message to correct channel object. +// Proxy manager makes sure that messages dispatched to each proxy +// actually target a channel provided by that proxy, so no rechecking is done. +// --------------------------------------------------------------------------- +// +void CSensrvPluginProxy::DispatchMessage(CSensrvMessage& aMessage, + TSensrvChannelId aChannelId) + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::DispatchMessage(aMessage.Function(): %d, aChannelId: %d)" ), aMessage.Function(), aChannelId ) ); + + iMutex.Wait(); + + TInt err(KErrNone); + TBool completeMessageOnError(ETrue); + + // Check state + if (iDeletionFlag) + { + // If proxy is marked for deletion, do not allow further messages + err = KErrNotFound; + } + else + { + if (iPluginState == EPluginStateLoaded) + { + // Get channel and pass message there + CSensrvChannel* channel = GetChannelForId(aChannelId); + + // Special case: When opening channel, create channel if it is not found + if (aMessage.Function() == ESensrvSrvReqOpenChannel && !channel) + { + // Get channel info + TSensrvChannelInfo* info = GetChannelInfoForId(aChannelId); + + if (info) + { + TRAPD(err, channel = CSensrvChannel::NewL(*info, *this)); + if (err == KErrNone) + { + // Add channel to channel list + err = iChannelList.Append(channel); + + if (err != KErrNone) + { + delete channel; // Deleting the channel that is allocated on the heap in case Append Failure. + channel = NULL; + ERROR_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::DispatchMessage - ERROR: Failed to append channel to array: %d" ), err ) ); + } + } + else + { + ERROR_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::DispatchMessage - ERROR: Failed to create channel: %d" ), err ) ); + } + } + else + { + ERROR_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::DispatchMessage - ERROR: No channel info found" ) ) ); + err = KErrNotFound; + } + } + + if (err == KErrNone) + { + if (channel) + { + channel->DispatchMessage(aMessage); + } + else + { + // If channel object doesn't exist, something is wrong. + ERROR_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::DispatchMessage - ERROR: No channel object" ) ) ); + err = KErrNotFound; + } + } + } + else if ( aMessage.Function() == ESensrvSrvReqOpenChannel + && iPluginState != EPluginStateUninitialized ) + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::DispatchMessage - Queuing open channel message" ) ) ); + + // If unloading/unloaded, queue initialization transaction. + if (iPluginState == EPluginStateUnloading || iPluginState == EPluginStateUnloaded) + { + err = EnqueueDelayedInitializeTransaction(); + } + + // Queue open transaction into wait queue until plugin can load itself. + if (err == KErrNone) + { + completeMessageOnError = EFalse; + + CSensrvTransaction* transaction = NULL; + + TRAP(err, transaction = CSensrvTransaction::NewL( + &aMessage, + this, + NULL, + CSensrvTransaction::ETransTypeDelayedOpenChannel)); + + if (err == KErrNone) + { + err = QueueTransaction(transaction, ETrue); + + if(err == KErrNone) + { + // Add transaction to monitor for the duration of the wait. + iTransactionMonitor->AddTransaction(transaction); + } + else + { + transaction->SetErrorCode(err); + transaction->Complete(); + delete transaction; + transaction = NULL; + } + } + } + + // Handle delayed initialize immediately, if already fully unloaded + if (err == KErrNone && iPluginState == EPluginStateUnloaded) + { + HandleNextTransaction(); + } + } + else + { + ERROR_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::DispatchMessage - ERROR: Plugin in invalid state: %d" ), iPluginState ) ); + err = KErrNotReady; + } + } + + if (err != KErrNone && completeMessageOnError) + { + aMessage.Complete(err); + } + + iMutex.Signal(); + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::DispatchMessage - return" ) ) ); + } + +// --------------------------------------------------------------------------- +// Checks if this proxy supports specified channel +// --------------------------------------------------------------------------- +// +TBool CSensrvPluginProxy::IsChannelSupported(TSensrvChannelId aChannelId) + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::IsChannelSupported(aChannelId: %d)" ), aChannelId ) ); + + TBool isSupported(EFalse); + + iMutex.Wait(); + + if (iIsInitialized) + { + TInt channelCount = iChannelInfoList.Count(); + if (channelCount > 0) + { + for(TInt j = 0; !isSupported && j < channelCount; j++) + { + if (iChannelInfoList[j].iChannelId == aChannelId) + { + isSupported = ETrue; + } + } + } + } + else + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::IsChannelSupported - Proxy not yet initialized" ) ) ); + } + + iMutex.Signal(); + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::IsChannelSupported - return %d" ), isSupported) ); + + return isSupported; + } + +// --------------------------------------------------------------------------- +// Gets channel object handling specified channel. +// --------------------------------------------------------------------------- +// +CSensrvChannel* CSensrvPluginProxy::GetChannelForId(TSensrvChannelId aChannelId) const + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::GetChannelForId(aChannelId: %d)" ), aChannelId ) ); + + CSensrvChannel* returnChannel = NULL; + + TInt channelCount = iChannelList.Count(); + for(TInt i = 0; !returnChannel && i < channelCount; i++) + { + if (iChannelList[i]->Id() == aChannelId) + { + returnChannel = iChannelList[i]; + } + } + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::GetChannelForId - return 0x%x" ), returnChannel ) ); + + return returnChannel; + } + + +// --------------------------------------------------------------------------- +// Cleans up everything related to terminated session. +// --------------------------------------------------------------------------- +// +void CSensrvPluginProxy::SessionTerminated( CSensrvSession* aSession ) + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::SessionTerminated(aSession: 0x%x)"),aSession ) ); + + iMutex.Wait(); + + // Cleanup any waiting transactions for this session + iLoadWaitQueue->Remove(aSession); + iTransactionMonitor->RemoveSessionTransactions(aSession); + + // Clean up mediators + if (iSsyMediator) + { + iSsyMediator->SessionTerminated(aSession); + } + + if (iServerMediator) + { + iServerMediator->SessionTerminated(aSession); + } + + + // Call session cleanup on each channel + TInt channelCount = iChannelList.Count(); + for(TInt i = 0; i < channelCount; i++) + { + iChannelList[i]->SessionTerminated(aSession); + } + + iMutex.Signal(); + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::SessionTerminated - return" )) ); + } + +// --------------------------------------------------------------------------- +// Handles SSY notification failure. +// This means going through all channels checking where failure possibly +// occurred, and of course any proxy level transactions. +// Note that this can execute transactions out of original sequence they +// have been notified to server mediator, but this should be no problem, +// each single channel can only have single ongoing transaction at SSY. +// Transactions of different channels do not interfere with each other. +// --------------------------------------------------------------------------- +// +void CSensrvPluginProxy::HandleSsyNotifyFailure() + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::HandleSsyNotifyFailure()" ) ) ); + + // Check queued transactions to determine if they are handled at SSY + CSensrvTransaction* transaction = iLoadWaitQueue->First(); + + if (transaction && transaction->State() == CSensrvTransaction::ETransStateNotifyFailed) + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::HandleSsyNotifyFailure - Notify failed transaction found" ) ) ); + transaction->SetState(CSensrvTransaction::ETransStateHandledAtSsy); + TransactionHandledAtSsy(transaction); + } + + if ( iSsyMediator + && iSsyMediator->ChannelChangeTransaction() + && iSsyMediator->ChannelChangeTransaction()->State() == CSensrvTransaction::ETransStateNotifyFailed) + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::HandleSsyNotifyFailure - Notify failed transaction found (ETransTypeMediatorChannelsChanged)" ) ) ); + iSsyMediator->ChannelChangeTransaction()->SetState(CSensrvTransaction::ETransStateHandledAtSsy); + TransactionHandledAtSsy(iSsyMediator->ChannelChangeTransaction()); + } + + // Pass notification to each channel + TInt channelCount = iChannelList.Count(); + for(TInt i = 0; i < channelCount; i++) + { + iChannelList[i]->HandleSsyNotifyFailure(); + } + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::HandleSsyNotifyFailure - return" ) ) ); + } + +// --------------------------------------------------------------------------- +// Unloads SSY as any timed out transactions probably mean that +// SSY has either crashed or is deadlocked. +// --------------------------------------------------------------------------- +// +void CSensrvPluginProxy::HandleTransactionTimeout() + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::HandleTransactionTimeout()" ) ) ); + + // Any transaction timeout results in unloading of the SSY + CleanupPlugin(); + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::HandleTransactionTimeout - return" ) ) ); + } + +// --------------------------------------------------------------------------- +// Deletes SSY mediator and closes thread. +// --------------------------------------------------------------------------- +// +void CSensrvPluginProxy::SsyThreadTerminated() + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::SsyThreadTerminated()" ) ) ); + + // Instead of delete, Free is used. + // It means that destructor of the iSsyMediator is not called. + // Calling the destructor causes KERN-EXEC 3 in servers main thread + // if SSY thread is not anymore alive. + // iSsyMediator inherit from CActive and calling ~CActive() while its + // scheduler is dead causes KERN-EXEC 3 panic. + iSsyMediator->Destruct(); + iSsyMediator->BaseDestruct(); + iProxyManager.ServerHeap()->Free( iSsyMediator ); + iSsyMediator = NULL; + + // Note: Server mediator is not deleted until proxy is deleted, + // as in some cases resulting in cleanup, its RunL-method is what initiated the sequence. + + iSsyThread.Close(); + + TPluginState previousState = iPluginState; + SetPluginState(EPluginStateUnloaded); + + // Cleanup needed in case SSY thread termination was uncontrolled. + if (previousState != EPluginStateUnloading) + { + CleanupPlugin(); + } + + // Notify server mediator with null transaction to handle next transaction + if (iLoadWaitQueue && iServerMediator && !iLoadWaitQueue->IsEmpty()) + { + iServerMediator->Notify(NULL); + } + + // Notify proxy manager that thread has terminated + iProxyManager.SsyThreadTerminated(); + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::SsyThreadTerminated - return" ) ) ); + } + +// --------------------------------------------------------------------------- +// Starts SSY unload timer if no clients +// --------------------------------------------------------------------------- +// +void CSensrvPluginProxy::StartUnloadTimerIfNeeded() + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::StartUnloadTimerIfNeeded()" ) ) ); + + if (!iUnloadTimer->IsActive() ) + { + if (GetTotalListenerCount()) + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::StartUnloadTimerIfNeeded - Listener found, aborting" ) ) ); + } + else if (iChannelChangeListenerCount > 0) + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::StartUnloadTimerIfNeeded - Change listener found, aborting" ) ) ); + } + else + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::StartUnloadTimerIfNeeded - No listeners found, starting unload timer" ) ) ); + iUnloadTimer->Set(iProxyManager.SsyInactivityPeriod()); + } + } + else + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::StartUnloadTimerIfNeeded - Unload timer already active or scheduler stopped" ) ) ); + } + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::StartUnloadTimerIfNeeded - return " ) ) ); + } + + +// --------------------------------------------------------------------------- +// Kill threads if they are still active +// --------------------------------------------------------------------------- +// +void CSensrvPluginProxy::TimerFired(TInt /*aTimerId*/) + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::TimerFired()" ) ) ); + + iMutex.Wait(); + + // Doublecheck that there is still zero listeners, just in case + if(!GetTotalListenerCount()) + { + CleanupPlugin(); + } + + iMutex.Signal(); + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::TimerFired - return " ) ) ); + } + +// --------------------------------------------------------------------------- +// Cleans up the plugin and thread +// --------------------------------------------------------------------------- +// +void CSensrvPluginProxy::CleanupPlugin() + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::CleanupPlugin()" ) ) ); + + // Something has failed, so notify proxy manager that proxy initialization is complete, + // if this happened during the first attempt to load plugin. + // Note that this will leave proxy with zero channels + // but there is not much we can do about it, as it is very unlikely that reload would be + // successfull either. + + if (!iIsInitialized || + iPluginState == EPluginStateUninitialized || + iPluginState == EPluginStateThreadInitializing || + iPluginState == EPluginStateThreadInitialized) + { + iPreviousSsyLoadFailed = ETrue; + // If first fail, fake initialized and notify manager to continue pending activities + // If proxy provides dynamic channels, notify manager to continue pending channel queries + if (!iIsInitialized || iDynamicChannelInfoList.Count() > 0) + { + iIsInitialized = ETrue; + iProxyManager.NotifyProxyInitialized(); + } + } + + // Cleanup channels + iChannelList.ResetAndDestroy(); + + // Cleanup all ongoing transactions. + if (iTransactionMonitor) + { + iTransactionMonitor->RemoveAllTransactions(); + } + + + if (iServerMediator) + { + + iMutex.Wait(); + iServerMediator->RemoveAllTransactions(); + iMutex.Signal(); + } + + if (iPluginState != EPluginStateUnloaded && iLoadWaitQueue) + { + // Load wait transactions are not cleared when cleanup is called from SsyThreadTerminated() + iLoadWaitQueue->RemoveAll(); + } + + // Clean up SSY mediator. Actual deletion of SSY mediator is done in SsyThreadTerminated() + if (iSsyMediator) + { + SetPluginState(EPluginStateUnloading); + iSsyMediator->Cleanup(); + } + else + { + SetPluginState(EPluginStateUnloaded); + } + + // Thread monitor needs to ensure that SSY thread dies. + // If cleanup was triggered by thread dying, this is not needed + if (iThreadMonitor && iPluginState != EPluginStateUnloaded) + { + iThreadMonitor->DelayedTermination(); + } + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::CleanupPlugin - return" ) ) ); + } + +// --------------------------------------------------------------------------- +// Queues transaction +// --------------------------------------------------------------------------- +// +TInt CSensrvPluginProxy::QueueTransaction(CSensrvTransaction* aTransaction, TBool aLast) + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::QueueTransaction(aTransaction: 0x%x, aLast: %d)" ), aTransaction, aLast ) ); + + __ASSERT_ALWAYS(aTransaction, User::Panic(KSensrvPanicCategory, ESensrvPanicNullTransaction)); + + TInt err(KErrNone); + + aTransaction->SetState(CSensrvTransaction::ETransStateQueued); + + err = iLoadWaitQueue->Add(aTransaction, aLast); + if (err != KErrNone) + { + ERROR_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::QueueTransaction - ERROR: Failed to add transaction to queue" ) ) ); + } + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::QueueTransaction - return %d" ), err ) ); + + return err; + } + +// --------------------------------------------------------------------------- +// Executes the first transaction in given queue, unless it is already executing, +// in which case nothing is done. +// --------------------------------------------------------------------------- +// +void CSensrvPluginProxy::HandleNextTransaction() + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::HandleNextTransaction()" ) ) ); + + CSensrvTransaction* transaction = iLoadWaitQueue->First(); + + if (transaction && !iDeletionFlag) + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::HandleNextTransaction - Handling transaction type: %d" ), transaction->Type() ) ); + if (transaction->State() == CSensrvTransaction::ETransStateQueued) + { + switch (transaction->Type()) + { + case CSensrvTransaction::ETransTypeLoadSsy: + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::HandleNextTransaction - ETransTypeLoadSsy" ) ) ); + transaction->SetState(CSensrvTransaction::ETransStateExecuting); + + // If SSY mediator is not yet initialized, it is an error + __ASSERT_ALWAYS(iSsyMediator, User::Panic(KSensrvPanicCategory, ESensrvPanicNullSsyMediator)); + + Mutex().Wait(); + // Notify SSY mediator that transaction is ready to be handled. + TInt err(iSsyMediator->Notify(transaction)); + Mutex().Signal(); + // If there was error, transaction needs to be removed from queue (which also completes it) + if (err == KErrNone) + { + iTransactionMonitor->AddTransaction(transaction); + } + else + { + ERROR_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::HandleNextTransaction - ERROR: Failed to handle next transaction: %d" ), err ) ); + transaction->SetErrorCode(err); + iLoadWaitQueue->Remove(transaction, CSensrvTransactionQueue::ERemovalTypeComplete); + transaction = NULL; + + // Since proxy only handles plugin level transactions (load), + // failure on any of them means we need to clean up the plugin, + // which will also clean up any pending transactions. + CleanupPlugin(); + } + } + break; + case CSensrvTransaction::ETransTypeDelayedInitialize: + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::HandleNextTransaction - ETransTypeDelayedInitialize" ) ) ); + + // Initialize only if state is unloaded + if (iPluginState == EPluginStateUnloaded) + { + iLoadWaitQueue->Remove(transaction, CSensrvTransactionQueue::ERemovalTypeComplete); + + // Request initialize + TRAPD(err, InitializePluginL()); + + if (err != KErrNone) + { + ERROR_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::HandleNextTransaction - ERROR: Failed to reinitialize plugin : %d" ), err ) ); + } + } + else + { + ERROR_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::HandleNextTransaction - ERROR: Attempted to reinitialize in invalid state: %d" ), iPluginState ) ); + } + } + break; + case CSensrvTransaction::ETransTypeDelayedOpenChannel: + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::HandleNextTransaction - ETransTypeDelayedOpenChannel" ) ) ); + + iTransactionMonitor->RemoveTransaction(transaction); + + // Extract message from transaction and call dispatch from proper handling + CSensrvMessage* message = transaction->ExtractMessage(); + + iLoadWaitQueue->Remove(transaction, CSensrvTransactionQueue::ERemovalTypeComplete); + + // No need to check error value, we already know message type is correct. + TSensrvChannelId channelId(0); + message->GetChannelId(channelId); + + DispatchMessage(*message, channelId); + + // Recursively handle next transaction + HandleNextTransaction(); + } + break; + default: + // Unexpected transaction type, so we do not know what to do with it + ERROR_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::HandleNextTransaction - ERROR: Invalid transaction type" ) ) ); + User::Panic(KSensrvPanicCategory, ESensrvPanicUnknownTransactionType); + break; + } + } + else + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::HandleNextTransaction - Previous transaction still executing" ) ) ); + } + } + else + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::HandleNextTransaction - No transaction to execute" ) ) ); + } + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::HandleNextTransaction - return" ) ) ); + } + +// --------------------------------------------------------------------------- +// Handles transaction finalization and completes transaction on proxy's queue. +// --------------------------------------------------------------------------- +// +void CSensrvPluginProxy::CompleteTransaction(CSensrvTransaction* aTransaction) + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::CompleteTransaction(aTransaction: 0x%x)" ), aTransaction ) ); + + __ASSERT_ALWAYS(aTransaction, User::Panic(KSensrvPanicCategory, ESensrvPanicNullTransaction)); + + switch (aTransaction->Type()) + { + // Proxy level transactions handled here + case CSensrvTransaction::ETransTypeLoadSsy: + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::CompleteTransaction - ETransTypeLoadSsy" ) ) ); + + TInt err = aTransaction->ErrorCode(); + + if ( err == KErrNone) + { + err = UpdateChannelInfoLists(); + + // Update plugin state + SetPluginState(EPluginStateLoaded); + } + else + { + ERROR_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::CompleteTransaction - ERROR: Load transaction failed %d" ), err ) ); + } + + if (err != KErrNone) + { + // Since there was an error, cleanup the plugin and thread + CleanupPlugin(); + } + else + { + // Proxy has been initialized, notify manager + // If proxy provides dynamic channels, notify manager to handle pending channel queries + if (!iIsInitialized || iDynamicChannelInfoList.Count() > 0) + { + iIsInitialized = ETrue; + iProxyManager.NotifyProxyInitialized(); + } + + // Initially there are no clients, so startup unload timer + StartUnloadTimerIfNeeded(); + } + } + break; + + case CSensrvTransaction::ETransTypeMediatorChannelsChanged: + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::CompleteTransaction - ETransTypeMediatorChannelsChanged" ) ) ); + + // Error is irrelevant, as we can't do anything about it anyway, and UpdateChannelInfoLists() + // does its own tracing. + UpdateChannelInfoLists(); + } + break; + + default: + // Unexpected transaction type, so we do not know what to do with it + ERROR_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::TransactionHandledAtSsy - ERROR: Invalid transaction type" ) ) ); + User::Panic(KSensrvPanicCategory, ESensrvPanicUnknownTransactionType); + break; + } + + // Complete the transaction + iTransactionMonitor->RemoveTransaction(aTransaction); + iLoadWaitQueue->Remove(aTransaction, CSensrvTransactionQueue::ERemovalTypeComplete); + + // Handle next transaction. + HandleNextTransaction(); + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::CompleteTransaction - return" ) ) ); + } + +// --------------------------------------------------------------------------- +// Goes through channel infos and returns pointer to one that matches given id. +// --------------------------------------------------------------------------- +// +TSensrvResourceChannelInfo* CSensrvPluginProxy::GetChannelInfoForId( TSensrvChannelId aChannelId ) + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::GetChannelInfoForId(aChannelId: %d)" ), aChannelId ) ); + + TSensrvResourceChannelInfo* info = NULL;; + + if (iIsInitialized) + { + TBool found(EFalse); + TInt channelCount = iChannelInfoList.Count(); + if (channelCount > 0) + { + for(TInt j = 0; !found && j < channelCount; j++) + { + if (iChannelInfoList[j].iChannelId == aChannelId) + { + info = &iChannelInfoList[j]; + found = ETrue; + } + } + } + } + else + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::GetChannelInfoForId - Proxy not yet initialized" ) ) ); + } + + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::GetChannelInfoForId - return 0x%x" ), info ) ); + + return info; + } + +// --------------------------------------------------------------------------- +// Set plugin state +// --------------------------------------------------------------------------- +// +void CSensrvPluginProxy::SetPluginState(TPluginState aState) + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::SetPluginState(aState: %d)" ), aState ) ); + + iPluginState = aState; + } + +// --------------------------------------------------------------------------- +// Gets total listener count from all channels +// --------------------------------------------------------------------------- +// +TInt CSensrvPluginProxy::GetTotalListenerCount() + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::GetTotalListenerCount()" ) ) ); + + TInt channelCount(iChannelList.Count()); + TInt listenerCount(0); + + for(TInt i = 0; i < channelCount; i ++) + { + listenerCount += iChannelList[i]->ListenerCount(); + } + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::GetTotalListenerCount - return: %d" ), listenerCount ) ); + + return listenerCount; + } + +// --------------------------------------------------------------------------- +// Grabs raw channel info data from SSY mediator and +// Updates channel info and removed channel info lists. +// --------------------------------------------------------------------------- +// +TInt CSensrvPluginProxy::UpdateChannelInfoLists() + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::UpdateChannelInfoLists()" ) ) ); + + TInt err(KErrNone); + + // Get new info into a temporary array. + RSensrvChannelInfoList newInfos; + + TAny** rawDataPtr = iSsyMediator->RawInfos(); + + if (*rawDataPtr) + { + // First item in raw data is count + TInt* countPointer = reinterpret_cast(*rawDataPtr); + + if (*countPointer > 0) + { + err = newInfos.Reserve(*countPointer); + + // Data starts after count + TSensrvChannelInfo* info = reinterpret_cast(countPointer + 1); + + // Loop through raw data, appending datas to info list + for (TInt newLoop = 0; err == KErrNone && newLoop < *countPointer; newLoop++) + { + err = newInfos.Append(*info++); + if (err != KErrNone) + { + ERROR_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::UpdateChannelInfoLists - ERROR: newInfos.Append failure: %d, count: %d" ), err, newLoop ) ); + newInfos.Reset(); + } + } + } + + // Free memory allocated by SSY mediator and set mediator's pointer to raw data to NULL + iProxyManager.ServerHeap()->Free(*rawDataPtr); + *rawDataPtr = NULL; + } + else + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::UpdateChannelInfoLists - No channels registered by SSY" ) ) ); + } + +#ifdef COMPONENT_TRACE_DEBUG + COMPONENT_TRACE( ( _L( "### Sensor Server - CSensrvPluginProxy::UpdateChannelInfoLists, initial channel lists:" )) ); + + COMPONENT_TRACE( ( _L( "### newInfos contents:" )) ); + iProxyManager.TraceChannelInfoList(newInfos); + + COMPONENT_TRACE( ( _L( "### iChannelInfoList contents:" )) ); + iProxyManager.TraceChannelInfoList(iChannelInfoList); + + COMPONENT_TRACE( ( _L( "### iRemovedChannelsInfoList contents:" )) ); + iProxyManager.TraceChannelInfoList(iRemovedChannelsInfoList); +#endif + + // Compare old infos to new infos and notify removals to sessions, + // add removed infos to iRemovedChannelsInfoList, + // destroy CSensrvChannel objects of removed channelsm, and + // remove old infos from iChannelInfoList. + for (TInt oldLoop = iChannelInfoList.Count() - 1; err == KErrNone && oldLoop >= 0 ; oldLoop--) + { + // If match was not found, this channel has been removed + const TSensrvChannelInfo& oldInfo(iChannelInfoList[oldLoop]); + TInt index = FindChannel(newInfos, oldInfo); + if (index == KErrNotFound) + { + // Notify interested sessions + iProxyManager.NotifyChannelChange(oldInfo, ESensrvChannelChangeTypeRemoved); + + // Add info to removed infos. + err = iRemovedChannelsInfoList.Append(oldInfo); + if (err != KErrNone) + { + // Error is ignored as we cannot do anything about this. It results in channel id + // being regenerated to this channel if it is readded later, which is inconvenient, but + // not critical. + ERROR_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::UpdateChannelInfoLists - ERROR: iRemovedChannelsInfoList.Append failure: %d, count: %d" ), err, oldLoop ) ); + } + + // Destroy and remove from channel list the related channel object as it is obsolete. + TInt channelCount = iChannelList.Count(); + for(TInt i = 0; i < channelCount; i++) + { + if (iChannelList[i]->Id() == oldInfo.iChannelId) + { + delete iChannelList[i]; + iChannelList.Remove(i); + break; + } + } + + // Remove channel info from iChannelInfoList + iChannelInfoList.Remove(oldLoop); + } + } + + // Compare new infos to old infos and notify additions to sessions, + // remove added infos from iRemovedChannelsInfoList if they are there, and + // append new infos to iChannelInfoList. + TInt newCount = newInfos.Count(); + for (TInt newLoop = 0; err == KErrNone && newLoop < newCount; newLoop++) + { + const TSensrvChannelInfo& newInfo(newInfos[newLoop]); + TInt index = FindChannel(newInfo, iChannelInfoList); + if (index >= 0 && index < iChannelInfoList.Count()) + { + // Update silently the actual data item size from SSY channel registration if still unset + TSensrvChannelInfo& oldInfo(iChannelInfoList[index]); + if (oldInfo.iDataItemSize <= 0 && newInfo.iDataItemSize > 0) + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::UpdateChannelInfoLists - channel %d, new data item size: %d" ), + oldInfo.iChannelId, newInfo.iDataItemSize ) ); + oldInfo.iDataItemSize = newInfo.iDataItemSize; + } + } + else + { + TSensrvResourceChannelInfo newResourceInfo(newInfo); + + // Store dynamic channel status + newResourceInfo.iDynamic = FindChannel(newInfo, iDynamicChannelInfoList) != KErrNotFound; // Store dynamic status + + err = iChannelInfoList.Append(newResourceInfo); + if (err == KErrNone) + { + // Notify interested sessions + iProxyManager.NotifyChannelChange(newInfo, ESensrvChannelChangeTypeAdded); + + // Remove from iRemovedChannelsInfoList, in case there has been this channel previously + index = FindChannel(newInfo, iRemovedChannelsInfoList); + if(index >= 0 && index < iRemovedChannelsInfoList.Count()) + { + iRemovedChannelsInfoList.Remove(index); + } + } + else + { + ERROR_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::UpdateChannelInfoLists - ERROR: iChannelInfoList.Append failure: %d, count: %d" ), err, newLoop ) ); + } + } + } + + // Note: It might be slightly more efficient to simply reset the iChannelInfoList and + // repopulate it with newInfos content as opposed to explicit appends and removes + // above, but that would create a risk that iChannelInfoList was left empty in + // case append fails to allocate new memory. Since there is no way to resurrect + // proxy with no channels once it has been unloaded, this is not acceptable. + +#ifdef COMPONENT_TRACE_DEBUG + COMPONENT_TRACE( ( _L( "### " )) ); + COMPONENT_TRACE( ( _L( "### Sensor Server - CSensrvPluginProxy::UpdateChannelInfoLists, after changes" )) ); + + COMPONENT_TRACE( ( _L( "### iChannelInfoList contents (should be same as newInfos):" )) ); + iProxyManager.TraceChannelInfoList(iChannelInfoList); + + COMPONENT_TRACE( ( _L( "### iRemovedChannelsInfoList contents (should have infos removed from iChannelInfoList added to it):" )) ); + iProxyManager.TraceChannelInfoList(iRemovedChannelsInfoList); +#endif + + // Cleanup newinfos + newInfos.Close(); + + if (iDeletionFlag) + { + // Cleanup bad proxy after its channels have been removed + CleanupPlugin(); + } + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::UpdateChannelInfoLists - return: %d" ), err ) ); + + return err; + } + + +// --------------------------------------------------------------------------- +// SSY thread main function. +// Creates new active scheduler and cleanup stack and installs those. +// Initializes SSY mediator. +// Starts the new active scheduler. +// --------------------------------------------------------------------------- +// +TInt CSensrvPluginProxy::SsyThreadFunction( TAny* aParameter ) + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::SsyThreadFunction(aParameter: 0x%x)" ), aParameter ) ); + + if (!aParameter) + { + ERROR_TRACE( ( _L( "Sensor Server - SsyThreadFunction() - ERROR: NULL proxy, cannot start thread." ) ) ); + return KErrBadHandle; + } + + __UHEAP_MARK; + +#ifdef MEMORY_TRACE_DEBUG + // TRACE heap usage + TInt heapSize = User::Heap().Size(); + TInt biggestBlock(0); + TInt heapAvail = User::Heap().Available(biggestBlock); + TInt used(heapSize-heapAvail); + MEMORY_TRACE( ( _L( "#### Sensor Server, SSY starting - HEAP: Size: %d, Available: %d, Used: %d" ), heapSize, heapAvail, used ) ); +#endif + + CSensrvPluginProxy* proxy = static_cast(aParameter); + + TInt err(KErrNone); + + // Create new cleanup stack + CTrapCleanup* cleanup = CTrapCleanup::New(); + + if ( cleanup ) + { + // Create and install the active scheduler we need + CSensrvSsyActiveScheduler* scheduler = NULL; + TRAP(err, scheduler = CSensrvSsyActiveScheduler::NewL()); + + if (err == KErrNone) + { + CActiveScheduler::Install( scheduler ); + + proxy->Mutex().Wait(); + + COMPONENT_TRACE( ( _L( "Sensor Server - SsyThreadFunction() - Started thread for plugin UID: 0x%x" ), proxy->iImplementationUid.iUid) ); + + // initialize SSY mediator + err = proxy->SsyMediator()->Initialize(); + + if (err == KErrNone) + { + // Initial notify to server mediator via null transaction + // Notifying NULL transaction cannot fail, so no error handling + proxy->ServerMediator()->Notify(NULL); + + proxy->Mutex().Signal(); + + COMPONENT_TRACE( ( _L( "Sensor Server - SsyThreadFunction() - Starting scheduler" )) ); + + CActiveScheduler::Start(); + + COMPONENT_TRACE( ( _L( "Sensor Server - SsyThreadFunction() - Scheduler stopped" )) ); + + // Signal final closure of ecom session for SSY thread + REComSession::FinalClose(); + } + else + { + ERROR_TRACE( ( _L( "Sensor Server - SsyThreadFunction() - ERROR: Failed to initialize SSY mediator, cannot start thread: %d." ),err ) ); + proxy->Mutex().Signal(); + } + + // Cleanup + delete scheduler; + scheduler = NULL; + } + else + { + ERROR_TRACE( ( _L( "Sensor Server - SsyThreadFunction() - ERROR: Failed to create scheduler, cannot start thread: %d." ),err ) ); + } + + delete cleanup; + cleanup = NULL; + } + else + { + ERROR_TRACE( ( _L( "Sensor Server - SsyThreadFunction() - ERROR: No memory to create cleanup stack, cannot start thread." ) ) ); + err = KErrNoMemory; + } + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::SsyThreadFunction - return" ) ) ); + +#ifdef MEMORY_TRACE_DEBUG + // TRACE heap usage + heapSize = User::Heap().Size(); + heapAvail = User::Heap().Available(biggestBlock); + TInt newUsed(heapSize-heapAvail); + MEMORY_TRACE( ( _L( "#### Sensor Server, SSY exit - HEAP: Size: %d, Available: %d, Used: %d, Change in used: %d" ), heapSize, heapAvail, newUsed, newUsed - used ) ); +#endif + + __UHEAP_MARKEND; + + return err; + } + +// --------------------------------------------------------------------------- +// Cleanup item implementation for plugin initialization +// --------------------------------------------------------------------------- +// +void CSensrvPluginProxy::CleanupInitializePlugin( TAny* aAny ) + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::CleanupInitializePlugin()" ) ) ); + + CSensrvPluginProxy* proxy = reinterpret_cast(aAny); + + if (proxy) + { + // Uninitialized RThread object also has valid handle to current thread + if (proxy->iSsyThread.Handle() && proxy->iSsyThread.Handle() != RThread().Handle()) + { + proxy->iSsyThread.Terminate(KErrCancel); + proxy->iSsyThread.Close(); + } + + // Clean up any pending channel open messages + proxy->iLoadWaitQueue->RemoveAll(); + proxy->iPreviousSsyLoadFailed = ETrue; + proxy->Mutex().Signal(); + } + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::CleanupInitializePlugin - return" ) ) ); + } + +// --------------------------------------------------------------------------- +// Finds channel from info list that matches to given channel info +// --------------------------------------------------------------------------- +// +TInt CSensrvPluginProxy::FindChannel( const TSensrvChannelInfo& aChannelInfo, + const RSensrvResourceChannelInfoList& aChannelInfoList ) + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::FindChannel (RSensrvResourceChannelInfoList)" ) ) ); + + TInt index = aChannelInfoList.Find(aChannelInfo, TSensrvResourceChannelInfo::CompareFindMatch); + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::FindChannel - index %d, return" ), index ) ); + + return index; + } + +// --------------------------------------------------------------------------- +// Finds channel from info list that matches to given channel info +// --------------------------------------------------------------------------- +// +TInt CSensrvPluginProxy::FindChannel( const RSensrvChannelInfoList& aChannelInfoList, + const TSensrvChannelInfo& aChannelInfo ) + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::FindChannel (RSensrvChannelInfoList) Reverse" ) ) ); + + TInt index = aChannelInfoList.Find(aChannelInfo, TSensrvResourceChannelInfo::CompareFindMatchReverse); + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::FindChannel - index %d, return" ), index ) ); + + return index; + } + +// --------------------------------------------------------------------------- +// Increments dynamic channel change listener count +// --------------------------------------------------------------------------- +// +void CSensrvPluginProxy::AddChannelChangeListener() + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::AddChannelChangeListener" ) ) ); + + ++iChannelChangeListenerCount; + StopUnloadTimer(); + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::AddChannelChangeListener - count %d return " ), + iChannelChangeListenerCount ) ); + } + +// --------------------------------------------------------------------------- +// Decrements dynamic channel change listener count +// --------------------------------------------------------------------------- +// +void CSensrvPluginProxy::RemoveChannelChangeListener() + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::RemoveChannelChangeListener" ) ) ); + + if (iChannelChangeListenerCount > 0) + { + --iChannelChangeListenerCount; + if (!iChannelChangeListenerCount) + { + StartUnloadTimerIfNeeded(); + } + } + else + { + ERROR_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::RemoveChannelChangeListener - ERROR: count corrupt" ) ) ); + } + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::RemoveChannelChangeListener - count %d return " ), + iChannelChangeListenerCount ) ); + } + +// --------------------------------------------------------------------------- +// Enqueues delayed initialize transaction +// --------------------------------------------------------------------------- +// +TInt CSensrvPluginProxy::EnqueueDelayedInitializeTransaction() + { + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::EnqueueDelayedInitializeTransaction" ) ) ); + + TInt err = KErrNone; + + // Enqueue initialization transaction if queue is empty. + if (iLoadWaitQueue->IsEmpty()) + { + CSensrvTransaction* transaction = NULL; + TRAP(err, transaction = CSensrvTransaction::NewL( + NULL, this, NULL, CSensrvTransaction::ETransTypeDelayedInitialize)); + if (err == KErrNone) + { + err = QueueTransaction(transaction, EFalse); + if (err != KErrNone) + { + delete transaction; + transaction = NULL; + } + } + else + { + ERROR_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::EnqueueDelayedInitializeTransaction - ERROR: Failed to create transaction err: %d" ), err ) ); + } + } + + COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvPluginProxy::EnqueueDelayedInitializeTransaction - return" ) ) ); + + return err; + }