os/graphics/graphicscomposition/surfaceupdate/src/surfaceupdateserver.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
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".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 #include "surfaceupdateserver.h"
    17 
    18 #include <graphics/compositionsurfaceupdate.h>
    19 #include <graphics/extensioncontainer.h>
    20 
    21 #include "surfaceupdate.h"
    22 #include "suerror.h"
    23 #ifdef TEST_SURFACE_UPDATE
    24 #include "surfaceupdatetest.h"
    25 #endif
    26 
    27 
    28 const TUint KDefaultHeapSize=0x10000;
    29 
    30 void *gProvider = NULL;
    31 RFastLock gProviderFastLock;
    32 
    33 /**
    34 The server maintains session with the clients. 
    35 It starts during the initialization of the Content update receiver thread.  
    36 */
    37 CSurfaceUpdateServer* CSurfaceUpdateServer::NewL()
    38 	{
    39 	CSurfaceUpdateServer* server = new (ELeave) CSurfaceUpdateServer(EPriorityStandard);
    40 	CleanupStack::PushL(server);
    41 	server->ConstructL();
    42 	CleanupStack::Pop();
    43 	return server;	
    44 	}
    45 	
    46 CSurfaceUpdateServer::CSurfaceUpdateServer(CActive::TPriority aPriority) :
    47 	CServer2(aPriority)
    48 	{
    49 	}
    50 	
    51 CSurfaceUpdateServer::~CSurfaceUpdateServer()
    52 	{
    53 	iUpdateReceiver.Close();
    54 	iUpdateReceiverPriorityOrder.ResetAndDestroy();
    55 	delete iServerProvider;
    56 	}	
    57 	
    58 void CSurfaceUpdateServer::ConstructL()
    59 	{
    60 	iServerProvider = CSurfaceUpdateServerProvider::NewL(EPriorityStandard, this);
    61 	}
    62 	
    63 /**
    64 Assign Content update receiver instance to particular screen. 
    65 The following calls of this function will override the previous. 
    66 
    67 @see MSurfaceUpdateServerProvider::Register
    68 */	
    69 TInt CSurfaceUpdateServer::Register(TInt aScreen, CBase* aUpdateReceiver, TInt aPriority)
    70 	{
    71 	if(aScreen < 0)
    72 		{
    73 		return KErrArgument;
    74 		}
    75 		
    76 	TInt err = KErrNone;
    77 	while((iUpdateReceiver.Count() <= aScreen) && (err == KErrNone))
    78 		{
    79 		err = iUpdateReceiver.Append(NULL);
    80 		}
    81 	
    82 	if(err == KErrNone)
    83 		{
    84 		TUpdateReceiverPriorityEntry *receiverPriorityEntry = NULL; 
    85 		if(!aUpdateReceiver)
    86 			{//Client wants to unregister the Content update receiver which has been associated with the given screen number.
    87 			MCompositionSurfaceUpdate* receiver = iUpdateReceiver[aScreen];
    88 			if(receiver)
    89 				{
    90 				TInt num = iUpdateReceiverPriorityOrder.Count() - 1;
    91 				for(;;)
    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;
    98 						break;
    99 						}
   100 					num--;
   101 					}
   102 				iUpdateReceiver[aScreen] = NULL; //unregister the Content update receiver by setting the entry to NULL
   103 				}
   104 			}
   105 		else
   106 			{
   107 	        CExtensionContainer* extCont=static_cast<CExtensionContainer*>(aUpdateReceiver);
   108 	        MCompositionSurfaceUpdate* updateReceiver=extCont->GetInterface<MCompositionSurfaceUpdate>();
   109 	        if (updateReceiver)
   110 	            {
   111                 receiverPriorityEntry = new TUpdateReceiverPriorityEntry;
   112                 if(!receiverPriorityEntry)
   113                     return KErrNoMemory;
   114                 receiverPriorityEntry->iPriority = aPriority;
   115                 receiverPriorityEntry->iUpdateReceiver = updateReceiver;
   116         
   117                 err = iUpdateReceiverPriorityOrder.InsertInOrder(receiverPriorityEntry, CSurfaceUpdateServer::CompareUpdateReceiverPriority);
   118                 if(err == KErrNone)
   119                     {
   120                     iUpdateReceiver[aScreen] = updateReceiver;
   121                     }
   122                 else
   123                     {
   124                     delete receiverPriorityEntry;
   125                     }
   126 	            }
   127 	        else
   128 	            {
   129 	            err=KErrArgument;
   130 	            }
   131 			}	
   132 		}
   133 	return err;
   134 	}
   135 
   136 /**
   137 Create a new session with a server. Derived from CSession2.
   138 
   139 @param aVersion required version of the server
   140 @param aMessage message from the client.
   141 @return New instance of the CSurfaceUpdateSession.
   142 */
   143 CSession2* CSurfaceUpdateServer::NewSessionL(const TVersion& aVersion, const RMessage2& /*aMessage*/) const
   144 	{
   145       // Check that the version is OK
   146 	TVersion v(KSurfaceUpdateServMajorVersionNumber,KSurfaceUpdateServMinorVersionNumber,KSurfaceUpdateServBuildVersionNumber);
   147 	if (!User::QueryVersionSupported(v,aVersion))
   148 		User::Leave(KErrNotSupported);	
   149 	
   150 	// Security is not an issue, any client can have connection to the server	
   151 	// Create the session.
   152 	return new (ELeave) CSurfaceUpdateSession(UpdateReceiverPriority());
   153 	}
   154 
   155 /**
   156 Utility function to panic the server
   157 
   158 @param aPanic Panic code
   159 */
   160 void CSurfaceUpdateServer::PanicServer(TSurfaceUpdateServPanic aPanic)
   161 	{
   162 	_LIT(KTxtServerPanic,"Surface Update Server panic");
   163 	User::Panic(KTxtServerPanic, aPanic);
   164 	}
   165 
   166 /**
   167 Provide composition receiver.
   168 
   169 @param aScreen targeted screen
   170 @return Composition receiver object, associated to particular screen
   171 */
   172 MCompositionSurfaceUpdate* CSurfaceUpdateServer::UpdateReceiver(TInt aScreen) const
   173 	{
   174 	if(aScreen >= iUpdateReceiver.Count())//negative value won't reach this point 
   175 		return NULL;
   176 	return iUpdateReceiver[aScreen];	
   177 	}
   178 
   179 TInt CSurfaceUpdateServer::ThreadFunction(TAny* aAny)
   180 	{
   181 	  // get clean-up stack
   182 	CTrapCleanup* cleanup=CTrapCleanup::New();
   183 	__ASSERT_ALWAYS(cleanup!=NULL, CSurfaceUpdateServer::PanicServer(EUpdateServPanicNoMemory));
   184 	
   185 	  // create an active scheduler and server
   186 	CActiveScheduler *pA = new CActiveScheduler;
   187 	__ASSERT_ALWAYS(pA != NULL, CSurfaceUpdateServer::PanicServer(EUpdateServPanicNoMemory));
   188 
   189 	  //Install the active scheduler
   190 	CActiveScheduler::Install(pA);
   191 
   192 	CSurfaceUpdateServer *pS = NULL;
   193 	TRAPD(err, pS = CSurfaceUpdateServer::NewL());
   194 	__ASSERT_ALWAYS(err == KErrNone, CSurfaceUpdateServer::PanicServer(EUpdateServPanicNoMemory));
   195 	
   196 	  // Start the server
   197 #ifndef TEST_SURFACE_UPDATE
   198 	err = pS->Start(KSurfaceUpdateServerName);
   199 #else
   200 	err = pS->Start(KTestSurfaceUpdateServerName);
   201 #endif
   202 	
   203 	if (err != KErrNone)
   204 		{
   205 		CSurfaceUpdateServer::PanicServer(EUpdateServPanicStartUp);
   206 		}
   207 	*(static_cast <MSurfaceUpdateServerProvider**> (aAny)) = pS->SurfaceUpdateProvider();
   208       
   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();
   214 
   215      // Tidy up... 	
   216 	delete pS;
   217 	delete pA;
   218 	delete cleanup; 
   219 	
   220 	return KErrNone;
   221 	}
   222 
   223 inline TInt CSurfaceUpdateServer::NumUpdateReceivers() const
   224 	{
   225 	return iUpdateReceiver.Count(); 
   226 	}
   227 
   228 /**
   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).
   231 
   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.
   235 */
   236 TInt CSurfaceUpdateServer::CompareUpdateReceiverPriority(const TUpdateReceiverPriorityEntry& aEntry1, const TUpdateReceiverPriorityEntry& aEntry2)
   237 	{
   238 	return aEntry2.iPriority - aEntry1.iPriority;
   239 	}
   240 
   241 /**
   242 class CSurfaceUpdateSession
   243 
   244 Maintain the channel between clients and the server. 
   245 Functions are provided will respond appropriately to client messages. 
   246 */
   247 
   248 CSurfaceUpdateSession::CSurfaceUpdateSession(const RPointerArray<TUpdateReceiverPriorityEntry>& aEntryList) :
   249 	CSession2(),
   250 	iUpdateReceiverEntryList(aEntryList)
   251 	{
   252 	}
   253 
   254 /**
   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.
   258 */
   259 CSurfaceUpdateSession::~CSurfaceUpdateSession()
   260 	{
   261 	CancelAllUpdateNotifications();
   262 	iUpdateReceiverNotificationBatches.ResetAndDestroy();
   263 	}
   264 
   265 /**
   266 Main function which deals with requests from clients.
   267 */	
   268 void CSurfaceUpdateSession::ServiceL(const RMessage2& aMessage)
   269 	{
   270 	switch (aMessage.Function())
   271 		{
   272 	case EUpdateServNotifyWhenAvailable:
   273 		NotifyWhenAvailable(aMessage);
   274 		return;
   275 	case EUpdateServNotifyWhenDisplayed:
   276 		NotifyWhenDisplayed(aMessage);
   277 		return;
   278 	case EUpdateServNotifyWhenDisplayedXTimes:
   279 		NotifyWhenDisplayedXTimes(aMessage);
   280 		return;
   281 	case EUpdateServSubmitUpdate:
   282 		SubmitUpdate(aMessage);
   283 		return;
   284 	case EUpdateServCancelAllNotifications:
   285 		CancelAllUpdateNotifications();
   286 		aMessage.Complete(KErrNone);
   287 		return;
   288 #ifdef TEST_SURFACE_UPDATE
   289 	case EUpdateServOOM:
   290 		{
   291 		SetHeapFailure(aMessage);
   292 		return;
   293 		}
   294 #endif
   295 	default:
   296 		PanicClient(aMessage, EUpdateServPanicBadRequest);
   297 		return;
   298 		}	 
   299 	}
   300 
   301 #ifdef TEST_SURFACE_UPDATE
   302 /**
   303   Simulate heap allocation failure for the SUS thread's heap.
   304   Aim for OOM testing.
   305  */
   306 void CSurfaceUpdateSession::SetHeapFailure(const RMessage2& aMessage)
   307 	{
   308 	TInt numElement = iUpdateReceiverNotificationBatches.Count();
   309 	TInt index = 0;
   310 	while(numElement)
   311 		{
   312 		CUpdateReceiverNotificationBatch* batch = iUpdateReceiverNotificationBatches[index];
   313 		if(batch->iType == EUpdateSrvReusable)
   314 			{
   315 			iUpdateReceiverNotificationBatches.Remove(index);
   316 			delete batch;
   317 			}
   318 		else
   319 			{
   320 			index++;
   321 			}
   322 		numElement--;            
   323 		}
   324 	if(numElement == 0)
   325 		{
   326 		iUpdateReceiverNotificationBatches.Reset();
   327 		}
   328 	TInt failRate = aMessage.Int0();
   329 	if(!failRate)
   330 		{
   331 		__UHEAP_RESET;
   332 		}
   333 	else
   334 		{
   335 		__UHEAP_SETFAIL(RHeap::EDeterministic, failRate);
   336 		}
   337 	aMessage.Complete(KErrNone);
   338 	}
   339 #endif
   340 
   341 void CSurfaceUpdateSession::PanicClient(const RMessage2& aMessage, TInt aPanic) const
   342 	{
   343 	_LIT(KTxtServer,"SurfUpServ");
   344 	aMessage.Panic(KTxtServer, aPanic);
   345 	}
   346 
   347 /**
   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.
   350 */	
   351 CUpdateReceiverNotificationBatch* CSurfaceUpdateSession::UpdateReceiverNotificationBatchL()
   352 	{
   353 	TInt numElement = iUpdateReceiverNotificationBatches.Count();
   354 	CUpdateReceiverNotificationBatch* notifier = NULL;
   355 	CSurfaceUpdateServer* server = (CSurfaceUpdateServer*) Server();
   356 	for(TInt index = 0; index < numElement; index++)
   357 		{
   358 		notifier = iUpdateReceiverNotificationBatches[index];
   359 		if(notifier->iType == EUpdateSrvReusable)
   360 			{
   361 			__ASSERT_ALWAYS(notifier->iMsg.IsNull(), CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity));
   362             notifier->SetNumUpdateReceivers(server->NumUpdateReceivers());
   363 			if(numElement > index + 1)
   364 				{
   365 			//to improve a search, append the element to the end of the array
   366 				iUpdateReceiverNotificationBatches.Remove(index);
   367 				iUpdateReceiverNotificationBatches.AppendL(notifier);
   368 				}
   369 			return notifier;
   370 			}
   371 		}
   372 	
   373 	notifier = new (ELeave) CUpdateReceiverNotificationBatch(this, server->NumUpdateReceivers());
   374 	CleanupStack::PushL(notifier);
   375 	iUpdateReceiverNotificationBatches.AppendL(notifier);
   376 	CleanupStack::Pop();
   377 	
   378 	return notifier;
   379 	}
   380 	
   381 void CSurfaceUpdateSession::NotifyWhenAvailable(const RMessage2& aMessage)
   382 	{
   383 	StoreNotification(iAvailable, aMessage, EUpdateSrvAvailable);
   384 	}
   385 	
   386 void CSurfaceUpdateSession::NotifyWhenDisplayed(const RMessage2& aMessage)
   387 	{
   388 	StoreNotification(iDisplayed, aMessage, EUpdateSrvDisplayed);
   389 	}
   390 	
   391 void CSurfaceUpdateSession::NotifyWhenDisplayedXTimes(const RMessage2& aMessage)
   392 	{
   393 	StoreNotification(iDisplayedXTimes, aMessage, EUpdateSrvDisplayedXTimes);
   394 	}
   395 
   396 void CSurfaceUpdateSession::StoreNotification(CUpdateReceiverNotificationBatch*& aNotifier, const RMessage2& aMessage, TNotificationType aType)
   397 	{
   398 	if(aNotifier)
   399 		{
   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);
   405 			return;
   406 			}
   407 		}
   408 	else
   409 		{
   410 		TRAPD(res, aNotifier = UpdateReceiverNotificationBatchL());
   411 		if(res != KErrNone)
   412 			{
   413 			aMessage.Complete(res);
   414 			return;
   415 			}
   416 		}	
   417 	
   418 	aNotifier->iMsg = aMessage;
   419 	aNotifier->iType=aType;
   420 	}
   421 
   422 /*
   423 Complete the outstanding requests and reset internal request variables to zero.
   424 @param aErr Error code for completion.   
   425 */ 	
   426 void CSurfaceUpdateSession::IssueRequestComplete(TInt aErr)
   427 	{
   428 	if(iAvailable)
   429 		{
   430 		if(!iAvailable->iMsg.IsNull())
   431 			{
   432 			iAvailable-> iMsg.Complete(aErr);
   433 			iAvailable->CheckForReuse();	 
   434 			}
   435 		iAvailable = NULL;
   436 		}
   437 
   438 	if(iDisplayed)
   439 		{
   440 		if(!iDisplayed -> iMsg.IsNull())
   441 			{
   442 			iDisplayed -> iMsg.Complete(aErr);
   443 			iDisplayed->CheckForReuse();
   444 			}
   445 		iDisplayed = NULL;
   446 		}
   447 
   448 	if(iDisplayedXTimes)
   449 		{
   450 		if(!iDisplayedXTimes->iMsg.IsNull())
   451 			{
   452 			iDisplayedXTimes->iMsg.Complete(aErr);
   453 			iDisplayedXTimes->CheckForReuse();
   454 			}
   455 		iDisplayedXTimes=NULL;
   456 		}
   457 	}
   458 
   459 /**
   460 Redirect call to the DoSubmitUpdateL; error handling
   461 */
   462 void CSurfaceUpdateSession::SubmitUpdate(const RMessage2& aMessage)
   463 	{
   464 	TInt err = KErrNone;
   465 	TRAP(err, DoSubmitUpdateL(aMessage));
   466 	if(err != KErrNone)
   467 		{
   468 		IssueRequestComplete(err);
   469 		}
   470 	aMessage.Complete(err);	
   471 	}
   472 
   473 /**
   474 Issue request for the update to the composition receiver; 
   475 ask notification on composition event if required.
   476 */	
   477 void CSurfaceUpdateSession::DoSubmitUpdateL(const RMessage2& aMessage)
   478 	{
   479 	TInt displayedXTimes = 0;
   480 	TInt screen;
   481 	TInt buffer;
   482 	TSurfaceId surfaceId;
   483 	TPckg<TSurfaceId> surfaceIdPckg(surfaceId);
   484 
   485 	RRegion *region = NULL;
   486 	TRect *rectangleList = NULL;
   487 
   488 	//extract the composition data
   489 	aMessage.ReadL(1, surfaceIdPckg);
   490 	
   491 	screen = aMessage.Int0();
   492 	buffer = aMessage.Int2();
   493 	
   494 	//validate parameters
   495 	if((screen < 0) || (buffer < 0))
   496 		{
   497 		User::Leave(KErrArgument);
   498 		}
   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) 
   502 		{
   503 		if(screen != KAllScreens)
   504 			User::Leave(KErrNotSupported);
   505 		}
   506 	else if(iUpdateMethod == EUpdateMethodPerScreen) 
   507 		{
   508 		if(screen == KAllScreens)
   509 			User::Leave(KErrNotSupported);
   510 		}
   511 	
   512 	TInt len = aMessage.GetDesLength(3);
   513 	if(len > 0)
   514 		{
   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);
   522 		}
   523 	if(iDisplayedXTimes)
   524 		{
   525 		displayedXTimes = iDisplayedXTimes -> iMsg.Int0();
   526 		if(displayedXTimes < 1)
   527 			{
   528 			iDisplayedXTimes->iMsg.Complete(KErrArgument);
   529 			iDisplayedXTimes->CheckForReuse();
   530 			iDisplayedXTimes = NULL;
   531 			}
   532 		}
   533 	
   534 	const CSurfaceUpdateServer* server = static_cast <const CSurfaceUpdateServer*> (Server());	
   535 	if(screen != KAllScreens)
   536 		{
   537 		MCompositionSurfaceUpdate* receiver = server->UpdateReceiver(screen);
   538 		if(!receiver)
   539 			{
   540 			User::Leave(KErrUpdateReceiverNotAvailable);
   541 			}
   542 		DispatchUpdate(surfaceId, buffer, region, &displayedXTimes, receiver);
   543 		iUpdateMethod = EUpdateMethodPerScreen;
   544 		}
   545 	else
   546 		{
   547 		DispatchUpdate(surfaceId, buffer, region, &displayedXTimes);
   548 		iUpdateMethod = EUpdateMethodGlobal;
   549 		}
   550 				
   551 	if(region)
   552 		{
   553 		CleanupStack::PopAndDestroy(2, rectangleList);
   554 		}
   555 	}
   556 
   557 /**
   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.  
   561  */
   562 void CSurfaceUpdateSession::DispatchUpdate(const TSurfaceId& aSurfaceId, TInt aBuffer, RRegion* aRegion, TInt* aDisplayedXTimes, MCompositionSurfaceUpdate* aReceiver)
   563 	{
   564 	TInt index = 1;
   565 	TInt numReceivers = 1;
   566 	TInt priority = 0;
   567 	
   568 	if(!aReceiver)
   569 		{
   570 		aReceiver = iUpdateReceiverEntryList[0]->iUpdateReceiver;
   571 		priority = iUpdateReceiverEntryList[0]->iPriority;
   572 		numReceivers = iUpdateReceiverEntryList.Count(); //get the number of all receivers present in the system
   573 		}
   574 	
   575 	for(;;)
   576 		{	
   577 		CUpdateReceiverNotification* receiverNotificationAvailable = NULL;
   578 		CUpdateReceiverNotification* receiverNotificationDisplayed = NULL;
   579 		CUpdateReceiverNotification* receiverNotificationDisplayedXTimes = NULL;
   580 		TUint32* timeStamp = NULL;
   581 	
   582 	//activate objects
   583 		if(iAvailable)
   584 			{
   585 			receiverNotificationAvailable = iAvailable->UpdateReceiverNotification();
   586 			if(!receiverNotificationAvailable)
   587 				{
   588 				iAvailable->iMsg.Complete(KErrNoMemory);
   589 				iAvailable->CheckForReuse();
   590 				iAvailable = NULL;
   591 				}
   592 			}
   593 
   594 		if(iDisplayed)
   595 			{
   596 			receiverNotificationDisplayed = iDisplayed->UpdateReceiverNotification(priority);
   597 			if(!receiverNotificationDisplayed)
   598 				{
   599 				iDisplayed->iMsg.Complete(KErrNoMemory);
   600 				iDisplayed->CheckForReuse();
   601 				iDisplayed = NULL;
   602 				}
   603 			}
   604 
   605 		if(iDisplayedXTimes)
   606 			{
   607 			receiverNotificationDisplayedXTimes = iDisplayedXTimes->UpdateReceiverNotification();
   608 			if(!receiverNotificationDisplayedXTimes)
   609 				{
   610 				iDisplayedXTimes->iMsg.Complete(KErrNoMemory);
   611 				iDisplayedXTimes->CheckForReuse();
   612 				iDisplayedXTimes = NULL;
   613 				}
   614 			}
   615 	
   616 		TRequestStatus *statusAvailable = NULL;
   617 		TRequestStatus *statusDisplayed = NULL;
   618 		TRequestStatus *statusDisplayedXTimes = NULL;
   619 	//activate all notifications
   620 		if(receiverNotificationAvailable)
   621 			{
   622 			statusAvailable = &(receiverNotificationAvailable->Status());
   623 			receiverNotificationAvailable->Activate();
   624 			}
   625 		if(receiverNotificationDisplayed)
   626 			{
   627 			statusDisplayed = &(receiverNotificationDisplayed->Status());
   628 			timeStamp = & receiverNotificationDisplayed -> iTimeStamp;
   629 			receiverNotificationDisplayed->Activate();
   630 			}
   631 		if(receiverNotificationDisplayedXTimes)
   632 			{
   633 			statusDisplayedXTimes = &(receiverNotificationDisplayedXTimes->Status());
   634 			receiverNotificationDisplayedXTimes->Activate();
   635 			}
   636 	//And finally, send request to the receiver   
   637 		aReceiver->ContentUpdated(aSurfaceId, aBuffer, aRegion,
   638 				statusAvailable, statusDisplayed, timeStamp, 
   639 				statusDisplayedXTimes, statusDisplayedXTimes ? aDisplayedXTimes : NULL);
   640 	
   641 		if(numReceivers > index)
   642 			{
   643 			priority = iUpdateReceiverEntryList[index]->iPriority;
   644 			aReceiver = iUpdateReceiverEntryList[index++]->iUpdateReceiver;
   645 			}
   646 		else
   647 			break;
   648 		}//for(;;)
   649 	
   650 	iAvailable = NULL;
   651 	iDisplayed = NULL;
   652 	iDisplayedXTimes = NULL;
   653 	}
   654 
   655 void CSurfaceUpdateSession::CancelAllUpdateNotifications()
   656 	{
   657 	//go through all notification objects and issue request complete for outstanding requests
   658 	TInt count = iUpdateReceiverNotificationBatches.Count();
   659 	
   660 	for(TInt index = 0; index < count; index++)
   661 		{
   662 		CUpdateReceiverNotificationBatch* notifier = iUpdateReceiverNotificationBatches[index];
   663 		if(!notifier->iMsg.IsNull())
   664 			{
   665 			notifier->iMsg.Complete(KErrCancel);
   666 			}
   667 		}
   668 
   669 	iAvailable = NULL;
   670 	iDisplayed = NULL;
   671 	iDisplayedXTimes = NULL;
   672 	}
   673 	
   674 //*********************
   675 CUpdateReceiverNotification::CUpdateReceiverNotification(CActive::TPriority aPriority, TInt aReceiverPriority, CUpdateReceiverNotificationBatch *aParentNotificationBatch) :
   676 	CActive(aPriority), iUpdateReceiverPriority(aReceiverPriority), iParentNotificationBatch(aParentNotificationBatch)
   677 	{
   678 	CActiveScheduler::Add(this);
   679 #ifdef TEST_SURFACE_UPDATE
   680 	iServer = iParentNotificationBatch->Server();
   681 #endif
   682 	}
   683 	
   684 CUpdateReceiverNotification::~CUpdateReceiverNotification()
   685 	{
   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));
   689 	}
   690 	
   691 void CUpdateReceiverNotification::DoCancel()
   692 	{
   693 	//Content Updates can not be cancelled. Content Updates must be allowed to complete normally.
   694 	CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity);
   695 	}
   696 
   697 /**
   698 Is triggered every time the GCE signals on notification objects.
   699 Delegates processing to the parent notification batch.   
   700 */	
   701 void CUpdateReceiverNotification::RunL()
   702 	{
   703 	// CReceiverNotification object is deleted here once it is set to self destroying when run.
   704 	if (iSelfDestructWhenRun)
   705 		{
   706 #ifdef TEST_SURFACE_UPDATE
   707 		DecNumberPendingNotifications();
   708 #endif
   709 		delete this;
   710 		return;
   711 		}
   712 	iParentNotificationBatch->ProcessNotificationEvent(this);
   713 	}
   714 	
   715 TRequestStatus& CUpdateReceiverNotification::Status()
   716 	{
   717 	return iStatus;	
   718 	}
   719 
   720 void CUpdateReceiverNotification::Activate()
   721 	{
   722 	iStatus = KRequestPending;
   723 	SetActive();
   724 	}
   725 
   726 #ifdef TEST_SURFACE_UPDATE
   727 void CUpdateReceiverNotification::DecNumberPendingNotifications()
   728 	{
   729 	if (iServer)
   730 		{
   731 		iServer-> iNumberPendingNotification--;
   732 		}
   733 	}
   734 #endif
   735 
   736 /**
   737 The class maintains the notification objects of the same type and attributed to a 
   738 particular submit update command.   
   739  */
   740 CUpdateReceiverNotificationBatch::CUpdateReceiverNotificationBatch(CSurfaceUpdateSession *aSession, TInt aNumReceivers) :
   741 	iSession(aSession), iNumUpdateReceivers(aNumReceivers)
   742 	{
   743 	CheckForReuse();
   744 	}
   745 
   746 CUpdateReceiverNotificationBatch::~CUpdateReceiverNotificationBatch()
   747 	{
   748 	TInt count = iUpdateReceiverNotifications.Count();
   749 	for(TInt index = 0; index < count; index++)
   750 		{
   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())
   756 			{
   757 			notifier->iSelfDestructWhenRun = ETrue;
   758 #ifdef TEST_SURFACE_UPDATE
   759 			IncNumberPendingNotifications();
   760 #endif
   761 			}
   762 		else
   763 			{
   764 			delete notifier;
   765 			}
   766 		}
   767 	iUpdateReceiverNotifications.Close();
   768 	}
   769 
   770 /**
   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.
   775 */
   776 void CUpdateReceiverNotificationBatch::ProcessNotificationEvent(CUpdateReceiverNotification* aReceiverNotification)
   777 	{
   778 	TInt index = iUpdateReceiverNotifications.Find(aReceiverNotification);
   779 	__ASSERT_DEBUG(index != KErrNotFound, CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity));
   780 	iUpdateReceiverNotifications.Remove(index);
   781 	if(iMsg.IsNull())
   782 		{
   783 		CheckForReuse();
   784 		delete aReceiverNotification;
   785 		return; // the message has already been completed, possibly, because of request cancelation
   786 		}
   787 	TBool oldCompleteWithSuccess = iCompleteWithSuccess;
   788 	TBool newCompleteWithSuccess = EFalse;
   789 	if(aReceiverNotification->iStatus.Int() == KErrNone)
   790 		{
   791 		iCompleteWithSuccess = ETrue;
   792 		newCompleteWithSuccess = ETrue;
   793 		}
   794 	
   795 	switch(iType)
   796 		{
   797 	case EUpdateSrvAvailable:
   798 		if(iUpdateReceiverNotifications.Count() == 0)
   799 			{
   800 			TInt res = iCompleteWithSuccess ? KErrNone : aReceiverNotification->iStatus.Int();
   801 			iMsg.Complete(res);
   802 			}
   803 		break;
   804 	case EUpdateSrvDisplayedXTimes:
   805 		if((newCompleteWithSuccess && (index == 0)) || (iUpdateReceiverNotifications.Count() == 0))
   806 			{
   807 			TInt res = iCompleteWithSuccess ? KErrNone : aReceiverNotification->iStatus.Int();
   808 			iMsg.Complete(res);
   809 			}
   810 		break;
   811 	case EUpdateSrvDisplayed:
   812 		if(newCompleteWithSuccess && 
   813 				((iHighestPriority < aReceiverNotification->iUpdateReceiverPriority) || !oldCompleteWithSuccess))
   814 			{
   815 			iHighestPriority = aReceiverNotification->iUpdateReceiverPriority;
   816 			iTimeStamp = aReceiverNotification->iTimeStamp;
   817 			}
   818 		if((newCompleteWithSuccess && (index == 0)) || (iUpdateReceiverNotifications.Count() == 0))
   819 			{
   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.
   822 			if(res == KErrNone)
   823 				{
   824 				res = iCompleteWithSuccess ? KErrNone : aReceiverNotification->iStatus.Int();
   825 				}
   826 			iMsg.Complete(res);
   827 			}
   828 		break;
   829 	default:	
   830 		break;
   831 		}
   832 	
   833 	delete aReceiverNotification;
   834 	CheckForReuse();
   835 	}
   836 
   837 /**
   838  The method allocates a notification object and inserts it into the list
   839 */ 
   840 CUpdateReceiverNotification* CUpdateReceiverNotificationBatch::UpdateReceiverNotification(TInt aReceiverPriority)
   841 	{
   842 	__ASSERT_DEBUG(iNumUpdateReceivers > iUpdateReceiverNotifications.Count(), CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity));
   843 	
   844 	CUpdateReceiverNotification* receiverNotification = new CUpdateReceiverNotification(CActive::EPriorityStandard, aReceiverPriority, this);
   845 	if(receiverNotification)
   846 		{
   847 		TInt res = iUpdateReceiverNotifications.Append(receiverNotification);
   848 		if(res != KErrNone)
   849 			{
   850 			delete receiverNotification;
   851 			receiverNotification = NULL;
   852 			}
   853 		}
   854 	
   855 	return receiverNotification;
   856 	}
   857 
   858 /**
   859 If notification list is empty mark the batch for further use
   860 */
   861 void CUpdateReceiverNotificationBatch::CheckForReuse()
   862 	{
   863 	if(iUpdateReceiverNotifications.Count() == 0)
   864 		{
   865 		iType = EUpdateSrvReusable;
   866 		iCompleteWithSuccess = EFalse;
   867 		iHighestPriority = 0;
   868 		iTimeStamp = 0;
   869 		}
   870 	}
   871 
   872 #ifdef TEST_SURFACE_UPDATE
   873 CSurfaceUpdateServer* CUpdateReceiverNotificationBatch::Server()
   874 	{
   875 	return (CSurfaceUpdateServer*)(iSession->Server());
   876 	}
   877 
   878 void CUpdateReceiverNotificationBatch::IncNumberPendingNotifications()
   879 	{
   880 	CServer2* server = static_cast<CServer2*> (Server());
   881 	if(server)
   882 		{
   883 		(static_cast<CSurfaceUpdateServer*> (server))-> iNumberPendingNotification++;
   884 		}
   885 	}
   886 #endif
   887 
   888 
   889 /**
   890 Set number of UpdateReceivers - called when update receivers are added/removed.
   891 
   892 @param aNumUpdateReceivers - new number of update receivers for the batch.
   893  */
   894 void CUpdateReceiverNotificationBatch::SetNumUpdateReceivers(TInt aNumUpdateReceivers)
   895     {
   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;
   901     }
   902 /**
   903 
   904 The class will be used by composition receiver
   905 */
   906 CSurfaceUpdateServerProvider* CSurfaceUpdateServerProvider::NewL(CActive::TPriority aPriority, CSurfaceUpdateServer* aServer)
   907 	{
   908 	CSurfaceUpdateServerProvider* serverProvider = new (ELeave) CSurfaceUpdateServerProvider(aPriority, aServer);
   909 	CleanupStack::PushL(serverProvider);
   910 	serverProvider->ConstructL();
   911 	CleanupStack::Pop();
   912 	return serverProvider;
   913 	}
   914 
   915 CSurfaceUpdateServerProvider::CSurfaceUpdateServerProvider(CActive::TPriority aPriority, CSurfaceUpdateServer* aServer) :
   916 								CActive(aPriority), iServer(aServer)
   917 	{
   918 	RThread thread;
   919 	iThreadId = thread.Id();
   920 	}
   921 	
   922 CSurfaceUpdateServerProvider::~CSurfaceUpdateServerProvider()
   923 	{
   924 	iSemaphore.Close();
   925 	Cancel();
   926 	}
   927 /**
   928 Create provider and add it to the active scheduler
   929 */
   930 void CSurfaceUpdateServerProvider::ConstructL()
   931 	{
   932 	User::LeaveIfError(iSemaphore.CreateLocal(0));
   933 	CActiveScheduler::Add(this);
   934 	iStatus = KRequestPending;
   935 	SetActive();
   936 	}
   937 
   938 /**  
   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
   942  */	
   943 EXPORT_C TInt CSurfaceUpdateServerProvider::Register(TInt aScreen, CBase* aReceiver, TInt aPriority)
   944 	{
   945 	RThread thread;
   946 	TInt res = thread.Open(iThreadId);
   947 	if(res == KErrNone)
   948 		{
   949 		iScreen = aScreen;
   950 		iUpdateReceiver = aReceiver;
   951 		iPriority = aPriority;
   952 
   953 		TRequestStatus* status = &iStatus;
   954 		thread.RequestComplete(status, EUpdateServEventRegister);
   955 		thread.Close();
   956 		iSemaphore.Wait();
   957 		res = iRegisterErr;
   958 		}
   959 	return res;
   960 	}
   961 
   962 /**
   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.
   966 */
   967 EXPORT_C void CSurfaceUpdateServerProvider::Terminate()
   968 	{
   969 #ifdef TEST_SURFACE_UPDATE
   970 	RThread thread;
   971 
   972 	if(thread.Open(iThreadId) == KErrNone)
   973 		{
   974 	    TInt err = gProviderFastLock.CreateLocal();
   975 	    __ASSERT_ALWAYS(err == KErrNone || err == KErrAlreadyExists, CSurfaceUpdateServer::PanicServer(EUpdateServPanicGlobalFastLock));
   976 	    
   977 	    gProviderFastLock.Wait();
   978 	    gProvider = NULL;
   979 		if (iServer)
   980 			{
   981 			while((static_cast<CSurfaceUpdateServer*> (iServer))-> iNumberPendingNotification)
   982 				User::After(TTimeIntervalMicroSeconds32(1000));
   983 			}
   984 		TRequestStatus* status = &iStatus;
   985 		thread.RequestComplete(status, EUpdateServEventTerminate);
   986 		
   987 		//wait until the thread dies
   988 		TRequestStatus status1;
   989 		thread.Logon(status1);
   990 		User::WaitForRequest(status1);
   991 		thread.Close();
   992 		
   993      	gProviderFastLock.Close();
   994 		}
   995 #endif
   996 	}
   997 
   998 /**
   999 The function processes signals which come from composition receiver thread.
  1000 */	
  1001 void CSurfaceUpdateServerProvider::RunL()
  1002 	{
  1003 	switch(iStatus.Int())
  1004 		{
  1005 	case EUpdateServEventTerminate:
  1006 		CActiveScheduler::Stop();
  1007 		return; 
  1008 	case EUpdateServEventRegister:
  1009 		iRegisterErr = iServer->Register(iScreen, iUpdateReceiver, iPriority);
  1010 		iUpdateReceiver = NULL;
  1011 		iStatus = KRequestPending;
  1012 		SetActive();
  1013 		iSemaphore.Signal();
  1014 		break;
  1015 	default :
  1016 		CSurfaceUpdateServer::PanicServer(EUpdateServPanicBadRequest); 
  1017 		iStatus = KRequestPending;
  1018 		SetActive();
  1019 		break;	
  1020 		}
  1021 	}
  1022 	
  1023 void CSurfaceUpdateServerProvider::DoCancel()
  1024 	{
  1025 	}
  1026 
  1027 /**
  1028 Spawn a thread within WSERV process. This will lead to starting the surface update server in it 
  1029 @publishedPartner
  1030 @prototype Intended to be used by Surface Update control flow
  1031 	
  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, 
  1036 		i.e. system is up.
  1037 
  1038 @return KErrNone if an operation is successful, any other system error codes otherwise
  1039 */
  1040 EXPORT_C TInt StartSurfaceUpdateServer(MSurfaceUpdateServerProvider*& aSurfaceUpdateServerProvider)
  1041 	{
  1042 #ifndef TEST_SURFACE_UPDATE
  1043 	TPtrC serverName(KSurfaceUpdateServerName);
  1044 #else
  1045 	TPtrC serverName(KTestSurfaceUpdateServerName);
  1046 #endif
  1047 	//locking
  1048 	TInt err = gProviderFastLock.CreateLocal();
  1049 	
  1050 	if (err != KErrNone && err != KErrAlreadyExists)
  1051 	    {
  1052         return err;
  1053 	    }
  1054 	
  1055 	gProviderFastLock.Wait();
  1056 
  1057 	TAny *provider = gProvider;
  1058 	if(provider)
  1059 		{
  1060 		aSurfaceUpdateServerProvider = static_cast <MSurfaceUpdateServerProvider*> (provider);
  1061 		gProviderFastLock.Signal();
  1062 		return KErrNone;
  1063 		}
  1064 	TFullName   name;
  1065 	RThread serverThread;
  1066 	TInt res = KErrAlreadyExists;
  1067 	
  1068 	TFindServer findSurfaceUpdateServer(serverName);
  1069 	  // Need to check that the server exists.
  1070 	if (findSurfaceUpdateServer.Next(name) !=KErrNone)
  1071 		{
  1072 		TTime tm;
  1073 		TBuf<32> buf;
  1074 		tm.UniversalTime();
  1075 		TRAP(res, tm.FormatL(buf, _L("_%H%T%S%C")));
  1076 		if(res != KErrNone)	
  1077 			{
  1078 			gProviderFastLock.Signal();
  1079 			return res;
  1080 			}
  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,
  1086 			KDefaultStackSize,
  1087 			KDefaultHeapSize,
  1088 			KDefaultHeapSize,
  1089 			(TAny*) &aSurfaceUpdateServerProvider
  1090 			);
  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.
  1093 		if (res==KErrNone)
  1094 			{
  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;
  1103 			}
  1104     // The thread has not been created - clearly there's been a problem.
  1105 		else
  1106 			{
  1107 			serverThread.Close();
  1108 			}
  1109 		}
  1110        gProviderFastLock.Signal();
  1111 		return res;
  1112 	}