|
1 <?xml version="1.0" encoding="utf-8"?> |
|
2 <!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. --> |
|
3 <!-- This component and the accompanying materials are made available under the terms of the License |
|
4 "Eclipse Public License v1.0" which accompanies this distribution, |
|
5 and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". --> |
|
6 <!-- Initial Contributors: |
|
7 Nokia Corporation - initial contribution. |
|
8 Contributors: |
|
9 --> |
|
10 <!DOCTYPE concept |
|
11 PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd"> |
|
12 <concept id="GUID-EBFD653D-6E6A-5F6F-88D7-8CCE07B4002D" xml:lang="en"><title>Publish |
|
13 and Subscribe</title><shortdesc>Publish and Subscribe allows global variables to be set and retrieved, |
|
14 and allows subscribers to be notified that variables have changed. </shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody> |
|
15 <p>The general pattern for using on the kernel side is almost the same as |
|
16 for the user side. However, different classes are used on the kernel side. |
|
17 It may be useful to compare kernel side usage with user side usage as described |
|
18 in the <xref href="GUID-A81C65CF-CF4E-571C-8080-9D387F46AAD6.dita">Publish and |
|
19 Subscribe</xref> guide for the user-side API. </p> |
|
20 <ul> |
|
21 <li id="GUID-BDAE8BFE-B0F9-5A3D-9E2B-6AC6280195E5"><p> <xref href="GUID-EBFD653D-6E6A-5F6F-88D7-8CCE07B4002D.dita#GUID-EBFD653D-6E6A-5F6F-88D7-8CCE07B4002D/GUID-AD33A76A-9A27-5D66-B583-64F360EC996E">Properties</xref> </p> </li> |
|
22 <li id="GUID-3D892E85-C506-5FF6-A8E2-3A9458800CBB"><p> <xref href="GUID-EBFD653D-6E6A-5F6F-88D7-8CCE07B4002D.dita#GUID-EBFD653D-6E6A-5F6F-88D7-8CCE07B4002D/GUID-E2261227-E747-53E0-9EE3-9CEC824C1832">Creating and closing a reference to a property</xref> </p> </li> |
|
23 <li id="GUID-728CCCEB-8F5F-5CA1-A650-803C94E64194"><p> <xref href="GUID-EBFD653D-6E6A-5F6F-88D7-8CCE07B4002D.dita#GUID-EBFD653D-6E6A-5F6F-88D7-8CCE07B4002D/GUID-C41886EF-24EC-58C2-A906-C4890CED3F3A">Defining a property</xref> </p> </li> |
|
24 <li id="GUID-FB0EC3DC-38E1-5701-AF84-47A814238163"><p> <xref href="GUID-EBFD653D-6E6A-5F6F-88D7-8CCE07B4002D.dita#GUID-EBFD653D-6E6A-5F6F-88D7-8CCE07B4002D/GUID-60F19D41-F9B5-5A21-9654-5D96CA6EE83E">Deleting a property</xref> </p> </li> |
|
25 <li id="GUID-FAE51C6E-1C39-593C-B2AD-7BEFAA257F72"><p> <xref href="GUID-EBFD653D-6E6A-5F6F-88D7-8CCE07B4002D.dita#GUID-EBFD653D-6E6A-5F6F-88D7-8CCE07B4002D/GUID-EBAA6B5C-CC73-5AE2-85CA-68B445828608">Publishing a property value</xref> </p> </li> |
|
26 <li id="GUID-2F1A3E2F-44C8-5532-8FA2-F49A4FC58623"><p> <xref href="GUID-EBFD653D-6E6A-5F6F-88D7-8CCE07B4002D.dita#GUID-EBFD653D-6E6A-5F6F-88D7-8CCE07B4002D/GUID-CA858A2A-4BF0-565D-8A6D-58AE32FEE304">Retrieving a property value</xref> </p> </li> |
|
27 <li id="GUID-C39FCE8D-082E-56E8-85B2-137B25B88C61"><p> <xref href="GUID-EBFD653D-6E6A-5F6F-88D7-8CCE07B4002D.dita#GUID-EBFD653D-6E6A-5F6F-88D7-8CCE07B4002D/GUID-984AB90D-FCCD-5383-B5D9-8D80AA83D989">Subscribing to, and unsubscribing from, a property </xref> </p> </li> |
|
28 <li id="GUID-E02C9293-56B4-5AC0-9DA8-F47E6796A07D"><p> <xref href="GUID-EBFD653D-6E6A-5F6F-88D7-8CCE07B4002D.dita#GUID-EBFD653D-6E6A-5F6F-88D7-8CCE07B4002D/GUID-21D8ADCA-9B39-5079-B4AD-FEBFCCB92049">Usage patterns</xref> </p> </li> |
|
29 </ul> |
|
30 <section id="GUID-AD33A76A-9A27-5D66-B583-64F360EC996E"><title>Properties</title> <p>A |
|
31 property has the two attributes: identity and type. </p> <p><b>Identity</b> </p> <p>A |
|
32 property is identified by a 64-bit integer made up of two 32-bit parts: the |
|
33 category and the key. </p> <p>A property belongs to a category, and a category |
|
34 is identified by a UID. </p> <p>A key is a 32-bit value that identifies a |
|
35 specific property within a category. The meaning applied to the key depends |
|
36 on the kind of enumeration scheme set up for the category. At its simplest, |
|
37 a key can be an index value. It can also be another UID, if the category is |
|
38 designed to be generally extensible. </p> <p><b>Type</b> </p> <p>A property |
|
39 can be: </p> <ul> |
|
40 <li id="GUID-083AF1CA-ACA1-53A3-A251-370DD1D06554"><p>a single 32-bit value </p> </li> |
|
41 <li id="GUID-6EA61CFF-F549-5FA2-A6AA-43683C802B8D"><p>a contiguous set of |
|
42 bytes, referred to as a byte-array, whose length can vary from 0 to 512 bytes </p> </li> |
|
43 </ul><p>Once defined, a property value can change, but the property type cannot. |
|
44 Byte-array type properties can also change length provided the length does |
|
45 not exceed the value <xref href="GUID-C4776034-D190-3FC4-AF45-C7F195093AC3.dita#GUID-C4776034-D190-3FC4-AF45-C7F195093AC3/GUID-57E64054-610A-31D1-AD7F-E2F9F9FC1DCB"><apiname>RProperty::KMaxPropertySize</apiname></xref>. The limit |
|
46 on size of property ensures some limit on RAM usage. </p><p>The API allows |
|
47 a byte-array text type property to be pre-allocated when it is defined. This |
|
48 means that the time taken to set the values is bounded. However, if the length |
|
49 of this property type subsequently increases, then memory allocation may take |
|
50 place, and no guarantees can be made on the time taken to set them.</p><p>Note |
|
51 that the <xref href="GUID-C4776034-D190-3FC4-AF45-C7F195093AC3.dita#GUID-C4776034-D190-3FC4-AF45-C7F195093AC3/GUID-F8DE443B-B208-353C-A98E-AA52C4FE6530"><apiname>RProperty::ELargeByteArray</apiname></xref> property type can never |
|
52 provide a real-time guarantee. </p><p>For code running kernel side, properties |
|
53 and their values are defined, set and retrieved using a <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita"><apiname>RPropertyRef</apiname></xref> object.</p> </section> |
|
54 <section id="GUID-E2261227-E747-53E0-9EE3-9CEC824C1832"><title>Creating and |
|
55 closing a reference to a property</title> <p>On the kernel side, all accesses |
|
56 to a property <i>must</i> be done through a property reference, an instance |
|
57 of a <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita"><apiname>RPropertyRef</apiname></xref>. </p> <p>You must create a reference |
|
58 to a property, before doing any operation on that property. By operation, |
|
59 we mean defining a property, subscribing to a property, publishing and retrieving |
|
60 a property value. The kernel will fault if you have not first created a reference. </p> <p>Only |
|
61 one property, as uniquely identified by its category and key, can be accessed |
|
62 by an instance of <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita"><apiname>RPropertyRef</apiname></xref>; however a property can |
|
63 be referenced by more than one instance of <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita"><apiname>RPropertyRef</apiname></xref>. </p> <p>Internally, |
|
64 properties are represented by <codeph>TProperty</codeph> objects, and these |
|
65 are reference counted. The act of creating a reference to a property results |
|
66 either in the creation of a <codeph>TProperty</codeph> object or an increase |
|
67 in the reference count of an existing object. The property itself has no attributes |
|
68 or "structure" until it is defined. </p> <p>Please note that the structure |
|
69 and management of <codeph>TProperty</codeph> objects are part of Symbian platform's |
|
70 internal implementation and will not be discussed further. </p> <fig id="GUID-8A0D9C1E-00D7-5369-AD9C-28AA9151612F"> |
|
71 <title>Objects internal to Symbian platform</title> |
|
72 <image href="GUID-31CE66F2-B36C-56ED-A399-BA9EFA179DED_d0e283609_href.png" placement="inline"/> |
|
73 </fig> <p>To establish a reference to a property, create an <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita"><apiname>RPropertyRef</apiname></xref> object, |
|
74 and then use one of the following functions: </p> <ul> |
|
75 <li id="GUID-87D76A73-6429-5D4C-8321-A98F756C30F5"><p> <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita#GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2/GUID-DBEDDC3A-AE6F-3CAF-B251-4AA556EAF21C"><apiname>RPropertyRef::Attach()</apiname></xref> - |
|
76 tries to open the property identified by the category and key, if it exists, |
|
77 but creates that property if it does not exist. Creation is simply the act |
|
78 of creating the internal <codeph>TProperty</codeph> object. The object has |
|
79 no type or "structure" associated with it other than the use of the category |
|
80 and key as identification markers. </p> </li> |
|
81 <li id="GUID-7D1AFF17-BB0A-57B9-9782-001E983D9EDE"><p> <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita#GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2/GUID-6F8EB0AB-C01A-3BFD-B334-D9C9FB923865"><apiname>RPropertyRef::Open()</apiname></xref> - |
|
82 tries to open the property identified by the category and key, and assumes |
|
83 that the property already exists; this fails if the property does not exist. </p> </li> |
|
84 </ul> <p>You can call these functions from a user thread running in supervisor |
|
85 mode, from a kernel thread or from a DFC. If calling from a user thread running |
|
86 in supervisor mode, then your thread must be running in a critical section. |
|
87 In debug mode, if a user thread is not in a critical section, then the kernel |
|
88 will fault. </p> <p>On successful return from these functions, the <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita"><apiname>RPropertyRef</apiname></xref> object |
|
89 owns a resource, the property, and this can then be defined and accessed through |
|
90 the <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita"><apiname>RPropertyRef</apiname></xref> object. </p> <p>It is difficult to make |
|
91 firm rules as to which one your code should use, but generally, you use <codeph>Open()</codeph> if |
|
92 you have no responsibility or interest in ensuring that the property exists. |
|
93 You would use <codeph>Attach()</codeph> if you were to have single or <i>joint</i> responsibility |
|
94 for ensuring that the property exists. It depends on the intent of the property |
|
95 and the role of your driver code in the system. </p> <p>Note that responsibility |
|
96 for creating the property does not necessarily align with who can define, |
|
97 delete, publish (write) or retrieve (read) a property value. This is governed |
|
98 by the intent of the property and, for retrieving and publishing, by the security |
|
99 policies in place. </p> <p>When the property is no longer needed, you can |
|
100 release it by calling <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita#GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2/GUID-3465CD78-C107-3AD9-AEAF-F97A94C1C462"><apiname>RPropertyRef::Close()</apiname></xref>. Closing the |
|
101 reference does not cause the property to disappear. This only happens when |
|
102 the <i>final</i> reference to the property is closed. </p> <p>Note that it |
|
103 is quite legitimate to attach to, or to open, a property that has not been |
|
104 defined, and in this case no error will be returned either. This enables the |
|
105 lazy definition of properties as used in some of the usage patterns. </p> <codeblock id="GUID-7F4295E4-F822-5128-B4EC-3AD3E71BD444" xml:space="preserve">const TUid KMyPropertyCat={0x10012345}; |
|
106 enum TMyPropertyKeys={EMyPropertyCounter,EMyPropertyName}; |
|
107 |
|
108 . . . |
|
109 |
|
110 // Attach to the ‘counter’ property. This creates the property |
|
111 // if it does not already exist. |
|
112 RPropertyRef counter; |
|
113 TInt r; |
|
114 r=counter.Attach(KMyPropertyCat,EMyPropertyCounter); |
|
115 |
|
116 // r should be KErrNone if sucessful or KErrNoMemory if there |
|
117 // is an out of memory failure. |
|
118 if (r != KErrNone) |
|
119 { |
|
120 // Handle the bad return value |
|
121 } |
|
122 |
|
123 // use the counter object... |
|
124 |
|
125 // when finished, release the property |
|
126 counter.Close(); |
|
127 </codeblock> </section> |
|
128 <section id="GUID-C41886EF-24EC-58C2-A906-C4890CED3F3A"><title>Defining a |
|
129 property </title> <p>Defining a property gives it "structure" i.e. attributes |
|
130 such as the property type, and the security policies that define the capabilities |
|
131 that a process must have to publish and retrieve the property value. </p> <p>A |
|
132 property is defined using the <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita#GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2/GUID-47F367CB-E663-3F97-AC0C-31A9DD6BD5E5"><apiname>RPropertyRef::Define()</apiname></xref> function. |
|
133 You can call this function from a user thread running in supervisor mode, |
|
134 from a kernel thread or from a DFC. If calling from a user thread running |
|
135 in supervisor mode, then your thread must be running in a critical section. |
|
136 In debug mode, if a user thread is not in a critical section, then the kernel |
|
137 will fault. </p> <p>You can call this function from a user thread running |
|
138 in supervisor mode, from a kernel thread or from a DFC. If calling from a |
|
139 user thread running in supervisor mode, then your thread must be running in |
|
140 a critical section. In debug mode, if a user thread is not in a critical section, |
|
141 then the kernel will fault. </p> <p>The information needed to define the property |
|
142 is passed to <codeph>Define()</codeph>. Note that a reference to the property |
|
143 must already have been established using <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita#GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2/GUID-DBEDDC3A-AE6F-3CAF-B251-4AA556EAF21C"><apiname>RPropertyRef::Attach()</apiname></xref> or <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita#GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2/GUID-6F8EB0AB-C01A-3BFD-B334-D9C9FB923865"><apiname>RPropertyRef::Open()</apiname></xref>. </p> <p>A |
|
144 property does not need to be defined before it can be accessed. This supports |
|
145 programming patterns where both publishers and subscribers may define the |
|
146 property. </p> <p>Once defined, a property persists until the system reboots, |
|
147 or the property is explicitly deleted. Its lifetime is not tied to that of |
|
148 the thread or process that originally defined it. This means that, when defining |
|
149 a property, it is important to check the return code from the call to <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita#GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2/GUID-47F367CB-E663-3F97-AC0C-31A9DD6BD5E5"><apiname>RPropertyRef::Define()</apiname></xref> to |
|
150 deal with the possibility that the property has previously been defined. </p> <p>The |
|
151 following code shows the definition of two properties, which we call: 'name' |
|
152 and 'counter': </p> <codeblock id="GUID-318DC2A6-FFE4-5781-9F78-5D5B4392585F" xml:space="preserve">const TUid KMyPropertyCat={0x10012345}; |
|
153 enum TMyPropertyKeys={EMyPropertyCounter,EMyPropertyName}; |
|
154 |
|
155 static _LIT_SECURITY_POLICY_PASS(KAllowAllPolicy); |
|
156 static _LIT_SECURITY_POLICY_C1(KPowerMgmtPolicy,ECapabilityPowerMgmt); |
|
157 |
|
158 TInt r; |
|
159 |
|
160 // Attaches to the ‘counter’ property. |
|
161 // If the property already exists, a new reference to it is created. |
|
162 // If the property does not exist, it is created. |
|
163 RPropertyRef counter; |
|
164 r=counter.Attach(KMyPropertyCat,EMyPropertyCounter); |
|
165 if (r != KErrNone) |
|
166 { |
|
167 // Handle the bad return value |
|
168 } |
|
169 |
|
170 // Attaches to the ‘name’ property. |
|
171 // If the property already exists, a new reference to it is created. |
|
172 // If the property does not exist, it is created. |
|
173 RPropertyRef name; |
|
174 r=name.Attach(KMyPropertyCat,EMyPropertyName); |
|
175 if (r != KErrNone) |
|
176 { |
|
177 // Handle the bad return value |
|
178 } |
|
179 |
|
180 // Now define the 'counter' property: |
|
181 // 1. Integer type |
|
182 // 2. Pre-allocated size has no meaning, and must be zero. |
|
183 // 3. Allow all processes to retrieve (read) the property. |
|
184 // 4. Only processes with power managament capability can write. |
|
185 // 5. Capability checks to be done against client thread's process. |
|
186 |
|
187 r=counter.Define(RProperty::EInt,KAllowAllPolicy,KPowerMgmtPolicy,0,iClientProcess); |
|
188 |
|
189 // You will probably need to check the return value. |
|
190 // It may legitimately by non-KErrNone. |
|
191 |
|
192 ... |
|
193 |
|
194 // Now define the 'name' property: |
|
195 // 1. Byte array |
|
196 // 2. Pre-allocate 100 bytes. |
|
197 // 3. Allow all processes to retrieve (read) the property. |
|
198 // 4. Only processes with power managament capability can write. |
|
199 // 5. Capability checks to be done against client thread's process. |
|
200 |
|
201 r=name.Define(RProperty::EByteArray,KAllowAllPolicy,KPowerMgmtPolicy,100,iClientProcess); |
|
202 |
|
203 // You will probably need to check the return value. |
|
204 // It may legitimately be non-KErrNone. |
|
205 ...</codeblock> <p>Once defined, a property value can change, but the property |
|
206 type cannot. Byte-array type properties can also change length provided the |
|
207 length does not exceed the 512 bytes, for <xref href="GUID-C4776034-D190-3FC4-AF45-C7F195093AC3.dita#GUID-C4776034-D190-3FC4-AF45-C7F195093AC3/GUID-19066DA4-B407-3C31-8472-371CA341BDC7"><apiname>RProperty::EByteArray</apiname></xref> types |
|
208 or 65535 bytes or <xref href="GUID-C4776034-D190-3FC4-AF45-C7F195093AC3.dita#GUID-C4776034-D190-3FC4-AF45-C7F195093AC3/GUID-F8DE443B-B208-353C-A98E-AA52C4FE6530"><apiname>RProperty::ELargeByteArray</apiname></xref> types. </p> <p>The |
|
209 API allows byte-array type properties to be pre-allocated when they are defined. |
|
210 This means that the time taken to set the values is bounded. However, if the |
|
211 length of these property types subsequently increases, then memory allocation |
|
212 may take place, and no guarantees can then be made on the time taken to set |
|
213 them. </p> <p> <b>Security notes:</b> </p> <ul> |
|
214 <li id="GUID-E46B65DD-5D93-5796-8762-D8637947350D"><p>Symbian platform defines |
|
215 a property category known as the system category that is reserved for system |
|
216 services, and is identified by the <xref href="GUID-A85740BD-BC85-345E-B24A-92F68EA56270.dita"><apiname>KUidSystemCategoryValue</apiname></xref> UID. |
|
217 To define a property within this category, then the process on whose behalf |
|
218 your code is doing the define operation must have the <i>writeDeviceData</i> capability, <xref href="GUID-C607209F-6FC5-31DE-8034-E5B799B857A8.dita"><apiname>ECapabilityWriteDeviceData</apiname></xref>. </p> <p>To |
|
219 ensure that this security check is made, you must pass a pointer to the appropriate <codeph>DProcess</codeph> object |
|
220 as the second parameter to <codeph>Define()</codeph>. If you omit this parameter, |
|
221 a null pointer is assumed by default, and <i>the security check is bypassed</i>. |
|
222 This may be legitimate if you are doing this on behalf of the kernel or on |
|
223 behalf of the driver itself. </p> </li> |
|
224 <li id="GUID-18AA5E54-23AE-564F-BCB0-0F9FF70DEFD5"><p>Whether you pass a <codeph>DProcess</codeph> pointer |
|
225 or not, the owner of the property is deemed to be the process that is <i>current</i> when |
|
226 the code runs. It is this, the current process, that you will need to pass |
|
227 to <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita#GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2/GUID-73FB49F1-E9EF-3CE3-A317-8888BAE49403"><apiname>RPropertyRef::Delete()</apiname></xref> at a later time. </p> </li> |
|
228 <li id="GUID-A941BD4F-E288-5A71-9F78-08351665AE73"><p>You also need to define |
|
229 two security policies: one to define the capabilities that will be required |
|
230 to publish (write to) the property, and the other to define the capabilities |
|
231 that will be required to retrieve (read) the property. Security policies are <xref href="GUID-81A285F6-3F87-3E77-9426-61BB16BC7109.dita"><apiname>TSecurityPolicy</apiname></xref> objects |
|
232 or their static equivalents. </p> <p>In the above code fragment, we specify |
|
233 that all processes in the system will be able to read the defined property |
|
234 but only those with power management capability will be able to write to the |
|
235 property - this is an arbitrary choice and is for illustration only. </p> </li> |
|
236 </ul> <p>In the above code fragments, <codeph>iClientProcess</codeph> is a |
|
237 pointer to the client thread's owning process object, and assumes that the |
|
238 driver code is making the request on behalf of a client, although this may |
|
239 not necessarily be so. Typically, if you need to keep this information, you |
|
240 could set this up in the logical channel constructor using the following code: </p> <codeblock id="GUID-33D0D5EA-8BB2-57DB-A327-D17A6A5C2D8E" xml:space="preserve">iClientProcess=&Kern::CurrentProcess();</codeblock> <p>The |
|
241 constructor code runs in the context of the client user thread. Note that <codeph>DProcess</codeph> is |
|
242 internal to Symbian. </p> </section> |
|
243 <section id="GUID-60F19D41-F9B5-5A21-9654-5D96CA6EE83E"><title>Deleting a |
|
244 property </title> <p>Deleting a property is the opposite of defining it. It |
|
245 removes type and security information. It does <i>not</i> remove a reference |
|
246 to the property. </p> <p>A property is deleted using the <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita#GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2/GUID-73FB49F1-E9EF-3CE3-A317-8888BAE49403"><apiname>RPropertyRef::Delete()</apiname></xref> function. |
|
247 You can call this function from a user thread running in supervisor mode, |
|
248 from a kernel thread or from a DFC. If calling from a user thread running |
|
249 in supervisor mode, then your thread must be running in a critical section. |
|
250 In debug mode, if a user thread is not in a critical section, then the kernel |
|
251 will fault. </p> <p>Any outstanding subscriptions for this property complete |
|
252 with <xref href="GUID-5E653C17-372C-32E1-A1B2-9E69A9991C40.dita"><apiname>KErrNotFound</apiname></xref>. </p> <p> <b>Security notes:</b> </p> <ul> |
|
253 <li id="GUID-1B901363-70E9-560B-9C56-C63BB6D180C0"><p>Only the owning process |
|
254 is allowed to delete the property. This is deemed to be the process that was |
|
255 current when the property was defined. However, to enforce this, you <i>must</i> pass |
|
256 into <xref href="GUID-331FCC3D-B326-37A1-8AF5-381320224BBE.dita#GUID-331FCC3D-B326-37A1-8AF5-381320224BBE/GUID-2838E746-C917-3FB0-B2BA-464C38B5944B"><apiname>RPropertyref::Delete()</apiname></xref> a pointer to the <codeph>DProcess</codeph> object |
|
257 that represents the owning process. If you omit to pass this parameter to <codeph>Delete()</codeph>, |
|
258 a null pointer is assumed by default, and <i>the security check is bypassed.</i>. |
|
259 This may be legitimate if you are doing this on behalf of the kernel or on |
|
260 behalf of the driver itself. </p> </li> |
|
261 </ul> <p>For example, extending the code fragment introduced in defining a |
|
262 property above: </p> <codeblock id="GUID-25FBD12A-4461-5A92-9961-960DB26FE3F8" xml:space="preserve">const TUid KMyPropertyCat={0x10012345}; |
|
263 enum TMyPropertyKeys={EMyPropertyCounter,EMyPropertyName}; |
|
264 |
|
265 static _LIT_SECURITY_POLICY_PASS(KAllowAllPolicy); |
|
266 static _LIT_SECURITY_POLICY_C1(KPowerMgmtPolicy,ECapabilityPowerMgmt); |
|
267 |
|
268 TInt r; |
|
269 |
|
270 // Attaches to the ‘counter’ property. |
|
271 // If the property already exists, a new reference to it is created. |
|
272 // If the property does not exist, it is created. |
|
273 RPropertyRef counter; |
|
274 r=counter.Attach(KMyPropertyCat,EMyPropertyCounter); |
|
275 if (r != KErrNone) |
|
276 { |
|
277 // Handle the bad return value |
|
278 } |
|
279 |
|
280 // Attaches to the ‘name’ property. |
|
281 // If the property already exists, a new reference to it is created. |
|
282 // If the property does not exist, it is created. |
|
283 RPropertyRef name; |
|
284 r=name.Attach(KMyPropertyCat,EMyPropertyName); |
|
285 if (r != KErrNone) |
|
286 { |
|
287 // Handle the bad return value |
|
288 } |
|
289 |
|
290 // Now define the 'counter' property: |
|
291 // 1. Integer type |
|
292 // 2. Pre-allocated size has no meaning, and must be zero. |
|
293 // 3. Allow all processes to retrieve (read) the property. |
|
294 // 4. Only processes with power managament capability can write. |
|
295 // 5. Capability checks to be done against client thread's process. |
|
296 |
|
297 r=counter.Define(RProperty::EInt,KAllowAllPolicy,KPowerMgmtPolicy,0,iClientProcess); |
|
298 |
|
299 // You will probably need to check the return value. |
|
300 // It may legitimately by non-KErrNone. |
|
301 |
|
302 ... |
|
303 |
|
304 // Now define the 'name' property: |
|
305 // 1. Byte array |
|
306 // 2. Pre-allocate 100 bytes. |
|
307 // 3. Allow all processes to retrieve (read) the property. |
|
308 // 4. Only processes with power managament capability can write. |
|
309 // 5. Capability checks to be done against client thread's process. |
|
310 |
|
311 r=name.Define(RProperty::EByteArray,KAllowAllPolicy,KPowerMgmtPolicy,100,iClientProcess); |
|
312 |
|
313 // You will probably need to check the return value. |
|
314 // It may legitimately by non-KErrNone. |
|
315 |
|
316 ... |
|
317 |
|
318 // Delete the ‘name’ property. |
|
319 // Assumes that the owning process is iClientProcess. This will be checked |
|
320 // as being the valid owner of the property. |
|
321 r=name.Delete(iClientProcess); |
|
322 if (r != KErrNone) |
|
323 { |
|
324 // deal with a non-KErrNone return value. |
|
325 } |
|
326 |
|
327 // Delete the ‘counter’ property. |
|
328 // Assumes that the owning process is iClientProcess. This will be checked |
|
329 // as being the valid owner of the property. |
|
330 r=name.Delete(iClientProcess); |
|
331 if (r != KErrNone) |
|
332 { |
|
333 // deal with a non-KErrNone return value. |
|
334 }</codeblock> </section> |
|
335 <section id="GUID-EBAA6B5C-CC73-5AE2-85CA-68B445828608"><title>Publishing |
|
336 a property value </title> <p>A property is published (written), using the <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita#GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2/GUID-D4B0220A-EB30-327C-B878-FBC5294A08F6"><apiname>RPropertyRef::Set()</apiname></xref> family |
|
337 of functions. </p> <p>This is guaranteed to have bounded execution time, suitable |
|
338 for high-priority, real-time tasks, except when publishing a byte-array property |
|
339 that requires the allocation of a larger space for the new value, or when |
|
340 publishing a large byte-array property type, as identified by <xref href="GUID-0B4D1D87-8C1B-3AEF-9C3D-3091FBDF3A6B.dita"><apiname>ELargeByteArray</apiname></xref>. </p> <p>Property |
|
341 values are written atomically. This means that it is not possible for threads |
|
342 reading a property to get a garbled value. </p> <p>All outstanding subscriptions |
|
343 for a property are completed when the value is published, even if it is exactly |
|
344 the same as the existing value. This means that a property can be used as |
|
345 a simple broadcast notification service. </p> <p>Publishing a property that |
|
346 is not defined is not necessarily a programming error. The <codeph>Set()</codeph> functions |
|
347 just return an error. If this is not expected for any particular usage, then |
|
348 the error must be checked and processed by the caller. </p> <p> <b>Security |
|
349 notes:</b> </p> <ul> |
|
350 <li id="GUID-DA84723A-B9F7-525C-908A-BC51AA8B0366"><p>If you pass a pointer |
|
351 to a <codeph>DProcess</codeph> object, then the capabilities of that process |
|
352 will be checked against those contained in the write security policy that |
|
353 was created and passed to <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita#GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2/GUID-47F367CB-E663-3F97-AC0C-31A9DD6BD5E5"><apiname>RPropertyRef::Define()</apiname></xref>. If you |
|
354 omit this <codeph>DProcess</codeph> parameter, a null pointer is assumed by |
|
355 default, and <i>the security check is bypassed</i>. This may be legitimate |
|
356 if you are doing this on behalf of the kernel or on behalf of the driver itself. </p> </li> |
|
357 </ul> <p>See the code fragment in the section <xref href="GUID-EBFD653D-6E6A-5F6F-88D7-8CCE07B4002D.dita#GUID-EBFD653D-6E6A-5F6F-88D7-8CCE07B4002D/GUID-CA858A2A-4BF0-565D-8A6D-58AE32FEE304">Retrieving |
|
358 a property value</xref> </p> </section> |
|
359 <section id="GUID-CA858A2A-4BF0-565D-8A6D-58AE32FEE304"><title>Retrieving |
|
360 a property value </title> <p>The current value of a property is retrieved |
|
361 (read) using the <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita#GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2/GUID-745E29E7-A26B-3207-ACA3-F8CC41FC7081"><apiname>RPropertyRef::Get()</apiname></xref> family of functions. </p> <p>This |
|
362 is guaranteed to have bounded execution time, suitable for high-priority, |
|
363 real-time tasks, except when retrieving a large byte-array property type, |
|
364 as identified by <xref href="GUID-0B4D1D87-8C1B-3AEF-9C3D-3091FBDF3A6B.dita"><apiname>ELargeByteArray</apiname></xref>. </p> <p>Property values |
|
365 are read atomically. This means that it is not possible for threads reading |
|
366 a property to get a garbled value. </p> <p>Retrieving a property that is not |
|
367 defined is not necessarily a programming error. The <codeph>Get()</codeph> functions |
|
368 just return an error. If this is not expected for any particular usage, then |
|
369 the error must be checked and processed by the caller. </p> <p>Integer properties |
|
370 must be accessed using the overload that takes an integer reference, whereas |
|
371 a byte-array property is accessed using the overload that takes a descriptor |
|
372 reference. </p> <p>The following code fragment shows publication and retrieval |
|
373 of a property. Note that it contains a race condition, especially if another |
|
374 thread is executing the same sequence to increment the ‘counter’ value. </p> <p> <b>Security |
|
375 notes:</b> </p> <ul> |
|
376 <li id="GUID-B117308F-416E-5BAE-880C-A162869799AD"><p>If you pass a pointer |
|
377 to a <codeph>DProcess</codeph> object, then the capabilities of that process |
|
378 will be checked against those contained in the read security policy that was |
|
379 created and passed to <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita#GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2/GUID-47F367CB-E663-3F97-AC0C-31A9DD6BD5E5"><apiname>RPropertyRef::Define()</apiname></xref>. If you omit |
|
380 this <codeph>DProcess</codeph> parameter, a null pointer is assumed by default, |
|
381 and <i>the security check is bypassed</i>. This may be legitimate if you are |
|
382 doing this on behalf of the kernel or on behalf of the driver itself. </p> </li> |
|
383 </ul> <codeblock id="GUID-75549D12-A2CA-5039-BB91-2ABF19058DE5" xml:space="preserve">const TUid KMyPropertyCat={0x10012345}; |
|
384 enum TMyPropertyKeys={EMyPropertyCounter,EMyPropertyName}; |
|
385 |
|
386 TInt r; |
|
387 |
|
388 RPropertyRef counter; |
|
389 RPropertyRef name; |
|
390 |
|
391 |
|
392 // Assume that the 'name' and 'counter' property references have |
|
393 // already been created. They may have been defined. |
|
394 // |
|
395 // Assume that the process to be used for security checking is iClientProcess. |
|
396 |
|
397 ... |
|
398 |
|
399 // publish a new name value. |
|
400 _LIT8(KSomeExampleName,"My example name"); |
|
401 r=name.Set(KSomeExampleName, iClientProcess); |
|
402 if (r != KErrNone) |
|
403 { |
|
404 // Check the return value. KErrNotFound means that the property has not yet been |
|
405 // defined which may be legitimate. |
|
406 // KErrArgument is a serious problem at this stage. |
|
407 // KErrPermissionDenied is a security violation; the process iClientProcess has |
|
408 // insufficient capability to do this operation. |
|
409 } |
|
410 |
|
411 |
|
412 // Retrieve the first 10 characters of the name value. |
|
413 // We are not doing any security checking for this operation, so no DProcess pointer |
|
414 // is passed to Get(). |
|
415 TBuf<10> n; |
|
416 r=name.Get(n); |
|
417 |
|
418 if ((r!= KErrNone) && (r != KErrOverflow)) |
|
419 { |
|
420 // Handle error value. |
|
421 } |
|
422 |
|
423 // retrieve and publish a new value using the attached ‘counter’ property |
|
424 TInt count; |
|
425 r=counter.Get(count); |
|
426 if (r==KErrNone) |
|
427 { |
|
428 r=counter.Set(++count); |
|
429 } |
|
430 else |
|
431 { |
|
432 // Handle bad return value |
|
433 } |
|
434 ... |
|
435 |
|
436 // When finised, release the property references. |
|
437 counter.Close(); |
|
438 name.Close();</codeblock> </section> |
|
439 <section id="GUID-984AB90D-FCCD-5383-B5D9-8D80AA83D989"><title>Subscribing |
|
440 to, and unsubscribing from, a property </title> <p>Subscribing to a property |
|
441 is the act of making an asynchronous request to be notified of a change to |
|
442 that property. </p> <p>You make a request for notification of a change to |
|
443 a property by calling the <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita#GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2/GUID-6DC06192-78AF-3B3D-8077-8479789AF006"><apiname>RPropertyRef::Subscribe()</apiname></xref> member |
|
444 function on a property reference object. Only one subscription request can |
|
445 be outstanding at any time for a given <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita"><apiname>RPropertyRef</apiname></xref> instance. </p> <p>You |
|
446 can cancel an outstanding subscription request by calling <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita#GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2/GUID-4AFB3074-E523-3404-8F0D-39995C35E045"><apiname>RPropertyRef::Cancel()</apiname></xref>. |
|
447 This is unsubscribing from the property. </p> <p>Subscribing to a property |
|
448 is a single request to be notified when the property is next updated, it does |
|
449 not generate an ongoing sequence of notifications for every change to that |
|
450 property's value. Neither does it provide the caller with the new value. In |
|
451 essence, the act of notification should be interpreted as “Property X has |
|
452 changed” rather than “Property X has changed to Y”. This means that the new |
|
453 value must be explicitly retrieved, if required. As a result, multiple updates |
|
454 may be collapsed into one notification, and subscribers may not have visibility |
|
455 of all intermediate values. </p> <p>This might appear to introduce a window |
|
456 of opportunity for a subscriber to be out of synchronisation with the property |
|
457 value – in particular, if the property is updated again before the subscriber |
|
458 thread has had the chance to process the original notification. However, a |
|
459 simple programming pattern, outlined in the second example below ensures this |
|
460 does not happen. The principle is that, before dealing with a subscription |
|
461 completion event, you should re-issue the subscription request. </p> <p>Note |
|
462 that if the property has not been defined, then a subscription request does |
|
463 not complete until the property is subsequently defined and published. Note |
|
464 that the request will complete with <xref href="GUID-213DE05E-24F7-3E94-9B35-F4A72B3EBFD8.dita"><apiname>KErrPermissionDenied</apiname></xref> if |
|
465 the subscribing process does not have sufficient capability as defined by |
|
466 the <xref href="GUID-81A285F6-3F87-3E77-9426-61BB16BC7109.dita"><apiname>TSecurityPolicy</apiname></xref> object supplied by the process defining |
|
467 the property. </p> <p>If the property is already defined, then the request |
|
468 completes immediately with <xref href="GUID-213DE05E-24F7-3E94-9B35-F4A72B3EBFD8.dita"><apiname>KErrPermissionDenied</apiname></xref> if the |
|
469 subscribing process does not have sufficient capability. </p> <p>The essence |
|
470 of subscribing to a property is that you pass a function into <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita#GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2/GUID-6DC06192-78AF-3B3D-8077-8479789AF006"><apiname>RPropertyRef::Subscribe()</apiname></xref> and |
|
471 that this function is called when the property value is published. You pass |
|
472 the function by wrapping it in <xref href="GUID-8A0F75CD-DC61-37EA-A23A-3A82080F0751.dita"><apiname>TPropertySubsRequest</apiname></xref> object |
|
473 and then pass this into <codeph>Subscribe()</codeph>. What the function does |
|
474 depends on the implementation, but you may want to re-subscribe to the property |
|
475 and then retrieve the property value, or you may want to set some flag. It |
|
476 all depends on the intent of the property and the driver code. </p> <p>The |
|
477 following code fragments show the general idea. </p> <codeblock id="GUID-DF8201DF-7812-5B39-8B0F-3CB664BA00FA" xml:space="preserve">const TUid KMyPropertyCat={0x10012345}; |
|
478 enum TMyPropertyKeys={EMyPropertyCounter,EMyPropertyName};</codeblock> <codeblock id="GUID-2162EE7C-B834-50ED-9C84-3CE004C0B7D6" xml:space="preserve">class DMyLogicalChannel : public DLogicalChannel |
|
479 { |
|
480 public : |
|
481 DMyLogicalChannel(); |
|
482 void OpenReference(); |
|
483 void SetUpSubscription(); |
|
484 ... |
|
485 private : |
|
486 static void HandleSubsComplete(TAny* aPtr, TInt aReason); |
|
487 ... |
|
488 private: |
|
489 RCounterRef iName; |
|
490 TBuf<10> iNameValue; |
|
491 DProcess iClientProcess; |
|
492 TPropertySubsRequest iSubsRequest; |
|
493 TInt iReason; |
|
494 }</codeblock> <codeblock id="GUID-4A655D83-07CD-5998-A540-16D4A5EABFC5" xml:space="preserve">DMyLogicalChannel::DMyLogicalChannel() : iSubsRequest(&HandleSubsComplete, this) |
|
495 { |
|
496 iClientProcess = &Kern::CurrentProcess(); |
|
497 // Other code omitted |
|
498 }</codeblock> <codeblock id="GUID-DB6F4AF7-8866-50C5-95FD-5BCA1F2B55CE" xml:space="preserve">void DMyLogicalChannel::OpenReference() |
|
499 { |
|
500 // Open a reference to the ‘name’ property, and assume that |
|
501 // the property has already been created and defined. |
|
502 |
|
503 TInt r |
|
504 ... |
|
505 r=iName.Open(KMyPropertyCat,EMyPropertyName); |
|
506 if (r != KErrNone) |
|
507 { |
|
508 // Handle bad return value. |
|
509 } |
|
510 ... |
|
511 }</codeblock> <codeblock id="GUID-217CFAF4-2CA6-588B-B3A2-667EB9A04FCA" xml:space="preserve">void DMyLogicalChannel::SetUpSubscription() |
|
512 { |
|
513 // Now ask to be notified when the 'name' property is updated. |
|
514 // This will eventually result in a call to the function HandleSubsComplete() |
|
515 // at some later time (asynchronously). |
|
516 // When eventually called, the pointer to this DMyLogicalChannel object will |
|
517 // be passed to HandleSubsComplete(). |
|
518 // |
|
519 ... |
|
520 iReason = KRequestPending; |
|
521 TInt r = iName.Subscribe(iSubsRequest); // ignoring security issues here. |
|
522 if (r != KErrNone) |
|
523 { |
|
524 // handle bad return code. |
|
525 } |
|
526 return; |
|
527 }</codeblock> <codeblock id="GUID-C2CD229F-F6CE-5EE3-9EBA-A69CED50FA07" xml:space="preserve">void DMyLogicalChannel::CancelSubscription() |
|
528 { |
|
529 if (iReason == KRequestPending) |
|
530 { |
|
531 iName.Cancel(iSubsRequest); |
|
532 } |
|
533 }</codeblock> <codeblock id="GUID-D5E046B5-4D56-5B82-B4B8-D943DC601338" xml:space="preserve">void DMyLogicaChannel::SubsCompleteFn(TAny* aPtr, TInt aReason) |
|
534 { |
|
535 // A static function called when a change to the property occurs. |
|
536 // aPtr will point to the DMyLogicalChannel object |
|
537 // (see the DMyLogicalChannel constructor) |
|
538 // aReason is the reason for the subscription completing. This may be: |
|
539 // KErrNone - for a normal completion. |
|
540 // KErrPermissionDenied - if the security check has failed. |
|
541 // KErrCancel - if the request was cancelled. |
|
542 // For a normal completion, setup another notification request before |
|
543 // getting the current value of the property. |
|
544 // |
|
545 DMyLogicaChannel* self = (DMyLogicaChannel*) aPtr; |
|
546 self->iReason = aReason; |
|
547 if (iReason == KErrNone) |
|
548 { |
|
549 self->SetUpSubscription(); |
|
550 self->Get(iNameValue,iClientProcess); |
|
551 return; |
|
552 } |
|
553 // Investigate the non-zero reason code. |
|
554 }</codeblock> </section> |
|
555 <section id="GUID-21D8ADCA-9B39-5079-B4AD-FEBFCCB92049"><title>Usage patterns</title> <p>There |
|
556 are three usage patterns that can easily be identified, labelled as: standard |
|
557 state, pure event distribution, and speculative publishing. </p> <p id="GUID-98103A8A-10E1-58FE-9613-A616E142AA2A"><b>Standard state</b> </p> <p>This |
|
558 pattern is used for events and state that are known to be used widely in the |
|
559 system. Examples of this might be battery level and signal strength, which |
|
560 are important in every phone. </p> <p>The publisher calls <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita#GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2/GUID-47F367CB-E663-3F97-AC0C-31A9DD6BD5E5"><apiname>RPropertyRef::Define()</apiname></xref> to |
|
561 create the appropriate property. For byte array or text properties, a size |
|
562 sufficient for all possible values should be reserved. An error of <xref href="GUID-D1D25122-F2B8-3C78-8599-84905BFD47B8.dita"><apiname>KErrAlreadyExists</apiname></xref> should |
|
563 be ignored. The publisher then publishes the property values as, and when, |
|
564 appropriate. If the <codeph>RPropertyRef::Set()</codeph> call fails, this |
|
565 should be treated as a serious error, since it indicates that important system |
|
566 state is not getting through. Appropriate action might include panicking or |
|
567 rebooting the system. Subscribers will use <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita#GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2/GUID-6DC06192-78AF-3B3D-8077-8479789AF006"><apiname>RPropertyRef::Subscribe()</apiname></xref> to |
|
568 request notification, and <codeph>RPropertyRef::Get()</codeph> to retrieve |
|
569 the property value on notification. </p> <p>The memory to store the property |
|
570 value will be permanently allocated, even if it turns out that no-one in the |
|
571 system needs that value. This does ensure that the value can always be published, |
|
572 even if the system is in an out of memory situation. For this reason, this |
|
573 approach should be limited to widely used and important state. The <xref href="GUID-EBFD653D-6E6A-5F6F-88D7-8CCE07B4002D.dita#GUID-EBFD653D-6E6A-5F6F-88D7-8CCE07B4002D/GUID-8D9E6222-DDBA-55CA-A96F-1DCBD99E3FD3">Speculative publishing</xref> pattern offers an approach for dealing with |
|
574 less important state. </p> <p id="GUID-5C82A92C-168D-5CD2-BE43-EE79AB500B14"><b>Pure event distribution</b> </p> <p>This |
|
575 pattern is used when events need to be distributed, not values. </p> <p>The |
|
576 publisher of the event simply uses an integer property, and calls <codeph>RPropertyRef::Set()</codeph> with |
|
577 any value. Even if the value of the property is not changed by this operation, |
|
578 all subscribers will be notified that a <codeph>Set()</codeph> has occurred, |
|
579 and by implication that the related event has occurred. </p> <p>Subscribers |
|
580 will be able to detect that an event has occurred, but will get no other information. |
|
581 The minimum possible memory is wasted on storage for the dummy value. </p> <p id="GUID-8D9E6222-DDBA-55CA-A96F-1DCBD99E3FD3"><b>Speculative publishing</b> </p> <p>This |
|
582 pattern is used when it is not known whether a value will be of interest to |
|
583 others or not. Unlike the <xref href="GUID-EBFD653D-6E6A-5F6F-88D7-8CCE07B4002D.dita#GUID-EBFD653D-6E6A-5F6F-88D7-8CCE07B4002D/GUID-98103A8A-10E1-58FE-9613-A616E142AA2A">standard |
|
584 state</xref> pattern, the publisher of the event does not call <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita#GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2/GUID-47F367CB-E663-3F97-AC0C-31A9DD6BD5E5"><apiname>RPropertyRef::Define()</apiname></xref> to |
|
585 create the property. Instead, it simply calls <codeph>RPropertyRef::Set()</codeph> as |
|
586 appropriate, and ignores any <xref href="GUID-5E653C17-372C-32E1-A1B2-9E69A9991C40.dita"><apiname>KErrNotFound</apiname></xref> error. </p> <p>When |
|
587 other code in the system, i.e. a potential subscriber, is interested in the |
|
588 state, it calls <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita#GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2/GUID-47F367CB-E663-3F97-AC0C-31A9DD6BD5E5"><apiname>RPropertyRef::Define()</apiname></xref> to create the property |
|
589 and allocate the memory for the value. An error of <xref href="GUID-D1D25122-F2B8-3C78-8599-84905BFD47B8.dita"><apiname>KErrAlreadyExists</apiname></xref> should |
|
590 be ignored, as this only indicates that some other code in the system is also |
|
591 interested in the value and has already created the property. </p> <p>The |
|
592 subscriber then calls <xref href="GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2.dita#GUID-39D6B924-3FA3-39E6-A6EA-88E2D1927AC2/GUID-6DC06192-78AF-3B3D-8077-8479789AF006"><apiname>RPropertyRef::Subscribe()</apiname></xref> and <codeph>RPropertyRef::Get()</codeph> as |
|
593 usual to interact with the property. On the first <codeph>Get()</codeph>, |
|
594 the subscriber may retrieve the property default value (zero, or a zero length |
|
595 descriptor). This must be substituted with a sensible default value for the |
|
596 property in question. </p> <p>Using this pattern, no memory is wasted on properties |
|
597 that have no subscribers, while the publisher code is simpler as there is |
|
598 no need for configuration as to which properties to publish. </p> <p>The publisher, |
|
599 however, wastes some time attempting to publish unneeded values, but this |
|
600 should not be an issue unless the value is very frequently updated. </p> <p>Where |
|
601 events are published very infrequently, the subscriber could have a dummy |
|
602 value for a long time, until the next publish event updates the value. Often |
|
603 this is not a problem as a default value can be substituted. For example a |
|
604 full/empty indicator for a battery level, none for signal strength etc. This |
|
605 pattern is unlikely to be useful if there is no suitable default value. </p> </section> |
|
606 </conbody></concept> |