featuremgmt/featureregistry/src/api/featreg.cpp
changeset 0 08ec8eefde2f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/featuremgmt/featureregistry/src/api/featreg.cpp	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,401 @@
+// Copyright (c) 2005-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:
+// Implementation of API for querying support for features on a device, and
+// receiving notification if features are added or removed.
+// 
+//
+
+#include <e32property.h>
+#include <e32cmn.h>
+#include <e32uid.h>
+#include "featreg.h"
+#include "featregpan.h"
+#include "featregcmn.h"
+
+/**
+ * Run setup exe, wait for completion: ends only once property defined, or failed
+ * @internalComponent
+ * @return KErrNone on success, or system-wide error code
+ */
+static TInt RunFeaturePropertySetupExe()
+	{
+	const TUidType setupExeUidType(KExecutableImageUid, TUid::Null(), KFeaturePropCat);
+	RProcess setupProc;
+	TInt result = setupProc.Create(KFeatRegSetupExe, KNullDesC, setupExeUidType);
+	if (result != KErrNone)
+		{
+		return result;
+		}
+	TRequestStatus setupStatus;
+	// request Rendezvous before Resume() to avoid race condition.
+	// Also note if request to rendezvous fails (OOM etc.) then setup exe may
+	// complete after query code, with feature property possibly undefined
+	setupProc.Rendezvous(setupStatus);
+	setupProc.Resume();
+	setupProc.Close();
+	User::WaitForRequest(setupStatus);
+	return setupStatus.Int();
+	}
+
+/**
+ * Dummy feature registry implementation object - never instantiated.
+ * @internalComponent
+ */
+class RFeatureRegistry::TImpl
+	{
+	TUint32 iDummy;
+	};
+
+/**
+ * Opens connection to the Feature Registry for making non-static queries.
+ * Note all non-static queries return state at the time Open() was called;
+ * Feature Registry changes are not observed until instance closed and re-opened.
+ *
+ * @return KErrNone if successful, negative system-wide error code if fails
+ * @publishedPartner
+ * @deprecated
+ */
+EXPORT_C TInt RFeatureRegistry::Open()
+	{
+	RProperty featureProperty;
+	TInt result = featureProperty.Attach(KFeaturePropCat, KFeaturePropKey);
+	if (result != KErrNone)
+		{
+		return result;
+		}
+
+	// read feature property header
+	TInt propertySize = 0;
+	TFeatureHeader header;
+	TPckg<TFeatureHeader> headerPckg(header);
+	TBool ranSetup = EFalse;
+	TInt setupResult = KErrNone;
+	while (ETrue)
+		{
+		result = featureProperty.Get(headerPckg);
+		if ((result == KErrOverflow)
+			|| ((result == KErrNone) && (headerPckg.Size() >= sizeof(TFeatureHeader))))
+			{
+			if (header.IsInvalid())
+				{
+				result = KErrCorrupt;
+				}
+			else
+				{
+				propertySize = header.PredictedPropertySize();
+				result = KErrOverflow;	// indicates successful outcome from this phase
+				}
+			break;
+			}
+		if (ranSetup)
+			{
+			if (setupResult == KErrNoMemory)
+				{
+				result = KErrNoMemory;
+				}
+			else if (setupResult == KErrCorrupt)
+				{
+				result = KErrCorrupt;
+				}
+			else
+				{
+				// must force an error return - other than KErrOverflow
+				result = KErrUnknown;
+				}
+			break;
+			}
+		setupResult = RunFeaturePropertySetupExe();
+		ranSetup = ETrue;
+		}
+
+	// allocate and read property. Iterate while overflow reported
+	// in case property is republished while reading it
+	while (result == KErrOverflow)
+		{
+		// the feature property data consists of only 32-bit values
+		// allocate in TUint32 blocks to cover any alignment issues
+		TUint32 size32 = (propertySize + sizeof(TUint32) - 1) / sizeof(TUint32);
+		TUint32* propertyBuf32 = new TUint32[size32];
+		TUint8* propertyBuf = reinterpret_cast<TUint8*>(propertyBuf32);
+		if (propertyBuf == NULL)
+			{
+			result = KErrNoMemory;
+			break;
+			}
+		TPtr8 propertyDes(propertyBuf, 0, propertySize);
+		result = featureProperty.Get(propertyDes);
+		if (propertyDes.Size() >= sizeof(TFeatureHeader))
+			{
+			const TFeatureHeader& headerRef = *(reinterpret_cast<const TFeatureHeader*>(propertyBuf));
+			// overflow checking for the following is already done by setup exe
+			if ((result == KErrNone) && (!headerRef.IsInvalidOrBadSize(propertyDes.Size())))
+				{
+				// success
+				iImpl = reinterpret_cast<TImpl*>(propertyBuf);
+				break;
+				}
+			// if it's not a valid overflow (where predicted size is indeed larger than maxsize), it's corrupt
+			if ((result != KErrOverflow) || (headerRef.PredictedPropertySize() < propertyDes.MaxSize()))
+				{
+				result = KErrCorrupt;
+				}
+			}
+		else
+			{
+			result = KErrCorrupt;
+			}
+		delete[] propertyBuf;
+		if (result != KErrOverflow)
+			{
+			result = KErrCorrupt;
+			break;
+			}
+		}
+
+	featureProperty.Close();
+	// panic in debug mode to alert system integrators that the setup exe
+	// is absent/inaccessible or the config data is invalid in this OS
+	// configuration: a serious problem
+	__ASSERT_DEBUG(result != KErrCorrupt, Panic(EFeatRegBadConfig));
+	return result;
+	}
+
+/**
+ * Queries support for feature on the device.
+ * Non-static version requiring open instance of class.
+ * Recommended when making multiple queries.
+ * Note: returns support for feature from the time Open() was called.
+ *
+ * @param aFeatureUid Unique identifier of feature being queried
+ * @return positive value if feature is supported, zero if feature is not supported,
+ *     or negative system-wide error code if could not be determined.
+ * @pre this registry instance is open
+ * @panic FeatReg EFeatRegInvalidUse if this registry instance is not open
+ * @publishedPartner
+ * @deprecated
+ */
+EXPORT_C TInt RFeatureRegistry::QuerySupport(TUid aFeatureUid)
+	{
+	TUint32 dummyInfo;
+	return QuerySupport(aFeatureUid, dummyInfo);
+	}
+
+/**
+ * Queries support for feature on the device.
+ * Non-static version requiring open instance of class.
+ * Recommended when making multiple queries.
+ * Note: returns support for feature from the time Open() was called.
+ *
+ * @param aFeatureUid Unique identifier of feature being queried
+ * @param aInfo addition status information about feature
+ * @return positive value if feature is supported, zero if feature is not supported,
+ *     or negative system-wide error code if could not be determined.
+ * @pre this registry instance is open
+ * @panic FeatReg EFeatRegInvalidUse if this registry instance is not open
+ * @publishedPartner
+ * @deprecated
+ */
+EXPORT_C TInt RFeatureRegistry::QuerySupport(TUid aFeatureUid, TUint32& aInfo)
+	{
+	__ASSERT_ALWAYS(iImpl != NULL, Panic(EFeatRegInvalidUse));
+
+	TFeatureHeader* header = reinterpret_cast<TFeatureHeader*>(iImpl);
+	TUint32 featureUid = aFeatureUid.iUid;
+
+	// try to find in feature entries first
+	TFeatureEntry* entry = reinterpret_cast<TFeatureEntry*>(header + 1);
+	if (header->iFeatureEntryCount > 0)
+		{
+		RArray<TFeatureEntry> entryArray(sizeof(TFeatureEntry), entry, header->iFeatureEntryCount);	
+		TFeatureEntry searchEntry = { featureUid , 0 };
+		TInt index = entryArray.FindInUnsignedKeyOrder(searchEntry);
+		if (index >= 0)
+			{
+			aInfo = entryArray[index].iInfo;
+			return aInfo & EStatusSupportBit;
+			}
+		}
+
+	// fall back to default ranges - first range to match wins
+	TFeatureRange* range = reinterpret_cast<TFeatureRange*>(entry + header->iFeatureEntryCount);
+	for (TInt i = header->iFeatureRangeCount; i > 0; --i, ++range)
+		{
+		if ((featureUid >= range->iLowUid) && (featureUid <= range->iHighUid))
+			{
+			aInfo = EStatusSupportBit;
+			return EStatusSupportBit;
+			}
+		}
+	
+	// final default: feature not supported
+	aInfo = 0;
+	return 0;
+	}
+
+/**
+ * Closes this registry instance.
+ * @publishedPartner
+ * @deprecated
+ */
+EXPORT_C void RFeatureRegistry::Close()
+	{
+	TUint8* propertyBuf = reinterpret_cast<TUint8*>(iImpl);
+	delete[] propertyBuf;
+	iImpl = NULL;
+	}
+
+/**
+ * Queries support for feature on the device.
+ * Static version recommended for single queries.
+ *
+ * @param aFeatureUid Unique identifier of feature being queried
+ * @return positive value if feature is supported, zero if feature is not supported,
+ *     or negative system-wide error code if could not be determined.
+ * @publishedPartner
+ * @deprecated
+ */
+EXPORT_C TInt RFeatureRegistry::QuerySupportS(TUid aFeatureUid)
+	{
+	TUint32 dummyInfo;
+	return QuerySupportS(aFeatureUid, dummyInfo);
+	}
+
+/**
+ * Queries support for feature on the device.
+ * Static version recommended for single queries.
+ *
+ * @param aFeatureUid Unique identifier of feature being queried
+ * @param aInfo addition status information about feature
+ * @return positive value if feature is supported, zero if feature is not supported,
+ *     or negative system-wide error code if could not be determined.
+ * @publishedPartner
+ * @deprecated
+ */
+EXPORT_C TInt RFeatureRegistry::QuerySupportS(TUid aFeatureUid, TUint32& aInfo)
+	{
+	RFeatureRegistry featReg;
+	TInt result = featReg.Open();
+	if (result == KErrNone)
+		{
+		result = featReg.QuerySupport(aFeatureUid, aInfo);
+		featReg.Close();
+		}
+	return result;
+	}
+
+/**
+ * Implementation class allocated when RFeatureRegistryNotify is opened.
+ *
+ * @internalComponent
+ */
+class RFeatureRegistryNotify::TImpl
+	{
+public:
+	RProperty iNotifyProperty;
+
+	TImpl()
+		: iNotifyProperty()
+		{
+		}
+	};
+
+/**
+ * Open instance of notify object so it can be subscribed to.
+ *
+ * @return KErrNone if successful, negative system-wide error code if not
+ * @internalComponent
+ */
+EXPORT_C TInt RFeatureRegistryNotify::Open()
+	{
+	iImpl = new TImpl;
+	if (iImpl == NULL)
+		{
+		return KErrNoMemory;
+		}
+	TInt result = iImpl->iNotifyProperty.Attach(KFeaturePropCat, KFeaturePropKey);
+	if (result != KErrNone)
+		{
+		// must clean up memory allocated above
+		delete iImpl;
+		iImpl = NULL;
+		return result;
+		}
+	// feature property and notify property are same in current implementation
+	// hence must ensure feature property is already published to avoid false
+	// notification when it is first published (just-in-time by the next query)
+	TFeatureHeader header;
+	TPckg<TFeatureHeader> headerPckg(header);
+	result = iImpl->iNotifyProperty.Get(headerPckg);
+	if (!((result == KErrOverflow)
+		|| ((result == KErrNone) && (headerPckg.Size() >= sizeof(TFeatureHeader)))))
+		{
+		RunFeaturePropertySetupExe();
+		}
+	// return fact that Attach() succeeded
+	return KErrNone;
+	}
+
+/**
+ * Issues an asynchronous request to be notified the next time the support
+ * status of any features change.
+ *
+ * To ensure that changes are not missed, always re-subscribe before
+ * querying the feature registry.
+ *
+ * If an outstanding request is cancelled through a call to Cancel(), then it
+ * completes with KErrCancel.
+ *
+ * @pre this instance of notify object must be Open and not already Subscribed to.
+ * @param aNotifyStatus The request status object to be signalled on update.
+ * @panic FeatReg EFeatRegInvalidUse if this registry notify instance is not open
+ * @internalComponent
+ */
+EXPORT_C void RFeatureRegistryNotify::Subscribe(TRequestStatus &aNotifyStatus)
+	{
+	__ASSERT_ALWAYS(iImpl != NULL, Panic(EFeatRegInvalidUse));
+	iImpl->iNotifyProperty.Subscribe(aNotifyStatus);
+	}
+
+/**
+ * Cancels an outstanding subscription request for notification of feature registry changes.
+ *
+ * If the request has not already completed, then it completes with KErrCancel.
+ *
+ * @pre this instance of notify object must be Open
+ * @panic FeatReg EFeatRegInvalidUse if this registry notify instance is not open
+ * @internalComponent
+ */
+EXPORT_C void RFeatureRegistryNotify::Cancel()
+	{
+	__ASSERT_ALWAYS(iImpl != NULL, Panic(EFeatRegInvalidUse));
+	iImpl->iNotifyProperty.Cancel();
+	}
+
+/**
+ * Closes the registry notify instance.
+ *
+ * Note: automatically cancels any outstanding notify subscription.
+ *
+ * @internalComponent
+ */
+EXPORT_C void RFeatureRegistryNotify::Close()
+	{
+	if (iImpl)
+		{
+		// Have checked RProperty::Close() cancels the outstanding subscription
+		iImpl->iNotifyProperty.Close();
+		}
+	delete iImpl;
+	iImpl = NULL;
+	}