sysstatemgmt/systemstateplugins/utilityplugins/src/lafshutdowneventobserveradaptor.cpp
changeset 83 11da52d4c847
parent 78 3f0699f2e14c
child 84 db3d1bc2aa9c
equal deleted inserted replaced
78:3f0699f2e14c 83:11da52d4c847
     1 // Copyright (c) 2008-2009 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 <e32debug.h>
       
    17 #include <savepriv.h>
       
    18 #include <s32mem.h>
       
    19 #include <ssm/ssmstatemanager.h>
       
    20 #include "lafshutdowneventobserveradaptor.h"
       
    21 
       
    22 _LIT( KLafShutDLL, "loadlafshutdown.dll" );
       
    23 typedef MSsmLoadLafShut* (*TFuncLoadLafShutL)(void);
       
    24 
       
    25 const TInt KNumConnectRetries	=10;
       
    26 //number of times re request the shutdown server for registered client array when
       
    27 //server side client array count is not equal to client side array count 
       
    28 const TInt KMaxNumOfRetries	= 2;
       
    29 
       
    30 const TUid KServerUid3={0x10004902};
       
    31 _LIT(KShutdownSrvName,"shutdownsrvs");
       
    32 
       
    33 /**
       
    34 Used to create an instance of CLafShutdownEventObserverAdaptor.
       
    35 
       
    36 @return	A pointer to an object of type CLafShutdownEventObserverAdaptor.
       
    37 */
       
    38 EXPORT_C MSsmUtility* CLafShutdownEventObserverAdaptor::NewL()
       
    39 	{
       
    40 	CLafShutdownEventObserverAdaptor* self = new (ELeave) CLafShutdownEventObserverAdaptor();
       
    41 	return static_cast<MSsmUtility*>(self);
       
    42 	}
       
    43 
       
    44 /**
       
    45 Used to Initialize the utlity plugin.
       
    46 @see MSsmUtility::InitializeL()
       
    47 */
       
    48 void CLafShutdownEventObserverAdaptor::InitializeL()
       
    49 	{
       
    50 	User::LeaveIfError(iLafShutLib.Load(KLafShutDLL));
       
    51 	TFuncLoadLafShutL lafShut = reinterpret_cast<TFuncLoadLafShutL>(iLafShutLib.Lookup(1));
       
    52 	iLafShutdown = lafShut();
       
    53 	User::LeaveIfNull(iLafShutdown);
       
    54 	iLafShutdown->CreateShutdownManager(*this);
       
    55 	}
       
    56 
       
    57 /**
       
    58 Starts the utility plugin.
       
    59 @see MSsmUtility::StartL()
       
    60 */
       
    61 void CLafShutdownEventObserverAdaptor::StartL()
       
    62 	{
       
    63 	User::LeaveIfError(iShutdownSrvSession.ConnectL());
       
    64 	}
       
    65 
       
    66 /**
       
    67 Release memory associated with this SUP.
       
    68 @see MSsmUtility::Release()
       
    69 */
       
    70 void CLafShutdownEventObserverAdaptor::Release()
       
    71 	{
       
    72 	iLafShutdown->DeleteShutdownManager();
       
    73 	iLafShutdown = NULL;
       
    74 	iLafShutLib.Close();
       
    75 	}
       
    76 
       
    77 /**
       
    78 This function notifies all client registered for shutdown notification, and issues a state change to shutdown.
       
    79 @panic EInvalidSession If shutdown server's session is invalid
       
    80 */
       
    81 void CLafShutdownEventObserverAdaptor::HandleShutdownEventL(MSaveObserver::TSaveType aAction, TBool aPowerOff, TPowerState aEvent)
       
    82 	{
       
    83 	__ASSERT_ALWAYS(iShutdownSrvSession.Handle(), User::Panic(KPanicShutdownEventObserverAdaptor, EInvalidSession));
       
    84 	//HandleShutdownEventL() will call NotifySave()
       
    85 	iShutdownSrvSession.HandleShutdownEventL(aAction, aPowerOff, aEvent);
       
    86 
       
    87 	//Connect to System State Manager
       
    88 	//Create a shutdown state for transition
       
    89 	//Request for shutdown transition passing the shutdown event
       
    90 	RSsmStateManager stateManager;
       
    91 	User::LeaveIfError(stateManager.Connect());
       
    92 	TSsmStateTransition state(ESsmShutdown, KSsmAnySubState, aEvent);
       
    93 	stateManager.RequestStateTransition(state);
       
    94 	stateManager.Close();
       
    95 	}
       
    96 
       
    97 /**
       
    98 @panic EInvalidSession If shutdown server's session is invalid
       
    99 */
       
   100 CArrayFix<TThreadId>* CLafShutdownEventObserverAdaptor::ClientArrayLC()
       
   101 	{
       
   102 	__ASSERT_ALWAYS(iShutdownSrvSession.Handle(), User::Panic(KPanicShutdownEventObserverAdaptor, EInvalidSession));
       
   103 	return iShutdownSrvSession.ClientArrayLC();
       
   104 	}
       
   105 
       
   106 /**
       
   107 @panic EInvalidSession If shutdown server's session is invalid
       
   108 */
       
   109 TBool CLafShutdownEventObserverAdaptor::IsClientHung(TThreadId aId) const
       
   110 	{
       
   111 	__ASSERT_ALWAYS(iShutdownSrvSession.Handle(), User::Panic(KPanicShutdownEventObserverAdaptor, EInvalidSession));
       
   112 	return iShutdownSrvSession.IsClientHung(aId);
       
   113 	}
       
   114 
       
   115 /**
       
   116 @panic EInvalidSession If shutdown server's session is invalid
       
   117 */
       
   118 void CLafShutdownEventObserverAdaptor::GetShutdownState(TBool& aPowerOff, TBool& aAllSessionsHavePendingRequest) const
       
   119 	{
       
   120 	__ASSERT_ALWAYS(iShutdownSrvSession.Handle(), User::Panic(KPanicShutdownEventObserverAdaptor, EInvalidSession));
       
   121 	iShutdownSrvSession.GetShutdownState(aPowerOff, aAllSessionsHavePendingRequest);
       
   122 	}
       
   123 
       
   124 CLafShutdownEventObserverAdaptor::CLafShutdownEventObserverAdaptor()
       
   125 	{
       
   126 	}
       
   127 
       
   128 CLafShutdownEventObserverAdaptor::~CLafShutdownEventObserverAdaptor()
       
   129 	{
       
   130 	}
       
   131 
       
   132 /**
       
   133 This method will establish the connection with the shutdown server. If the shutdown server
       
   134 is not started yet, it will be started.
       
   135 @return KErrNone The connection was established successfully.
       
   136 @return Some other system-wide error codes
       
   137 */
       
   138 TInt CLafShutdownEventObserverAdaptor::RShutdownSrvSession::ConnectL()
       
   139 	{
       
   140 	TInt err=KErrNone;
       
   141 	TInt retry=KNumConnectRetries;
       
   142 	FOREVER
       
   143 		{
       
   144 		err = CreateSession(__SHUTDOWN_SERVER_NAME, TVersion(KShutdownMajorVN,KShutdownMinorVN,KShutdownBuildVN), KShutdownMessageSlots);
       
   145 		if ((--retry>0) && ((err==KErrNotFound) || (err==KErrServerTerminated)))
       
   146 			{
       
   147 			err = StartServerL();
       
   148 			if ((err!=KErrNone) && (err!=KErrAlreadyExists))
       
   149 				{
       
   150 				break;
       
   151 				}
       
   152 			}
       
   153 		else
       
   154 			{
       
   155 			break;
       
   156 			}
       
   157 		}
       
   158 	return err;
       
   159 	}
       
   160 
       
   161 /**
       
   162 This method starts the shutdown server.
       
   163 @return KErrNone The server was started successfully.
       
   164 @return KErrAlreadyExists The server is started already.
       
   165 @return Some other system-wide error codes
       
   166 */
       
   167 TInt CLafShutdownEventObserverAdaptor::RShutdownSrvSession::StartServerL()
       
   168 	{
       
   169 	TInt error=KErrNone;
       
   170 	const TUidType serverUid(KNullUid,KNullUid,KServerUid3);
       
   171 
       
   172 	RProcess server;
       
   173 	error = server.Create(KShutdownSrvName,KNullDesC,serverUid);
       
   174 	if(error!=KErrNone)
       
   175 		return error;
       
   176  	TRequestStatus stat;
       
   177 	server.Rendezvous(stat);
       
   178  	if (stat!=KRequestPending)
       
   179  		server.Kill(0);		// abort startup
       
   180  	else
       
   181  		server.Resume();	// logon OK - start the server
       
   182  	User::WaitForRequest(stat);		// wait for start or death
       
   183  	// we can't use the 'exit reason' if the server panicked as this
       
   184  	// is the panic 'reason' and may be '0' which cannot be distinguished
       
   185  	// from KErrNone
       
   186  	error=(server.ExitType()==EExitPanic) ? KErrGeneral : stat.Int();
       
   187 	server.Close();
       
   188 	return error;
       
   189 	}
       
   190 
       
   191 /**
       
   192 This method has to be called, when the registered clients have to be notified that a 
       
   193 particular action has to be done, such as MSaveObserver::ESaveData, MSaveObserver::ESaveAll, 
       
   194 MSaveObserver::EReleaseRAM,...
       
   195 If the requested action is not MSaveObserver::ESaveNone, the method will call 
       
   196 CServShutdownServer::NotifySave().
       
   197 @param aAction The type of the requested action
       
   198 @param aPowerOff If it is non-zero, this is the beginning of a powerdown sequence.
       
   199 @param aEvent The type of the powerdown event (power off or restart)
       
   200 @leave KErrNotSupported Leaves if aEvent is invalid  
       
   201 @see CServShutdownServer::NotifySave()
       
   202 @see TPowerState
       
   203 */
       
   204 void CLafShutdownEventObserverAdaptor::RShutdownSrvSession::HandleShutdownEventL(MSaveObserver::TSaveType aAction, TBool aPowerOff, TPowerState aEvent)
       
   205 	{
       
   206 	SendReceive(EEventObsAdaptHandleShutdown, TIpcArgs(aAction, aPowerOff, aEvent));
       
   207 	}
       
   208 
       
   209 /**
       
   210 This method creates an array of CArrayFix<TThreadId> type and appends to it the
       
   211 thread id-s of the all registered clients.
       
   212 The created CArrayFix<TThreadId> instance will be pushed on the cleanup stack.
       
   213 Logic for this function is as follows
       
   214 step1: Request the shutdown server to get the count of registered clients.
       
   215 step2: Create buffer of size arrayCount * sizeof(TThreadId).
       
   216 step3: Request the shutdown server to get the array of registered clients. If some client 
       
   217 	   is registered after step 2 then server will return new count and empty buffer.
       
   218 step4: If buffer is emptey and server side client array is not equal to client side array 
       
   219 	   count then repeat the step 3 for 2 times.
       
   220 step5: if client side array count is equal to server side client array count then append thread ids 
       
   221 	   to array and return the array else return empty array.	
       
   222 @return A pointer to a CArrayFix<TThreadId> array with the client thread id-s.if client side array count 
       
   223 		is equal to server side client array count then append thread ids to array and return the array else return empty array.
       
   224 */
       
   225 CArrayFix<TThreadId>* CLafShutdownEventObserverAdaptor::RShutdownSrvSession::ClientArrayLC()
       
   226 	{
       
   227 	CArrayFix<TThreadId>* clientArray = new (ELeave) CArrayFixFlat<TThreadId>(2);
       
   228 	CleanupStack::PushL(clientArray);
       
   229 
       
   230 	//arrayCount refers to the array count at server side
       
   231 	TInt arrayCount = 0;
       
   232 	TPckg<TInt> pckg(arrayCount);
       
   233 	User::LeaveIfError(SendReceive(EEventObsAdaptClientArrayCount, TIpcArgs(&pckg)));
       
   234 	//return an empty array because arrayCount is 0
       
   235 	if (arrayCount > 0)
       
   236 		{
       
   237 		CBufFlat* buffer = CBufFlat::NewL(arrayCount * sizeof(TThreadId));
       
   238 		CleanupStack::PushL(buffer);
       
   239 		
       
   240 	    TPtr8 bufPtr = buffer->Ptr(0);
       
   241 		TInt clientSideArrayCount = 0;			//clientSideArrayCount refers to the array count at client side
       
   242 		//Request the server to get the registered clients. If server side array count is not equal to client 
       
   243 		//side array count then retry to request the server for KMaxNumOfRetries times 
       
   244 		for (TInt numOfRetries = 0; clientSideArrayCount != arrayCount && numOfRetries <= KMaxNumOfRetries; ++numOfRetries )
       
   245 			{
       
   246 			clientSideArrayCount = arrayCount;
       
   247 			buffer->ResizeL(clientSideArrayCount * sizeof(TThreadId));
       
   248 			bufPtr.Set(buffer->Ptr(0));
       
   249 			User::LeaveIfError(SendReceive(EEventObsAdaptClientArray, TIpcArgs(&bufPtr,clientSideArrayCount,&pckg)));
       
   250 			}
       
   251 
       
   252 		if (clientSideArrayCount != arrayCount)		//retries exhausted and count doesn't match
       
   253 			{
       
   254 			CleanupStack::PopAndDestroy(buffer);
       
   255 			User::Leave(KErrGeneral);
       
   256 			}
       
   257 			
       
   258 		RBufReadStream readStream(*buffer);
       
   259 		readStream.PushL();
       
   260 		TKeyArrayFix key(0,ECmpTInt);
       
   261 
       
   262 		for (TInt i = 0; i < arrayCount; ++i)
       
   263 			{
       
   264 			const TInt32 threadHighBit = readStream.ReadUint32L();
       
   265 			const TInt32 threadLowBit = readStream.ReadUint32L();
       
   266 			TThreadId threadId(MAKE_TINT64(threadHighBit, threadLowBit)); 
       
   267 			TInt pos;
       
   268 			if (0 != clientArray->Find(threadId,key,pos))
       
   269 				{
       
   270 			    clientArray->AppendL(threadId);  
       
   271 				}
       
   272 			}
       
   273 		readStream.Pop();
       
   274 		readStream.Close();
       
   275 		CleanupStack::PopAndDestroy(buffer);
       
   276 		}
       
   277 	return clientArray;
       
   278 	}
       
   279 /**
       
   280 This method checks for pending request of a client's thread, which is passed through aId.
       
   281 @param aId Client's thread id.
       
   282 @return ETrue if the client with this thread id has no pending request otherwise EFalse.
       
   283 */
       
   284 TBool CLafShutdownEventObserverAdaptor::RShutdownSrvSession::IsClientHung(TThreadId aId) const
       
   285 	{
       
   286 	TBool retVal = EFalse;
       
   287 	TPckg<TInt32> pkg1(aId);
       
   288 	TPckg<TInt32> pkg2(retVal);
       
   289 	TIpcArgs args(&pkg1, &pkg2);
       
   290 
       
   291 	SendReceive(EEventObsAdaptIsClientHung, args);
       
   292 
       
   293 	return retVal;
       
   294 	}
       
   295 
       
   296 /**
       
   297 This method returns an information about the shutdown status.
       
   298 @param aPowerOff An output parameter. It will be non-zero, if a powerdown sequence 
       
   299 				 has been initiated.
       
   300 @param aAllSessionsHavePendingRequest It will be non-zero, if all clients has pending requests.
       
   301 */
       
   302 void CLafShutdownEventObserverAdaptor::RShutdownSrvSession::GetShutdownState(TBool& aPowerOff, TBool& aAllSessionsHavePendingRequest) const
       
   303 	{
       
   304 	TPckg<TBool> powerOff(aPowerOff);
       
   305 	TPckg<TBool> allSessionsHavePendingRequest(aAllSessionsHavePendingRequest);
       
   306 	TIpcArgs args(&powerOff, &allSessionsHavePendingRequest);
       
   307 	SendReceive(EEventObsAdaptGetShutdownState, args);
       
   308 	}
       
   309