1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/featuremgmt/featureregistry/src/api/featreg.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,401 @@
1.4 +// Copyright (c) 2005-2009 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 +// Implementation of API for querying support for features on a device, and
1.18 +// receiving notification if features are added or removed.
1.19 +//
1.20 +//
1.21 +
1.22 +#include <e32property.h>
1.23 +#include <e32cmn.h>
1.24 +#include <e32uid.h>
1.25 +#include "featreg.h"
1.26 +#include "featregpan.h"
1.27 +#include "featregcmn.h"
1.28 +
1.29 +/**
1.30 + * Run setup exe, wait for completion: ends only once property defined, or failed
1.31 + * @internalComponent
1.32 + * @return KErrNone on success, or system-wide error code
1.33 + */
1.34 +static TInt RunFeaturePropertySetupExe()
1.35 + {
1.36 + const TUidType setupExeUidType(KExecutableImageUid, TUid::Null(), KFeaturePropCat);
1.37 + RProcess setupProc;
1.38 + TInt result = setupProc.Create(KFeatRegSetupExe, KNullDesC, setupExeUidType);
1.39 + if (result != KErrNone)
1.40 + {
1.41 + return result;
1.42 + }
1.43 + TRequestStatus setupStatus;
1.44 + // request Rendezvous before Resume() to avoid race condition.
1.45 + // Also note if request to rendezvous fails (OOM etc.) then setup exe may
1.46 + // complete after query code, with feature property possibly undefined
1.47 + setupProc.Rendezvous(setupStatus);
1.48 + setupProc.Resume();
1.49 + setupProc.Close();
1.50 + User::WaitForRequest(setupStatus);
1.51 + return setupStatus.Int();
1.52 + }
1.53 +
1.54 +/**
1.55 + * Dummy feature registry implementation object - never instantiated.
1.56 + * @internalComponent
1.57 + */
1.58 +class RFeatureRegistry::TImpl
1.59 + {
1.60 + TUint32 iDummy;
1.61 + };
1.62 +
1.63 +/**
1.64 + * Opens connection to the Feature Registry for making non-static queries.
1.65 + * Note all non-static queries return state at the time Open() was called;
1.66 + * Feature Registry changes are not observed until instance closed and re-opened.
1.67 + *
1.68 + * @return KErrNone if successful, negative system-wide error code if fails
1.69 + * @publishedPartner
1.70 + * @deprecated
1.71 + */
1.72 +EXPORT_C TInt RFeatureRegistry::Open()
1.73 + {
1.74 + RProperty featureProperty;
1.75 + TInt result = featureProperty.Attach(KFeaturePropCat, KFeaturePropKey);
1.76 + if (result != KErrNone)
1.77 + {
1.78 + return result;
1.79 + }
1.80 +
1.81 + // read feature property header
1.82 + TInt propertySize = 0;
1.83 + TFeatureHeader header;
1.84 + TPckg<TFeatureHeader> headerPckg(header);
1.85 + TBool ranSetup = EFalse;
1.86 + TInt setupResult = KErrNone;
1.87 + while (ETrue)
1.88 + {
1.89 + result = featureProperty.Get(headerPckg);
1.90 + if ((result == KErrOverflow)
1.91 + || ((result == KErrNone) && (headerPckg.Size() >= sizeof(TFeatureHeader))))
1.92 + {
1.93 + if (header.IsInvalid())
1.94 + {
1.95 + result = KErrCorrupt;
1.96 + }
1.97 + else
1.98 + {
1.99 + propertySize = header.PredictedPropertySize();
1.100 + result = KErrOverflow; // indicates successful outcome from this phase
1.101 + }
1.102 + break;
1.103 + }
1.104 + if (ranSetup)
1.105 + {
1.106 + if (setupResult == KErrNoMemory)
1.107 + {
1.108 + result = KErrNoMemory;
1.109 + }
1.110 + else if (setupResult == KErrCorrupt)
1.111 + {
1.112 + result = KErrCorrupt;
1.113 + }
1.114 + else
1.115 + {
1.116 + // must force an error return - other than KErrOverflow
1.117 + result = KErrUnknown;
1.118 + }
1.119 + break;
1.120 + }
1.121 + setupResult = RunFeaturePropertySetupExe();
1.122 + ranSetup = ETrue;
1.123 + }
1.124 +
1.125 + // allocate and read property. Iterate while overflow reported
1.126 + // in case property is republished while reading it
1.127 + while (result == KErrOverflow)
1.128 + {
1.129 + // the feature property data consists of only 32-bit values
1.130 + // allocate in TUint32 blocks to cover any alignment issues
1.131 + TUint32 size32 = (propertySize + sizeof(TUint32) - 1) / sizeof(TUint32);
1.132 + TUint32* propertyBuf32 = new TUint32[size32];
1.133 + TUint8* propertyBuf = reinterpret_cast<TUint8*>(propertyBuf32);
1.134 + if (propertyBuf == NULL)
1.135 + {
1.136 + result = KErrNoMemory;
1.137 + break;
1.138 + }
1.139 + TPtr8 propertyDes(propertyBuf, 0, propertySize);
1.140 + result = featureProperty.Get(propertyDes);
1.141 + if (propertyDes.Size() >= sizeof(TFeatureHeader))
1.142 + {
1.143 + const TFeatureHeader& headerRef = *(reinterpret_cast<const TFeatureHeader*>(propertyBuf));
1.144 + // overflow checking for the following is already done by setup exe
1.145 + if ((result == KErrNone) && (!headerRef.IsInvalidOrBadSize(propertyDes.Size())))
1.146 + {
1.147 + // success
1.148 + iImpl = reinterpret_cast<TImpl*>(propertyBuf);
1.149 + break;
1.150 + }
1.151 + // if it's not a valid overflow (where predicted size is indeed larger than maxsize), it's corrupt
1.152 + if ((result != KErrOverflow) || (headerRef.PredictedPropertySize() < propertyDes.MaxSize()))
1.153 + {
1.154 + result = KErrCorrupt;
1.155 + }
1.156 + }
1.157 + else
1.158 + {
1.159 + result = KErrCorrupt;
1.160 + }
1.161 + delete[] propertyBuf;
1.162 + if (result != KErrOverflow)
1.163 + {
1.164 + result = KErrCorrupt;
1.165 + break;
1.166 + }
1.167 + }
1.168 +
1.169 + featureProperty.Close();
1.170 + // panic in debug mode to alert system integrators that the setup exe
1.171 + // is absent/inaccessible or the config data is invalid in this OS
1.172 + // configuration: a serious problem
1.173 + __ASSERT_DEBUG(result != KErrCorrupt, Panic(EFeatRegBadConfig));
1.174 + return result;
1.175 + }
1.176 +
1.177 +/**
1.178 + * Queries support for feature on the device.
1.179 + * Non-static version requiring open instance of class.
1.180 + * Recommended when making multiple queries.
1.181 + * Note: returns support for feature from the time Open() was called.
1.182 + *
1.183 + * @param aFeatureUid Unique identifier of feature being queried
1.184 + * @return positive value if feature is supported, zero if feature is not supported,
1.185 + * or negative system-wide error code if could not be determined.
1.186 + * @pre this registry instance is open
1.187 + * @panic FeatReg EFeatRegInvalidUse if this registry instance is not open
1.188 + * @publishedPartner
1.189 + * @deprecated
1.190 + */
1.191 +EXPORT_C TInt RFeatureRegistry::QuerySupport(TUid aFeatureUid)
1.192 + {
1.193 + TUint32 dummyInfo;
1.194 + return QuerySupport(aFeatureUid, dummyInfo);
1.195 + }
1.196 +
1.197 +/**
1.198 + * Queries support for feature on the device.
1.199 + * Non-static version requiring open instance of class.
1.200 + * Recommended when making multiple queries.
1.201 + * Note: returns support for feature from the time Open() was called.
1.202 + *
1.203 + * @param aFeatureUid Unique identifier of feature being queried
1.204 + * @param aInfo addition status information about feature
1.205 + * @return positive value if feature is supported, zero if feature is not supported,
1.206 + * or negative system-wide error code if could not be determined.
1.207 + * @pre this registry instance is open
1.208 + * @panic FeatReg EFeatRegInvalidUse if this registry instance is not open
1.209 + * @publishedPartner
1.210 + * @deprecated
1.211 + */
1.212 +EXPORT_C TInt RFeatureRegistry::QuerySupport(TUid aFeatureUid, TUint32& aInfo)
1.213 + {
1.214 + __ASSERT_ALWAYS(iImpl != NULL, Panic(EFeatRegInvalidUse));
1.215 +
1.216 + TFeatureHeader* header = reinterpret_cast<TFeatureHeader*>(iImpl);
1.217 + TUint32 featureUid = aFeatureUid.iUid;
1.218 +
1.219 + // try to find in feature entries first
1.220 + TFeatureEntry* entry = reinterpret_cast<TFeatureEntry*>(header + 1);
1.221 + if (header->iFeatureEntryCount > 0)
1.222 + {
1.223 + RArray<TFeatureEntry> entryArray(sizeof(TFeatureEntry), entry, header->iFeatureEntryCount);
1.224 + TFeatureEntry searchEntry = { featureUid , 0 };
1.225 + TInt index = entryArray.FindInUnsignedKeyOrder(searchEntry);
1.226 + if (index >= 0)
1.227 + {
1.228 + aInfo = entryArray[index].iInfo;
1.229 + return aInfo & EStatusSupportBit;
1.230 + }
1.231 + }
1.232 +
1.233 + // fall back to default ranges - first range to match wins
1.234 + TFeatureRange* range = reinterpret_cast<TFeatureRange*>(entry + header->iFeatureEntryCount);
1.235 + for (TInt i = header->iFeatureRangeCount; i > 0; --i, ++range)
1.236 + {
1.237 + if ((featureUid >= range->iLowUid) && (featureUid <= range->iHighUid))
1.238 + {
1.239 + aInfo = EStatusSupportBit;
1.240 + return EStatusSupportBit;
1.241 + }
1.242 + }
1.243 +
1.244 + // final default: feature not supported
1.245 + aInfo = 0;
1.246 + return 0;
1.247 + }
1.248 +
1.249 +/**
1.250 + * Closes this registry instance.
1.251 + * @publishedPartner
1.252 + * @deprecated
1.253 + */
1.254 +EXPORT_C void RFeatureRegistry::Close()
1.255 + {
1.256 + TUint8* propertyBuf = reinterpret_cast<TUint8*>(iImpl);
1.257 + delete[] propertyBuf;
1.258 + iImpl = NULL;
1.259 + }
1.260 +
1.261 +/**
1.262 + * Queries support for feature on the device.
1.263 + * Static version recommended for single queries.
1.264 + *
1.265 + * @param aFeatureUid Unique identifier of feature being queried
1.266 + * @return positive value if feature is supported, zero if feature is not supported,
1.267 + * or negative system-wide error code if could not be determined.
1.268 + * @publishedPartner
1.269 + * @deprecated
1.270 + */
1.271 +EXPORT_C TInt RFeatureRegistry::QuerySupportS(TUid aFeatureUid)
1.272 + {
1.273 + TUint32 dummyInfo;
1.274 + return QuerySupportS(aFeatureUid, dummyInfo);
1.275 + }
1.276 +
1.277 +/**
1.278 + * Queries support for feature on the device.
1.279 + * Static version recommended for single queries.
1.280 + *
1.281 + * @param aFeatureUid Unique identifier of feature being queried
1.282 + * @param aInfo addition status information about feature
1.283 + * @return positive value if feature is supported, zero if feature is not supported,
1.284 + * or negative system-wide error code if could not be determined.
1.285 + * @publishedPartner
1.286 + * @deprecated
1.287 + */
1.288 +EXPORT_C TInt RFeatureRegistry::QuerySupportS(TUid aFeatureUid, TUint32& aInfo)
1.289 + {
1.290 + RFeatureRegistry featReg;
1.291 + TInt result = featReg.Open();
1.292 + if (result == KErrNone)
1.293 + {
1.294 + result = featReg.QuerySupport(aFeatureUid, aInfo);
1.295 + featReg.Close();
1.296 + }
1.297 + return result;
1.298 + }
1.299 +
1.300 +/**
1.301 + * Implementation class allocated when RFeatureRegistryNotify is opened.
1.302 + *
1.303 + * @internalComponent
1.304 + */
1.305 +class RFeatureRegistryNotify::TImpl
1.306 + {
1.307 +public:
1.308 + RProperty iNotifyProperty;
1.309 +
1.310 + TImpl()
1.311 + : iNotifyProperty()
1.312 + {
1.313 + }
1.314 + };
1.315 +
1.316 +/**
1.317 + * Open instance of notify object so it can be subscribed to.
1.318 + *
1.319 + * @return KErrNone if successful, negative system-wide error code if not
1.320 + * @internalComponent
1.321 + */
1.322 +EXPORT_C TInt RFeatureRegistryNotify::Open()
1.323 + {
1.324 + iImpl = new TImpl;
1.325 + if (iImpl == NULL)
1.326 + {
1.327 + return KErrNoMemory;
1.328 + }
1.329 + TInt result = iImpl->iNotifyProperty.Attach(KFeaturePropCat, KFeaturePropKey);
1.330 + if (result != KErrNone)
1.331 + {
1.332 + // must clean up memory allocated above
1.333 + delete iImpl;
1.334 + iImpl = NULL;
1.335 + return result;
1.336 + }
1.337 + // feature property and notify property are same in current implementation
1.338 + // hence must ensure feature property is already published to avoid false
1.339 + // notification when it is first published (just-in-time by the next query)
1.340 + TFeatureHeader header;
1.341 + TPckg<TFeatureHeader> headerPckg(header);
1.342 + result = iImpl->iNotifyProperty.Get(headerPckg);
1.343 + if (!((result == KErrOverflow)
1.344 + || ((result == KErrNone) && (headerPckg.Size() >= sizeof(TFeatureHeader)))))
1.345 + {
1.346 + RunFeaturePropertySetupExe();
1.347 + }
1.348 + // return fact that Attach() succeeded
1.349 + return KErrNone;
1.350 + }
1.351 +
1.352 +/**
1.353 + * Issues an asynchronous request to be notified the next time the support
1.354 + * status of any features change.
1.355 + *
1.356 + * To ensure that changes are not missed, always re-subscribe before
1.357 + * querying the feature registry.
1.358 + *
1.359 + * If an outstanding request is cancelled through a call to Cancel(), then it
1.360 + * completes with KErrCancel.
1.361 + *
1.362 + * @pre this instance of notify object must be Open and not already Subscribed to.
1.363 + * @param aNotifyStatus The request status object to be signalled on update.
1.364 + * @panic FeatReg EFeatRegInvalidUse if this registry notify instance is not open
1.365 + * @internalComponent
1.366 + */
1.367 +EXPORT_C void RFeatureRegistryNotify::Subscribe(TRequestStatus &aNotifyStatus)
1.368 + {
1.369 + __ASSERT_ALWAYS(iImpl != NULL, Panic(EFeatRegInvalidUse));
1.370 + iImpl->iNotifyProperty.Subscribe(aNotifyStatus);
1.371 + }
1.372 +
1.373 +/**
1.374 + * Cancels an outstanding subscription request for notification of feature registry changes.
1.375 + *
1.376 + * If the request has not already completed, then it completes with KErrCancel.
1.377 + *
1.378 + * @pre this instance of notify object must be Open
1.379 + * @panic FeatReg EFeatRegInvalidUse if this registry notify instance is not open
1.380 + * @internalComponent
1.381 + */
1.382 +EXPORT_C void RFeatureRegistryNotify::Cancel()
1.383 + {
1.384 + __ASSERT_ALWAYS(iImpl != NULL, Panic(EFeatRegInvalidUse));
1.385 + iImpl->iNotifyProperty.Cancel();
1.386 + }
1.387 +
1.388 +/**
1.389 + * Closes the registry notify instance.
1.390 + *
1.391 + * Note: automatically cancels any outstanding notify subscription.
1.392 + *
1.393 + * @internalComponent
1.394 + */
1.395 +EXPORT_C void RFeatureRegistryNotify::Close()
1.396 + {
1.397 + if (iImpl)
1.398 + {
1.399 + // Have checked RProperty::Close() cancels the outstanding subscription
1.400 + iImpl->iNotifyProperty.Close();
1.401 + }
1.402 + delete iImpl;
1.403 + iImpl = NULL;
1.404 + }