commsprocess/commsrootserverconfig/Te_Configurator/util/src/configloader.cpp
changeset 0 dfb7c4ff071f
child 25 9d7ce34704c8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/commsprocess/commsrootserverconfig/Te_Configurator/util/src/configloader.cpp	Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,497 @@
+// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include <e32base.h>
+#include <e32property.h>
+#include <c32root.h>
+#include <cfshared.h>
+#include <comms-infras/commsdebugutility.h>
+
+#include "configloader.h"
+
+__FLOG_STMT(_LIT8(KC32LogSubsys, "RootServer");)
+__FLOG_STMT(_LIT8(KC32LogComponent, "Configloader");)
+
+/** When unloading C32 forced we try first in a graceful manner, if it hasn't
+unloaded after this timeout it is asked to shutdown immediately.
+This will happen if C32 has "hanging" sessions.
+ */
+const TInt KGracefulTimeout = 90 * 1000000;
+
+#if defined (__EPOC32__)
+#define PDD_NAME _L("EUART1")
+#define LDD_NAME _L("ECOMM")
+#endif
+
+EXPORT_C TInt ConfigLoader::LoadConfig(MHarnessLogAdaptor* aHarnessLogger)
+/** Connect to the Comms Rootserver and request load of the Socket Server CPM.
+Returns when it is loaded. 
+*/
+	{
+	__FLOG_DECLARATION_VARIABLE;
+	__FLOG_OPEN(KC32LogSubsys, KC32LogComponent);
+	__FLOG(_L("ConfigLoader::LoadConfig"));
+	
+	TInt result;
+	
+#if defined (__EPOC32__)
+	TPtrC pddName = PDD_NAME;
+	TPtrC lddName = LDD_NAME;
+
+	// Load the communications drivers first - no use starting C32 without them.
+	result = User::LoadPhysicalDevice(pddName);
+	if (result!=KErrNone && result!=KErrAlreadyExists)
+		{
+		__FLOG_2(_L("ConfigLoader::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);
+		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);
+		}
+
+	result=User::LoadLogicalDevice(lddName);
+	if (result!=KErrNone && result!=KErrAlreadyExists)
+		{
+		__FLOG_2(_L("ConfigLoader::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);	
+		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);
+		}
+#endif
+
+	// Boot the Comms Process, but avoid loading the Phonebook Synchronizer.
+	#ifdef __FLOG_ACTIVE
+		TBool warmBoot = TestC32ExeStarted(__logger__);
+	#else
+		TBool warmBoot = TestC32ExeStarted();
+	#endif
+	if(warmBoot)
+		{
+		aHarnessLogger->Log(_L("Starting C32Start warm-boot"));
+		}
+	else
+		{
+		aHarnessLogger->Log(_L("Starting C32Start cold-boot"));
+		}
+	
+	RProcess C32Start;
+	result = C32Start.Create(KCommC32StartExe,KNullDesC);
+
+	// Kill the existing configurator process.
+	TRequestStatus status;
+	C32Start.Logon(status);
+	C32Start.Kill(KErrNone);
+	User::WaitForRequest(status);
+	
+	// Create a timer in case some other entity holds an open handle on the
+	// configurator which prevents the kernel from destroying it.  We timeout
+	// after one second.
+	TAutoClose<RTimer> timer;
+	if(timer.iObj.CreateLocal() == KErrNone)
+		{
+		// Request destruction notification so we know when it is safe to start
+		// the process again.
+		TRequestStatus destructionStatus;
+		C32Start.NotifyDestruction(destructionStatus);
+		C32Start.Close();
+	
+		enum{ KProcessDestructionTimeout = 1000000 };
+  					
+		TRequestStatus timerStatus;
+		timer.iObj.After(timerStatus, KProcessDestructionTimeout);
+		
+		// Wait for the process to be destroyed or for the timeout.
+		User::WaitForRequest(destructionStatus, timerStatus);
+		if(timerStatus.Int() == KRequestPending)
+			{
+			timer.iObj.Cancel();
+			User::WaitForRequest(timerStatus);
+			}
+		else
+			{
+			User::CancelMiscNotifier(destructionStatus);
+			User::WaitForRequest(destructionStatus);
+			
+			__FLOG_1(_L("ConfigLoader::LoadConfig - existing configurator process has still not been destroyed after %f.0s"), KProcessDestructionTimeout / 1000000.0);
+			}
+		}
+	else
+		{
+		C32Start.Close();
+		}
+
+	_LIT(KPhbkSyncCMI, "phbsync.cmi");
+	result=WarmBootC32(KPhbkSyncCMI);
+	
+	if(result == KErrNone)
+		{
+		aHarnessLogger->Log(warmBoot ? _L("C32Start warm-boot succeeded") : _L("C32Start cold-boot succeeded"));
+		__FLOG(_L("ConfigLoader::LoadConfig - succeeded"));
+		}
+	else
+		{
+		aHarnessLogger->Log(warmBoot ? _L("C32Start warm-boot failed with error %d") : _L("C32Start cold-boot failed with error %d"), result);
+		__FLOG_1(_L("CConfigLoader::LoadConfig - failed with error %d"), result);
+		}
+	__FLOG_CLOSE;
+
+	return result;
+	}
+
+// Helper fn: build a list of instances of CPMs running C32.DLL
+void ConfigLoader::BuildConfigCPMListL(RRootServ& aRootServer, RUnloadInfoArray& aInfo, TDes8& aDispList)
+	{
+	__FLOG_DECLARATION_VARIABLE;
+	__FLOG_OPENC(KC32LogSubsys, KC32LogComponent);
+	__FLOG(_L8("ConfigLoader::BuildConfigCPMListL"));
+
+	TRSIter iter;
+	TCFModuleName modName;
+	TRSModuleInfo modInfo;
+	aInfo.ResetAndDestroy();
+	aDispList.SetLength(0);
+	while(aRootServer.EnumerateModules(iter, modName) == KErrNone)
+		{
+		if(aRootServer.GetModuleInfo(modName, modInfo) == KErrNone)
+			{
+			_LIT(KC32DLL, "dummycpm.DLL");
+			if(modInfo.iParams.iDll.MatchF(KC32DLL) >= 0)
+				{
+				TConfigSvrUnloadInfo* unloadInfo = new(ELeave) TConfigSvrUnloadInfo;
+				unloadInfo->iName.Copy(modInfo.iParams.iName);
+				unloadInfo->iState=modInfo.iParams.iState;
+				unloadInfo->iStatus=KErrNone;
+				if(aDispList.Length() != 0)
+					{
+					aDispList.Append(_L8(", "));
+					}
+				aDispList.Append(unloadInfo->iName);
+				TInt err = aInfo.Append(unloadInfo);
+				if(err != KErrNone)
+					{
+					delete unloadInfo;
+					User::Leave(err);
+					}
+				}
+			}
+		}
+	
+	__FLOG_CLOSE_CLEANUP;
+	}
+
+#ifdef __FLOG_ACTIVE
+	TBool ConfigLoader::TestC32ExeStarted(RFileLogger& __logger__)
+#else
+	TBool ConfigLoader::TestC32ExeStarted()
+#endif
+	{
+	__FLOG(_L8("ConfigLoader::TestC32ExeStarted"));
+
+	_LIT(KC32StartName,"*");
+	TBool ret = EFalse;
+	TFullName fn;
+	TFindProcess fp(KC32StartName);
+	while(!ret && fp.Next(fn) == KErrNone)
+		{
+		RProcess proc;
+		TInt result = proc.Open(fn);
+		if(result == KErrNone)
+			{
+			TUidType type = proc.Type();
+			if(type[2] == KUidCommsProcess && proc.ExitType() == EExitPending) 
+				{
+				ret = ETrue;
+				}
+			proc.Close();	
+			}
+		}
+
+	return ret;
+	}
+
+#ifdef __FLOG_ACTIVE
+	TBool ConfigLoader::KillC32Exe(RFileLogger& __logger__)
+#else
+	TBool ConfigLoader::KillC32Exe()
+#endif
+	{
+	__FLOG(_L8("ConfigLoader::KillC32Exe"));
+
+	_LIT(KC32StartName,"*");
+	TBool ret = EFalse;
+	TFullName fn;
+	TFindProcess fp(KC32StartName);
+	while(!ret && fp.Next(fn) == KErrNone)
+		{
+		RProcess proc;
+		TInt result = proc.Open(fn);
+		if(result == KErrNone)
+			{
+			TUidType type = proc.Type();
+			if(type[2] == KUidCommsProcess) 
+				{
+				proc.Kill(KErrNone);
+				}
+			proc.Close();	
+			}
+		}
+
+	return ret;
+	}
+
+#ifdef __FLOG_ACTIVE
+	void ConfigLoader::DoUnLoadConfigL(TCFShutdownType aType, MHarnessLogAdaptor* aHarnessLogger, RFileLogger& __logger__)
+#else
+	void ConfigLoader::DoUnLoadConfigL(TCFShutdownType aType, MHarnessLogAdaptor* aHarnessLogger)
+#endif
+	{
+	__FLOG_1(_L8("ConfigLoader::DoUnLoadConfigL - CommsFW::TCFShutdownType==%d"), aType);
+
+	// No need to restart C32 if C32(c32exe) is not started...
+#ifdef __FLOG_ACTIVE
+	if (!TestC32ExeStarted(__logger__))
+#else
+	if (!TestC32ExeStarted())
+#endif
+		{
+		aHarnessLogger->Log(_L8("C32 is not running so it does not need to be shutdown"));
+		__FLOG(_L8("ConfigLoader::DoUnLoadConfigL - C32 is not running so it does not need to be shutdown"));
+
+		return;
+		}
+
+	// Start the Comms Process
+	_LIT(KPhbkSyncCMI, "phbsync.cmi");
+	TInt err=StartC32WithCMISuppressions(KPhbkSyncCMI);
+
+	// With the Staged Start-up Architecture it is likely that C32 modules continue to load after the ECoreComponentsStarted
+	// state which releases StartC32() and RSocketServ::Connect(). So here we wait until the RootServer is fully configured before
+	// starting the shutdown, which avoids various races (modules may not be bound yet, or even loaded at all by the Configurator
+	// and hence invisible to this unloading code)
+	RProperty configurationProperty;
+	configurationProperty.Attach(KUidSystemCategory, KUidC32StartPropertyKey.iUid);	// needs the KEY
+	TInt propertyValue = EInitialising;	// set to safe state
+	TInt propertyResult = configurationProperty.Get(propertyValue);
+	TRequestStatus propertyStatus;
+	while(propertyValue < EConfigurationComplete)
+		{
+		configurationProperty.Subscribe(propertyStatus);
+		
+		if(configurationProperty.Get(propertyValue) == KErrNone && propertyValue == EConfigurationComplete)
+			{
+			configurationProperty.Cancel();
+			}
+		User::WaitForRequest(propertyStatus);
+		}
+
+	RRootServ rootserver;
+	if(err==KErrNone)
+		{
+		err=rootserver.Connect();
+		}
+	User::LeaveIfError(err);
+	CleanupClosePushL(rootserver);
+	
+	// Find all instances of CPMs running C32.DLL. We treat them all equally rather than trying anything
+	// clever such as telling the Main Thread to shutdown last, etc - C32 does whatever is best
+
+	RUnloadInfoArray unloadArray(16);
+	CleanupClosePushL(unloadArray);
+	TBuf8<256> modList;
+	BuildConfigCPMListL(rootserver, unloadArray, modList);
+
+	aHarnessLogger->Log(_L8("%d modules to shutdown: %S"), unloadArray.Count(), &modList);
+
+	// Start by asking all of the C32 threads to unload when there are no sessions
+	TInt numLoaded = unloadArray.Count();
+	TInt mod;
+	for(mod = numLoaded - 1; mod >= 0; --mod)
+		{
+		TConfigSvrUnloadInfo* info = unloadArray[mod];
+		__FLOG_1(_L8("ConfigLoader::DoUnLoadConfigL - UnloadCPM(%S, EGraceful)"), &info->iName);
+		rootserver.UnloadCpm(info->iStatus, info->iName, EGraceful);
+		}
+
+	// Start polling to see when they all complete unloading - crude but easy. 
+	const TInt KPollPeriod = 2000 * 1000;
+	TUint maxPolls = 0xFFFFFFFF;	// a saintly degree of patience
+	if(aType==EImmediate)
+		{
+		// Limited patience for the unload; 
+		maxPolls = KGracefulTimeout / KPollPeriod;
+		}
+	TUint poll;
+	RUnloadInfoArray pollUnloadArray(16);
+	BuildConfigCPMListL(rootserver, pollUnloadArray, modList);
+	for(poll = maxPolls; poll != 0 && pollUnloadArray.Count() > 0; --poll)
+		{
+		User::After(KPollPeriod);
+		// See what's left - an earlier version of this code relied upon the unload completions for this, but unload
+		// may complete prematurely with failure if the unbind times out. It can legitimately do this if waiting for
+		// a session to timeout
+		BuildConfigCPMListL(rootserver, pollUnloadArray, modList);
+		if(pollUnloadArray.Count() > 0)
+			{
+			aHarnessLogger->Log(_L8("[%d]:%d remaining: %S"), poll, pollUnloadArray.Count(), &modList);
+			}
+		}
+	pollUnloadArray.ResetAndDestroy();
+
+	if(poll == 0 && unloadArray.Count() > 0)
+	    {
+	    __FLOG(_L8("Reached maxpolls, gave up."));
+	    }
+
+	// Cancel any remaining unloads and eat the events
+	for(mod = unloadArray.Count() - 1; mod >= 0; --mod)
+		{
+		TConfigSvrUnloadInfo* info = unloadArray[mod];
+		__FLOG_1(_L8("ConfigLoader::DoUnLoadConfigL - CancelUnloadCPM(%S)"), &info->iName);
+		rootserver.CancelUnloadCpm(info->iName);
+		User::WaitForRequest(info->iStatus);
+		}
+
+	// See what's left
+	BuildConfigCPMListL(rootserver, unloadArray, modList);
+
+	err = KErrNone; // Will use this to catch first error below.
+	if(unloadArray.Count() > 0 && aType == EImmediate)
+		{
+		__FLOG(_L8("Entering EImmediate loop."));
+		// No more waiting; we order immediate unloads
+		for(mod = 0; mod < unloadArray.Count(); mod++)
+			{
+			TConfigSvrUnloadInfo* info = unloadArray[mod];
+			__FLOG_2(_L8("ConfigLoader::DoUnLoadConfigL - Module: %S, State %d"), &info->iName, info->iState);
+			if(mod == 0)
+				{
+				aHarnessLogger->Log(_L8("Timed-out waiting for shutdown"));
+				err = KErrTimedOut;
+				}
+			aHarnessLogger->Log(_L8("Re-trying %S with EImmediate shutdown"), &info->iName);
+			__FLOG_1(_L8("ConfigLoader::DoUnLoadConfigL - UnloadCPM(%S, EImmediate)"), &info->iName);
+			rootserver.UnloadCpm(info->iStatus, info->iName, EImmediate);
+			}
+			
+		// Wait for them all to return.
+		for(mod = 0; mod < unloadArray.Count(); mod++)
+			{
+			TConfigSvrUnloadInfo* info = unloadArray[mod];
+			__FLOG_2(_L8("ConfigLoader::DoUnLoadConfigL - Module: %S, State %d"), &info->iName, info->iState);
+			aHarnessLogger->Log(_L8("Waiting for %S to unload"), &info->iName);
+			__FLOG_1(_L8("ConfigLoader::DoUnLoadConfigL - WaitForUnloadCPM(%S, EImmediate)"), &info->iName);
+			User::WaitForRequest(info->iStatus);
+			}
+		}
+
+	// Display the status of any remaining modules.  The first module that
+	// failed to unload becomes the error code for all.
+	for(mod = unloadArray.Count() - 1; mod >= 0; --mod)
+		{
+		TConfigSvrUnloadInfo* info = unloadArray[mod];
+		if(info->iStatus != KErrNone && info->iStatus != KErrRSModuleNotLoaded)
+			{
+			__FLOG_3(_L8("ConfigLoader::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);
+			aHarnessLogger->Log(_L8("Unresponsive Module: %S cannot be unloaded due to error %d and is stuck in state %d"), &info->iName, info->iStatus.Int(), info->iState);
+			if(err==KErrNone)
+				{
+    			err=info->iStatus.Int();
+				}
+			}
+		else
+			{
+			__FLOG_2(_L8("ConfigLoader::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);
+			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);
+			}
+		}
+	if(err==KErrNone)
+		{
+		aHarnessLogger->Log(_L("Shutdown completed"));
+		}
+	CleanupStack::PopAndDestroy(2);	// unloadArray, rootserver
+	
+	#if defined (__EPOC32__)	
+	TPtrC pddName = PDD_NAME;
+	TPtrC lddName = LDD_NAME;
+
+	TInt retDD = User::FreePhysicalDevice(pddName);
+	if (retDD != KErrNone)
+		{
+		aHarnessLogger->Log(_L8("Failed unloading Physical Device Driver \"%S\" due to error %d"), &pddName, retDD);	
+		}
+	
+	retDD = User::FreeLogicalDevice(lddName);
+	if (retDD != KErrNone)
+		{
+		aHarnessLogger->Log(_L8("Failed unloading Logical Device Driver \"%S\" due to error %d"), &lddName, retDD);	
+		}
+	#endif
+	
+	// Leave with last seen error, if any
+	if(err!=KErrNone)
+		{
+		User::Leave(err);
+		}
+	}
+
+
+EXPORT_C TInt ConfigLoader::UnLoadConfig(MHarnessLogAdaptor* aHarnessLogger)
+/**
+Connects to the Comms Rootserver and requests unload of the Socket Server CPM.
+Returns when it is unloaded.
+*/
+	{
+	__FLOG_DECLARATION_VARIABLE;
+	__FLOG_OPEN(KC32LogSubsys, KC32LogComponent);
+	__FLOG(_L8("ConfigLoader::UnLoadConfig"));
+	__FLOG_CLOSE;
+
+	TInt err = UnLoadConfig(EGraceful, aHarnessLogger);
+	
+	return err;
+    }
+
+EXPORT_C TInt ConfigLoader::UnLoadConfig(CommsFW::TCFShutdownType aType, MHarnessLogAdaptor* aHarnessLogger)
+/**
+Connects to the Comms Rootserver and requests unload of the Socket Server CPM.
+Returns when it is unloaded.
+*/
+	{
+	__FLOG_DECLARATION_VARIABLE;
+	__FLOG_OPEN(KC32LogSubsys, KC32LogComponent);
+	__FLOG_1(_L8("ConfigLoader::UnLoadConfig - CommsFW::TCFShutdownType==%d."), aType);
+
+#ifdef __FLOG_ACTIVE
+	TRAPD(err, DoUnLoadConfigL(aType, aHarnessLogger, __logger__));
+#else
+	TRAPD(err, DoUnLoadConfigL(aType, aHarnessLogger));
+#endif
+
+	if(err == KErrNone)
+		{
+		__FLOG(_L("ConfigLoader::UnLoadConfig - succeeded."));
+		}
+	else
+		{
+		__FLOG_1(_L("ConfigLoader::UnLoadConfig - failed with error %d.  The C32 process is in an unstable state and will be killed."), err);
+		aHarnessLogger->Log(_L("Shutdown failed with error %d.  The C32 process is in an unstable state and will be killed."), err);
+		
+		#ifdef __FLOG_ACTIVE
+			KillC32Exe(__logger__);
+		#else
+			KillC32Exe();
+		#endif
+		}
+		
+	__FLOG_CLOSE;
+	
+	return err;
+	}
+