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