First public contribution.
     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();