|
1 // Copyright (c) 2005-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 // Implementation of API for querying support for features on a device, and |
|
15 // receiving notification if features are added or removed. |
|
16 // |
|
17 // |
|
18 |
|
19 #include <e32property.h> |
|
20 #include <e32cmn.h> |
|
21 #include <e32uid.h> |
|
22 #include "featreg.h" |
|
23 #include "featregpan.h" |
|
24 #include "featregcmn.h" |
|
25 |
|
26 /** |
|
27 * Run setup exe, wait for completion: ends only once property defined, or failed |
|
28 * @internalComponent |
|
29 * @return KErrNone on success, or system-wide error code |
|
30 */ |
|
31 static TInt RunFeaturePropertySetupExe() |
|
32 { |
|
33 const TUidType setupExeUidType(KExecutableImageUid, TUid::Null(), KFeaturePropCat); |
|
34 RProcess setupProc; |
|
35 TInt result = setupProc.Create(KFeatRegSetupExe, KNullDesC, setupExeUidType); |
|
36 if (result != KErrNone) |
|
37 { |
|
38 return result; |
|
39 } |
|
40 TRequestStatus setupStatus; |
|
41 // request Rendezvous before Resume() to avoid race condition. |
|
42 // Also note if request to rendezvous fails (OOM etc.) then setup exe may |
|
43 // complete after query code, with feature property possibly undefined |
|
44 setupProc.Rendezvous(setupStatus); |
|
45 setupProc.Resume(); |
|
46 setupProc.Close(); |
|
47 User::WaitForRequest(setupStatus); |
|
48 return setupStatus.Int(); |
|
49 } |
|
50 |
|
51 /** |
|
52 * Dummy feature registry implementation object - never instantiated. |
|
53 * @internalComponent |
|
54 */ |
|
55 class RFeatureRegistry::TImpl |
|
56 { |
|
57 TUint32 iDummy; |
|
58 }; |
|
59 |
|
60 /** |
|
61 * Opens connection to the Feature Registry for making non-static queries. |
|
62 * Note all non-static queries return state at the time Open() was called; |
|
63 * Feature Registry changes are not observed until instance closed and re-opened. |
|
64 * |
|
65 * @return KErrNone if successful, negative system-wide error code if fails |
|
66 * @publishedPartner |
|
67 * @deprecated |
|
68 */ |
|
69 EXPORT_C TInt RFeatureRegistry::Open() |
|
70 { |
|
71 RProperty featureProperty; |
|
72 TInt result = featureProperty.Attach(KFeaturePropCat, KFeaturePropKey); |
|
73 if (result != KErrNone) |
|
74 { |
|
75 return result; |
|
76 } |
|
77 |
|
78 // read feature property header |
|
79 TInt propertySize = 0; |
|
80 TFeatureHeader header; |
|
81 TPckg<TFeatureHeader> headerPckg(header); |
|
82 TBool ranSetup = EFalse; |
|
83 TInt setupResult = KErrNone; |
|
84 while (ETrue) |
|
85 { |
|
86 result = featureProperty.Get(headerPckg); |
|
87 if ((result == KErrOverflow) |
|
88 || ((result == KErrNone) && (headerPckg.Size() >= sizeof(TFeatureHeader)))) |
|
89 { |
|
90 if (header.IsInvalid()) |
|
91 { |
|
92 result = KErrCorrupt; |
|
93 } |
|
94 else |
|
95 { |
|
96 propertySize = header.PredictedPropertySize(); |
|
97 result = KErrOverflow; // indicates successful outcome from this phase |
|
98 } |
|
99 break; |
|
100 } |
|
101 if (ranSetup) |
|
102 { |
|
103 if (setupResult == KErrNoMemory) |
|
104 { |
|
105 result = KErrNoMemory; |
|
106 } |
|
107 else if (setupResult == KErrCorrupt) |
|
108 { |
|
109 result = KErrCorrupt; |
|
110 } |
|
111 else |
|
112 { |
|
113 // must force an error return - other than KErrOverflow |
|
114 result = KErrUnknown; |
|
115 } |
|
116 break; |
|
117 } |
|
118 setupResult = RunFeaturePropertySetupExe(); |
|
119 ranSetup = ETrue; |
|
120 } |
|
121 |
|
122 // allocate and read property. Iterate while overflow reported |
|
123 // in case property is republished while reading it |
|
124 while (result == KErrOverflow) |
|
125 { |
|
126 // the feature property data consists of only 32-bit values |
|
127 // allocate in TUint32 blocks to cover any alignment issues |
|
128 TUint32 size32 = (propertySize + sizeof(TUint32) - 1) / sizeof(TUint32); |
|
129 TUint32* propertyBuf32 = new TUint32[size32]; |
|
130 TUint8* propertyBuf = reinterpret_cast<TUint8*>(propertyBuf32); |
|
131 if (propertyBuf == NULL) |
|
132 { |
|
133 result = KErrNoMemory; |
|
134 break; |
|
135 } |
|
136 TPtr8 propertyDes(propertyBuf, 0, propertySize); |
|
137 result = featureProperty.Get(propertyDes); |
|
138 if (propertyDes.Size() >= sizeof(TFeatureHeader)) |
|
139 { |
|
140 const TFeatureHeader& headerRef = *(reinterpret_cast<const TFeatureHeader*>(propertyBuf)); |
|
141 // overflow checking for the following is already done by setup exe |
|
142 if ((result == KErrNone) && (!headerRef.IsInvalidOrBadSize(propertyDes.Size()))) |
|
143 { |
|
144 // success |
|
145 iImpl = reinterpret_cast<TImpl*>(propertyBuf); |
|
146 break; |
|
147 } |
|
148 // if it's not a valid overflow (where predicted size is indeed larger than maxsize), it's corrupt |
|
149 if ((result != KErrOverflow) || (headerRef.PredictedPropertySize() < propertyDes.MaxSize())) |
|
150 { |
|
151 result = KErrCorrupt; |
|
152 } |
|
153 } |
|
154 else |
|
155 { |
|
156 result = KErrCorrupt; |
|
157 } |
|
158 delete[] propertyBuf; |
|
159 if (result != KErrOverflow) |
|
160 { |
|
161 result = KErrCorrupt; |
|
162 break; |
|
163 } |
|
164 } |
|
165 |
|
166 featureProperty.Close(); |
|
167 // panic in debug mode to alert system integrators that the setup exe |
|
168 // is absent/inaccessible or the config data is invalid in this OS |
|
169 // configuration: a serious problem |
|
170 __ASSERT_DEBUG(result != KErrCorrupt, Panic(EFeatRegBadConfig)); |
|
171 return result; |
|
172 } |
|
173 |
|
174 /** |
|
175 * Queries support for feature on the device. |
|
176 * Non-static version requiring open instance of class. |
|
177 * Recommended when making multiple queries. |
|
178 * Note: returns support for feature from the time Open() was called. |
|
179 * |
|
180 * @param aFeatureUid Unique identifier of feature being queried |
|
181 * @return positive value if feature is supported, zero if feature is not supported, |
|
182 * or negative system-wide error code if could not be determined. |
|
183 * @pre this registry instance is open |
|
184 * @panic FeatReg EFeatRegInvalidUse if this registry instance is not open |
|
185 * @publishedPartner |
|
186 * @deprecated |
|
187 */ |
|
188 EXPORT_C TInt RFeatureRegistry::QuerySupport(TUid aFeatureUid) |
|
189 { |
|
190 TUint32 dummyInfo; |
|
191 return QuerySupport(aFeatureUid, dummyInfo); |
|
192 } |
|
193 |
|
194 /** |
|
195 * Queries support for feature on the device. |
|
196 * Non-static version requiring open instance of class. |
|
197 * Recommended when making multiple queries. |
|
198 * Note: returns support for feature from the time Open() was called. |
|
199 * |
|
200 * @param aFeatureUid Unique identifier of feature being queried |
|
201 * @param aInfo addition status information about feature |
|
202 * @return positive value if feature is supported, zero if feature is not supported, |
|
203 * or negative system-wide error code if could not be determined. |
|
204 * @pre this registry instance is open |
|
205 * @panic FeatReg EFeatRegInvalidUse if this registry instance is not open |
|
206 * @publishedPartner |
|
207 * @deprecated |
|
208 */ |
|
209 EXPORT_C TInt RFeatureRegistry::QuerySupport(TUid aFeatureUid, TUint32& aInfo) |
|
210 { |
|
211 __ASSERT_ALWAYS(iImpl != NULL, Panic(EFeatRegInvalidUse)); |
|
212 |
|
213 TFeatureHeader* header = reinterpret_cast<TFeatureHeader*>(iImpl); |
|
214 TUint32 featureUid = aFeatureUid.iUid; |
|
215 |
|
216 // try to find in feature entries first |
|
217 TFeatureEntry* entry = reinterpret_cast<TFeatureEntry*>(header + 1); |
|
218 if (header->iFeatureEntryCount > 0) |
|
219 { |
|
220 RArray<TFeatureEntry> entryArray(sizeof(TFeatureEntry), entry, header->iFeatureEntryCount); |
|
221 TFeatureEntry searchEntry = { featureUid , 0 }; |
|
222 TInt index = entryArray.FindInUnsignedKeyOrder(searchEntry); |
|
223 if (index >= 0) |
|
224 { |
|
225 aInfo = entryArray[index].iInfo; |
|
226 return aInfo & EStatusSupportBit; |
|
227 } |
|
228 } |
|
229 |
|
230 // fall back to default ranges - first range to match wins |
|
231 TFeatureRange* range = reinterpret_cast<TFeatureRange*>(entry + header->iFeatureEntryCount); |
|
232 for (TInt i = header->iFeatureRangeCount; i > 0; --i, ++range) |
|
233 { |
|
234 if ((featureUid >= range->iLowUid) && (featureUid <= range->iHighUid)) |
|
235 { |
|
236 aInfo = EStatusSupportBit; |
|
237 return EStatusSupportBit; |
|
238 } |
|
239 } |
|
240 |
|
241 // final default: feature not supported |
|
242 aInfo = 0; |
|
243 return 0; |
|
244 } |
|
245 |
|
246 /** |
|
247 * Closes this registry instance. |
|
248 * @publishedPartner |
|
249 * @deprecated |
|
250 */ |
|
251 EXPORT_C void RFeatureRegistry::Close() |
|
252 { |
|
253 TUint8* propertyBuf = reinterpret_cast<TUint8*>(iImpl); |
|
254 delete[] propertyBuf; |
|
255 iImpl = NULL; |
|
256 } |
|
257 |
|
258 /** |
|
259 * Queries support for feature on the device. |
|
260 * Static version recommended for single queries. |
|
261 * |
|
262 * @param aFeatureUid Unique identifier of feature being queried |
|
263 * @return positive value if feature is supported, zero if feature is not supported, |
|
264 * or negative system-wide error code if could not be determined. |
|
265 * @publishedPartner |
|
266 * @deprecated |
|
267 */ |
|
268 EXPORT_C TInt RFeatureRegistry::QuerySupportS(TUid aFeatureUid) |
|
269 { |
|
270 TUint32 dummyInfo; |
|
271 return QuerySupportS(aFeatureUid, dummyInfo); |
|
272 } |
|
273 |
|
274 /** |
|
275 * Queries support for feature on the device. |
|
276 * Static version recommended for single queries. |
|
277 * |
|
278 * @param aFeatureUid Unique identifier of feature being queried |
|
279 * @param aInfo addition status information about feature |
|
280 * @return positive value if feature is supported, zero if feature is not supported, |
|
281 * or negative system-wide error code if could not be determined. |
|
282 * @publishedPartner |
|
283 * @deprecated |
|
284 */ |
|
285 EXPORT_C TInt RFeatureRegistry::QuerySupportS(TUid aFeatureUid, TUint32& aInfo) |
|
286 { |
|
287 RFeatureRegistry featReg; |
|
288 TInt result = featReg.Open(); |
|
289 if (result == KErrNone) |
|
290 { |
|
291 result = featReg.QuerySupport(aFeatureUid, aInfo); |
|
292 featReg.Close(); |
|
293 } |
|
294 return result; |
|
295 } |
|
296 |
|
297 /** |
|
298 * Implementation class allocated when RFeatureRegistryNotify is opened. |
|
299 * |
|
300 * @internalComponent |
|
301 */ |
|
302 class RFeatureRegistryNotify::TImpl |
|
303 { |
|
304 public: |
|
305 RProperty iNotifyProperty; |
|
306 |
|
307 TImpl() |
|
308 : iNotifyProperty() |
|
309 { |
|
310 } |
|
311 }; |
|
312 |
|
313 /** |
|
314 * Open instance of notify object so it can be subscribed to. |
|
315 * |
|
316 * @return KErrNone if successful, negative system-wide error code if not |
|
317 * @internalComponent |
|
318 */ |
|
319 EXPORT_C TInt RFeatureRegistryNotify::Open() |
|
320 { |
|
321 iImpl = new TImpl; |
|
322 if (iImpl == NULL) |
|
323 { |
|
324 return KErrNoMemory; |
|
325 } |
|
326 TInt result = iImpl->iNotifyProperty.Attach(KFeaturePropCat, KFeaturePropKey); |
|
327 if (result != KErrNone) |
|
328 { |
|
329 // must clean up memory allocated above |
|
330 delete iImpl; |
|
331 iImpl = NULL; |
|
332 return result; |
|
333 } |
|
334 // feature property and notify property are same in current implementation |
|
335 // hence must ensure feature property is already published to avoid false |
|
336 // notification when it is first published (just-in-time by the next query) |
|
337 TFeatureHeader header; |
|
338 TPckg<TFeatureHeader> headerPckg(header); |
|
339 result = iImpl->iNotifyProperty.Get(headerPckg); |
|
340 if (!((result == KErrOverflow) |
|
341 || ((result == KErrNone) && (headerPckg.Size() >= sizeof(TFeatureHeader))))) |
|
342 { |
|
343 RunFeaturePropertySetupExe(); |
|
344 } |
|
345 // return fact that Attach() succeeded |
|
346 return KErrNone; |
|
347 } |
|
348 |
|
349 /** |
|
350 * Issues an asynchronous request to be notified the next time the support |
|
351 * status of any features change. |
|
352 * |
|
353 * To ensure that changes are not missed, always re-subscribe before |
|
354 * querying the feature registry. |
|
355 * |
|
356 * If an outstanding request is cancelled through a call to Cancel(), then it |
|
357 * completes with KErrCancel. |
|
358 * |
|
359 * @pre this instance of notify object must be Open and not already Subscribed to. |
|
360 * @param aNotifyStatus The request status object to be signalled on update. |
|
361 * @panic FeatReg EFeatRegInvalidUse if this registry notify instance is not open |
|
362 * @internalComponent |
|
363 */ |
|
364 EXPORT_C void RFeatureRegistryNotify::Subscribe(TRequestStatus &aNotifyStatus) |
|
365 { |
|
366 __ASSERT_ALWAYS(iImpl != NULL, Panic(EFeatRegInvalidUse)); |
|
367 iImpl->iNotifyProperty.Subscribe(aNotifyStatus); |
|
368 } |
|
369 |
|
370 /** |
|
371 * Cancels an outstanding subscription request for notification of feature registry changes. |
|
372 * |
|
373 * If the request has not already completed, then it completes with KErrCancel. |
|
374 * |
|
375 * @pre this instance of notify object must be Open |
|
376 * @panic FeatReg EFeatRegInvalidUse if this registry notify instance is not open |
|
377 * @internalComponent |
|
378 */ |
|
379 EXPORT_C void RFeatureRegistryNotify::Cancel() |
|
380 { |
|
381 __ASSERT_ALWAYS(iImpl != NULL, Panic(EFeatRegInvalidUse)); |
|
382 iImpl->iNotifyProperty.Cancel(); |
|
383 } |
|
384 |
|
385 /** |
|
386 * Closes the registry notify instance. |
|
387 * |
|
388 * Note: automatically cancels any outstanding notify subscription. |
|
389 * |
|
390 * @internalComponent |
|
391 */ |
|
392 EXPORT_C void RFeatureRegistryNotify::Close() |
|
393 { |
|
394 if (iImpl) |
|
395 { |
|
396 // Have checked RProperty::Close() cancels the outstanding subscription |
|
397 iImpl->iNotifyProperty.Close(); |
|
398 } |
|
399 delete iImpl; |
|
400 iImpl = NULL; |
|
401 } |