sl@0: // Copyright (c) 2006-2010 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include "surfaceupdateserver.h" sl@0: sl@0: #include sl@0: #include sl@0: sl@0: #include "surfaceupdate.h" sl@0: #include "suerror.h" sl@0: #ifdef TEST_SURFACE_UPDATE sl@0: #include "surfaceupdatetest.h" sl@0: #endif sl@0: sl@0: sl@0: const TUint KDefaultHeapSize=0x10000; sl@0: sl@0: void *gProvider = NULL; sl@0: RFastLock gProviderFastLock; sl@0: sl@0: /** sl@0: The server maintains session with the clients. sl@0: It starts during the initialization of the Content update receiver thread. sl@0: */ sl@0: CSurfaceUpdateServer* CSurfaceUpdateServer::NewL() sl@0: { sl@0: CSurfaceUpdateServer* server = new (ELeave) CSurfaceUpdateServer(EPriorityStandard); sl@0: CleanupStack::PushL(server); sl@0: server->ConstructL(); sl@0: CleanupStack::Pop(); sl@0: return server; sl@0: } sl@0: sl@0: CSurfaceUpdateServer::CSurfaceUpdateServer(CActive::TPriority aPriority) : sl@0: CServer2(aPriority) sl@0: { sl@0: } sl@0: sl@0: CSurfaceUpdateServer::~CSurfaceUpdateServer() sl@0: { sl@0: iUpdateReceiver.Close(); sl@0: iUpdateReceiverPriorityOrder.ResetAndDestroy(); sl@0: delete iServerProvider; sl@0: } sl@0: sl@0: void CSurfaceUpdateServer::ConstructL() sl@0: { sl@0: iServerProvider = CSurfaceUpdateServerProvider::NewL(EPriorityStandard, this); sl@0: } sl@0: sl@0: /** sl@0: Assign Content update receiver instance to particular screen. sl@0: The following calls of this function will override the previous. sl@0: sl@0: @see MSurfaceUpdateServerProvider::Register sl@0: */ sl@0: TInt CSurfaceUpdateServer::Register(TInt aScreen, CBase* aUpdateReceiver, TInt aPriority) sl@0: { sl@0: if(aScreen < 0) sl@0: { sl@0: return KErrArgument; sl@0: } sl@0: sl@0: TInt err = KErrNone; sl@0: while((iUpdateReceiver.Count() <= aScreen) && (err == KErrNone)) sl@0: { sl@0: err = iUpdateReceiver.Append(NULL); sl@0: } sl@0: sl@0: if(err == KErrNone) sl@0: { sl@0: TUpdateReceiverPriorityEntry *receiverPriorityEntry = NULL; sl@0: if(!aUpdateReceiver) sl@0: {//Client wants to unregister the Content update receiver which has been associated with the given screen number. sl@0: MCompositionSurfaceUpdate* receiver = iUpdateReceiver[aScreen]; sl@0: if(receiver) sl@0: { sl@0: TInt num = iUpdateReceiverPriorityOrder.Count() - 1; sl@0: for(;;) sl@0: {//Content update receiver must be in priority list, therefore we don't need to check num >= 0 sl@0: receiverPriorityEntry = iUpdateReceiverPriorityOrder[num]; sl@0: if(receiverPriorityEntry->iUpdateReceiver == receiver) sl@0: {//remove the Content update receiver from the priority list sl@0: iUpdateReceiverPriorityOrder.Remove(num); sl@0: delete receiverPriorityEntry; sl@0: break; sl@0: } sl@0: num--; sl@0: } sl@0: iUpdateReceiver[aScreen] = NULL; //unregister the Content update receiver by setting the entry to NULL sl@0: } sl@0: } sl@0: else sl@0: { sl@0: CExtensionContainer* extCont=static_cast(aUpdateReceiver); sl@0: MCompositionSurfaceUpdate* updateReceiver=extCont->GetInterface(); sl@0: if (updateReceiver) sl@0: { sl@0: receiverPriorityEntry = new TUpdateReceiverPriorityEntry; sl@0: if(!receiverPriorityEntry) sl@0: return KErrNoMemory; sl@0: receiverPriorityEntry->iPriority = aPriority; sl@0: receiverPriorityEntry->iUpdateReceiver = updateReceiver; sl@0: sl@0: err = iUpdateReceiverPriorityOrder.InsertInOrder(receiverPriorityEntry, CSurfaceUpdateServer::CompareUpdateReceiverPriority); sl@0: if(err == KErrNone) sl@0: { sl@0: iUpdateReceiver[aScreen] = updateReceiver; sl@0: } sl@0: else sl@0: { sl@0: delete receiverPriorityEntry; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: err=KErrArgument; sl@0: } sl@0: } sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: Create a new session with a server. Derived from CSession2. sl@0: sl@0: @param aVersion required version of the server sl@0: @param aMessage message from the client. sl@0: @return New instance of the CSurfaceUpdateSession. sl@0: */ sl@0: CSession2* CSurfaceUpdateServer::NewSessionL(const TVersion& aVersion, const RMessage2& /*aMessage*/) const sl@0: { sl@0: // Check that the version is OK sl@0: TVersion v(KSurfaceUpdateServMajorVersionNumber,KSurfaceUpdateServMinorVersionNumber,KSurfaceUpdateServBuildVersionNumber); sl@0: if (!User::QueryVersionSupported(v,aVersion)) sl@0: User::Leave(KErrNotSupported); sl@0: sl@0: // Security is not an issue, any client can have connection to the server sl@0: // Create the session. sl@0: return new (ELeave) CSurfaceUpdateSession(UpdateReceiverPriority()); sl@0: } sl@0: sl@0: /** sl@0: Utility function to panic the server sl@0: sl@0: @param aPanic Panic code sl@0: */ sl@0: void CSurfaceUpdateServer::PanicServer(TSurfaceUpdateServPanic aPanic) sl@0: { sl@0: _LIT(KTxtServerPanic,"Surface Update Server panic"); sl@0: User::Panic(KTxtServerPanic, aPanic); sl@0: } sl@0: sl@0: /** sl@0: Provide composition receiver. sl@0: sl@0: @param aScreen targeted screen sl@0: @return Composition receiver object, associated to particular screen sl@0: */ sl@0: MCompositionSurfaceUpdate* CSurfaceUpdateServer::UpdateReceiver(TInt aScreen) const sl@0: { sl@0: if(aScreen >= iUpdateReceiver.Count())//negative value won't reach this point sl@0: return NULL; sl@0: return iUpdateReceiver[aScreen]; sl@0: } sl@0: sl@0: TInt CSurfaceUpdateServer::ThreadFunction(TAny* aAny) sl@0: { sl@0: // get clean-up stack sl@0: CTrapCleanup* cleanup=CTrapCleanup::New(); sl@0: __ASSERT_ALWAYS(cleanup!=NULL, CSurfaceUpdateServer::PanicServer(EUpdateServPanicNoMemory)); sl@0: sl@0: // create an active scheduler and server sl@0: CActiveScheduler *pA = new CActiveScheduler; sl@0: __ASSERT_ALWAYS(pA != NULL, CSurfaceUpdateServer::PanicServer(EUpdateServPanicNoMemory)); sl@0: sl@0: //Install the active scheduler sl@0: CActiveScheduler::Install(pA); sl@0: sl@0: CSurfaceUpdateServer *pS = NULL; sl@0: TRAPD(err, pS = CSurfaceUpdateServer::NewL()); sl@0: __ASSERT_ALWAYS(err == KErrNone, CSurfaceUpdateServer::PanicServer(EUpdateServPanicNoMemory)); sl@0: sl@0: // Start the server sl@0: #ifndef TEST_SURFACE_UPDATE sl@0: err = pS->Start(KSurfaceUpdateServerName); sl@0: #else sl@0: err = pS->Start(KTestSurfaceUpdateServerName); sl@0: #endif sl@0: sl@0: if (err != KErrNone) sl@0: { sl@0: CSurfaceUpdateServer::PanicServer(EUpdateServPanicStartUp); sl@0: } sl@0: *(static_cast (aAny)) = pS->SurfaceUpdateProvider(); sl@0: sl@0: // Let everyone know that we are ready to sl@0: // deal with requests. sl@0: RThread::Rendezvous(KErrNone); sl@0: // And start fielding requests from client(s). sl@0: CActiveScheduler::Start(); sl@0: sl@0: // Tidy up... sl@0: delete pS; sl@0: delete pA; sl@0: delete cleanup; sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: inline TInt CSurfaceUpdateServer::NumUpdateReceivers() const sl@0: { sl@0: return iUpdateReceiver.Count(); sl@0: } sl@0: sl@0: /** sl@0: Compare two content update receiver entries according to their priority. sl@0: The function is used when receiver priority entry is inserted/retrieved from the array (iCompReceiverPriorityOrder). sl@0: sl@0: @return zero, if the priorities of two receivers are equal; sl@0: a negative value, if the priority of the first receiver is less than the priority of the second one; sl@0: a positive value, if the priority of the first receiver is greater than the priority of the second one. sl@0: */ sl@0: TInt CSurfaceUpdateServer::CompareUpdateReceiverPriority(const TUpdateReceiverPriorityEntry& aEntry1, const TUpdateReceiverPriorityEntry& aEntry2) sl@0: { sl@0: return aEntry2.iPriority - aEntry1.iPriority; sl@0: } sl@0: sl@0: /** sl@0: class CSurfaceUpdateSession sl@0: sl@0: Maintain the channel between clients and the server. sl@0: Functions are provided will respond appropriately to client messages. sl@0: */ sl@0: sl@0: CSurfaceUpdateSession::CSurfaceUpdateSession(const RPointerArray& aEntryList) : sl@0: CSession2(), sl@0: iUpdateReceiverEntryList(aEntryList) sl@0: { sl@0: } sl@0: sl@0: /** sl@0: Cancel any outstanding client notification requests. sl@0: All resources owned by the session will either be immediately released or sl@0: scheduled for deferred deletion. sl@0: */ sl@0: CSurfaceUpdateSession::~CSurfaceUpdateSession() sl@0: { sl@0: CancelAllUpdateNotifications(); sl@0: iUpdateReceiverNotificationBatches.ResetAndDestroy(); sl@0: } sl@0: sl@0: /** sl@0: Main function which deals with requests from clients. sl@0: */ sl@0: void CSurfaceUpdateSession::ServiceL(const RMessage2& aMessage) sl@0: { sl@0: switch (aMessage.Function()) sl@0: { sl@0: case EUpdateServNotifyWhenAvailable: sl@0: NotifyWhenAvailable(aMessage); sl@0: return; sl@0: case EUpdateServNotifyWhenDisplayed: sl@0: NotifyWhenDisplayed(aMessage); sl@0: return; sl@0: case EUpdateServNotifyWhenDisplayedXTimes: sl@0: NotifyWhenDisplayedXTimes(aMessage); sl@0: return; sl@0: case EUpdateServSubmitUpdate: sl@0: SubmitUpdate(aMessage); sl@0: return; sl@0: case EUpdateServCancelAllNotifications: sl@0: CancelAllUpdateNotifications(); sl@0: aMessage.Complete(KErrNone); sl@0: return; sl@0: #ifdef TEST_SURFACE_UPDATE sl@0: case EUpdateServOOM: sl@0: { sl@0: SetHeapFailure(aMessage); sl@0: return; sl@0: } sl@0: #endif sl@0: default: sl@0: PanicClient(aMessage, EUpdateServPanicBadRequest); sl@0: return; sl@0: } sl@0: } sl@0: sl@0: #ifdef TEST_SURFACE_UPDATE sl@0: /** sl@0: Simulate heap allocation failure for the SUS thread's heap. sl@0: Aim for OOM testing. sl@0: */ sl@0: void CSurfaceUpdateSession::SetHeapFailure(const RMessage2& aMessage) sl@0: { sl@0: TInt numElement = iUpdateReceiverNotificationBatches.Count(); sl@0: TInt index = 0; sl@0: while(numElement) sl@0: { sl@0: CUpdateReceiverNotificationBatch* batch = iUpdateReceiverNotificationBatches[index]; sl@0: if(batch->iType == EUpdateSrvReusable) sl@0: { sl@0: iUpdateReceiverNotificationBatches.Remove(index); sl@0: delete batch; sl@0: } sl@0: else sl@0: { sl@0: index++; sl@0: } sl@0: numElement--; sl@0: } sl@0: if(numElement == 0) sl@0: { sl@0: iUpdateReceiverNotificationBatches.Reset(); sl@0: } sl@0: TInt failRate = aMessage.Int0(); sl@0: if(!failRate) sl@0: { sl@0: __UHEAP_RESET; sl@0: } sl@0: else sl@0: { sl@0: __UHEAP_SETFAIL(RHeap::EDeterministic, failRate); sl@0: } sl@0: aMessage.Complete(KErrNone); sl@0: } sl@0: #endif sl@0: sl@0: void CSurfaceUpdateSession::PanicClient(const RMessage2& aMessage, TInt aPanic) const sl@0: { sl@0: _LIT(KTxtServer,"SurfUpServ"); sl@0: aMessage.Panic(KTxtServer, aPanic); sl@0: } sl@0: sl@0: /** sl@0: Return first inactive spare notification object stored in the notification array, sl@0: create a new one if fail to find it in the array. sl@0: */ sl@0: CUpdateReceiverNotificationBatch* CSurfaceUpdateSession::UpdateReceiverNotificationBatchL() sl@0: { sl@0: TInt numElement = iUpdateReceiverNotificationBatches.Count(); sl@0: CUpdateReceiverNotificationBatch* notifier = NULL; sl@0: CSurfaceUpdateServer* server = (CSurfaceUpdateServer*) Server(); sl@0: for(TInt index = 0; index < numElement; index++) sl@0: { sl@0: notifier = iUpdateReceiverNotificationBatches[index]; sl@0: if(notifier->iType == EUpdateSrvReusable) sl@0: { sl@0: __ASSERT_ALWAYS(notifier->iMsg.IsNull(), CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity)); sl@0: notifier->SetNumUpdateReceivers(server->NumUpdateReceivers()); sl@0: if(numElement > index + 1) sl@0: { sl@0: //to improve a search, append the element to the end of the array sl@0: iUpdateReceiverNotificationBatches.Remove(index); sl@0: iUpdateReceiverNotificationBatches.AppendL(notifier); sl@0: } sl@0: return notifier; sl@0: } sl@0: } sl@0: sl@0: notifier = new (ELeave) CUpdateReceiverNotificationBatch(this, server->NumUpdateReceivers()); sl@0: CleanupStack::PushL(notifier); sl@0: iUpdateReceiverNotificationBatches.AppendL(notifier); sl@0: CleanupStack::Pop(); sl@0: sl@0: return notifier; sl@0: } sl@0: sl@0: void CSurfaceUpdateSession::NotifyWhenAvailable(const RMessage2& aMessage) sl@0: { sl@0: StoreNotification(iAvailable, aMessage, EUpdateSrvAvailable); sl@0: } sl@0: sl@0: void CSurfaceUpdateSession::NotifyWhenDisplayed(const RMessage2& aMessage) sl@0: { sl@0: StoreNotification(iDisplayed, aMessage, EUpdateSrvDisplayed); sl@0: } sl@0: sl@0: void CSurfaceUpdateSession::NotifyWhenDisplayedXTimes(const RMessage2& aMessage) sl@0: { sl@0: StoreNotification(iDisplayedXTimes, aMessage, EUpdateSrvDisplayedXTimes); sl@0: } sl@0: sl@0: void CSurfaceUpdateSession::StoreNotification(CUpdateReceiverNotificationBatch*& aNotifier, const RMessage2& aMessage, TNotificationType aType) sl@0: { sl@0: if(aNotifier) sl@0: { sl@0: if(!aNotifier->iMsg.IsNull()) sl@0: {//not expected behaviour sl@0: //would happen if a client sends the same notification request in a row sl@0: IssueRequestComplete(KErrCancel); sl@0: PanicClient(aMessage, EUpdateServPanicDataIntegrity); sl@0: return; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: TRAPD(res, aNotifier = UpdateReceiverNotificationBatchL()); sl@0: if(res != KErrNone) sl@0: { sl@0: aMessage.Complete(res); sl@0: return; sl@0: } sl@0: } sl@0: sl@0: aNotifier->iMsg = aMessage; sl@0: aNotifier->iType=aType; sl@0: } sl@0: sl@0: /* sl@0: Complete the outstanding requests and reset internal request variables to zero. sl@0: @param aErr Error code for completion. sl@0: */ sl@0: void CSurfaceUpdateSession::IssueRequestComplete(TInt aErr) sl@0: { sl@0: if(iAvailable) sl@0: { sl@0: if(!iAvailable->iMsg.IsNull()) sl@0: { sl@0: iAvailable-> iMsg.Complete(aErr); sl@0: iAvailable->CheckForReuse(); sl@0: } sl@0: iAvailable = NULL; sl@0: } sl@0: sl@0: if(iDisplayed) sl@0: { sl@0: if(!iDisplayed -> iMsg.IsNull()) sl@0: { sl@0: iDisplayed -> iMsg.Complete(aErr); sl@0: iDisplayed->CheckForReuse(); sl@0: } sl@0: iDisplayed = NULL; sl@0: } sl@0: sl@0: if(iDisplayedXTimes) sl@0: { sl@0: if(!iDisplayedXTimes->iMsg.IsNull()) sl@0: { sl@0: iDisplayedXTimes->iMsg.Complete(aErr); sl@0: iDisplayedXTimes->CheckForReuse(); sl@0: } sl@0: iDisplayedXTimes=NULL; sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Redirect call to the DoSubmitUpdateL; error handling sl@0: */ sl@0: void CSurfaceUpdateSession::SubmitUpdate(const RMessage2& aMessage) sl@0: { sl@0: TInt err = KErrNone; sl@0: TRAP(err, DoSubmitUpdateL(aMessage)); sl@0: if(err != KErrNone) sl@0: { sl@0: IssueRequestComplete(err); sl@0: } sl@0: aMessage.Complete(err); sl@0: } sl@0: sl@0: /** sl@0: Issue request for the update to the composition receiver; sl@0: ask notification on composition event if required. sl@0: */ sl@0: void CSurfaceUpdateSession::DoSubmitUpdateL(const RMessage2& aMessage) sl@0: { sl@0: TInt displayedXTimes = 0; sl@0: TInt screen; sl@0: TInt buffer; sl@0: TSurfaceId surfaceId; sl@0: TPckg surfaceIdPckg(surfaceId); sl@0: sl@0: RRegion *region = NULL; sl@0: TRect *rectangleList = NULL; sl@0: sl@0: //extract the composition data sl@0: aMessage.ReadL(1, surfaceIdPckg); sl@0: sl@0: screen = aMessage.Int0(); sl@0: buffer = aMessage.Int2(); sl@0: sl@0: //validate parameters sl@0: if((screen < 0) || (buffer < 0)) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: //Check that we haven't used another update method before sl@0: //The comparison is slightly optimized for performance as oppose to code size sl@0: if(iUpdateMethod == EUpdateMethodGlobal) sl@0: { sl@0: if(screen != KAllScreens) sl@0: User::Leave(KErrNotSupported); sl@0: } sl@0: else if(iUpdateMethod == EUpdateMethodPerScreen) sl@0: { sl@0: if(screen == KAllScreens) sl@0: User::Leave(KErrNotSupported); sl@0: } sl@0: sl@0: TInt len = aMessage.GetDesLength(3); sl@0: if(len > 0) sl@0: { sl@0: rectangleList = (TRect*) (User::AllocL(len)); sl@0: CleanupStack::PushL(rectangleList); sl@0: TPtr8 ptrRect(reinterpret_cast (rectangleList), len); sl@0: aMessage.ReadL(3, ptrRect); sl@0: TInt regionCount = len / sizeof(TRect); sl@0: region = new (ELeave) RRegion(regionCount, rectangleList); sl@0: CleanupStack::PushL(region); sl@0: } sl@0: if(iDisplayedXTimes) sl@0: { sl@0: displayedXTimes = iDisplayedXTimes -> iMsg.Int0(); sl@0: if(displayedXTimes < 1) sl@0: { sl@0: iDisplayedXTimes->iMsg.Complete(KErrArgument); sl@0: iDisplayedXTimes->CheckForReuse(); sl@0: iDisplayedXTimes = NULL; sl@0: } sl@0: } sl@0: sl@0: const CSurfaceUpdateServer* server = static_cast (Server()); sl@0: if(screen != KAllScreens) sl@0: { sl@0: MCompositionSurfaceUpdate* receiver = server->UpdateReceiver(screen); sl@0: if(!receiver) sl@0: { sl@0: User::Leave(KErrUpdateReceiverNotAvailable); sl@0: } sl@0: DispatchUpdate(surfaceId, buffer, region, &displayedXTimes, receiver); sl@0: iUpdateMethod = EUpdateMethodPerScreen; sl@0: } sl@0: else sl@0: { sl@0: DispatchUpdate(surfaceId, buffer, region, &displayedXTimes); sl@0: iUpdateMethod = EUpdateMethodGlobal; sl@0: } sl@0: sl@0: if(region) sl@0: { sl@0: CleanupStack::PopAndDestroy(2, rectangleList); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Dispatch update to the composition update receivers. sl@0: The function could fail to allocate the notification objects sl@0: due to memory shortage, however, the content update command will still be submitted to the GCE. sl@0: */ sl@0: void CSurfaceUpdateSession::DispatchUpdate(const TSurfaceId& aSurfaceId, TInt aBuffer, RRegion* aRegion, TInt* aDisplayedXTimes, MCompositionSurfaceUpdate* aReceiver) sl@0: { sl@0: TInt index = 1; sl@0: TInt numReceivers = 1; sl@0: TInt priority = 0; sl@0: sl@0: if(!aReceiver) sl@0: { sl@0: aReceiver = iUpdateReceiverEntryList[0]->iUpdateReceiver; sl@0: priority = iUpdateReceiverEntryList[0]->iPriority; sl@0: numReceivers = iUpdateReceiverEntryList.Count(); //get the number of all receivers present in the system sl@0: } sl@0: sl@0: for(;;) sl@0: { sl@0: CUpdateReceiverNotification* receiverNotificationAvailable = NULL; sl@0: CUpdateReceiverNotification* receiverNotificationDisplayed = NULL; sl@0: CUpdateReceiverNotification* receiverNotificationDisplayedXTimes = NULL; sl@0: TUint32* timeStamp = NULL; sl@0: sl@0: //activate objects sl@0: if(iAvailable) sl@0: { sl@0: receiverNotificationAvailable = iAvailable->UpdateReceiverNotification(); sl@0: if(!receiverNotificationAvailable) sl@0: { sl@0: iAvailable->iMsg.Complete(KErrNoMemory); sl@0: iAvailable->CheckForReuse(); sl@0: iAvailable = NULL; sl@0: } sl@0: } sl@0: sl@0: if(iDisplayed) sl@0: { sl@0: receiverNotificationDisplayed = iDisplayed->UpdateReceiverNotification(priority); sl@0: if(!receiverNotificationDisplayed) sl@0: { sl@0: iDisplayed->iMsg.Complete(KErrNoMemory); sl@0: iDisplayed->CheckForReuse(); sl@0: iDisplayed = NULL; sl@0: } sl@0: } sl@0: sl@0: if(iDisplayedXTimes) sl@0: { sl@0: receiverNotificationDisplayedXTimes = iDisplayedXTimes->UpdateReceiverNotification(); sl@0: if(!receiverNotificationDisplayedXTimes) sl@0: { sl@0: iDisplayedXTimes->iMsg.Complete(KErrNoMemory); sl@0: iDisplayedXTimes->CheckForReuse(); sl@0: iDisplayedXTimes = NULL; sl@0: } sl@0: } sl@0: sl@0: TRequestStatus *statusAvailable = NULL; sl@0: TRequestStatus *statusDisplayed = NULL; sl@0: TRequestStatus *statusDisplayedXTimes = NULL; sl@0: //activate all notifications sl@0: if(receiverNotificationAvailable) sl@0: { sl@0: statusAvailable = &(receiverNotificationAvailable->Status()); sl@0: receiverNotificationAvailable->Activate(); sl@0: } sl@0: if(receiverNotificationDisplayed) sl@0: { sl@0: statusDisplayed = &(receiverNotificationDisplayed->Status()); sl@0: timeStamp = & receiverNotificationDisplayed -> iTimeStamp; sl@0: receiverNotificationDisplayed->Activate(); sl@0: } sl@0: if(receiverNotificationDisplayedXTimes) sl@0: { sl@0: statusDisplayedXTimes = &(receiverNotificationDisplayedXTimes->Status()); sl@0: receiverNotificationDisplayedXTimes->Activate(); sl@0: } sl@0: //And finally, send request to the receiver sl@0: aReceiver->ContentUpdated(aSurfaceId, aBuffer, aRegion, sl@0: statusAvailable, statusDisplayed, timeStamp, sl@0: statusDisplayedXTimes, statusDisplayedXTimes ? aDisplayedXTimes : NULL); sl@0: sl@0: if(numReceivers > index) sl@0: { sl@0: priority = iUpdateReceiverEntryList[index]->iPriority; sl@0: aReceiver = iUpdateReceiverEntryList[index++]->iUpdateReceiver; sl@0: } sl@0: else sl@0: break; sl@0: }//for(;;) sl@0: sl@0: iAvailable = NULL; sl@0: iDisplayed = NULL; sl@0: iDisplayedXTimes = NULL; sl@0: } sl@0: sl@0: void CSurfaceUpdateSession::CancelAllUpdateNotifications() sl@0: { sl@0: //go through all notification objects and issue request complete for outstanding requests sl@0: TInt count = iUpdateReceiverNotificationBatches.Count(); sl@0: sl@0: for(TInt index = 0; index < count; index++) sl@0: { sl@0: CUpdateReceiverNotificationBatch* notifier = iUpdateReceiverNotificationBatches[index]; sl@0: if(!notifier->iMsg.IsNull()) sl@0: { sl@0: notifier->iMsg.Complete(KErrCancel); sl@0: } sl@0: } sl@0: sl@0: iAvailable = NULL; sl@0: iDisplayed = NULL; sl@0: iDisplayedXTimes = NULL; sl@0: } sl@0: sl@0: //********************* sl@0: CUpdateReceiverNotification::CUpdateReceiverNotification(CActive::TPriority aPriority, TInt aReceiverPriority, CUpdateReceiverNotificationBatch *aParentNotificationBatch) : sl@0: CActive(aPriority), iUpdateReceiverPriority(aReceiverPriority), iParentNotificationBatch(aParentNotificationBatch) sl@0: { sl@0: CActiveScheduler::Add(this); sl@0: #ifdef TEST_SURFACE_UPDATE sl@0: iServer = iParentNotificationBatch->Server(); sl@0: #endif sl@0: } sl@0: sl@0: CUpdateReceiverNotification::~CUpdateReceiverNotification() sl@0: { sl@0: //Content updates can not be cancelled. The user must ensure that the associated content update sl@0: //is complete before deleting this object. sl@0: __ASSERT_ALWAYS(!IsActive(), CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity)); sl@0: } sl@0: sl@0: void CUpdateReceiverNotification::DoCancel() sl@0: { sl@0: //Content Updates can not be cancelled. Content Updates must be allowed to complete normally. sl@0: CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity); sl@0: } sl@0: sl@0: /** sl@0: Is triggered every time the GCE signals on notification objects. sl@0: Delegates processing to the parent notification batch. sl@0: */ sl@0: void CUpdateReceiverNotification::RunL() sl@0: { sl@0: // CReceiverNotification object is deleted here once it is set to self destroying when run. sl@0: if (iSelfDestructWhenRun) sl@0: { sl@0: #ifdef TEST_SURFACE_UPDATE sl@0: DecNumberPendingNotifications(); sl@0: #endif sl@0: delete this; sl@0: return; sl@0: } sl@0: iParentNotificationBatch->ProcessNotificationEvent(this); sl@0: } sl@0: sl@0: TRequestStatus& CUpdateReceiverNotification::Status() sl@0: { sl@0: return iStatus; sl@0: } sl@0: sl@0: void CUpdateReceiverNotification::Activate() sl@0: { sl@0: iStatus = KRequestPending; sl@0: SetActive(); sl@0: } sl@0: sl@0: #ifdef TEST_SURFACE_UPDATE sl@0: void CUpdateReceiverNotification::DecNumberPendingNotifications() sl@0: { sl@0: if (iServer) sl@0: { sl@0: iServer-> iNumberPendingNotification--; sl@0: } sl@0: } sl@0: #endif sl@0: sl@0: /** sl@0: The class maintains the notification objects of the same type and attributed to a sl@0: particular submit update command. sl@0: */ sl@0: CUpdateReceiverNotificationBatch::CUpdateReceiverNotificationBatch(CSurfaceUpdateSession *aSession, TInt aNumReceivers) : sl@0: iSession(aSession), iNumUpdateReceivers(aNumReceivers) sl@0: { sl@0: CheckForReuse(); sl@0: } sl@0: sl@0: CUpdateReceiverNotificationBatch::~CUpdateReceiverNotificationBatch() sl@0: { sl@0: TInt count = iUpdateReceiverNotifications.Count(); sl@0: for(TInt index = 0; index < count; index++) sl@0: { sl@0: CUpdateReceiverNotification* notifier = iUpdateReceiverNotifications[index]; sl@0: // CReceiverNotification active object cannot be destroyed if it is active and waiting for sl@0: // receiver to complete the notification. It deletes itself inside its RunL function when the sl@0: // notification is completed. sl@0: if (notifier->IsActive()) sl@0: { sl@0: notifier->iSelfDestructWhenRun = ETrue; sl@0: #ifdef TEST_SURFACE_UPDATE sl@0: IncNumberPendingNotifications(); sl@0: #endif sl@0: } sl@0: else sl@0: { sl@0: delete notifier; sl@0: } sl@0: } sl@0: iUpdateReceiverNotifications.Close(); sl@0: } sl@0: sl@0: /** sl@0: The function processes signal from composition receiver. sl@0: It completes outstanding messages on the client and set timestamp parameters if appropriate. sl@0: Note that this object will not be removed from the sl@0: array (CSurfaceUpdateSession:: iReceiverNotifications) and can be reused later. sl@0: */ sl@0: void CUpdateReceiverNotificationBatch::ProcessNotificationEvent(CUpdateReceiverNotification* aReceiverNotification) sl@0: { sl@0: TInt index = iUpdateReceiverNotifications.Find(aReceiverNotification); sl@0: __ASSERT_DEBUG(index != KErrNotFound, CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity)); sl@0: iUpdateReceiverNotifications.Remove(index); sl@0: if(iMsg.IsNull()) sl@0: { sl@0: CheckForReuse(); sl@0: delete aReceiverNotification; sl@0: return; // the message has already been completed, possibly, because of request cancelation sl@0: } sl@0: TBool oldCompleteWithSuccess = iCompleteWithSuccess; sl@0: TBool newCompleteWithSuccess = EFalse; sl@0: if(aReceiverNotification->iStatus.Int() == KErrNone) sl@0: { sl@0: iCompleteWithSuccess = ETrue; sl@0: newCompleteWithSuccess = ETrue; sl@0: } sl@0: sl@0: switch(iType) sl@0: { sl@0: case EUpdateSrvAvailable: sl@0: if(iUpdateReceiverNotifications.Count() == 0) sl@0: { sl@0: TInt res = iCompleteWithSuccess ? KErrNone : aReceiverNotification->iStatus.Int(); sl@0: iMsg.Complete(res); sl@0: } sl@0: break; sl@0: case EUpdateSrvDisplayedXTimes: sl@0: if((newCompleteWithSuccess && (index == 0)) || (iUpdateReceiverNotifications.Count() == 0)) sl@0: { sl@0: TInt res = iCompleteWithSuccess ? KErrNone : aReceiverNotification->iStatus.Int(); sl@0: iMsg.Complete(res); sl@0: } sl@0: break; sl@0: case EUpdateSrvDisplayed: sl@0: if(newCompleteWithSuccess && sl@0: ((iHighestPriority < aReceiverNotification->iUpdateReceiverPriority) || !oldCompleteWithSuccess)) sl@0: { sl@0: iHighestPriority = aReceiverNotification->iUpdateReceiverPriority; sl@0: iTimeStamp = aReceiverNotification->iTimeStamp; sl@0: } sl@0: if((newCompleteWithSuccess && (index == 0)) || (iUpdateReceiverNotifications.Count() == 0)) sl@0: { sl@0: TPckgBuf p(iTimeStamp); sl@0: TInt res = iMsg.Write(0, p); //We must not leave here as it will cause panic on Active scheduler. This would be inappropriate for the server side thread. sl@0: if(res == KErrNone) sl@0: { sl@0: res = iCompleteWithSuccess ? KErrNone : aReceiverNotification->iStatus.Int(); sl@0: } sl@0: iMsg.Complete(res); sl@0: } sl@0: break; sl@0: default: sl@0: break; sl@0: } sl@0: sl@0: delete aReceiverNotification; sl@0: CheckForReuse(); sl@0: } sl@0: sl@0: /** sl@0: The method allocates a notification object and inserts it into the list sl@0: */ sl@0: CUpdateReceiverNotification* CUpdateReceiverNotificationBatch::UpdateReceiverNotification(TInt aReceiverPriority) sl@0: { sl@0: __ASSERT_DEBUG(iNumUpdateReceivers > iUpdateReceiverNotifications.Count(), CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity)); sl@0: sl@0: CUpdateReceiverNotification* receiverNotification = new CUpdateReceiverNotification(CActive::EPriorityStandard, aReceiverPriority, this); sl@0: if(receiverNotification) sl@0: { sl@0: TInt res = iUpdateReceiverNotifications.Append(receiverNotification); sl@0: if(res != KErrNone) sl@0: { sl@0: delete receiverNotification; sl@0: receiverNotification = NULL; sl@0: } sl@0: } sl@0: sl@0: return receiverNotification; sl@0: } sl@0: sl@0: /** sl@0: If notification list is empty mark the batch for further use sl@0: */ sl@0: void CUpdateReceiverNotificationBatch::CheckForReuse() sl@0: { sl@0: if(iUpdateReceiverNotifications.Count() == 0) sl@0: { sl@0: iType = EUpdateSrvReusable; sl@0: iCompleteWithSuccess = EFalse; sl@0: iHighestPriority = 0; sl@0: iTimeStamp = 0; sl@0: } sl@0: } sl@0: sl@0: #ifdef TEST_SURFACE_UPDATE sl@0: CSurfaceUpdateServer* CUpdateReceiverNotificationBatch::Server() sl@0: { sl@0: return (CSurfaceUpdateServer*)(iSession->Server()); sl@0: } sl@0: sl@0: void CUpdateReceiverNotificationBatch::IncNumberPendingNotifications() sl@0: { sl@0: CServer2* server = static_cast (Server()); sl@0: if(server) sl@0: { sl@0: (static_cast (server))-> iNumberPendingNotification++; sl@0: } sl@0: } sl@0: #endif sl@0: sl@0: sl@0: /** sl@0: Set number of UpdateReceivers - called when update receivers are added/removed. sl@0: sl@0: @param aNumUpdateReceivers - new number of update receivers for the batch. sl@0: */ sl@0: void CUpdateReceiverNotificationBatch::SetNumUpdateReceivers(TInt aNumUpdateReceivers) sl@0: { sl@0: __ASSERT_DEBUG(aNumUpdateReceivers >= 0 && aNumUpdateReceivers < 1000 /* arbitrary "large" limit */, sl@0: CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity)); sl@0: __ASSERT_DEBUG(iType == EUpdateSrvReusable, sl@0: CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity)); sl@0: iNumUpdateReceivers = aNumUpdateReceivers; sl@0: } sl@0: /** sl@0: sl@0: The class will be used by composition receiver sl@0: */ sl@0: CSurfaceUpdateServerProvider* CSurfaceUpdateServerProvider::NewL(CActive::TPriority aPriority, CSurfaceUpdateServer* aServer) sl@0: { sl@0: CSurfaceUpdateServerProvider* serverProvider = new (ELeave) CSurfaceUpdateServerProvider(aPriority, aServer); sl@0: CleanupStack::PushL(serverProvider); sl@0: serverProvider->ConstructL(); sl@0: CleanupStack::Pop(); sl@0: return serverProvider; sl@0: } sl@0: sl@0: CSurfaceUpdateServerProvider::CSurfaceUpdateServerProvider(CActive::TPriority aPriority, CSurfaceUpdateServer* aServer) : sl@0: CActive(aPriority), iServer(aServer) sl@0: { sl@0: RThread thread; sl@0: iThreadId = thread.Id(); sl@0: } sl@0: sl@0: CSurfaceUpdateServerProvider::~CSurfaceUpdateServerProvider() sl@0: { sl@0: iSemaphore.Close(); sl@0: Cancel(); sl@0: } sl@0: /** sl@0: Create provider and add it to the active scheduler sl@0: */ sl@0: void CSurfaceUpdateServerProvider::ConstructL() sl@0: { sl@0: User::LeaveIfError(iSemaphore.CreateLocal(0)); sl@0: CActiveScheduler::Add(this); sl@0: iStatus = KRequestPending; sl@0: SetActive(); sl@0: } sl@0: sl@0: /** sl@0: Assign composition receiver instance to particular screen. sl@0: The following calls of this function for the same screen will override the previous. sl@0: @see MSurfaceUpdateServerProvider::::Register sl@0: */ sl@0: EXPORT_C TInt CSurfaceUpdateServerProvider::Register(TInt aScreen, CBase* aReceiver, TInt aPriority) sl@0: { sl@0: RThread thread; sl@0: TInt res = thread.Open(iThreadId); sl@0: if(res == KErrNone) sl@0: { sl@0: iScreen = aScreen; sl@0: iUpdateReceiver = aReceiver; sl@0: iPriority = aPriority; sl@0: sl@0: TRequestStatus* status = &iStatus; sl@0: thread.RequestComplete(status, EUpdateServEventRegister); sl@0: thread.Close(); sl@0: iSemaphore.Wait(); sl@0: res = iRegisterErr; sl@0: } sl@0: return res; sl@0: } sl@0: sl@0: /** sl@0: Terminate the SUS and release all memory associated with it. sl@0: The function was introduced for debugging purpose only and is not considered sl@0: as part of public API. sl@0: */ sl@0: EXPORT_C void CSurfaceUpdateServerProvider::Terminate() sl@0: { sl@0: #ifdef TEST_SURFACE_UPDATE sl@0: RThread thread; sl@0: sl@0: if(thread.Open(iThreadId) == KErrNone) sl@0: { sl@0: TInt err = gProviderFastLock.CreateLocal(); sl@0: __ASSERT_ALWAYS(err == KErrNone || err == KErrAlreadyExists, CSurfaceUpdateServer::PanicServer(EUpdateServPanicGlobalFastLock)); sl@0: sl@0: gProviderFastLock.Wait(); sl@0: gProvider = NULL; sl@0: if (iServer) sl@0: { sl@0: while((static_cast (iServer))-> iNumberPendingNotification) sl@0: User::After(TTimeIntervalMicroSeconds32(1000)); sl@0: } sl@0: TRequestStatus* status = &iStatus; sl@0: thread.RequestComplete(status, EUpdateServEventTerminate); sl@0: sl@0: //wait until the thread dies sl@0: TRequestStatus status1; sl@0: thread.Logon(status1); sl@0: User::WaitForRequest(status1); sl@0: thread.Close(); sl@0: sl@0: gProviderFastLock.Close(); sl@0: } sl@0: #endif sl@0: } sl@0: sl@0: /** sl@0: The function processes signals which come from composition receiver thread. sl@0: */ sl@0: void CSurfaceUpdateServerProvider::RunL() sl@0: { sl@0: switch(iStatus.Int()) sl@0: { sl@0: case EUpdateServEventTerminate: sl@0: CActiveScheduler::Stop(); sl@0: return; sl@0: case EUpdateServEventRegister: sl@0: iRegisterErr = iServer->Register(iScreen, iUpdateReceiver, iPriority); sl@0: iUpdateReceiver = NULL; sl@0: iStatus = KRequestPending; sl@0: SetActive(); sl@0: iSemaphore.Signal(); sl@0: break; sl@0: default : sl@0: CSurfaceUpdateServer::PanicServer(EUpdateServPanicBadRequest); sl@0: iStatus = KRequestPending; sl@0: SetActive(); sl@0: break; sl@0: } sl@0: } sl@0: sl@0: void CSurfaceUpdateServerProvider::DoCancel() sl@0: { sl@0: } sl@0: sl@0: /** sl@0: Spawn a thread within WSERV process. This will lead to starting the surface update server in it sl@0: @publishedPartner sl@0: @prototype Intended to be used by Surface Update control flow sl@0: sl@0: @param aUpdateProvider - [out] reference pointer to surface update server provider, sl@0: which will be set when the server is started. The variable will be used to registry sl@0: composition receiver instances. The caller doesn't acquire the ownership of this instance, sl@0: thus mustn't delete it. The pointer will be valid until server is operating, sl@0: i.e. system is up. sl@0: sl@0: @return KErrNone if an operation is successful, any other system error codes otherwise sl@0: */ sl@0: EXPORT_C TInt StartSurfaceUpdateServer(MSurfaceUpdateServerProvider*& aSurfaceUpdateServerProvider) sl@0: { sl@0: #ifndef TEST_SURFACE_UPDATE sl@0: TPtrC serverName(KSurfaceUpdateServerName); sl@0: #else sl@0: TPtrC serverName(KTestSurfaceUpdateServerName); sl@0: #endif sl@0: //locking sl@0: TInt err = gProviderFastLock.CreateLocal(); sl@0: sl@0: if (err != KErrNone && err != KErrAlreadyExists) sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: gProviderFastLock.Wait(); sl@0: sl@0: TAny *provider = gProvider; sl@0: if(provider) sl@0: { sl@0: aSurfaceUpdateServerProvider = static_cast (provider); sl@0: gProviderFastLock.Signal(); sl@0: return KErrNone; sl@0: } sl@0: TFullName name; sl@0: RThread serverThread; sl@0: TInt res = KErrAlreadyExists; sl@0: sl@0: TFindServer findSurfaceUpdateServer(serverName); sl@0: // Need to check that the server exists. sl@0: if (findSurfaceUpdateServer.Next(name) !=KErrNone) sl@0: { sl@0: TTime tm; sl@0: TBuf<32> buf; sl@0: tm.UniversalTime(); sl@0: TRAP(res, tm.FormatL(buf, _L("_%H%T%S%C"))); sl@0: if(res != KErrNone) sl@0: { sl@0: gProviderFastLock.Signal(); sl@0: return res; sl@0: } sl@0: TBuf<128> threadName(serverName); sl@0: threadName.Append(buf); //guarantee uniqueness of the thread name sl@0: // Create the thread for the server. sl@0: res = serverThread.Create(threadName, sl@0: CSurfaceUpdateServer::ThreadFunction, sl@0: KDefaultStackSize, sl@0: KDefaultHeapSize, sl@0: KDefaultHeapSize, sl@0: (TAny*) &aSurfaceUpdateServerProvider sl@0: ); sl@0: // The thread has been created OK so get it started - however sl@0: // we need to make sure that it has started before we continue. sl@0: if (res==KErrNone) sl@0: { sl@0: TRequestStatus rendezvousStatus; sl@0: TThreadPriority priority = RThread().Priority(); sl@0: serverThread.SetPriority(priority); // The same as the priority of the creating thread sl@0: serverThread.Rendezvous(rendezvousStatus); sl@0: serverThread.Resume(); sl@0: User::WaitForRequest(rendezvousStatus); sl@0: res = rendezvousStatus.Int(); sl@0: gProvider = aSurfaceUpdateServerProvider; sl@0: } sl@0: // The thread has not been created - clearly there's been a problem. sl@0: else sl@0: { sl@0: serverThread.Close(); sl@0: } sl@0: } sl@0: gProviderFastLock.Signal(); sl@0: return res; sl@0: }