Update contrib.
1 // Copyright (c) 2006-2010 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
16 #include "surfaceupdateserver.h"
18 #include <graphics/compositionsurfaceupdate.h>
19 #include <graphics/extensioncontainer.h>
21 #include "surfaceupdate.h"
23 #ifdef TEST_SURFACE_UPDATE
24 #include "surfaceupdatetest.h"
28 const TUint KDefaultHeapSize=0x10000;
30 void *gProvider = NULL;
31 RFastLock gProviderFastLock;
34 The server maintains session with the clients.
35 It starts during the initialization of the Content update receiver thread.
37 CSurfaceUpdateServer* CSurfaceUpdateServer::NewL()
39 CSurfaceUpdateServer* server = new (ELeave) CSurfaceUpdateServer(EPriorityStandard);
40 CleanupStack::PushL(server);
46 CSurfaceUpdateServer::CSurfaceUpdateServer(CActive::TPriority aPriority) :
51 CSurfaceUpdateServer::~CSurfaceUpdateServer()
53 iUpdateReceiver.Close();
54 iUpdateReceiverPriorityOrder.ResetAndDestroy();
55 delete iServerProvider;
58 void CSurfaceUpdateServer::ConstructL()
60 iServerProvider = CSurfaceUpdateServerProvider::NewL(EPriorityStandard, this);
64 Assign Content update receiver instance to particular screen.
65 The following calls of this function will override the previous.
67 @see MSurfaceUpdateServerProvider::Register
69 TInt CSurfaceUpdateServer::Register(TInt aScreen, CBase* aUpdateReceiver, TInt aPriority)
77 while((iUpdateReceiver.Count() <= aScreen) && (err == KErrNone))
79 err = iUpdateReceiver.Append(NULL);
84 TUpdateReceiverPriorityEntry *receiverPriorityEntry = NULL;
86 {//Client wants to unregister the Content update receiver which has been associated with the given screen number.
87 MCompositionSurfaceUpdate* receiver = iUpdateReceiver[aScreen];
90 TInt num = iUpdateReceiverPriorityOrder.Count() - 1;
92 {//Content update receiver must be in priority list, therefore we don't need to check num >= 0
93 receiverPriorityEntry = iUpdateReceiverPriorityOrder[num];
94 if(receiverPriorityEntry->iUpdateReceiver == receiver)
95 {//remove the Content update receiver from the priority list
96 iUpdateReceiverPriorityOrder.Remove(num);
97 delete receiverPriorityEntry;
102 iUpdateReceiver[aScreen] = NULL; //unregister the Content update receiver by setting the entry to NULL
107 CExtensionContainer* extCont=static_cast<CExtensionContainer*>(aUpdateReceiver);
108 MCompositionSurfaceUpdate* updateReceiver=extCont->GetInterface<MCompositionSurfaceUpdate>();
111 receiverPriorityEntry = new TUpdateReceiverPriorityEntry;
112 if(!receiverPriorityEntry)
114 receiverPriorityEntry->iPriority = aPriority;
115 receiverPriorityEntry->iUpdateReceiver = updateReceiver;
117 err = iUpdateReceiverPriorityOrder.InsertInOrder(receiverPriorityEntry, CSurfaceUpdateServer::CompareUpdateReceiverPriority);
120 iUpdateReceiver[aScreen] = updateReceiver;
124 delete receiverPriorityEntry;
137 Create a new session with a server. Derived from CSession2.
139 @param aVersion required version of the server
140 @param aMessage message from the client.
141 @return New instance of the CSurfaceUpdateSession.
143 CSession2* CSurfaceUpdateServer::NewSessionL(const TVersion& aVersion, const RMessage2& /*aMessage*/) const
145 // Check that the version is OK
146 TVersion v(KSurfaceUpdateServMajorVersionNumber,KSurfaceUpdateServMinorVersionNumber,KSurfaceUpdateServBuildVersionNumber);
147 if (!User::QueryVersionSupported(v,aVersion))
148 User::Leave(KErrNotSupported);
150 // Security is not an issue, any client can have connection to the server
151 // Create the session.
152 return new (ELeave) CSurfaceUpdateSession(UpdateReceiverPriority());
156 Utility function to panic the server
158 @param aPanic Panic code
160 void CSurfaceUpdateServer::PanicServer(TSurfaceUpdateServPanic aPanic)
162 _LIT(KTxtServerPanic,"Surface Update Server panic");
163 User::Panic(KTxtServerPanic, aPanic);
167 Provide composition receiver.
169 @param aScreen targeted screen
170 @return Composition receiver object, associated to particular screen
172 MCompositionSurfaceUpdate* CSurfaceUpdateServer::UpdateReceiver(TInt aScreen) const
174 if(aScreen >= iUpdateReceiver.Count())//negative value won't reach this point
176 return iUpdateReceiver[aScreen];
179 TInt CSurfaceUpdateServer::ThreadFunction(TAny* aAny)
181 // get clean-up stack
182 CTrapCleanup* cleanup=CTrapCleanup::New();
183 __ASSERT_ALWAYS(cleanup!=NULL, CSurfaceUpdateServer::PanicServer(EUpdateServPanicNoMemory));
185 // create an active scheduler and server
186 CActiveScheduler *pA = new CActiveScheduler;
187 __ASSERT_ALWAYS(pA != NULL, CSurfaceUpdateServer::PanicServer(EUpdateServPanicNoMemory));
189 //Install the active scheduler
190 CActiveScheduler::Install(pA);
192 CSurfaceUpdateServer *pS = NULL;
193 TRAPD(err, pS = CSurfaceUpdateServer::NewL());
194 __ASSERT_ALWAYS(err == KErrNone, CSurfaceUpdateServer::PanicServer(EUpdateServPanicNoMemory));
197 #ifndef TEST_SURFACE_UPDATE
198 err = pS->Start(KSurfaceUpdateServerName);
200 err = pS->Start(KTestSurfaceUpdateServerName);
205 CSurfaceUpdateServer::PanicServer(EUpdateServPanicStartUp);
207 *(static_cast <MSurfaceUpdateServerProvider**> (aAny)) = pS->SurfaceUpdateProvider();
209 // Let everyone know that we are ready to
210 // deal with requests.
211 RThread::Rendezvous(KErrNone);
212 // And start fielding requests from client(s).
213 CActiveScheduler::Start();
223 inline TInt CSurfaceUpdateServer::NumUpdateReceivers() const
225 return iUpdateReceiver.Count();
229 Compare two content update receiver entries according to their priority.
230 The function is used when receiver priority entry is inserted/retrieved from the array (iCompReceiverPriorityOrder).
232 @return zero, if the priorities of two receivers are equal;
233 a negative value, if the priority of the first receiver is less than the priority of the second one;
234 a positive value, if the priority of the first receiver is greater than the priority of the second one.
236 TInt CSurfaceUpdateServer::CompareUpdateReceiverPriority(const TUpdateReceiverPriorityEntry& aEntry1, const TUpdateReceiverPriorityEntry& aEntry2)
238 return aEntry2.iPriority - aEntry1.iPriority;
242 class CSurfaceUpdateSession
244 Maintain the channel between clients and the server.
245 Functions are provided will respond appropriately to client messages.
248 CSurfaceUpdateSession::CSurfaceUpdateSession(const RPointerArray<TUpdateReceiverPriorityEntry>& aEntryList) :
250 iUpdateReceiverEntryList(aEntryList)
255 Cancel any outstanding client notification requests.
256 All resources owned by the session will either be immediately released or
257 scheduled for deferred deletion.
259 CSurfaceUpdateSession::~CSurfaceUpdateSession()
261 CancelAllUpdateNotifications();
262 iUpdateReceiverNotificationBatches.ResetAndDestroy();
266 Main function which deals with requests from clients.
268 void CSurfaceUpdateSession::ServiceL(const RMessage2& aMessage)
270 switch (aMessage.Function())
272 case EUpdateServNotifyWhenAvailable:
273 NotifyWhenAvailable(aMessage);
275 case EUpdateServNotifyWhenDisplayed:
276 NotifyWhenDisplayed(aMessage);
278 case EUpdateServNotifyWhenDisplayedXTimes:
279 NotifyWhenDisplayedXTimes(aMessage);
281 case EUpdateServSubmitUpdate:
282 SubmitUpdate(aMessage);
284 case EUpdateServCancelAllNotifications:
285 CancelAllUpdateNotifications();
286 aMessage.Complete(KErrNone);
288 #ifdef TEST_SURFACE_UPDATE
291 SetHeapFailure(aMessage);
296 PanicClient(aMessage, EUpdateServPanicBadRequest);
301 #ifdef TEST_SURFACE_UPDATE
303 Simulate heap allocation failure for the SUS thread's heap.
306 void CSurfaceUpdateSession::SetHeapFailure(const RMessage2& aMessage)
308 TInt numElement = iUpdateReceiverNotificationBatches.Count();
312 CUpdateReceiverNotificationBatch* batch = iUpdateReceiverNotificationBatches[index];
313 if(batch->iType == EUpdateSrvReusable)
315 iUpdateReceiverNotificationBatches.Remove(index);
326 iUpdateReceiverNotificationBatches.Reset();
328 TInt failRate = aMessage.Int0();
335 __UHEAP_SETFAIL(RHeap::EDeterministic, failRate);
337 aMessage.Complete(KErrNone);
341 void CSurfaceUpdateSession::PanicClient(const RMessage2& aMessage, TInt aPanic) const
343 _LIT(KTxtServer,"SurfUpServ");
344 aMessage.Panic(KTxtServer, aPanic);
348 Return first inactive spare notification object stored in the notification array,
349 create a new one if fail to find it in the array.
351 CUpdateReceiverNotificationBatch* CSurfaceUpdateSession::UpdateReceiverNotificationBatchL()
353 TInt numElement = iUpdateReceiverNotificationBatches.Count();
354 CUpdateReceiverNotificationBatch* notifier = NULL;
355 CSurfaceUpdateServer* server = (CSurfaceUpdateServer*) Server();
356 for(TInt index = 0; index < numElement; index++)
358 notifier = iUpdateReceiverNotificationBatches[index];
359 if(notifier->iType == EUpdateSrvReusable)
361 __ASSERT_ALWAYS(notifier->iMsg.IsNull(), CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity));
362 notifier->SetNumUpdateReceivers(server->NumUpdateReceivers());
363 if(numElement > index + 1)
365 //to improve a search, append the element to the end of the array
366 iUpdateReceiverNotificationBatches.Remove(index);
367 iUpdateReceiverNotificationBatches.AppendL(notifier);
373 notifier = new (ELeave) CUpdateReceiverNotificationBatch(this, server->NumUpdateReceivers());
374 CleanupStack::PushL(notifier);
375 iUpdateReceiverNotificationBatches.AppendL(notifier);
381 void CSurfaceUpdateSession::NotifyWhenAvailable(const RMessage2& aMessage)
383 StoreNotification(iAvailable, aMessage, EUpdateSrvAvailable);
386 void CSurfaceUpdateSession::NotifyWhenDisplayed(const RMessage2& aMessage)
388 StoreNotification(iDisplayed, aMessage, EUpdateSrvDisplayed);
391 void CSurfaceUpdateSession::NotifyWhenDisplayedXTimes(const RMessage2& aMessage)
393 StoreNotification(iDisplayedXTimes, aMessage, EUpdateSrvDisplayedXTimes);
396 void CSurfaceUpdateSession::StoreNotification(CUpdateReceiverNotificationBatch*& aNotifier, const RMessage2& aMessage, TNotificationType aType)
400 if(!aNotifier->iMsg.IsNull())
401 {//not expected behaviour
402 //would happen if a client sends the same notification request in a row
403 IssueRequestComplete(KErrCancel);
404 PanicClient(aMessage, EUpdateServPanicDataIntegrity);
410 TRAPD(res, aNotifier = UpdateReceiverNotificationBatchL());
413 aMessage.Complete(res);
418 aNotifier->iMsg = aMessage;
419 aNotifier->iType=aType;
423 Complete the outstanding requests and reset internal request variables to zero.
424 @param aErr Error code for completion.
426 void CSurfaceUpdateSession::IssueRequestComplete(TInt aErr)
430 if(!iAvailable->iMsg.IsNull())
432 iAvailable-> iMsg.Complete(aErr);
433 iAvailable->CheckForReuse();
440 if(!iDisplayed -> iMsg.IsNull())
442 iDisplayed -> iMsg.Complete(aErr);
443 iDisplayed->CheckForReuse();
450 if(!iDisplayedXTimes->iMsg.IsNull())
452 iDisplayedXTimes->iMsg.Complete(aErr);
453 iDisplayedXTimes->CheckForReuse();
455 iDisplayedXTimes=NULL;
460 Redirect call to the DoSubmitUpdateL; error handling
462 void CSurfaceUpdateSession::SubmitUpdate(const RMessage2& aMessage)
465 TRAP(err, DoSubmitUpdateL(aMessage));
468 IssueRequestComplete(err);
470 aMessage.Complete(err);
474 Issue request for the update to the composition receiver;
475 ask notification on composition event if required.
477 void CSurfaceUpdateSession::DoSubmitUpdateL(const RMessage2& aMessage)
479 TInt displayedXTimes = 0;
482 TSurfaceId surfaceId;
483 TPckg<TSurfaceId> surfaceIdPckg(surfaceId);
485 RRegion *region = NULL;
486 TRect *rectangleList = NULL;
488 //extract the composition data
489 aMessage.ReadL(1, surfaceIdPckg);
491 screen = aMessage.Int0();
492 buffer = aMessage.Int2();
494 //validate parameters
495 if((screen < 0) || (buffer < 0))
497 User::Leave(KErrArgument);
499 //Check that we haven't used another update method before
500 //The comparison is slightly optimized for performance as oppose to code size
501 if(iUpdateMethod == EUpdateMethodGlobal)
503 if(screen != KAllScreens)
504 User::Leave(KErrNotSupported);
506 else if(iUpdateMethod == EUpdateMethodPerScreen)
508 if(screen == KAllScreens)
509 User::Leave(KErrNotSupported);
512 TInt len = aMessage.GetDesLength(3);
515 rectangleList = (TRect*) (User::AllocL(len));
516 CleanupStack::PushL(rectangleList);
517 TPtr8 ptrRect(reinterpret_cast<TUint8*> (rectangleList), len);
518 aMessage.ReadL(3, ptrRect);
519 TInt regionCount = len / sizeof(TRect);
520 region = new (ELeave) RRegion(regionCount, rectangleList);
521 CleanupStack::PushL(region);
525 displayedXTimes = iDisplayedXTimes -> iMsg.Int0();
526 if(displayedXTimes < 1)
528 iDisplayedXTimes->iMsg.Complete(KErrArgument);
529 iDisplayedXTimes->CheckForReuse();
530 iDisplayedXTimes = NULL;
534 const CSurfaceUpdateServer* server = static_cast <const CSurfaceUpdateServer*> (Server());
535 if(screen != KAllScreens)
537 MCompositionSurfaceUpdate* receiver = server->UpdateReceiver(screen);
540 User::Leave(KErrUpdateReceiverNotAvailable);
542 DispatchUpdate(surfaceId, buffer, region, &displayedXTimes, receiver);
543 iUpdateMethod = EUpdateMethodPerScreen;
547 DispatchUpdate(surfaceId, buffer, region, &displayedXTimes);
548 iUpdateMethod = EUpdateMethodGlobal;
553 CleanupStack::PopAndDestroy(2, rectangleList);
558 Dispatch update to the composition update receivers.
559 The function could fail to allocate the notification objects
560 due to memory shortage, however, the content update command will still be submitted to the GCE.
562 void CSurfaceUpdateSession::DispatchUpdate(const TSurfaceId& aSurfaceId, TInt aBuffer, RRegion* aRegion, TInt* aDisplayedXTimes, MCompositionSurfaceUpdate* aReceiver)
565 TInt numReceivers = 1;
570 aReceiver = iUpdateReceiverEntryList[0]->iUpdateReceiver;
571 priority = iUpdateReceiverEntryList[0]->iPriority;
572 numReceivers = iUpdateReceiverEntryList.Count(); //get the number of all receivers present in the system
577 CUpdateReceiverNotification* receiverNotificationAvailable = NULL;
578 CUpdateReceiverNotification* receiverNotificationDisplayed = NULL;
579 CUpdateReceiverNotification* receiverNotificationDisplayedXTimes = NULL;
580 TUint32* timeStamp = NULL;
585 receiverNotificationAvailable = iAvailable->UpdateReceiverNotification();
586 if(!receiverNotificationAvailable)
588 iAvailable->iMsg.Complete(KErrNoMemory);
589 iAvailable->CheckForReuse();
596 receiverNotificationDisplayed = iDisplayed->UpdateReceiverNotification(priority);
597 if(!receiverNotificationDisplayed)
599 iDisplayed->iMsg.Complete(KErrNoMemory);
600 iDisplayed->CheckForReuse();
607 receiverNotificationDisplayedXTimes = iDisplayedXTimes->UpdateReceiverNotification();
608 if(!receiverNotificationDisplayedXTimes)
610 iDisplayedXTimes->iMsg.Complete(KErrNoMemory);
611 iDisplayedXTimes->CheckForReuse();
612 iDisplayedXTimes = NULL;
616 TRequestStatus *statusAvailable = NULL;
617 TRequestStatus *statusDisplayed = NULL;
618 TRequestStatus *statusDisplayedXTimes = NULL;
619 //activate all notifications
620 if(receiverNotificationAvailable)
622 statusAvailable = &(receiverNotificationAvailable->Status());
623 receiverNotificationAvailable->Activate();
625 if(receiverNotificationDisplayed)
627 statusDisplayed = &(receiverNotificationDisplayed->Status());
628 timeStamp = & receiverNotificationDisplayed -> iTimeStamp;
629 receiverNotificationDisplayed->Activate();
631 if(receiverNotificationDisplayedXTimes)
633 statusDisplayedXTimes = &(receiverNotificationDisplayedXTimes->Status());
634 receiverNotificationDisplayedXTimes->Activate();
636 //And finally, send request to the receiver
637 aReceiver->ContentUpdated(aSurfaceId, aBuffer, aRegion,
638 statusAvailable, statusDisplayed, timeStamp,
639 statusDisplayedXTimes, statusDisplayedXTimes ? aDisplayedXTimes : NULL);
641 if(numReceivers > index)
643 priority = iUpdateReceiverEntryList[index]->iPriority;
644 aReceiver = iUpdateReceiverEntryList[index++]->iUpdateReceiver;
652 iDisplayedXTimes = NULL;
655 void CSurfaceUpdateSession::CancelAllUpdateNotifications()
657 //go through all notification objects and issue request complete for outstanding requests
658 TInt count = iUpdateReceiverNotificationBatches.Count();
660 for(TInt index = 0; index < count; index++)
662 CUpdateReceiverNotificationBatch* notifier = iUpdateReceiverNotificationBatches[index];
663 if(!notifier->iMsg.IsNull())
665 notifier->iMsg.Complete(KErrCancel);
671 iDisplayedXTimes = NULL;
674 //*********************
675 CUpdateReceiverNotification::CUpdateReceiverNotification(CActive::TPriority aPriority, TInt aReceiverPriority, CUpdateReceiverNotificationBatch *aParentNotificationBatch) :
676 CActive(aPriority), iUpdateReceiverPriority(aReceiverPriority), iParentNotificationBatch(aParentNotificationBatch)
678 CActiveScheduler::Add(this);
679 #ifdef TEST_SURFACE_UPDATE
680 iServer = iParentNotificationBatch->Server();
684 CUpdateReceiverNotification::~CUpdateReceiverNotification()
686 //Content updates can not be cancelled. The user must ensure that the associated content update
687 //is complete before deleting this object.
688 __ASSERT_ALWAYS(!IsActive(), CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity));
691 void CUpdateReceiverNotification::DoCancel()
693 //Content Updates can not be cancelled. Content Updates must be allowed to complete normally.
694 CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity);
698 Is triggered every time the GCE signals on notification objects.
699 Delegates processing to the parent notification batch.
701 void CUpdateReceiverNotification::RunL()
703 // CReceiverNotification object is deleted here once it is set to self destroying when run.
704 if (iSelfDestructWhenRun)
706 #ifdef TEST_SURFACE_UPDATE
707 DecNumberPendingNotifications();
712 iParentNotificationBatch->ProcessNotificationEvent(this);
715 TRequestStatus& CUpdateReceiverNotification::Status()
720 void CUpdateReceiverNotification::Activate()
722 iStatus = KRequestPending;
726 #ifdef TEST_SURFACE_UPDATE
727 void CUpdateReceiverNotification::DecNumberPendingNotifications()
731 iServer-> iNumberPendingNotification--;
737 The class maintains the notification objects of the same type and attributed to a
738 particular submit update command.
740 CUpdateReceiverNotificationBatch::CUpdateReceiverNotificationBatch(CSurfaceUpdateSession *aSession, TInt aNumReceivers) :
741 iSession(aSession), iNumUpdateReceivers(aNumReceivers)
746 CUpdateReceiverNotificationBatch::~CUpdateReceiverNotificationBatch()
748 TInt count = iUpdateReceiverNotifications.Count();
749 for(TInt index = 0; index < count; index++)
751 CUpdateReceiverNotification* notifier = iUpdateReceiverNotifications[index];
752 // CReceiverNotification active object cannot be destroyed if it is active and waiting for
753 // receiver to complete the notification. It deletes itself inside its RunL function when the
754 // notification is completed.
755 if (notifier->IsActive())
757 notifier->iSelfDestructWhenRun = ETrue;
758 #ifdef TEST_SURFACE_UPDATE
759 IncNumberPendingNotifications();
767 iUpdateReceiverNotifications.Close();
771 The function processes signal from composition receiver.
772 It completes outstanding messages on the client and set timestamp parameters if appropriate.
773 Note that this object will not be removed from the
774 array (CSurfaceUpdateSession:: iReceiverNotifications) and can be reused later.
776 void CUpdateReceiverNotificationBatch::ProcessNotificationEvent(CUpdateReceiverNotification* aReceiverNotification)
778 TInt index = iUpdateReceiverNotifications.Find(aReceiverNotification);
779 __ASSERT_DEBUG(index != KErrNotFound, CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity));
780 iUpdateReceiverNotifications.Remove(index);
784 delete aReceiverNotification;
785 return; // the message has already been completed, possibly, because of request cancelation
787 TBool oldCompleteWithSuccess = iCompleteWithSuccess;
788 TBool newCompleteWithSuccess = EFalse;
789 if(aReceiverNotification->iStatus.Int() == KErrNone)
791 iCompleteWithSuccess = ETrue;
792 newCompleteWithSuccess = ETrue;
797 case EUpdateSrvAvailable:
798 if(iUpdateReceiverNotifications.Count() == 0)
800 TInt res = iCompleteWithSuccess ? KErrNone : aReceiverNotification->iStatus.Int();
804 case EUpdateSrvDisplayedXTimes:
805 if((newCompleteWithSuccess && (index == 0)) || (iUpdateReceiverNotifications.Count() == 0))
807 TInt res = iCompleteWithSuccess ? KErrNone : aReceiverNotification->iStatus.Int();
811 case EUpdateSrvDisplayed:
812 if(newCompleteWithSuccess &&
813 ((iHighestPriority < aReceiverNotification->iUpdateReceiverPriority) || !oldCompleteWithSuccess))
815 iHighestPriority = aReceiverNotification->iUpdateReceiverPriority;
816 iTimeStamp = aReceiverNotification->iTimeStamp;
818 if((newCompleteWithSuccess && (index == 0)) || (iUpdateReceiverNotifications.Count() == 0))
820 TPckgBuf<TUint32> p(iTimeStamp);
821 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.
824 res = iCompleteWithSuccess ? KErrNone : aReceiverNotification->iStatus.Int();
833 delete aReceiverNotification;
838 The method allocates a notification object and inserts it into the list
840 CUpdateReceiverNotification* CUpdateReceiverNotificationBatch::UpdateReceiverNotification(TInt aReceiverPriority)
842 __ASSERT_DEBUG(iNumUpdateReceivers > iUpdateReceiverNotifications.Count(), CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity));
844 CUpdateReceiverNotification* receiverNotification = new CUpdateReceiverNotification(CActive::EPriorityStandard, aReceiverPriority, this);
845 if(receiverNotification)
847 TInt res = iUpdateReceiverNotifications.Append(receiverNotification);
850 delete receiverNotification;
851 receiverNotification = NULL;
855 return receiverNotification;
859 If notification list is empty mark the batch for further use
861 void CUpdateReceiverNotificationBatch::CheckForReuse()
863 if(iUpdateReceiverNotifications.Count() == 0)
865 iType = EUpdateSrvReusable;
866 iCompleteWithSuccess = EFalse;
867 iHighestPriority = 0;
872 #ifdef TEST_SURFACE_UPDATE
873 CSurfaceUpdateServer* CUpdateReceiverNotificationBatch::Server()
875 return (CSurfaceUpdateServer*)(iSession->Server());
878 void CUpdateReceiverNotificationBatch::IncNumberPendingNotifications()
880 CServer2* server = static_cast<CServer2*> (Server());
883 (static_cast<CSurfaceUpdateServer*> (server))-> iNumberPendingNotification++;
890 Set number of UpdateReceivers - called when update receivers are added/removed.
892 @param aNumUpdateReceivers - new number of update receivers for the batch.
894 void CUpdateReceiverNotificationBatch::SetNumUpdateReceivers(TInt aNumUpdateReceivers)
896 __ASSERT_DEBUG(aNumUpdateReceivers >= 0 && aNumUpdateReceivers < 1000 /* arbitrary "large" limit */,
897 CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity));
898 __ASSERT_DEBUG(iType == EUpdateSrvReusable,
899 CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity));
900 iNumUpdateReceivers = aNumUpdateReceivers;
904 The class will be used by composition receiver
906 CSurfaceUpdateServerProvider* CSurfaceUpdateServerProvider::NewL(CActive::TPriority aPriority, CSurfaceUpdateServer* aServer)
908 CSurfaceUpdateServerProvider* serverProvider = new (ELeave) CSurfaceUpdateServerProvider(aPriority, aServer);
909 CleanupStack::PushL(serverProvider);
910 serverProvider->ConstructL();
912 return serverProvider;
915 CSurfaceUpdateServerProvider::CSurfaceUpdateServerProvider(CActive::TPriority aPriority, CSurfaceUpdateServer* aServer) :
916 CActive(aPriority), iServer(aServer)
919 iThreadId = thread.Id();
922 CSurfaceUpdateServerProvider::~CSurfaceUpdateServerProvider()
928 Create provider and add it to the active scheduler
930 void CSurfaceUpdateServerProvider::ConstructL()
932 User::LeaveIfError(iSemaphore.CreateLocal(0));
933 CActiveScheduler::Add(this);
934 iStatus = KRequestPending;
939 Assign composition receiver instance to particular screen.
940 The following calls of this function for the same screen will override the previous.
941 @see MSurfaceUpdateServerProvider::::Register
943 EXPORT_C TInt CSurfaceUpdateServerProvider::Register(TInt aScreen, CBase* aReceiver, TInt aPriority)
946 TInt res = thread.Open(iThreadId);
950 iUpdateReceiver = aReceiver;
951 iPriority = aPriority;
953 TRequestStatus* status = &iStatus;
954 thread.RequestComplete(status, EUpdateServEventRegister);
963 Terminate the SUS and release all memory associated with it.
964 The function was introduced for debugging purpose only and is not considered
965 as part of public API.
967 EXPORT_C void CSurfaceUpdateServerProvider::Terminate()
969 #ifdef TEST_SURFACE_UPDATE
972 if(thread.Open(iThreadId) == KErrNone)
974 TInt err = gProviderFastLock.CreateLocal();
975 __ASSERT_ALWAYS(err == KErrNone || err == KErrAlreadyExists, CSurfaceUpdateServer::PanicServer(EUpdateServPanicGlobalFastLock));
977 gProviderFastLock.Wait();
981 while((static_cast<CSurfaceUpdateServer*> (iServer))-> iNumberPendingNotification)
982 User::After(TTimeIntervalMicroSeconds32(1000));
984 TRequestStatus* status = &iStatus;
985 thread.RequestComplete(status, EUpdateServEventTerminate);
987 //wait until the thread dies
988 TRequestStatus status1;
989 thread.Logon(status1);
990 User::WaitForRequest(status1);
993 gProviderFastLock.Close();
999 The function processes signals which come from composition receiver thread.
1001 void CSurfaceUpdateServerProvider::RunL()
1003 switch(iStatus.Int())
1005 case EUpdateServEventTerminate:
1006 CActiveScheduler::Stop();
1008 case EUpdateServEventRegister:
1009 iRegisterErr = iServer->Register(iScreen, iUpdateReceiver, iPriority);
1010 iUpdateReceiver = NULL;
1011 iStatus = KRequestPending;
1013 iSemaphore.Signal();
1016 CSurfaceUpdateServer::PanicServer(EUpdateServPanicBadRequest);
1017 iStatus = KRequestPending;
1023 void CSurfaceUpdateServerProvider::DoCancel()
1028 Spawn a thread within WSERV process. This will lead to starting the surface update server in it
1030 @prototype Intended to be used by Surface Update control flow
1032 @param aUpdateProvider - [out] reference pointer to surface update server provider,
1033 which will be set when the server is started. The variable will be used to registry
1034 composition receiver instances. The caller doesn't acquire the ownership of this instance,
1035 thus mustn't delete it. The pointer will be valid until server is operating,
1038 @return KErrNone if an operation is successful, any other system error codes otherwise
1040 EXPORT_C TInt StartSurfaceUpdateServer(MSurfaceUpdateServerProvider*& aSurfaceUpdateServerProvider)
1042 #ifndef TEST_SURFACE_UPDATE
1043 TPtrC serverName(KSurfaceUpdateServerName);
1045 TPtrC serverName(KTestSurfaceUpdateServerName);
1048 TInt err = gProviderFastLock.CreateLocal();
1050 if (err != KErrNone && err != KErrAlreadyExists)
1055 gProviderFastLock.Wait();
1057 TAny *provider = gProvider;
1060 aSurfaceUpdateServerProvider = static_cast <MSurfaceUpdateServerProvider*> (provider);
1061 gProviderFastLock.Signal();
1065 RThread serverThread;
1066 TInt res = KErrAlreadyExists;
1068 TFindServer findSurfaceUpdateServer(serverName);
1069 // Need to check that the server exists.
1070 if (findSurfaceUpdateServer.Next(name) !=KErrNone)
1075 TRAP(res, tm.FormatL(buf, _L("_%H%T%S%C")));
1078 gProviderFastLock.Signal();
1081 TBuf<128> threadName(serverName);
1082 threadName.Append(buf); //guarantee uniqueness of the thread name
1083 // Create the thread for the server.
1084 res = serverThread.Create(threadName,
1085 CSurfaceUpdateServer::ThreadFunction,
1089 (TAny*) &aSurfaceUpdateServerProvider
1091 // The thread has been created OK so get it started - however
1092 // we need to make sure that it has started before we continue.
1095 TRequestStatus rendezvousStatus;
1096 TThreadPriority priority = RThread().Priority();
1097 serverThread.SetPriority(priority); // The same as the priority of the creating thread
1098 serverThread.Rendezvous(rendezvousStatus);
1099 serverThread.Resume();
1100 User::WaitForRequest(rendezvousStatus);
1101 res = rendezvousStatus.Int();
1102 gProvider = aSurfaceUpdateServerProvider;
1104 // The thread has not been created - clearly there's been a problem.
1107 serverThread.Close();
1110 gProviderFastLock.Signal();