datacommsserver/esockserver/test/util/src/esockloader.cpp
changeset 0 dfb7c4ff071f
equal deleted inserted replaced
-1:000000000000 0:dfb7c4ff071f
       
     1 // Copyright (c) 2003-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 <e32base.h>
       
    17 #include <e32property.h>
       
    18 #include <c32root.h>
       
    19 #include <cfshared.h>
       
    20 #include <comms-infras/commsdebugutility.h>
       
    21 
       
    22 #include "esockloader.h"
       
    23 
       
    24 __FLOG_STMT(_LIT8(KESockLogSubsys, "esock");)
       
    25 __FLOG_STMT(_LIT8(KESockLogComponent, "esockloader");)
       
    26 
       
    27 /** When unloading ESock forced we try first in a graceful manner, if it hasn't
       
    28 unloaded after this timeout it is asked to shutdown immediately.
       
    29 This will happen if ESock has "hanging" sessions.
       
    30  */
       
    31 const TInt KGracefulTimeout = 90 * 1000000;
       
    32 
       
    33 #if defined (__WINS__)
       
    34 #define PDD_NAME _L("ECDRV")
       
    35 #define LDD_NAME _L("ECOMM")
       
    36 #else
       
    37 #define PDD_NAME _L("EUART1")
       
    38 #define LDD_NAME _L("ECOMM")
       
    39 #endif
       
    40 
       
    41 EXPORT_C TInt ESockLoader::LoadESock(MHarnessLogAdaptor* aHarnessLogger)
       
    42 /** Connect to the Comms Rootserver and request load of the Socket Server CPM.
       
    43 Returns when it is loaded. 
       
    44 */
       
    45 	{
       
    46 	__FLOG_DECLARATION_VARIABLE;
       
    47 	__FLOG_OPEN(KESockLogSubsys, KESockLogComponent);
       
    48 	__FLOG(_L("ESockLoader::LoadESock"));
       
    49 	
       
    50 	TPtrC pddName = PDD_NAME;
       
    51 	TPtrC lddName = LDD_NAME;
       
    52 
       
    53 	// Load the communications drivers first - no use starting C32 without them.
       
    54 	TInt result = User::LoadPhysicalDevice(pddName);
       
    55 	if (result!=KErrNone && result!=KErrAlreadyExists)
       
    56 		{
       
    57 		__FLOG_2(_L("ESockLoader::LoadConfig - could not load Serial Physical Device Driver \"%S\" due to error %d so the device's COMM ports will not be available"), &pddName, result);
       
    58 		aHarnessLogger->Log(_L("Could not load Serial Physical Device Driver \"%S\" due to error %d so the device's COMM ports will not be available"), &pddName, result);
       
    59 		}
       
    60 
       
    61 	result=User::LoadLogicalDevice(lddName);
       
    62 	if (result!=KErrNone && result!=KErrAlreadyExists)
       
    63 		{
       
    64 		__FLOG_2(_L("ESockLoader::LoadConfig - could not load Serial Logical Device Driver \"%S\" due to error %d so the device's COMM ports will not be available"), &lddName, result);	
       
    65 		aHarnessLogger->Log(_L("Could not load Serial Logical Device Driver \"%S\" due to error %d so the device's COMM ports will not be available"), &lddName, result);
       
    66 		}
       
    67 
       
    68 	// Boot the Comms Process, but avoid loading the Phonebook Synchronizer.
       
    69 	#ifdef __FLOG_ACTIVE
       
    70 		TBool warmBoot = TestC32ExeStarted(__logger__);
       
    71 	#else
       
    72 		TBool warmBoot = TestC32ExeStarted();
       
    73 	#endif
       
    74 	if(warmBoot)
       
    75 		{
       
    76 		aHarnessLogger->Log(_L("Starting C32Start warm-boot"));
       
    77 		}
       
    78 	else
       
    79 		{
       
    80 		aHarnessLogger->Log(_L("Starting C32Start cold-boot"));
       
    81 		}
       
    82 	_LIT(KPhbkSyncCMI, "phbsync.cmi");
       
    83 	result=WarmBootC32(KPhbkSyncCMI);
       
    84 	
       
    85 	if(result == KErrNone)
       
    86 		{
       
    87 		aHarnessLogger->Log(warmBoot ? _L("C32Start warm-boot succeeded") : _L("C32Start cold-boot succeeded"));
       
    88 		__FLOG(_L("ESockLoader::LoadESock - succeeded"));
       
    89 		}
       
    90 	else
       
    91 		{
       
    92 		aHarnessLogger->Log(warmBoot ? _L("C32Start warm-boot failed with error %d") : _L("C32Start cold-boot failed with error %d"), result);
       
    93 		__FLOG_1(_L("ESockLoader::LoadESock - failed with error %d"), result);
       
    94 		}
       
    95 	__FLOG_CLOSE;
       
    96 
       
    97 	return result;
       
    98 	}
       
    99 
       
   100 // Helper fn: build a list of instances of CPMs running ESOCKSVR.DLL
       
   101 void ESockLoader::BuildESockCPMListL(RRootServ& aRootServer, RUnloadInfoArray& aInfo, TDes8& aDispList)
       
   102 	{
       
   103 	__FLOG_DECLARATION_VARIABLE;
       
   104 	__FLOG_OPENC(KESockLogSubsys, KESockLogComponent);
       
   105 	__FLOG(_L8("ESockLoader::BuildConfigCPMListL"));
       
   106 
       
   107 	TRSIter iter;
       
   108 	TCFModuleName modName;
       
   109 	TRSModuleInfo modInfo;
       
   110 	aInfo.ResetAndDestroy();
       
   111 	aDispList.SetLength(0);
       
   112 	while(aRootServer.EnumerateModules(iter, modName) == KErrNone)
       
   113 		{
       
   114 		if(aRootServer.GetModuleInfo(modName, modInfo) == KErrNone)
       
   115 			{
       
   116 			_LIT(KESockSvrDLL, "*ESOCKSVR.DLL");
       
   117 			if(modInfo.iParams.iDll.MatchF(KESockSvrDLL) >= 0)
       
   118 				{
       
   119 				TESockSvrUnloadInfo* unloadInfo = new(ELeave) TESockSvrUnloadInfo;
       
   120 				unloadInfo->iName.Copy(modInfo.iParams.iName);
       
   121 				unloadInfo->iState=modInfo.iParams.iState;
       
   122 				unloadInfo->iStatus=KErrNone;
       
   123 				if(aDispList.Length() != 0)
       
   124 					{
       
   125 					aDispList.Append(_L8(", "));
       
   126 					}
       
   127 				aDispList.Append(unloadInfo->iName);
       
   128 				TInt err = aInfo.Append(unloadInfo);
       
   129 				if(err != KErrNone)
       
   130 					{
       
   131 					delete unloadInfo;
       
   132 					User::Leave(err);
       
   133 					}
       
   134 				}
       
   135 			}
       
   136 		}
       
   137 	
       
   138 	__FLOG_CLOSE_CLEANUP;
       
   139 	}
       
   140 
       
   141 #ifdef __FLOG_ACTIVE
       
   142 	TBool ESockLoader::TestC32ExeStarted(RFileLogger& __logger__)
       
   143 #else
       
   144 	TBool ESockLoader::TestC32ExeStarted()
       
   145 #endif
       
   146 	{
       
   147 	__FLOG(_L8("ESockLoader::TestC32ExeStarted"));
       
   148 
       
   149 	_LIT(KC32StartName,"*");
       
   150 	TBool ret = EFalse;
       
   151 	TFullName fn;
       
   152 	TFindProcess fp(KC32StartName);
       
   153 	while(!ret && fp.Next(fn) == KErrNone)
       
   154 		{
       
   155 		RProcess proc;
       
   156 		TInt result = proc.Open(fn);
       
   157 		if(result == KErrNone)
       
   158 			{
       
   159 			TUidType type = proc.Type();
       
   160 			if(type[2] == KUidCommsProcess && proc.ExitType() == EExitPending) 
       
   161 				{
       
   162 				ret = ETrue;
       
   163 				}
       
   164 			proc.Close();	
       
   165 			}
       
   166 		}
       
   167 
       
   168 	return ret;
       
   169 	}
       
   170 
       
   171 #ifdef __FLOG_ACTIVE
       
   172 	TBool ESockLoader::KillC32Exe(RFileLogger& __logger__)
       
   173 #else
       
   174 	TBool ESockLoader::KillC32Exe()
       
   175 #endif
       
   176 	{
       
   177 	__FLOG(_L8("ESockLoader::KillC32Exe"));
       
   178 
       
   179 	_LIT(KC32StartName,"*");
       
   180 	TBool ret = EFalse;
       
   181 	TFullName fn;
       
   182 	TFindProcess fp(KC32StartName);
       
   183 	while(!ret && fp.Next(fn) == KErrNone)
       
   184 		{
       
   185 		RProcess proc;
       
   186 		TInt result = proc.Open(fn);
       
   187 		if(result == KErrNone)
       
   188 			{
       
   189 			TUidType type = proc.Type();
       
   190 			if(type[2] == KUidCommsProcess) 
       
   191 				{
       
   192 				proc.Kill(KErrNone);
       
   193 				}
       
   194 			proc.Close();	
       
   195 			}
       
   196 		}
       
   197 
       
   198 	return ret;
       
   199 	}
       
   200 	
       
   201 #ifdef __FLOG_ACTIVE
       
   202 	void ESockLoader::DoUnloadESockL(TCFShutdownType aType, MHarnessLogAdaptor* aHarnessLogger, RFileLogger& __logger__)
       
   203 #else
       
   204 	void ESockLoader::DoUnloadESockL(TCFShutdownType aType, MHarnessLogAdaptor* aHarnessLogger)
       
   205 #endif
       
   206 	{
       
   207 	__FLOG_1(_L8("ESockLoader::DoUnLoadConfigL - CommsFW::TCFShutdownType==%d"), aType);
       
   208 
       
   209 	// No need to restart esock (c32exe.exe) if esock (c32exe.exe) is not started...
       
   210 #ifdef __FLOG_ACTIVE
       
   211 	if (!TestC32ExeStarted(__logger__))
       
   212 #else
       
   213 	if (!TestC32ExeStarted())
       
   214 #endif
       
   215 		{
       
   216 		aHarnessLogger->Log(_L8("C32 is not running so it does not need to be shutdown"));
       
   217 		__FLOG(_L8("ESockLoader::DoUnloadESockL - C32 is not running so it does not need to be shutdown"));
       
   218 
       
   219 		return;
       
   220 		}		
       
   221 	
       
   222 	// Start the Comms Process
       
   223 	_LIT(KPhbkSyncCMI, "phbsync.cmi");
       
   224 	TInt err=StartC32WithCMISuppressions(KPhbkSyncCMI);
       
   225 
       
   226 	int leakValue;
       
   227 	RProperty leakProperty;
       
   228 	TBool checkForLeaks; //if enabled
       
   229 	
       
   230 	//The root server should have been started so we can attack to the leak Property now
       
   231 	checkForLeaks = (leakProperty.Attach(KUidCommsProcess, KUidCommsModuleLeakCounter) == KErrNone);
       
   232 	CleanupClosePushL(leakProperty);
       
   233 	if (checkForLeaks)
       
   234 		{
       
   235 		checkForLeaks = (leakProperty.Get(leakValue) == KErrNone);	
       
   236 		}
       
   237 
       
   238 	// With the Staged Start-up Architecture it is likely that ESOCK modules continue to load after the ECoreComponentsStarted
       
   239 	// state which releases StartC32() and RSocketServ::Connect(). So here we wait until the RootServer is fully configured before
       
   240 	// starting the shutdown, which avoids various races (modules may not be bound yet, or even loaded at all by the Configurator
       
   241 	// and hence invisible to this unloading code)
       
   242 	RProperty configurationProperty;
       
   243 	configurationProperty.Attach(KUidSystemCategory, KUidC32StartPropertyKey.iUid);	// needs the KEY
       
   244 	TInt propertyValue = EInitialising;	// set to safe state
       
   245 	TInt propertyResult = configurationProperty.Get(propertyValue);
       
   246 	TRequestStatus propertyStatus;
       
   247 	while(propertyValue < EConfigurationComplete)
       
   248 		{
       
   249 		configurationProperty.Subscribe(propertyStatus);
       
   250 		
       
   251 		if(configurationProperty.Get(propertyValue) == KErrNone && propertyValue == EConfigurationComplete)
       
   252 			{
       
   253 			configurationProperty.Cancel();
       
   254 			}
       
   255 		User::WaitForRequest(propertyStatus);
       
   256 		}
       
   257 
       
   258 	RRootServ rootserver;
       
   259 	if(err==KErrNone)
       
   260 		{
       
   261 		err=rootserver.Connect();
       
   262 		}
       
   263 	User::LeaveIfError(err);
       
   264 	CleanupClosePushL(rootserver);
       
   265 	
       
   266 	// Find all instances of CPMs running ESOCKSVR.DLL. We treat them all equally rather than trying anything
       
   267 	// clever such as telling the Main Thread to shutdown last, etc - ESOCK does whatever is best
       
   268 
       
   269 	RUnloadInfoArray unloadArray(16);
       
   270 	CleanupClosePushL(unloadArray);
       
   271 	TBuf8<256> modList;
       
   272 	BuildESockCPMListL(rootserver, unloadArray, modList);
       
   273 
       
   274 	aHarnessLogger->Log(_L8("%d modules to shutdown: %S"), unloadArray.Count(), &modList);
       
   275 
       
   276 	// Start by asking all of the ESOCK threads to unload when there are no sessions
       
   277 	TInt numLoaded = unloadArray.Count();
       
   278 	TInt mod;
       
   279 	for(mod = numLoaded - 1; mod >= 0; --mod)
       
   280 		{
       
   281 		TESockSvrUnloadInfo* info = unloadArray[mod];
       
   282 		__FLOG_1(_L8("ESockLoader::DoUnLoadConfigL - UnloadCPM(%S, EGraceful)"), &info->iName);
       
   283 		rootserver.UnloadCpm(info->iStatus, info->iName, EGraceful);
       
   284 		}
       
   285 
       
   286 	// Start polling to see when they all complete unloading - crude but easy. 
       
   287 	const TInt KPollPeriod = 2000 * 1000;
       
   288 	TUint maxPolls = 0xFFFFFFFF;	// a saintly degree of patience
       
   289 	if(aType==EImmediate)
       
   290 		{
       
   291 		// Limited patience for the unload; 
       
   292 		maxPolls = KGracefulTimeout / KPollPeriod;
       
   293 		}
       
   294 	TUint poll;
       
   295 	RUnloadInfoArray pollUnloadArray(16);
       
   296 	BuildESockCPMListL(rootserver, pollUnloadArray, modList);
       
   297 	for(poll = maxPolls; poll != 0 && pollUnloadArray.Count() > 0; --poll)
       
   298 		{
       
   299 		User::After(KPollPeriod);
       
   300 		// See what's left - an earlier version of this code relied upon the unload completions for this, but unload
       
   301 		// may complete prematurely with failure if the unbind times out. It can legitimately do this if waiting for
       
   302 		// a session to timeout
       
   303 		BuildESockCPMListL(rootserver, pollUnloadArray, modList);
       
   304 		if(pollUnloadArray.Count() > 0)
       
   305 			{
       
   306 			aHarnessLogger->Log(_L8("[%d]:%d remaining: %S"), poll, pollUnloadArray.Count(), &modList);
       
   307 			}
       
   308 		}
       
   309 	pollUnloadArray.ResetAndDestroy();
       
   310 
       
   311 	if(poll == 0 && unloadArray.Count() > 0)
       
   312 	    {
       
   313 	    __FLOG(_L8("Reached maxpolls, gave up."));
       
   314 	    }
       
   315 	
       
   316 	// Cancel any remaining unloads and eat the events
       
   317 	for(mod = unloadArray.Count() - 1; mod >= 0; --mod)
       
   318 		{
       
   319 		TESockSvrUnloadInfo* info = unloadArray[mod];
       
   320 		__FLOG_1(_L8("ESockLoader::DoUnLoadConfigL - CancelUnloadCPM(%S)"), &info->iName);
       
   321 		rootserver.CancelUnloadCpm(info->iName);
       
   322 		User::WaitForRequest(info->iStatus);
       
   323 		}
       
   324 
       
   325 	// See what's left
       
   326 	BuildESockCPMListL(rootserver, unloadArray, modList);
       
   327 
       
   328 	err = KErrNone; // Will use this to catch first error below.
       
   329 	if(unloadArray.Count() > 0 && aType == EImmediate)
       
   330 		{
       
   331 		__FLOG(_L8("Entering EImmediate loop."));
       
   332 		// No more waiting; we order immediate unloads
       
   333 		for(mod = 0; mod < unloadArray.Count(); mod++)
       
   334 			{
       
   335 			TESockSvrUnloadInfo* info = unloadArray[mod];
       
   336 			__FLOG_2(_L8("ESockLoader::DoUnLoadConfigL - Module: %S, State %d"), &info->iName, info->iState);
       
   337 			if(mod == 0)
       
   338 				{
       
   339 				aHarnessLogger->Log(_L8("Timed-out waiting for shutdowns"));
       
   340 				err = KErrTimedOut;
       
   341 				}
       
   342 			aHarnessLogger->Log(_L8("Re-trying %S with EImmediate shutdown"), &info->iName);
       
   343 			__FLOG_1(_L8("ESockLoader::DoUnLoadConfigL - UnloadCPM(%S, EImmediate)"), &info->iName);
       
   344 			rootserver.UnloadCpm(info->iStatus, info->iName, EImmediate);
       
   345 			}
       
   346 			
       
   347 		// Wait for them all to return.
       
   348 		for(mod = 0; mod < unloadArray.Count(); mod++)
       
   349 			{
       
   350 			TESockSvrUnloadInfo* info = unloadArray[mod];
       
   351 			__FLOG_2(_L8("ESockLoader::DoUnLoadConfigL - Module: %S, State %d"), &info->iName, info->iState);
       
   352 			aHarnessLogger->Log(_L8("Waiting for %S to unload."), &info->iName);
       
   353 			__FLOG_1(_L8("ESockLoader::DoUnLoadConfigL - WaitForUnloadCPM(%S, EImmediate)"), &info->iName);
       
   354 			User::WaitForRequest(info->iStatus);
       
   355 			}
       
   356 		}
       
   357 
       
   358 	// Display the status of any remaining modules.  The first module that
       
   359 	// failed to unload becomes the error code for all.
       
   360 	for(mod = unloadArray.Count() - 1; mod >= 0; --mod)
       
   361 		{
       
   362 		TESockSvrUnloadInfo* info = unloadArray[mod];
       
   363 		if(info->iStatus != KErrNone && info->iStatus != KErrRSModuleNotLoaded)
       
   364 			{
       
   365 			__FLOG_3(_L8("ESockLoader::DoUnLoadConfigL - Unresponsive Module: %S cannot be gracefully or immediatly unloaded due to error %d and is stuck in state %d"), &info->iName, info->iStatus.Int(), info->iState);
       
   366 			aHarnessLogger->Log(_L8("Unresponsive Module: %S cannot be unloaded due to error %d"), &info->iName, info->iStatus.Int());
       
   367 			if(err==KErrNone)
       
   368 				{
       
   369     			err=info->iStatus.Int();
       
   370 				}
       
   371 			}
       
   372 		else
       
   373 			{
       
   374 			__FLOG_2(_L8("ESockLoader::DoUnLoadConfigL - Unresponsive Module: %S could not be gracefully unloaded and had to be immediatly unloaded while it was stuck in state %d"), &info->iName, info->iState);
       
   375 			aHarnessLogger->Log(_L8("Unresponsive Module: %S could not be gracefully unloaded and had to be immediatly unloaded while it was stuck in state %d"), &info->iName, info->iState);
       
   376 			}
       
   377 		}
       
   378 	if(err==KErrNone)
       
   379 		{
       
   380 		aHarnessLogger->Log(_L("Shutdown completed"));
       
   381 		}
       
   382 	CleanupStack::PopAndDestroy(2);	// unloadArray, rootserver
       
   383 	
       
   384 	// Leave with last seen error, if any
       
   385 	if(err!=KErrNone)
       
   386 		{
       
   387 		User::Leave(err);
       
   388 		}
       
   389 		
       
   390 	if (checkForLeaks)
       
   391 		{
       
   392 		TInt leakVal2;
       
   393 		if (leakProperty.Get(leakVal2) == KErrNone)
       
   394 			{
       
   395 			if (leakVal2 > leakValue)
       
   396 				{
       
   397 				User::Leave(KModuleLeaked);
       
   398 				}
       
   399 			}
       
   400 		}
       
   401 	CleanupStack::Pop(&leakProperty);
       
   402 	leakProperty.Close();
       
   403 	}
       
   404 
       
   405 
       
   406 EXPORT_C TInt ESockLoader::UnloadESock(MHarnessLogAdaptor* aHarnessLogger)
       
   407 /**
       
   408 Connects to the Comms Rootserver and requests unload of the Socket Server CPM.
       
   409 Returns when it is unloaded.
       
   410 */
       
   411 	{
       
   412 	__FLOG_DECLARATION_VARIABLE;
       
   413 	__FLOG_OPEN(KESockLogSubsys, KESockLogComponent);
       
   414 	__FLOG(_L8("ESockLoader::UnloadESock"));
       
   415 	__FLOG_CLOSE;
       
   416 
       
   417 	TInt err = UnloadESock(EGraceful, aHarnessLogger);
       
   418 	
       
   419 	return err;
       
   420     }
       
   421 
       
   422 EXPORT_C TInt ESockLoader::UnloadESock(CommsFW::TCFShutdownType aType, MHarnessLogAdaptor* aHarnessLogger)
       
   423 /**
       
   424 Connects to the Comms Rootserver and requests unload of the Socket Server CPM.
       
   425 Returns when it is unloaded.
       
   426 */
       
   427 	{
       
   428 	__FLOG_DECLARATION_VARIABLE;
       
   429 	__FLOG_OPEN(KESockLogSubsys, KESockLogComponent);
       
   430 	__FLOG_1(_L8("ESockLoader::UnloadESock, CommsFW::TCFShutdownType==%d."), aType);
       
   431 
       
   432 #ifdef __FLOG_ACTIVE
       
   433 	TRAPD(err, DoUnloadESockL(aType, aHarnessLogger, __logger__));
       
   434 #else
       
   435 	TRAPD(err, DoUnloadESockL(aType, aHarnessLogger));
       
   436 #endif
       
   437 
       
   438 	if(err == KErrNone)
       
   439 		{
       
   440 		__FLOG(_L("ESockLoader::UnLoadConfig - succeeded."));
       
   441 		}
       
   442 	else
       
   443 		{
       
   444 		__FLOG_1(_L("ESockLoader::UnLoadConfig - failed with error %d.  The C32 process is in an unstable state and will be killed."), err);
       
   445 		aHarnessLogger->Log(_L("Shutdown failed with error %d.  The C32 process is in an unstable state and will be killed."), err);
       
   446 		
       
   447 		#ifdef __FLOG_ACTIVE
       
   448 			KillC32Exe(__logger__);
       
   449 		#else
       
   450 			KillC32Exe();
       
   451 		#endif
       
   452 		}
       
   453 		
       
   454 	__FLOG_CLOSE;
       
   455 	
       
   456 	return err;
       
   457 	}
       
   458