1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/graphics/graphicscomposition/surfaceupdate/src/surfaceupdateserver.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1112 @@
1.4 +// Copyright (c) 2006-2010 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include "surfaceupdateserver.h"
1.20 +
1.21 +#include <graphics/compositionsurfaceupdate.h>
1.22 +#include <graphics/extensioncontainer.h>
1.23 +
1.24 +#include "surfaceupdate.h"
1.25 +#include "suerror.h"
1.26 +#ifdef TEST_SURFACE_UPDATE
1.27 +#include "surfaceupdatetest.h"
1.28 +#endif
1.29 +
1.30 +
1.31 +const TUint KDefaultHeapSize=0x10000;
1.32 +
1.33 +void *gProvider = NULL;
1.34 +RFastLock gProviderFastLock;
1.35 +
1.36 +/**
1.37 +The server maintains session with the clients.
1.38 +It starts during the initialization of the Content update receiver thread.
1.39 +*/
1.40 +CSurfaceUpdateServer* CSurfaceUpdateServer::NewL()
1.41 + {
1.42 + CSurfaceUpdateServer* server = new (ELeave) CSurfaceUpdateServer(EPriorityStandard);
1.43 + CleanupStack::PushL(server);
1.44 + server->ConstructL();
1.45 + CleanupStack::Pop();
1.46 + return server;
1.47 + }
1.48 +
1.49 +CSurfaceUpdateServer::CSurfaceUpdateServer(CActive::TPriority aPriority) :
1.50 + CServer2(aPriority)
1.51 + {
1.52 + }
1.53 +
1.54 +CSurfaceUpdateServer::~CSurfaceUpdateServer()
1.55 + {
1.56 + iUpdateReceiver.Close();
1.57 + iUpdateReceiverPriorityOrder.ResetAndDestroy();
1.58 + delete iServerProvider;
1.59 + }
1.60 +
1.61 +void CSurfaceUpdateServer::ConstructL()
1.62 + {
1.63 + iServerProvider = CSurfaceUpdateServerProvider::NewL(EPriorityStandard, this);
1.64 + }
1.65 +
1.66 +/**
1.67 +Assign Content update receiver instance to particular screen.
1.68 +The following calls of this function will override the previous.
1.69 +
1.70 +@see MSurfaceUpdateServerProvider::Register
1.71 +*/
1.72 +TInt CSurfaceUpdateServer::Register(TInt aScreen, CBase* aUpdateReceiver, TInt aPriority)
1.73 + {
1.74 + if(aScreen < 0)
1.75 + {
1.76 + return KErrArgument;
1.77 + }
1.78 +
1.79 + TInt err = KErrNone;
1.80 + while((iUpdateReceiver.Count() <= aScreen) && (err == KErrNone))
1.81 + {
1.82 + err = iUpdateReceiver.Append(NULL);
1.83 + }
1.84 +
1.85 + if(err == KErrNone)
1.86 + {
1.87 + TUpdateReceiverPriorityEntry *receiverPriorityEntry = NULL;
1.88 + if(!aUpdateReceiver)
1.89 + {//Client wants to unregister the Content update receiver which has been associated with the given screen number.
1.90 + MCompositionSurfaceUpdate* receiver = iUpdateReceiver[aScreen];
1.91 + if(receiver)
1.92 + {
1.93 + TInt num = iUpdateReceiverPriorityOrder.Count() - 1;
1.94 + for(;;)
1.95 + {//Content update receiver must be in priority list, therefore we don't need to check num >= 0
1.96 + receiverPriorityEntry = iUpdateReceiverPriorityOrder[num];
1.97 + if(receiverPriorityEntry->iUpdateReceiver == receiver)
1.98 + {//remove the Content update receiver from the priority list
1.99 + iUpdateReceiverPriorityOrder.Remove(num);
1.100 + delete receiverPriorityEntry;
1.101 + break;
1.102 + }
1.103 + num--;
1.104 + }
1.105 + iUpdateReceiver[aScreen] = NULL; //unregister the Content update receiver by setting the entry to NULL
1.106 + }
1.107 + }
1.108 + else
1.109 + {
1.110 + CExtensionContainer* extCont=static_cast<CExtensionContainer*>(aUpdateReceiver);
1.111 + MCompositionSurfaceUpdate* updateReceiver=extCont->GetInterface<MCompositionSurfaceUpdate>();
1.112 + if (updateReceiver)
1.113 + {
1.114 + receiverPriorityEntry = new TUpdateReceiverPriorityEntry;
1.115 + if(!receiverPriorityEntry)
1.116 + return KErrNoMemory;
1.117 + receiverPriorityEntry->iPriority = aPriority;
1.118 + receiverPriorityEntry->iUpdateReceiver = updateReceiver;
1.119 +
1.120 + err = iUpdateReceiverPriorityOrder.InsertInOrder(receiverPriorityEntry, CSurfaceUpdateServer::CompareUpdateReceiverPriority);
1.121 + if(err == KErrNone)
1.122 + {
1.123 + iUpdateReceiver[aScreen] = updateReceiver;
1.124 + }
1.125 + else
1.126 + {
1.127 + delete receiverPriorityEntry;
1.128 + }
1.129 + }
1.130 + else
1.131 + {
1.132 + err=KErrArgument;
1.133 + }
1.134 + }
1.135 + }
1.136 + return err;
1.137 + }
1.138 +
1.139 +/**
1.140 +Create a new session with a server. Derived from CSession2.
1.141 +
1.142 +@param aVersion required version of the server
1.143 +@param aMessage message from the client.
1.144 +@return New instance of the CSurfaceUpdateSession.
1.145 +*/
1.146 +CSession2* CSurfaceUpdateServer::NewSessionL(const TVersion& aVersion, const RMessage2& /*aMessage*/) const
1.147 + {
1.148 + // Check that the version is OK
1.149 + TVersion v(KSurfaceUpdateServMajorVersionNumber,KSurfaceUpdateServMinorVersionNumber,KSurfaceUpdateServBuildVersionNumber);
1.150 + if (!User::QueryVersionSupported(v,aVersion))
1.151 + User::Leave(KErrNotSupported);
1.152 +
1.153 + // Security is not an issue, any client can have connection to the server
1.154 + // Create the session.
1.155 + return new (ELeave) CSurfaceUpdateSession(UpdateReceiverPriority());
1.156 + }
1.157 +
1.158 +/**
1.159 +Utility function to panic the server
1.160 +
1.161 +@param aPanic Panic code
1.162 +*/
1.163 +void CSurfaceUpdateServer::PanicServer(TSurfaceUpdateServPanic aPanic)
1.164 + {
1.165 + _LIT(KTxtServerPanic,"Surface Update Server panic");
1.166 + User::Panic(KTxtServerPanic, aPanic);
1.167 + }
1.168 +
1.169 +/**
1.170 +Provide composition receiver.
1.171 +
1.172 +@param aScreen targeted screen
1.173 +@return Composition receiver object, associated to particular screen
1.174 +*/
1.175 +MCompositionSurfaceUpdate* CSurfaceUpdateServer::UpdateReceiver(TInt aScreen) const
1.176 + {
1.177 + if(aScreen >= iUpdateReceiver.Count())//negative value won't reach this point
1.178 + return NULL;
1.179 + return iUpdateReceiver[aScreen];
1.180 + }
1.181 +
1.182 +TInt CSurfaceUpdateServer::ThreadFunction(TAny* aAny)
1.183 + {
1.184 + // get clean-up stack
1.185 + CTrapCleanup* cleanup=CTrapCleanup::New();
1.186 + __ASSERT_ALWAYS(cleanup!=NULL, CSurfaceUpdateServer::PanicServer(EUpdateServPanicNoMemory));
1.187 +
1.188 + // create an active scheduler and server
1.189 + CActiveScheduler *pA = new CActiveScheduler;
1.190 + __ASSERT_ALWAYS(pA != NULL, CSurfaceUpdateServer::PanicServer(EUpdateServPanicNoMemory));
1.191 +
1.192 + //Install the active scheduler
1.193 + CActiveScheduler::Install(pA);
1.194 +
1.195 + CSurfaceUpdateServer *pS = NULL;
1.196 + TRAPD(err, pS = CSurfaceUpdateServer::NewL());
1.197 + __ASSERT_ALWAYS(err == KErrNone, CSurfaceUpdateServer::PanicServer(EUpdateServPanicNoMemory));
1.198 +
1.199 + // Start the server
1.200 +#ifndef TEST_SURFACE_UPDATE
1.201 + err = pS->Start(KSurfaceUpdateServerName);
1.202 +#else
1.203 + err = pS->Start(KTestSurfaceUpdateServerName);
1.204 +#endif
1.205 +
1.206 + if (err != KErrNone)
1.207 + {
1.208 + CSurfaceUpdateServer::PanicServer(EUpdateServPanicStartUp);
1.209 + }
1.210 + *(static_cast <MSurfaceUpdateServerProvider**> (aAny)) = pS->SurfaceUpdateProvider();
1.211 +
1.212 + // Let everyone know that we are ready to
1.213 + // deal with requests.
1.214 + RThread::Rendezvous(KErrNone);
1.215 + // And start fielding requests from client(s).
1.216 + CActiveScheduler::Start();
1.217 +
1.218 + // Tidy up...
1.219 + delete pS;
1.220 + delete pA;
1.221 + delete cleanup;
1.222 +
1.223 + return KErrNone;
1.224 + }
1.225 +
1.226 +inline TInt CSurfaceUpdateServer::NumUpdateReceivers() const
1.227 + {
1.228 + return iUpdateReceiver.Count();
1.229 + }
1.230 +
1.231 +/**
1.232 +Compare two content update receiver entries according to their priority.
1.233 +The function is used when receiver priority entry is inserted/retrieved from the array (iCompReceiverPriorityOrder).
1.234 +
1.235 +@return zero, if the priorities of two receivers are equal;
1.236 +a negative value, if the priority of the first receiver is less than the priority of the second one;
1.237 +a positive value, if the priority of the first receiver is greater than the priority of the second one.
1.238 +*/
1.239 +TInt CSurfaceUpdateServer::CompareUpdateReceiverPriority(const TUpdateReceiverPriorityEntry& aEntry1, const TUpdateReceiverPriorityEntry& aEntry2)
1.240 + {
1.241 + return aEntry2.iPriority - aEntry1.iPriority;
1.242 + }
1.243 +
1.244 +/**
1.245 +class CSurfaceUpdateSession
1.246 +
1.247 +Maintain the channel between clients and the server.
1.248 +Functions are provided will respond appropriately to client messages.
1.249 +*/
1.250 +
1.251 +CSurfaceUpdateSession::CSurfaceUpdateSession(const RPointerArray<TUpdateReceiverPriorityEntry>& aEntryList) :
1.252 + CSession2(),
1.253 + iUpdateReceiverEntryList(aEntryList)
1.254 + {
1.255 + }
1.256 +
1.257 +/**
1.258 +Cancel any outstanding client notification requests.
1.259 +All resources owned by the session will either be immediately released or
1.260 +scheduled for deferred deletion.
1.261 +*/
1.262 +CSurfaceUpdateSession::~CSurfaceUpdateSession()
1.263 + {
1.264 + CancelAllUpdateNotifications();
1.265 + iUpdateReceiverNotificationBatches.ResetAndDestroy();
1.266 + }
1.267 +
1.268 +/**
1.269 +Main function which deals with requests from clients.
1.270 +*/
1.271 +void CSurfaceUpdateSession::ServiceL(const RMessage2& aMessage)
1.272 + {
1.273 + switch (aMessage.Function())
1.274 + {
1.275 + case EUpdateServNotifyWhenAvailable:
1.276 + NotifyWhenAvailable(aMessage);
1.277 + return;
1.278 + case EUpdateServNotifyWhenDisplayed:
1.279 + NotifyWhenDisplayed(aMessage);
1.280 + return;
1.281 + case EUpdateServNotifyWhenDisplayedXTimes:
1.282 + NotifyWhenDisplayedXTimes(aMessage);
1.283 + return;
1.284 + case EUpdateServSubmitUpdate:
1.285 + SubmitUpdate(aMessage);
1.286 + return;
1.287 + case EUpdateServCancelAllNotifications:
1.288 + CancelAllUpdateNotifications();
1.289 + aMessage.Complete(KErrNone);
1.290 + return;
1.291 +#ifdef TEST_SURFACE_UPDATE
1.292 + case EUpdateServOOM:
1.293 + {
1.294 + SetHeapFailure(aMessage);
1.295 + return;
1.296 + }
1.297 +#endif
1.298 + default:
1.299 + PanicClient(aMessage, EUpdateServPanicBadRequest);
1.300 + return;
1.301 + }
1.302 + }
1.303 +
1.304 +#ifdef TEST_SURFACE_UPDATE
1.305 +/**
1.306 + Simulate heap allocation failure for the SUS thread's heap.
1.307 + Aim for OOM testing.
1.308 + */
1.309 +void CSurfaceUpdateSession::SetHeapFailure(const RMessage2& aMessage)
1.310 + {
1.311 + TInt numElement = iUpdateReceiverNotificationBatches.Count();
1.312 + TInt index = 0;
1.313 + while(numElement)
1.314 + {
1.315 + CUpdateReceiverNotificationBatch* batch = iUpdateReceiverNotificationBatches[index];
1.316 + if(batch->iType == EUpdateSrvReusable)
1.317 + {
1.318 + iUpdateReceiverNotificationBatches.Remove(index);
1.319 + delete batch;
1.320 + }
1.321 + else
1.322 + {
1.323 + index++;
1.324 + }
1.325 + numElement--;
1.326 + }
1.327 + if(numElement == 0)
1.328 + {
1.329 + iUpdateReceiverNotificationBatches.Reset();
1.330 + }
1.331 + TInt failRate = aMessage.Int0();
1.332 + if(!failRate)
1.333 + {
1.334 + __UHEAP_RESET;
1.335 + }
1.336 + else
1.337 + {
1.338 + __UHEAP_SETFAIL(RHeap::EDeterministic, failRate);
1.339 + }
1.340 + aMessage.Complete(KErrNone);
1.341 + }
1.342 +#endif
1.343 +
1.344 +void CSurfaceUpdateSession::PanicClient(const RMessage2& aMessage, TInt aPanic) const
1.345 + {
1.346 + _LIT(KTxtServer,"SurfUpServ");
1.347 + aMessage.Panic(KTxtServer, aPanic);
1.348 + }
1.349 +
1.350 +/**
1.351 +Return first inactive spare notification object stored in the notification array,
1.352 +create a new one if fail to find it in the array.
1.353 +*/
1.354 +CUpdateReceiverNotificationBatch* CSurfaceUpdateSession::UpdateReceiverNotificationBatchL()
1.355 + {
1.356 + TInt numElement = iUpdateReceiverNotificationBatches.Count();
1.357 + CUpdateReceiverNotificationBatch* notifier = NULL;
1.358 + CSurfaceUpdateServer* server = (CSurfaceUpdateServer*) Server();
1.359 + for(TInt index = 0; index < numElement; index++)
1.360 + {
1.361 + notifier = iUpdateReceiverNotificationBatches[index];
1.362 + if(notifier->iType == EUpdateSrvReusable)
1.363 + {
1.364 + __ASSERT_ALWAYS(notifier->iMsg.IsNull(), CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity));
1.365 + notifier->SetNumUpdateReceivers(server->NumUpdateReceivers());
1.366 + if(numElement > index + 1)
1.367 + {
1.368 + //to improve a search, append the element to the end of the array
1.369 + iUpdateReceiverNotificationBatches.Remove(index);
1.370 + iUpdateReceiverNotificationBatches.AppendL(notifier);
1.371 + }
1.372 + return notifier;
1.373 + }
1.374 + }
1.375 +
1.376 + notifier = new (ELeave) CUpdateReceiverNotificationBatch(this, server->NumUpdateReceivers());
1.377 + CleanupStack::PushL(notifier);
1.378 + iUpdateReceiverNotificationBatches.AppendL(notifier);
1.379 + CleanupStack::Pop();
1.380 +
1.381 + return notifier;
1.382 + }
1.383 +
1.384 +void CSurfaceUpdateSession::NotifyWhenAvailable(const RMessage2& aMessage)
1.385 + {
1.386 + StoreNotification(iAvailable, aMessage, EUpdateSrvAvailable);
1.387 + }
1.388 +
1.389 +void CSurfaceUpdateSession::NotifyWhenDisplayed(const RMessage2& aMessage)
1.390 + {
1.391 + StoreNotification(iDisplayed, aMessage, EUpdateSrvDisplayed);
1.392 + }
1.393 +
1.394 +void CSurfaceUpdateSession::NotifyWhenDisplayedXTimes(const RMessage2& aMessage)
1.395 + {
1.396 + StoreNotification(iDisplayedXTimes, aMessage, EUpdateSrvDisplayedXTimes);
1.397 + }
1.398 +
1.399 +void CSurfaceUpdateSession::StoreNotification(CUpdateReceiverNotificationBatch*& aNotifier, const RMessage2& aMessage, TNotificationType aType)
1.400 + {
1.401 + if(aNotifier)
1.402 + {
1.403 + if(!aNotifier->iMsg.IsNull())
1.404 + {//not expected behaviour
1.405 + //would happen if a client sends the same notification request in a row
1.406 + IssueRequestComplete(KErrCancel);
1.407 + PanicClient(aMessage, EUpdateServPanicDataIntegrity);
1.408 + return;
1.409 + }
1.410 + }
1.411 + else
1.412 + {
1.413 + TRAPD(res, aNotifier = UpdateReceiverNotificationBatchL());
1.414 + if(res != KErrNone)
1.415 + {
1.416 + aMessage.Complete(res);
1.417 + return;
1.418 + }
1.419 + }
1.420 +
1.421 + aNotifier->iMsg = aMessage;
1.422 + aNotifier->iType=aType;
1.423 + }
1.424 +
1.425 +/*
1.426 +Complete the outstanding requests and reset internal request variables to zero.
1.427 +@param aErr Error code for completion.
1.428 +*/
1.429 +void CSurfaceUpdateSession::IssueRequestComplete(TInt aErr)
1.430 + {
1.431 + if(iAvailable)
1.432 + {
1.433 + if(!iAvailable->iMsg.IsNull())
1.434 + {
1.435 + iAvailable-> iMsg.Complete(aErr);
1.436 + iAvailable->CheckForReuse();
1.437 + }
1.438 + iAvailable = NULL;
1.439 + }
1.440 +
1.441 + if(iDisplayed)
1.442 + {
1.443 + if(!iDisplayed -> iMsg.IsNull())
1.444 + {
1.445 + iDisplayed -> iMsg.Complete(aErr);
1.446 + iDisplayed->CheckForReuse();
1.447 + }
1.448 + iDisplayed = NULL;
1.449 + }
1.450 +
1.451 + if(iDisplayedXTimes)
1.452 + {
1.453 + if(!iDisplayedXTimes->iMsg.IsNull())
1.454 + {
1.455 + iDisplayedXTimes->iMsg.Complete(aErr);
1.456 + iDisplayedXTimes->CheckForReuse();
1.457 + }
1.458 + iDisplayedXTimes=NULL;
1.459 + }
1.460 + }
1.461 +
1.462 +/**
1.463 +Redirect call to the DoSubmitUpdateL; error handling
1.464 +*/
1.465 +void CSurfaceUpdateSession::SubmitUpdate(const RMessage2& aMessage)
1.466 + {
1.467 + TInt err = KErrNone;
1.468 + TRAP(err, DoSubmitUpdateL(aMessage));
1.469 + if(err != KErrNone)
1.470 + {
1.471 + IssueRequestComplete(err);
1.472 + }
1.473 + aMessage.Complete(err);
1.474 + }
1.475 +
1.476 +/**
1.477 +Issue request for the update to the composition receiver;
1.478 +ask notification on composition event if required.
1.479 +*/
1.480 +void CSurfaceUpdateSession::DoSubmitUpdateL(const RMessage2& aMessage)
1.481 + {
1.482 + TInt displayedXTimes = 0;
1.483 + TInt screen;
1.484 + TInt buffer;
1.485 + TSurfaceId surfaceId;
1.486 + TPckg<TSurfaceId> surfaceIdPckg(surfaceId);
1.487 +
1.488 + RRegion *region = NULL;
1.489 + TRect *rectangleList = NULL;
1.490 +
1.491 + //extract the composition data
1.492 + aMessage.ReadL(1, surfaceIdPckg);
1.493 +
1.494 + screen = aMessage.Int0();
1.495 + buffer = aMessage.Int2();
1.496 +
1.497 + //validate parameters
1.498 + if((screen < 0) || (buffer < 0))
1.499 + {
1.500 + User::Leave(KErrArgument);
1.501 + }
1.502 + //Check that we haven't used another update method before
1.503 + //The comparison is slightly optimized for performance as oppose to code size
1.504 + if(iUpdateMethod == EUpdateMethodGlobal)
1.505 + {
1.506 + if(screen != KAllScreens)
1.507 + User::Leave(KErrNotSupported);
1.508 + }
1.509 + else if(iUpdateMethod == EUpdateMethodPerScreen)
1.510 + {
1.511 + if(screen == KAllScreens)
1.512 + User::Leave(KErrNotSupported);
1.513 + }
1.514 +
1.515 + TInt len = aMessage.GetDesLength(3);
1.516 + if(len > 0)
1.517 + {
1.518 + rectangleList = (TRect*) (User::AllocL(len));
1.519 + CleanupStack::PushL(rectangleList);
1.520 + TPtr8 ptrRect(reinterpret_cast<TUint8*> (rectangleList), len);
1.521 + aMessage.ReadL(3, ptrRect);
1.522 + TInt regionCount = len / sizeof(TRect);
1.523 + region = new (ELeave) RRegion(regionCount, rectangleList);
1.524 + CleanupStack::PushL(region);
1.525 + }
1.526 + if(iDisplayedXTimes)
1.527 + {
1.528 + displayedXTimes = iDisplayedXTimes -> iMsg.Int0();
1.529 + if(displayedXTimes < 1)
1.530 + {
1.531 + iDisplayedXTimes->iMsg.Complete(KErrArgument);
1.532 + iDisplayedXTimes->CheckForReuse();
1.533 + iDisplayedXTimes = NULL;
1.534 + }
1.535 + }
1.536 +
1.537 + const CSurfaceUpdateServer* server = static_cast <const CSurfaceUpdateServer*> (Server());
1.538 + if(screen != KAllScreens)
1.539 + {
1.540 + MCompositionSurfaceUpdate* receiver = server->UpdateReceiver(screen);
1.541 + if(!receiver)
1.542 + {
1.543 + User::Leave(KErrUpdateReceiverNotAvailable);
1.544 + }
1.545 + DispatchUpdate(surfaceId, buffer, region, &displayedXTimes, receiver);
1.546 + iUpdateMethod = EUpdateMethodPerScreen;
1.547 + }
1.548 + else
1.549 + {
1.550 + DispatchUpdate(surfaceId, buffer, region, &displayedXTimes);
1.551 + iUpdateMethod = EUpdateMethodGlobal;
1.552 + }
1.553 +
1.554 + if(region)
1.555 + {
1.556 + CleanupStack::PopAndDestroy(2, rectangleList);
1.557 + }
1.558 + }
1.559 +
1.560 +/**
1.561 + Dispatch update to the composition update receivers.
1.562 + The function could fail to allocate the notification objects
1.563 + due to memory shortage, however, the content update command will still be submitted to the GCE.
1.564 + */
1.565 +void CSurfaceUpdateSession::DispatchUpdate(const TSurfaceId& aSurfaceId, TInt aBuffer, RRegion* aRegion, TInt* aDisplayedXTimes, MCompositionSurfaceUpdate* aReceiver)
1.566 + {
1.567 + TInt index = 1;
1.568 + TInt numReceivers = 1;
1.569 + TInt priority = 0;
1.570 +
1.571 + if(!aReceiver)
1.572 + {
1.573 + aReceiver = iUpdateReceiverEntryList[0]->iUpdateReceiver;
1.574 + priority = iUpdateReceiverEntryList[0]->iPriority;
1.575 + numReceivers = iUpdateReceiverEntryList.Count(); //get the number of all receivers present in the system
1.576 + }
1.577 +
1.578 + for(;;)
1.579 + {
1.580 + CUpdateReceiverNotification* receiverNotificationAvailable = NULL;
1.581 + CUpdateReceiverNotification* receiverNotificationDisplayed = NULL;
1.582 + CUpdateReceiverNotification* receiverNotificationDisplayedXTimes = NULL;
1.583 + TUint32* timeStamp = NULL;
1.584 +
1.585 + //activate objects
1.586 + if(iAvailable)
1.587 + {
1.588 + receiverNotificationAvailable = iAvailable->UpdateReceiverNotification();
1.589 + if(!receiverNotificationAvailable)
1.590 + {
1.591 + iAvailable->iMsg.Complete(KErrNoMemory);
1.592 + iAvailable->CheckForReuse();
1.593 + iAvailable = NULL;
1.594 + }
1.595 + }
1.596 +
1.597 + if(iDisplayed)
1.598 + {
1.599 + receiverNotificationDisplayed = iDisplayed->UpdateReceiverNotification(priority);
1.600 + if(!receiverNotificationDisplayed)
1.601 + {
1.602 + iDisplayed->iMsg.Complete(KErrNoMemory);
1.603 + iDisplayed->CheckForReuse();
1.604 + iDisplayed = NULL;
1.605 + }
1.606 + }
1.607 +
1.608 + if(iDisplayedXTimes)
1.609 + {
1.610 + receiverNotificationDisplayedXTimes = iDisplayedXTimes->UpdateReceiverNotification();
1.611 + if(!receiverNotificationDisplayedXTimes)
1.612 + {
1.613 + iDisplayedXTimes->iMsg.Complete(KErrNoMemory);
1.614 + iDisplayedXTimes->CheckForReuse();
1.615 + iDisplayedXTimes = NULL;
1.616 + }
1.617 + }
1.618 +
1.619 + TRequestStatus *statusAvailable = NULL;
1.620 + TRequestStatus *statusDisplayed = NULL;
1.621 + TRequestStatus *statusDisplayedXTimes = NULL;
1.622 + //activate all notifications
1.623 + if(receiverNotificationAvailable)
1.624 + {
1.625 + statusAvailable = &(receiverNotificationAvailable->Status());
1.626 + receiverNotificationAvailable->Activate();
1.627 + }
1.628 + if(receiverNotificationDisplayed)
1.629 + {
1.630 + statusDisplayed = &(receiverNotificationDisplayed->Status());
1.631 + timeStamp = & receiverNotificationDisplayed -> iTimeStamp;
1.632 + receiverNotificationDisplayed->Activate();
1.633 + }
1.634 + if(receiverNotificationDisplayedXTimes)
1.635 + {
1.636 + statusDisplayedXTimes = &(receiverNotificationDisplayedXTimes->Status());
1.637 + receiverNotificationDisplayedXTimes->Activate();
1.638 + }
1.639 + //And finally, send request to the receiver
1.640 + aReceiver->ContentUpdated(aSurfaceId, aBuffer, aRegion,
1.641 + statusAvailable, statusDisplayed, timeStamp,
1.642 + statusDisplayedXTimes, statusDisplayedXTimes ? aDisplayedXTimes : NULL);
1.643 +
1.644 + if(numReceivers > index)
1.645 + {
1.646 + priority = iUpdateReceiverEntryList[index]->iPriority;
1.647 + aReceiver = iUpdateReceiverEntryList[index++]->iUpdateReceiver;
1.648 + }
1.649 + else
1.650 + break;
1.651 + }//for(;;)
1.652 +
1.653 + iAvailable = NULL;
1.654 + iDisplayed = NULL;
1.655 + iDisplayedXTimes = NULL;
1.656 + }
1.657 +
1.658 +void CSurfaceUpdateSession::CancelAllUpdateNotifications()
1.659 + {
1.660 + //go through all notification objects and issue request complete for outstanding requests
1.661 + TInt count = iUpdateReceiverNotificationBatches.Count();
1.662 +
1.663 + for(TInt index = 0; index < count; index++)
1.664 + {
1.665 + CUpdateReceiverNotificationBatch* notifier = iUpdateReceiverNotificationBatches[index];
1.666 + if(!notifier->iMsg.IsNull())
1.667 + {
1.668 + notifier->iMsg.Complete(KErrCancel);
1.669 + }
1.670 + }
1.671 +
1.672 + iAvailable = NULL;
1.673 + iDisplayed = NULL;
1.674 + iDisplayedXTimes = NULL;
1.675 + }
1.676 +
1.677 +//*********************
1.678 +CUpdateReceiverNotification::CUpdateReceiverNotification(CActive::TPriority aPriority, TInt aReceiverPriority, CUpdateReceiverNotificationBatch *aParentNotificationBatch) :
1.679 + CActive(aPriority), iUpdateReceiverPriority(aReceiverPriority), iParentNotificationBatch(aParentNotificationBatch)
1.680 + {
1.681 + CActiveScheduler::Add(this);
1.682 +#ifdef TEST_SURFACE_UPDATE
1.683 + iServer = iParentNotificationBatch->Server();
1.684 +#endif
1.685 + }
1.686 +
1.687 +CUpdateReceiverNotification::~CUpdateReceiverNotification()
1.688 + {
1.689 + //Content updates can not be cancelled. The user must ensure that the associated content update
1.690 + //is complete before deleting this object.
1.691 + __ASSERT_ALWAYS(!IsActive(), CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity));
1.692 + }
1.693 +
1.694 +void CUpdateReceiverNotification::DoCancel()
1.695 + {
1.696 + //Content Updates can not be cancelled. Content Updates must be allowed to complete normally.
1.697 + CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity);
1.698 + }
1.699 +
1.700 +/**
1.701 +Is triggered every time the GCE signals on notification objects.
1.702 +Delegates processing to the parent notification batch.
1.703 +*/
1.704 +void CUpdateReceiverNotification::RunL()
1.705 + {
1.706 + // CReceiverNotification object is deleted here once it is set to self destroying when run.
1.707 + if (iSelfDestructWhenRun)
1.708 + {
1.709 +#ifdef TEST_SURFACE_UPDATE
1.710 + DecNumberPendingNotifications();
1.711 +#endif
1.712 + delete this;
1.713 + return;
1.714 + }
1.715 + iParentNotificationBatch->ProcessNotificationEvent(this);
1.716 + }
1.717 +
1.718 +TRequestStatus& CUpdateReceiverNotification::Status()
1.719 + {
1.720 + return iStatus;
1.721 + }
1.722 +
1.723 +void CUpdateReceiverNotification::Activate()
1.724 + {
1.725 + iStatus = KRequestPending;
1.726 + SetActive();
1.727 + }
1.728 +
1.729 +#ifdef TEST_SURFACE_UPDATE
1.730 +void CUpdateReceiverNotification::DecNumberPendingNotifications()
1.731 + {
1.732 + if (iServer)
1.733 + {
1.734 + iServer-> iNumberPendingNotification--;
1.735 + }
1.736 + }
1.737 +#endif
1.738 +
1.739 +/**
1.740 +The class maintains the notification objects of the same type and attributed to a
1.741 +particular submit update command.
1.742 + */
1.743 +CUpdateReceiverNotificationBatch::CUpdateReceiverNotificationBatch(CSurfaceUpdateSession *aSession, TInt aNumReceivers) :
1.744 + iSession(aSession), iNumUpdateReceivers(aNumReceivers)
1.745 + {
1.746 + CheckForReuse();
1.747 + }
1.748 +
1.749 +CUpdateReceiverNotificationBatch::~CUpdateReceiverNotificationBatch()
1.750 + {
1.751 + TInt count = iUpdateReceiverNotifications.Count();
1.752 + for(TInt index = 0; index < count; index++)
1.753 + {
1.754 + CUpdateReceiverNotification* notifier = iUpdateReceiverNotifications[index];
1.755 + // CReceiverNotification active object cannot be destroyed if it is active and waiting for
1.756 + // receiver to complete the notification. It deletes itself inside its RunL function when the
1.757 + // notification is completed.
1.758 + if (notifier->IsActive())
1.759 + {
1.760 + notifier->iSelfDestructWhenRun = ETrue;
1.761 +#ifdef TEST_SURFACE_UPDATE
1.762 + IncNumberPendingNotifications();
1.763 +#endif
1.764 + }
1.765 + else
1.766 + {
1.767 + delete notifier;
1.768 + }
1.769 + }
1.770 + iUpdateReceiverNotifications.Close();
1.771 + }
1.772 +
1.773 +/**
1.774 +The function processes signal from composition receiver.
1.775 +It completes outstanding messages on the client and set timestamp parameters if appropriate.
1.776 +Note that this object will not be removed from the
1.777 +array (CSurfaceUpdateSession:: iReceiverNotifications) and can be reused later.
1.778 +*/
1.779 +void CUpdateReceiverNotificationBatch::ProcessNotificationEvent(CUpdateReceiverNotification* aReceiverNotification)
1.780 + {
1.781 + TInt index = iUpdateReceiverNotifications.Find(aReceiverNotification);
1.782 + __ASSERT_DEBUG(index != KErrNotFound, CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity));
1.783 + iUpdateReceiverNotifications.Remove(index);
1.784 + if(iMsg.IsNull())
1.785 + {
1.786 + CheckForReuse();
1.787 + delete aReceiverNotification;
1.788 + return; // the message has already been completed, possibly, because of request cancelation
1.789 + }
1.790 + TBool oldCompleteWithSuccess = iCompleteWithSuccess;
1.791 + TBool newCompleteWithSuccess = EFalse;
1.792 + if(aReceiverNotification->iStatus.Int() == KErrNone)
1.793 + {
1.794 + iCompleteWithSuccess = ETrue;
1.795 + newCompleteWithSuccess = ETrue;
1.796 + }
1.797 +
1.798 + switch(iType)
1.799 + {
1.800 + case EUpdateSrvAvailable:
1.801 + if(iUpdateReceiverNotifications.Count() == 0)
1.802 + {
1.803 + TInt res = iCompleteWithSuccess ? KErrNone : aReceiverNotification->iStatus.Int();
1.804 + iMsg.Complete(res);
1.805 + }
1.806 + break;
1.807 + case EUpdateSrvDisplayedXTimes:
1.808 + if((newCompleteWithSuccess && (index == 0)) || (iUpdateReceiverNotifications.Count() == 0))
1.809 + {
1.810 + TInt res = iCompleteWithSuccess ? KErrNone : aReceiverNotification->iStatus.Int();
1.811 + iMsg.Complete(res);
1.812 + }
1.813 + break;
1.814 + case EUpdateSrvDisplayed:
1.815 + if(newCompleteWithSuccess &&
1.816 + ((iHighestPriority < aReceiverNotification->iUpdateReceiverPriority) || !oldCompleteWithSuccess))
1.817 + {
1.818 + iHighestPriority = aReceiverNotification->iUpdateReceiverPriority;
1.819 + iTimeStamp = aReceiverNotification->iTimeStamp;
1.820 + }
1.821 + if((newCompleteWithSuccess && (index == 0)) || (iUpdateReceiverNotifications.Count() == 0))
1.822 + {
1.823 + TPckgBuf<TUint32> p(iTimeStamp);
1.824 + 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.
1.825 + if(res == KErrNone)
1.826 + {
1.827 + res = iCompleteWithSuccess ? KErrNone : aReceiverNotification->iStatus.Int();
1.828 + }
1.829 + iMsg.Complete(res);
1.830 + }
1.831 + break;
1.832 + default:
1.833 + break;
1.834 + }
1.835 +
1.836 + delete aReceiverNotification;
1.837 + CheckForReuse();
1.838 + }
1.839 +
1.840 +/**
1.841 + The method allocates a notification object and inserts it into the list
1.842 +*/
1.843 +CUpdateReceiverNotification* CUpdateReceiverNotificationBatch::UpdateReceiverNotification(TInt aReceiverPriority)
1.844 + {
1.845 + __ASSERT_DEBUG(iNumUpdateReceivers > iUpdateReceiverNotifications.Count(), CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity));
1.846 +
1.847 + CUpdateReceiverNotification* receiverNotification = new CUpdateReceiverNotification(CActive::EPriorityStandard, aReceiverPriority, this);
1.848 + if(receiverNotification)
1.849 + {
1.850 + TInt res = iUpdateReceiverNotifications.Append(receiverNotification);
1.851 + if(res != KErrNone)
1.852 + {
1.853 + delete receiverNotification;
1.854 + receiverNotification = NULL;
1.855 + }
1.856 + }
1.857 +
1.858 + return receiverNotification;
1.859 + }
1.860 +
1.861 +/**
1.862 +If notification list is empty mark the batch for further use
1.863 +*/
1.864 +void CUpdateReceiverNotificationBatch::CheckForReuse()
1.865 + {
1.866 + if(iUpdateReceiverNotifications.Count() == 0)
1.867 + {
1.868 + iType = EUpdateSrvReusable;
1.869 + iCompleteWithSuccess = EFalse;
1.870 + iHighestPriority = 0;
1.871 + iTimeStamp = 0;
1.872 + }
1.873 + }
1.874 +
1.875 +#ifdef TEST_SURFACE_UPDATE
1.876 +CSurfaceUpdateServer* CUpdateReceiverNotificationBatch::Server()
1.877 + {
1.878 + return (CSurfaceUpdateServer*)(iSession->Server());
1.879 + }
1.880 +
1.881 +void CUpdateReceiverNotificationBatch::IncNumberPendingNotifications()
1.882 + {
1.883 + CServer2* server = static_cast<CServer2*> (Server());
1.884 + if(server)
1.885 + {
1.886 + (static_cast<CSurfaceUpdateServer*> (server))-> iNumberPendingNotification++;
1.887 + }
1.888 + }
1.889 +#endif
1.890 +
1.891 +
1.892 +/**
1.893 +Set number of UpdateReceivers - called when update receivers are added/removed.
1.894 +
1.895 +@param aNumUpdateReceivers - new number of update receivers for the batch.
1.896 + */
1.897 +void CUpdateReceiverNotificationBatch::SetNumUpdateReceivers(TInt aNumUpdateReceivers)
1.898 + {
1.899 + __ASSERT_DEBUG(aNumUpdateReceivers >= 0 && aNumUpdateReceivers < 1000 /* arbitrary "large" limit */,
1.900 + CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity));
1.901 + __ASSERT_DEBUG(iType == EUpdateSrvReusable,
1.902 + CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity));
1.903 + iNumUpdateReceivers = aNumUpdateReceivers;
1.904 + }
1.905 +/**
1.906 +
1.907 +The class will be used by composition receiver
1.908 +*/
1.909 +CSurfaceUpdateServerProvider* CSurfaceUpdateServerProvider::NewL(CActive::TPriority aPriority, CSurfaceUpdateServer* aServer)
1.910 + {
1.911 + CSurfaceUpdateServerProvider* serverProvider = new (ELeave) CSurfaceUpdateServerProvider(aPriority, aServer);
1.912 + CleanupStack::PushL(serverProvider);
1.913 + serverProvider->ConstructL();
1.914 + CleanupStack::Pop();
1.915 + return serverProvider;
1.916 + }
1.917 +
1.918 +CSurfaceUpdateServerProvider::CSurfaceUpdateServerProvider(CActive::TPriority aPriority, CSurfaceUpdateServer* aServer) :
1.919 + CActive(aPriority), iServer(aServer)
1.920 + {
1.921 + RThread thread;
1.922 + iThreadId = thread.Id();
1.923 + }
1.924 +
1.925 +CSurfaceUpdateServerProvider::~CSurfaceUpdateServerProvider()
1.926 + {
1.927 + iSemaphore.Close();
1.928 + Cancel();
1.929 + }
1.930 +/**
1.931 +Create provider and add it to the active scheduler
1.932 +*/
1.933 +void CSurfaceUpdateServerProvider::ConstructL()
1.934 + {
1.935 + User::LeaveIfError(iSemaphore.CreateLocal(0));
1.936 + CActiveScheduler::Add(this);
1.937 + iStatus = KRequestPending;
1.938 + SetActive();
1.939 + }
1.940 +
1.941 +/**
1.942 + Assign composition receiver instance to particular screen.
1.943 + The following calls of this function for the same screen will override the previous.
1.944 + @see MSurfaceUpdateServerProvider::::Register
1.945 + */
1.946 +EXPORT_C TInt CSurfaceUpdateServerProvider::Register(TInt aScreen, CBase* aReceiver, TInt aPriority)
1.947 + {
1.948 + RThread thread;
1.949 + TInt res = thread.Open(iThreadId);
1.950 + if(res == KErrNone)
1.951 + {
1.952 + iScreen = aScreen;
1.953 + iUpdateReceiver = aReceiver;
1.954 + iPriority = aPriority;
1.955 +
1.956 + TRequestStatus* status = &iStatus;
1.957 + thread.RequestComplete(status, EUpdateServEventRegister);
1.958 + thread.Close();
1.959 + iSemaphore.Wait();
1.960 + res = iRegisterErr;
1.961 + }
1.962 + return res;
1.963 + }
1.964 +
1.965 +/**
1.966 +Terminate the SUS and release all memory associated with it.
1.967 +The function was introduced for debugging purpose only and is not considered
1.968 +as part of public API.
1.969 +*/
1.970 +EXPORT_C void CSurfaceUpdateServerProvider::Terminate()
1.971 + {
1.972 +#ifdef TEST_SURFACE_UPDATE
1.973 + RThread thread;
1.974 +
1.975 + if(thread.Open(iThreadId) == KErrNone)
1.976 + {
1.977 + TInt err = gProviderFastLock.CreateLocal();
1.978 + __ASSERT_ALWAYS(err == KErrNone || err == KErrAlreadyExists, CSurfaceUpdateServer::PanicServer(EUpdateServPanicGlobalFastLock));
1.979 +
1.980 + gProviderFastLock.Wait();
1.981 + gProvider = NULL;
1.982 + if (iServer)
1.983 + {
1.984 + while((static_cast<CSurfaceUpdateServer*> (iServer))-> iNumberPendingNotification)
1.985 + User::After(TTimeIntervalMicroSeconds32(1000));
1.986 + }
1.987 + TRequestStatus* status = &iStatus;
1.988 + thread.RequestComplete(status, EUpdateServEventTerminate);
1.989 +
1.990 + //wait until the thread dies
1.991 + TRequestStatus status1;
1.992 + thread.Logon(status1);
1.993 + User::WaitForRequest(status1);
1.994 + thread.Close();
1.995 +
1.996 + gProviderFastLock.Close();
1.997 + }
1.998 +#endif
1.999 + }
1.1000 +
1.1001 +/**
1.1002 +The function processes signals which come from composition receiver thread.
1.1003 +*/
1.1004 +void CSurfaceUpdateServerProvider::RunL()
1.1005 + {
1.1006 + switch(iStatus.Int())
1.1007 + {
1.1008 + case EUpdateServEventTerminate:
1.1009 + CActiveScheduler::Stop();
1.1010 + return;
1.1011 + case EUpdateServEventRegister:
1.1012 + iRegisterErr = iServer->Register(iScreen, iUpdateReceiver, iPriority);
1.1013 + iUpdateReceiver = NULL;
1.1014 + iStatus = KRequestPending;
1.1015 + SetActive();
1.1016 + iSemaphore.Signal();
1.1017 + break;
1.1018 + default :
1.1019 + CSurfaceUpdateServer::PanicServer(EUpdateServPanicBadRequest);
1.1020 + iStatus = KRequestPending;
1.1021 + SetActive();
1.1022 + break;
1.1023 + }
1.1024 + }
1.1025 +
1.1026 +void CSurfaceUpdateServerProvider::DoCancel()
1.1027 + {
1.1028 + }
1.1029 +
1.1030 +/**
1.1031 +Spawn a thread within WSERV process. This will lead to starting the surface update server in it
1.1032 +@publishedPartner
1.1033 +@prototype Intended to be used by Surface Update control flow
1.1034 +
1.1035 +@param aUpdateProvider - [out] reference pointer to surface update server provider,
1.1036 + which will be set when the server is started. The variable will be used to registry
1.1037 + composition receiver instances. The caller doesn't acquire the ownership of this instance,
1.1038 + thus mustn't delete it. The pointer will be valid until server is operating,
1.1039 + i.e. system is up.
1.1040 +
1.1041 +@return KErrNone if an operation is successful, any other system error codes otherwise
1.1042 +*/
1.1043 +EXPORT_C TInt StartSurfaceUpdateServer(MSurfaceUpdateServerProvider*& aSurfaceUpdateServerProvider)
1.1044 + {
1.1045 +#ifndef TEST_SURFACE_UPDATE
1.1046 + TPtrC serverName(KSurfaceUpdateServerName);
1.1047 +#else
1.1048 + TPtrC serverName(KTestSurfaceUpdateServerName);
1.1049 +#endif
1.1050 + //locking
1.1051 + TInt err = gProviderFastLock.CreateLocal();
1.1052 +
1.1053 + if (err != KErrNone && err != KErrAlreadyExists)
1.1054 + {
1.1055 + return err;
1.1056 + }
1.1057 +
1.1058 + gProviderFastLock.Wait();
1.1059 +
1.1060 + TAny *provider = gProvider;
1.1061 + if(provider)
1.1062 + {
1.1063 + aSurfaceUpdateServerProvider = static_cast <MSurfaceUpdateServerProvider*> (provider);
1.1064 + gProviderFastLock.Signal();
1.1065 + return KErrNone;
1.1066 + }
1.1067 + TFullName name;
1.1068 + RThread serverThread;
1.1069 + TInt res = KErrAlreadyExists;
1.1070 +
1.1071 + TFindServer findSurfaceUpdateServer(serverName);
1.1072 + // Need to check that the server exists.
1.1073 + if (findSurfaceUpdateServer.Next(name) !=KErrNone)
1.1074 + {
1.1075 + TTime tm;
1.1076 + TBuf<32> buf;
1.1077 + tm.UniversalTime();
1.1078 + TRAP(res, tm.FormatL(buf, _L("_%H%T%S%C")));
1.1079 + if(res != KErrNone)
1.1080 + {
1.1081 + gProviderFastLock.Signal();
1.1082 + return res;
1.1083 + }
1.1084 + TBuf<128> threadName(serverName);
1.1085 + threadName.Append(buf); //guarantee uniqueness of the thread name
1.1086 + // Create the thread for the server.
1.1087 + res = serverThread.Create(threadName,
1.1088 + CSurfaceUpdateServer::ThreadFunction,
1.1089 + KDefaultStackSize,
1.1090 + KDefaultHeapSize,
1.1091 + KDefaultHeapSize,
1.1092 + (TAny*) &aSurfaceUpdateServerProvider
1.1093 + );
1.1094 + // The thread has been created OK so get it started - however
1.1095 + // we need to make sure that it has started before we continue.
1.1096 + if (res==KErrNone)
1.1097 + {
1.1098 + TRequestStatus rendezvousStatus;
1.1099 + TThreadPriority priority = RThread().Priority();
1.1100 + serverThread.SetPriority(priority); // The same as the priority of the creating thread
1.1101 + serverThread.Rendezvous(rendezvousStatus);
1.1102 + serverThread.Resume();
1.1103 + User::WaitForRequest(rendezvousStatus);
1.1104 + res = rendezvousStatus.Int();
1.1105 + gProvider = aSurfaceUpdateServerProvider;
1.1106 + }
1.1107 + // The thread has not been created - clearly there's been a problem.
1.1108 + else
1.1109 + {
1.1110 + serverThread.Close();
1.1111 + }
1.1112 + }
1.1113 + gProviderFastLock.Signal();
1.1114 + return res;
1.1115 + }