OLD | NEW |
| (Empty) |
1 # C bindings guide | |
2 | |
3 The Mojo C bindings are a way to talk the Mojom protocol, the canonical protocol | |
4 for communication between Mojo programs. The library under `bindings/` provides | |
5 functionality for encoding, decoding and other computation, so it needs to be | |
6 linked together with C code generated from .mojom files. These C bindings are | |
7 lower-level than the C++ bindings (or any other language, for that matter), | |
8 are more error-prone, and require some knowledge of the C Mojo API and the | |
9 mojom encoding format. This document assumes the reader knows about (or knows | |
10 how to look up) this relevant information. Consequently, C bindings can also | |
11 be faster; generated bindings are smaller than the C++ equivalent, while | |
12 encoding and decoding is faster. The intention is to use them only when you | |
13 require speed and flexibility. | |
14 | |
15 ## Structs | |
16 | |
17 Let's look at what the generated code looks like for the following struct: | |
18 | |
19 ``` mojom | |
20 module example; | |
21 | |
22 enum Gender { MALE, FEMALE }; | |
23 struct Person { | |
24 uint32 age; | |
25 string name; | |
26 Gender gender; | |
27 }; | |
28 ``` | |
29 | |
30 A small snippet of the generated C code for the struct and enum: | |
31 | |
32 ```C | |
33 // Generated code for mojom enum 'example.Gender'. | |
34 typedef uint32_t example_Gender; | |
35 enum example_Gender_Enum { | |
36 examples_Gender_MALE = 0, | |
37 examples_Gender_MALE = 1, | |
38 }; | |
39 | |
40 // Generated code for mojom struct 'example.Person'. | |
41 union example_PersonPtr { | |
42 struct example_Person* ptr; | |
43 uint64_t offset; | |
44 }; | |
45 struct example_Person { | |
46 struct MojomStructHeader header_; | |
47 uint32_t age; | |
48 example_Gender gender; | |
49 union MojomStringHeaderPtr name; | |
50 }; | |
51 ``` | |
52 | |
53 The mojom wire format of a struct is comparable to the C memory model of a | |
54 struct, with some restrictions; in the example above, we see that the order of | |
55 the fields is different between the mojom and C structs, since the generated C | |
56 structs are in packing order, not ordinal order. Although not applicable in this | |
57 example, there may be additional fields inserted in the generated C struct for | |
58 padding purposes -- since 4-byte data types need to be 4-byte aligned, the | |
59 generated C bindings may include some fields not explicitly present in the | |
60 mojom. Since it's not immediately obvious where padding fields could be | |
61 inserted, it helps to examine the generated C struct to make sure what the | |
62 fields are, and if possible, set them using field initializers. The | |
63 `example_PersonPtr` union is used to represent an offset in the encoded form, or | |
64 a pointer in the unencoded form. | |
65 | |
66 Since mojom objects appear in depth-first order relative to their parent object, | |
67 we can use a `struct MojomBuffer` and calls to `MojomBuffer_Allocate(..)` to | |
68 linearly allocate space. The struct needs to be constructed and provided by the | |
69 user, and it contains 3 fields: A pointer to the buffer, size of the buffer in | |
70 bytes, and the byte-position of the next allocation, typically set to 0. | |
71 | |
72 For instance, to allocate space for the `name` parameter of an `example_Person`, | |
73 we can do so this way: | |
74 ```C | |
75 char byte_buffer[512] = {0}; | |
76 struct MojomBuffer buf = {byte_buffer, sizeof(byte_buffer), 0}; | |
77 | |
78 // First allocate space for the example_Person struct: | |
79 struct example_Person* person = | |
80 (struct example_Person*)MojomBuffer_Allocate(&buf, sizeof(struct example_Pers
on)); | |
81 | |
82 // Allocate enough space for a 10 character string. | |
83 person->name.ptr = (struct MojomStringHeader*)MojomBuffer_Allocate( | |
84 &buf, | |
85 sizeof(struct MojomStringHeader) + 10); | |
86 ``` | |
87 | |
88 We can extract how much buffer space was used by reading `buf.num_byes_used`. | |
89 | |
90 Along with the C struct, there are some functions generated that help encode and | |
91 decode mojom structs, amongst other things. For the `example.Person` mojom | |
92 struct, the following functions are generated: | |
93 | |
94 ```c | |
95 struct example_Person* example_Person_DeepCopy( | |
96 struct MojomBuffer* in_buffer, | |
97 struct example_Person* in_data); | |
98 | |
99 void example_Person_EncodePointersAndHandles( | |
100 struct example_Person* inout_struct, uint32_t in_struct_size, | |
101 struct MojomHandleBuffer* inout_handle_buffer); | |
102 | |
103 void example_Person_DecodePointersAndHandles( | |
104 struct example_Person* inout_struct, uint32_t in_struct_size, | |
105 MojomHandle inout_handles[], uin32_t in_num_handles); | |
106 | |
107 MojomValidationResult example_Person_Validate( | |
108 const struct example_Person* in_struct, uint32_t in_struct_size, | |
109 uint32_t in_num_handles); | |
110 ``` | |
111 | |
112 The generated `example_Person_DeepCopy(..)` function is used to copy over the | |
113 `in_data` into another buffer, specified by `MojomBuffer`. The primary purpose | |
114 of this function is "linearize" a given `struct example_Person` and its | |
115 referenced objects into the new buffer. This essentially recursively copies all | |
116 objects in encoding order. The returned copy can then be encoded. | |
117 | |
118 Example usage copying a struct example_Person `person`: | |
119 ```c | |
120 ... | |
121 char byte_buffer[512] = {0}; | |
122 struct MojomBuffer buf = {byte_buffer, sizeof(byte_buffer), 0}; | |
123 struct example_Person* new_person = example_Person_DeepCopy(&buf, person); | |
124 assert(new_person != NULL); | |
125 ... | |
126 ``` | |
127 | |
128 The generated `example_Person_EncodePointersAndHandles(..)` is used to encode | |
129 a given C struct so that it's in wire-format, ready to send over a message pipe. | |
130 This encoding process involves translating pointers into relative offsets, and | |
131 extracting handles out of the struct into a separate handle array (and replacing | |
132 the handle values in the struct with references into the handle array). The | |
133 supplied `struct MojomHandleBuffer` needs to be constructed and provided by the | |
134 user and contains 3 fields: pointer to a handles array, the size of the array | |
135 (number of elements), and the starting offset into the array where handles can | |
136 be moved into (typically set to 0). | |
137 | |
138 The generated `example_Person_DecodePointersAndHandles(..)` does the inverse -- | |
139 it translates relative offsets into pointers, and moves handles out of the | |
140 handle array and into the struct (based on the encoded offset into the array). | |
141 In practice, before decoding a mojom struct into a usable C struct, it should be | |
142 first validated; this function may crash on invalid encoded data. | |
143 | |
144 The generated `example_Person_Validate(..)` validates an encoded `struct | |
145 example_Person`. The function returns `MOJOM_VALIDATION_ERROR_NONE` if the | |
146 struct is valid, in which case the struct can be decoded. See | |
147 `bindings/validation.h` for more error codes. | |
148 | |
149 ## Interfaces | |
150 | |
151 It isn't enough to talk to other mojo applications by encoding structs and | |
152 referenced objects alone; communication happens via interface message calls | |
153 (i.e., sending mojom messages), so we need to frame our structs this way. The | |
154 following example describes what's generated for interfaces. Consider an | |
155 interface `Population` with a message `GetPerson()` that returns a `Person` | |
156 object given their name: | |
157 | |
158 ```mojom | |
159 module example; | |
160 | |
161 [ServiceName="example.EmployeeRegistry"] | |
162 interface EmployeeRegistry { | |
163 GetPerson(string name) => (Person person); | |
164 }; | |
165 ``` | |
166 | |
167 The generated code: | |
168 ```C | |
169 #define example_EmployeeRegistry__ServiceName \ | |
170 ((const char*)"example::EmployeeRegistry") | |
171 #define example_EmployeeRegistry__CurrentVersion ((uint32_t)0) | |
172 | |
173 // For message GetPerson: | |
174 #define example_EmployeeRegistry_GetPerson__Ordinal ((uint32_t)0) | |
175 #define example_EmployeeRegistry_GetPerson__MinVersion ((uint32_t)0) | |
176 | |
177 // Request struct for GetPerson(): | |
178 struct example_EmployeeRegistry_GetPerson_Request { | |
179 struct MojomStructHeader header_; | |
180 struct MojomStringHeaderPtr name; | |
181 }; | |
182 | |
183 // Response struct for GetPerson(): | |
184 struct example_EmployeeRegistry_GetPerson_Response { | |
185 struct MojomStructHeader header_; | |
186 struct example_PersonPtr person; | |
187 }; | |
188 ``` | |
189 | |
190 We see that the parameters (and return value) of the `GetPerson(..)` message are | |
191 contained within mojom structs. To send a `GetPerson(..)` request, an interface | |
192 request message must be constructed. An interface request message for | |
193 `GetPerson(..)` consists of the following data in the following order: | |
194 | |
195 1. `struct MojomMessageWithRequestId`. This contains: | |
196 - the message ordinal (generated above) which represents which message it is. | |
197 - flags that say if it's a request or response. | |
198 - a request ID, since this message is expecting a response. | |
199 - (see `bindings/message.h`) | |
200 2. `struct examples_EmployeeRegistry_GetPerson_Request`. This contains the | |
201 actual parameters for GetPerson(). | |
202 | |
203 Since the request parameters are just a mojom struct, all relevant functions for | |
204 structs are also generated (see above), e.g, ` void | |
205 examples_EmployeeRegistry_GetPerson_Request_EncodePointersAndHandles()`. Once | |
206 the request struct has been encoded, the buffer containing the above two structs | |
207 can be written to a message pipe. | |
208 | |
209 On the other hand, when reading an incoming message, the message header must | |
210 first be validated using | |
211 ``` | |
212 MojomValidationResult MojomMessage_ValidateHeader(const void* in_buf, | |
213 uint32_t in_buf_size); | |
214 ``` | |
215 - If the message arrives on the client side: | |
216 1. It must be validated as a response message. | |
217 2. You must check that the message ordinal is known and expects a response | |
218 message. | |
219 - If the message arrives on the server side: | |
220 1. It must be validated as a request message, and that it's a known ordinal. | |
221 2. If the message's ordinal is known to expect a response, the request message | |
222 must be validated as expecting a response. | |
223 | |
224 If valid, it is safe to look at the `request_id` in `struct MojomMessage`, and | |
225 the `ordinal` describing the message. By checking if it's any of | |
226 `example_EmployeeRegistry_*__Ordinal`, you can further validate that it is a | |
227 request or expects a response. See `bindings/message.h` for more functions that | |
228 help validate message headers. Once the message header is fully validated, you | |
229 must also validate the request or response mojom struct following the message | |
230 header using the generated `*_Validate(..)` function. | |
231 | |
232 Note that validation is run on encoded messages and structs on the wire -- | |
233 decoding a struct without validating it first is dangerous. | |
234 | |
235 ## Enums and Constants | |
236 | |
237 Example mojom code: | |
238 ``` mojom | |
239 module example; | |
240 | |
241 enum MyEnum { Zero, One, Four = 4, Five }; | |
242 const uint64 kMyConst = 34; | |
243 ``` | |
244 | |
245 Generated C code: | |
246 ``` C | |
247 typedef uint32_t example_MyEnum; | |
248 enum example_MyEnum_Enum { | |
249 examples_MyEnum_Zero = 0, | |
250 examples_MyEnum_One = 1, | |
251 examples_MyEnum_Four = 4, | |
252 examples_MyEnum_Five = 5, | |
253 }; | |
254 | |
255 #define example_kMyConst ((uint64_t)34) | |
256 ``` | |
257 | |
258 ## Tagged Unions | |
259 | |
260 Example mojom code: | |
261 ``` mojom | |
262 module example; | |
263 | |
264 union MyUnion { | |
265 int8 f0; | |
266 string f1; | |
267 MyUnion f2; | |
268 }; | |
269 | |
270 struct StructWithUnion { | |
271 MyUnion u; | |
272 } | |
273 ``` | |
274 Generated C code: | |
275 ```C | |
276 // Generated code for the Tags enum for |MyUnion|. | |
277 typedef uint32_t example_MyUnion_Tag; | |
278 enum example_MyUnion_Tag_Enum { | |
279 example_MyUnion_Tag_f0 = 0, | |
280 example_MyUnion_Tag_f1 = 1, | |
281 example_MyUnion_Tag_f2 = 2, | |
282 example_MyUnion_Tag__UNKNOWN__ = 0xFFFFFFFF, | |
283 }; | |
284 | |
285 // Generated code for |MyUnion|. | |
286 union example_MyUnionPtr { | |
287 struct example_MyUnion* ptr; | |
288 uint64_t offset; | |
289 }; | |
290 struct example_MyUnion { | |
291 uint32_t size; | |
292 example_MyUnion_Tag tag; | |
293 union { | |
294 int8_t f_f0; | |
295 union MojomStringHeaderPtr f_f1; | |
296 union example_MyUnionPtr f_f2; | |
297 uint64_t unknown; | |
298 } data; | |
299 }; | |
300 | |
301 // Snippet of generated code for |StructWithUnion|. | |
302 struct example_StructWithUnion { | |
303 struct MojomStructHeader header_; | |
304 struct example_MyUnion u; | |
305 }; | |
306 ``` | |
307 | |
308 Note that the `MyUnion` inside the `MyUnion` is a pointer object, whereas the | |
309 `MyUnion` inside `StructWithUnion` is inlined. The only case when unions are | |
310 pointer objects are when they are inside another union, otherwise they are | |
311 inlined. Unions are initialized by setting their size and their tag. The size is | |
312 always 16 bytes if the union is not null (4 for the size field, 4 for the tag, | |
313 and 8 for the data). The tag must be set to one defined in the generated enum of | |
314 tags. The unknown tag isn't meant to be encoded over the wire, and exists as an | |
315 initial value for a union's tag, but the tag should be set to a valid tag | |
316 before being written to wire. A union whose size is 0 is considered null. Unlike | |
317 for structs, there are no functions generated for unions, since unions are never | |
318 encoded as a top-level object type on the wire. | |
319 | |
320 ## Arrays and Strings | |
321 | |
322 Arrays and strings (which are just arrays of characters) are not top-level data | |
323 types; they can only be defined within a struct, union or interface message. | |
324 Arrays inside structs are pointers to an array object. The array object's byte | |
325 layout is as follow: | |
326 1. `struct MojomArrayHeader`. This contains: | |
327 - Number of bytes in the array (this includes the header and the data | |
328 following the array header; see `2.`) | |
329 - Number of elements in the array. | |
330 - (see `bindings/array.h` for more details) | |
331 2. The contents of the array (the size of this is accounted for in the number | |
332 of bytes specified in the array header). | |
333 | |
334 Note that if the array contains pointer objects (structs, arrays, maps), the | |
335 array contains only the 8-byte pointers (or offsets in its encoded form) -- the | |
336 objects' data follow the array contents, and their size is not accounted for in | |
337 the array header. | |
338 | |
339 Example of how to allocate and initialize a new array of 5 int32s, and set each | |
340 one: | |
341 ```C | |
342 ... | |
343 struct MojomArrayHeader* int32_array = MojomArray_New(&buf, 5, sizeof(int32_t)); | |
344 *MOJOM_ARRAY_INDEX(int32_array, int32_t, 0) = 10; | |
345 *MOJOM_ARRAY_INDEX(int32_array, int32_t, 1) = 20; | |
346 *MOJOM_ARRAY_INDEX(int32_array, int32_t, 2) = 30; | |
347 *MOJOM_ARRAY_INDEX(int32_array, int32_t, 3) = 40; | |
348 *MOJOM_ARRAY_INDEX(int32_array, int32_t, 4) = 50; | |
349 ``` | |
350 | |
351 Here, `MojomArray_New(..)` allocates space for the buffer and initializes the | |
352 header, while the `MOJOM_ARRAY_INDEX(.., i)` macro returns the address of the | |
353 `i`th element. | |
354 | |
355 TODO(vardhan): Explain how to make an array of bools. | |
356 | |
357 Since a mojom string is an array of UTF-8 encoded characters, you can use | |
358 `MojomArray_New(&buf, NUM_CHARACTERS, sizeof(uint8_t))` if they are ASCII | |
359 characters. Otherwise, since UTF-8 characters may be variable-sized, you must be | |
360 careful to set the number of characters appropriately, as it may not be the same | |
361 as the number of bytes (minus the header). By convention, mojom strings are not | |
362 null-terminated. | |
363 | |
364 ## Maps | |
365 | |
366 Maps on the wire are mojom structs with two arrays; one for the keys, and one | |
367 for the values. The `i`th element in the keys array corresponds to the `i`th | |
368 element in the values array. As such, both arrays must have the same number | |
369 of elements, and neither may be null. | |
370 | |
371 # Additional Readings | |
372 * [Internals of the generated bindings](INTERNALS.md) | |
OLD | NEW |