4 # Copyright (C) 2012 The Android Open Source Project
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
10 # http://www.apache.org/licenses/LICENSE-2.0
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
20 A set of classes (models) each closely representing an XML node in the
21 metadata_definitions.xml file.
23 Node: Base class for most nodes.
24 Entry: A node corresponding to <entry> elements.
25 Clone: A node corresponding to <clone> elements.
26 MergedEntry: A node corresponding to either <entry> or <clone> elements.
27 Kind: A node corresponding to <dynamic>, <static>, <controls> elements.
28 InnerNamespace: A node corresponding to a <namespace> nested under a <kind>.
29 OuterNamespace: A node corresponding to a <namespace> with <kind> children.
30 Section: A node corresponding to a <section> element.
31 Enum: A class corresponding an <enum> element within an <entry>
32 EnumValue: A class corresponding to a <value> element within an Enum
33 Metadata: Root node that also provides tree construction functionality.
34 Tag: A node corresponding to a top level <tag> element.
35 Typedef: A node corresponding to a <typedef> element under <types>.
40 from collections import OrderedDict
44 Base class for most nodes that are part of the Metadata graph.
46 Attributes (Read-Only):
47 parent: An edge to a parent Node.
48 name: A string describing the name, usually but not always the 'name'
49 attribute of the corresponding XML node.
64 def find_all(self, pred):
66 Find all descendants that match the predicate.
69 pred: a predicate function that acts as a filter for a Node
72 A sequence of all descendants for which pred(node) is true,
73 in a pre-order visit order.
78 if self._get_children() is None:
81 for i in self._get_children():
82 for j in i.find_all(pred):
85 def find_first(self, pred):
87 Find the first descendant that matches the predicate.
90 pred: a predicate function that acts as a filter for a Node
93 The first Node from find_all(pred), or None if there were no results.
95 for i in self.find_all(pred):
100 def find_parent_first(self, pred):
102 Find the first ancestor that matches the predicate.
105 pred: A predicate function that acts as a filter for a Node
108 The first ancestor closest to the node for which pred(node) is true.
110 for i in self.find_parents(pred):
115 def find_parents(self, pred):
117 Find all ancestors that match the predicate.
120 pred: A predicate function that acts as a filter for a Node
123 A sequence of all ancestors (closest to furthest) from the node,
124 where pred(node) is true.
128 while parent is not None:
131 parent = parent.parent
133 def sort_children(self):
135 Sorts the immediate children in-place.
137 self._sort_by_name(self._children)
139 def _sort_by_name(self, what):
140 what.sort(key=lambda x: x.name)
143 return lambda x: x.name
145 # Iterate over all children nodes. None when node doesn't support children.
146 def _get_children(self):
147 return (i for i in self._children)
149 def _children_name_map_matching(self, match=lambda x: True):
151 for i in self._get_children():
157 def _dictionary_by_name(values):
164 def validate_tree(self):
166 Sanity check the tree recursively, ensuring for a node n, all children's
170 True if validation succeeds, False otherwise.
173 children = self._get_children()
177 for child in self._get_children():
178 if child.parent != self:
179 print >> sys.stderr, ("ERROR: Node '%s' doesn't match the parent" + \
180 "(expected: %s, actual %s)") \
181 %(child, self, child.parent)
184 succ = child.validate_tree() and succ
189 return "<%s name='%s'>" %(self.__class__, self.name)
191 class Metadata(Node):
193 A node corresponding to a <metadata> entry.
195 Attributes (Read-Only):
196 parent: An edge to the parent Node. This is always None for Metadata.
197 outer_namespaces: A sequence of immediate OuterNamespace children.
198 tags: A sequence of all Tag instances available in the graph.
199 types: An iterable of all Typedef instances available in the graph.
204 Initialize with no children. Use insert_* functions and then
205 construct_graph() to build up the Metadata from some source.
209 # kind => { name => entry }
210 self._entry_map = { 'static': {}, 'dynamic': {}, 'controls': {} }
211 self._entries_ordered = [] # list of ordered Entry/Clone instances
217 self._outer_namespaces = None
222 def outer_namespaces(self):
223 if self._outer_namespaces is None:
226 return (i for i in self._outer_namespaces)
230 return (i for i in self._tags)
234 return (i for i in self._types)
236 def _get_properties(self):
238 for i in self._entries:
241 for i in self._clones:
244 def insert_tag(self, tag, description=""):
246 Insert a tag into the metadata.
249 tag: A string identifier for a tag.
250 description: A string description for a tag.
253 metadata.insert_tag("BC", "Backwards Compatibility for old API")
256 Subsequent calls to insert_tag with the same tag are safe (they will
259 tag_ids = [tg.name for tg in self.tags if tg.name == tag]
261 self._tags.append(Tag(tag, self, description))
263 def insert_type(self, type_name, type_selector="typedef", **kwargs):
265 Insert a type into the metadata.
268 type_name: A type's name
269 type_selector: The selector for the type, e.g. 'typedef'
271 Args (if type_selector == 'typedef'):
272 languages: A map of 'language name' -> 'fully qualified class path'
275 metadata.insert_type('rectangle', 'typedef',
276 { 'java': 'android.graphics.Rect' })
279 Subsequent calls to insert_type with the same type name are safe (they
283 if type_selector != 'typedef':
284 raise ValueError("Unsupported type_selector given " + type_selector)
286 type_names = [tp.name for tp in self.types if tp.name == tp]
288 self._types.append(Typedef(type_name, self, kwargs.get('languages')))
290 def insert_entry(self, entry):
292 Insert an entry into the metadata.
295 entry: A key-value dictionary describing an entry. Refer to
296 Entry#__init__ for the keys required/optional.
299 Subsequent calls to insert_entry with the same entry+kind name are safe
300 (they will be ignored).
303 self._entries.append(e)
304 self._entry_map[e.kind][e.name] = e
305 self._entries_ordered.append(e)
307 def insert_clone(self, clone):
309 Insert a clone into the metadata.
312 clone: A key-value dictionary describing a clone. Refer to
313 Clone#__init__ for the keys required/optional.
316 Subsequent calls to insert_clone with the same clone+kind name are safe
317 (they will be ignored). Also the target entry need not be inserted
318 ahead of the clone entry.
320 # figure out corresponding entry later. allow clone insert, entry insert
322 c = Clone(entry, **clone)
323 self._entry_map[c.kind][c.name] = c
324 self._clones.append(c)
325 self._entries_ordered.append(c)
327 def prune_clones(self):
329 Remove all clones that don't point to an existing entry.
332 This should be called after all insert_entry/insert_clone calls have
336 for p in self._clones:
338 remove_list.append(p)
340 for p in remove_list:
342 # remove from parent's entries list
343 if p.parent is not None:
344 p.parent._entries.remove(p)
345 # remove from parents' _leafs list
346 for ancestor in p.find_parents(lambda x: not isinstance(x, Metadata)):
347 ancestor._leafs.remove(p)
349 # remove from global list
350 self._clones.remove(p)
351 self._entry_map[p.kind].pop(p.name)
352 self._entries_ordered.remove(p)
354 def is_entry_this_kind(self, entry, kind):
356 Check if input entry if of input kind
359 entry: an Entry object
360 kind: a string. Possible values are "static", "dynamic", "controls"
363 A boolean indicating whether input entry is of input kind.
365 if kind not in ("static", "dynamic", "controls"):
366 assert(False), "Unknown kind value " + kind
368 return entry.name in self._entry_map[kind]
370 # After all entries/clones are inserted,
371 # invoke this to generate the parent/child node graph all these objects
372 def construct_graph(self):
374 Generate the graph recursively, after which all Entry nodes will be
375 accessible recursively by crawling through the outer_namespaces sequence.
378 This is safe to be called multiple times at any time. It should be done at
379 least once or there will be no graph.
382 self._construct_tags()
384 self._construct_types()
386 self._construct_clones()
388 self._construct_outer_namespaces()
391 def _construct_tags(self):
392 tag_dict = self._dictionary_by_name(self.tags)
393 for p in self._get_properties():
395 for tag_id in p._tag_ids:
396 tag = tag_dict.get(tag_id)
398 if tag not in p._tags:
401 if p not in tag.entries:
402 tag._entries.append(p)
404 def _construct_types(self):
405 type_dict = self._dictionary_by_name(self.types)
406 for p in self._get_properties():
408 type_node = type_dict.get(p._type_name)
409 p._typedef = type_node
411 if p not in type_node.entries:
412 type_node._entries.append(p)
414 def _construct_clones(self):
415 for p in self._clones:
416 target_kind = p.target_kind
417 target_entry = self._entry_map[target_kind].get(p.name)
418 p._entry = target_entry
420 # should not throw if we pass validation
421 # but can happen when importing obsolete CSV entries
422 if target_entry is None:
423 print >> sys.stderr, ("WARNING: Clone entry '%s' target kind '%s'" + \
424 " has no corresponding entry") \
425 %(p.name, p.target_kind)
427 def _construct_outer_namespaces(self):
429 if self._outer_namespaces is None: #the first time this runs
430 self._outer_namespaces = []
432 root = self._dictionary_by_name(self._outer_namespaces)
433 for ons_name, ons in root.iteritems():
436 for p in self._entries_ordered:
437 ons_name = p.get_outer_namespace()
438 ons = root.get(ons_name, OuterNamespace(ons_name, self))
441 if p not in ons._leafs:
444 for ons_name, ons in root.iteritems():
448 self._construct_sections(ons)
450 if ons not in self._outer_namespaces:
451 self._outer_namespaces.append(ons)
455 def _construct_sections(self, outer_namespace):
457 sections_dict = self._dictionary_by_name(outer_namespace.sections)
458 for sec_name, sec in sections_dict.iteritems():
462 for p in outer_namespace._leafs:
463 does_exist = sections_dict.get(p.get_section())
465 sec = sections_dict.get(p.get_section(), \
466 Section(p.get_section(), outer_namespace))
467 sections_dict[p.get_section()] = sec
471 if p not in sec._leafs:
474 for sec_name, sec in sections_dict.iteritems():
476 if not sec.validate_tree():
477 print >> sys.stderr, ("ERROR: Failed to validate tree in " + \
478 "construct_sections (start), with section = '%s'")\
481 self._construct_kinds(sec)
483 if sec not in outer_namespace.sections:
484 outer_namespace._sections.append(sec)
486 if not sec.validate_tree():
487 print >> sys.stderr, ("ERROR: Failed to validate tree in " + \
488 "construct_sections (end), with section = '%s'") \
491 # 'controls', 'static' 'dynamic'. etc
492 def _construct_kinds(self, section):
493 for kind in section.kinds:
495 section.validate_tree()
497 group_entry_by_kind = itertools.groupby(section._leafs, lambda x: x.kind)
498 leaf_it = ((k, g) for k, g in group_entry_by_kind)
500 # allow multiple kinds with the same name. merge if adjacent
501 # e.g. dynamic,dynamic,static,static,dynamic -> dynamic,static,dynamic
502 # this helps maintain ABI compatibility when adding an entry in a new kind
503 for idx, (kind_name, entry_it) in enumerate(leaf_it):
504 if idx >= len(section._kinds):
505 kind = Kind(kind_name, section)
506 section._kinds.append(kind)
507 section.validate_tree()
509 kind = section._kinds[idx]
512 if p not in kind._leafs:
513 kind._leafs.append(p)
515 for kind in section._kinds:
517 self._construct_inner_namespaces(kind)
519 self._construct_entries(kind)
522 if not section.validate_tree():
523 print >> sys.stderr, ("ERROR: Failed to validate tree in " + \
524 "construct_kinds, with kind = '%s'") %(kind)
526 if not kind.validate_tree():
527 print >> sys.stderr, ("ERROR: Failed to validate tree in " + \
528 "construct_kinds, with kind = '%s'") %(kind)
530 def _construct_inner_namespaces(self, parent, depth=0):
531 #parent is InnerNamespace or Kind
532 ins_dict = self._dictionary_by_name(parent.namespaces)
533 for name, ins in ins_dict.iteritems():
536 for p in parent._leafs:
537 ins_list = p.get_inner_namespace_list()
539 if len(ins_list) > depth:
540 ins_str = ins_list[depth]
541 ins = ins_dict.get(ins_str, InnerNamespace(ins_str, parent))
542 ins_dict[ins_str] = ins
544 if p not in ins._leafs:
547 for name, ins in ins_dict.iteritems():
549 # construct children INS
550 self._construct_inner_namespaces(ins, depth + 1)
552 # construct children entries
553 self._construct_entries(ins, depth + 1)
555 if ins not in parent.namespaces:
556 parent._namespaces.append(ins)
558 if not ins.validate_tree():
559 print >> sys.stderr, ("ERROR: Failed to validate tree in " + \
560 "construct_inner_namespaces, with ins = '%s'") \
563 # doesnt construct the entries, so much as links them
564 def _construct_entries(self, parent, depth=0):
565 #parent is InnerNamespace or Kind
566 entry_dict = self._dictionary_by_name(parent.entries)
567 for p in parent._leafs:
568 ins_list = p.get_inner_namespace_list()
570 if len(ins_list) == depth:
571 entry = entry_dict.get(p.name, p)
572 entry_dict[p.name] = entry
574 for name, entry in entry_dict.iteritems():
576 old_parent = entry.parent
577 entry._parent = parent
579 if entry not in parent.entries:
580 parent._entries.append(entry)
582 if old_parent is not None and old_parent != parent:
583 print >> sys.stderr, ("ERROR: Parent changed from '%s' to '%s' for " + \
585 %(old_parent.name, parent.name, entry.name)
587 def _get_children(self):
588 if self.outer_namespaces is not None:
589 for i in self.outer_namespaces:
592 if self.tags is not None:
598 A tag Node corresponding to a top-level <tag> element.
600 Attributes (Read-Only):
602 id: The name of the tag, e.g. for <tag id="BC"/> id = 'BC'
603 description: The description of the tag, the contents of the <tag> element.
604 parent: An edge to the parent, which is always the Metadata root node.
605 entries: A sequence of edges to entries/clones that are using this Tag.
607 def __init__(self, name, parent, description=""):
608 self._name = name # 'id' attribute in XML
610 self._description = description
611 self._parent = parent
613 # all entries that have this tag, including clones
614 self._entries = [] # filled in by Metadata#construct_tags
621 def description(self):
622 return self._description
626 return (i for i in self._entries)
628 def _get_children(self):
633 A typedef Node corresponding to a <typedef> element under a top-level <types>.
635 Attributes (Read-Only):
636 name: The name of this typedef as a string.
637 languages: A dictionary of 'language name' -> 'fully qualified class'.
638 parent: An edge to the parent, which is always the Metadata root node.
639 entries: An iterable over all entries which reference this typedef.
641 def __init__(self, name, parent, languages=None):
643 self._parent = parent
645 # all entries that have this typedef
646 self._entries = [] # filled in by Metadata#construct_types
648 self._languages = languages or {}
652 return self._languages
656 return (i for i in self._entries)
658 def _get_children(self):
661 class OuterNamespace(Node):
663 A node corresponding to a <namespace> element under <metadata>
665 Attributes (Read-Only):
666 name: The name attribute of the <namespace name="foo"> element.
667 parent: An edge to the parent, which is always the Metadata root node.
668 sections: A sequence of Section children.
670 def __init__(self, name, parent, sections=[]):
672 self._parent = parent # MetadataSet
673 self._sections = sections[:]
676 self._children = self._sections
680 return (i for i in self._sections)
684 A node corresponding to a <section> element under <namespace>
686 Attributes (Read-Only):
687 name: The name attribute of the <section name="foo"> element.
688 parent: An edge to the parent, which is always an OuterNamespace instance.
689 description: A string description of the section, or None.
690 kinds: A sequence of Kind children.
691 merged_kinds: A sequence of virtual Kind children,
692 with each Kind's children merged by the kind.name
693 hal_versions: A set of tuples (major, minor) describing all the HAL versions entries in this section have
695 def __init__(self, name, parent, description=None, kinds=[]):
697 self._parent = parent
698 self._description = description
699 self._kinds = kinds[:]
704 def description(self):
705 return self._description
709 return (i for i in self._kinds)
712 def hal_versions(self):
714 for i in self._kinds:
715 for entry in i.entries:
716 hal_versions.add( (entry.hal_major_version, entry.hal_minor_version) )
717 for namespace in i.namespaces:
718 hal_versions.update(namespace.hal_versions)
721 def sort_children(self):
723 # order is always controls,static,dynamic
724 find_child = lambda x: [i for i in self._get_children() if i.name == x]
725 new_lst = find_child('controls') \
726 + find_child('static') \
727 + find_child('dynamic')
728 self._kinds = new_lst
731 def _get_children(self):
732 return (i for i in self.kinds)
735 def merged_kinds(self):
737 def aggregate_by_name(acc, el):
738 existing = [i for i in acc if i.name == el.name]
742 k = Kind(el.name, el.parent)
745 k._namespaces.extend(el._namespaces)
746 k._entries.extend(el._entries)
750 new_kinds_lst = reduce(aggregate_by_name, self.kinds, [])
752 for k in new_kinds_lst:
755 def combine_kinds_into_single_node(self):
757 Combines the section's Kinds into a single node.
759 Combines all the children (kinds) of this section into a single
763 A new Kind node that collapses all Kind siblings into one, combining
764 all their children together.
766 For example, given self.kinds == [ x, y ]
772 a new instance z is returned in this example.
775 The children of the kinds are the same references as before, that is
776 their parents will point to the old parents and not to the new parent.
778 combined = Kind(name="combined", parent=self)
780 for k in self._get_children():
781 combined._namespaces.extend(k.namespaces)
782 combined._entries.extend(k.entries)
788 A node corresponding to one of: <static>,<dynamic>,<controls> under a
791 Attributes (Read-Only):
792 name: A string which is one of 'static', 'dynamic, or 'controls'.
793 parent: An edge to the parent, which is always a Section instance.
794 namespaces: A sequence of InnerNamespace children.
795 entries: A sequence of Entry/Clone children.
796 merged_entries: A sequence of MergedEntry virtual nodes from entries
798 def __init__(self, name, parent):
800 self._parent = parent
801 self._namespaces = []
807 def namespaces(self):
808 return self._namespaces
815 def merged_entries(self):
816 for i in self.entries:
819 def sort_children(self):
820 self._namespaces.sort(key=self._get_name())
821 self._entries.sort(key=self._get_name())
823 def _get_children(self):
824 for i in self.namespaces:
826 for i in self.entries:
829 def combine_children_by_name(self):
831 Combine multiple children with the same name into a single node.
834 A new Kind where all of the children with the same name were combined.
850 The returned Kind will look like this:
859 This operation is not recursive. To combine the grandchildren and other
860 ancestors, call this method on the ancestor nodes.
862 return Kind._combine_children_by_name(self, new_type=type(self))
864 # new_type is either Kind or InnerNamespace
866 def _combine_children_by_name(self, new_type):
867 new_ins_dict = OrderedDict()
868 new_ent_dict = OrderedDict()
870 for ins in self.namespaces:
871 new_ins = new_ins_dict.setdefault(ins.name,
872 InnerNamespace(ins.name, parent=self))
873 new_ins._namespaces.extend(ins.namespaces)
874 new_ins._entries.extend(ins.entries)
876 for ent in self.entries:
877 new_ent = new_ent_dict.setdefault(ent.name,
880 kind = new_type(self.name, self.parent)
881 kind._namespaces = new_ins_dict.values()
882 kind._entries = new_ent_dict.values()
886 class InnerNamespace(Node):
888 A node corresponding to a <namespace> which is an ancestor of a Kind.
889 These namespaces may have other namespaces recursively, or entries as leafs.
891 Attributes (Read-Only):
892 name: Name attribute from the element, e.g. <namespace name="foo"> -> 'foo'
893 parent: An edge to the parent, which is an InnerNamespace or a Kind.
894 namespaces: A sequence of InnerNamespace children.
895 entries: A sequence of Entry/Clone children.
896 merged_entries: A sequence of MergedEntry virtual nodes from entries
897 hal_versions: A set of tuples (major, minor) describing all the HAL versions entries in this section have
899 def __init__(self, name, parent):
901 self._parent = parent
902 self._namespaces = []
907 def namespaces(self):
908 return self._namespaces
915 def hal_versions(self):
917 for entry in self.entries:
918 hal_versions.add( (entry.hal_major_version, entry.hal_minor_version) )
919 for namespace in self.namespaces:
920 hal_versions.update(namespace.hal_versions)
924 def merged_entries(self):
925 for i in self.entries:
928 def sort_children(self):
929 self._namespaces.sort(key=self._get_name())
930 self._entries.sort(key=self._get_name())
932 def _get_children(self):
933 for i in self.namespaces:
935 for i in self.entries:
938 def combine_children_by_name(self):
940 Combine multiple children with the same name into a single node.
943 A new InnerNamespace where all of the children with the same name were
948 Given an InnerNamespace i:
960 The returned InnerNamespace will look like this:
969 This operation is not recursive. To combine the grandchildren and other
970 ancestors, call this method on the ancestor nodes.
972 return Kind._combine_children_by_name(self, new_type=type(self))
974 class EnumValue(Node):
976 A class corresponding to a <value> element within an <enum> within an <entry>.
978 Attributes (Read-Only):
979 name: A string, e.g. 'ON' or 'OFF'
980 id: An optional numeric string, e.g. '0' or '0xFF'
981 deprecated: A boolean, True if the enum should be deprecated.
983 hidden: A boolean, True if the enum should be hidden.
984 ndk_hidden: A boolean, True if the enum should be hidden in NDK
985 notes: A string describing the notes, or None.
986 sdk_notes: A string describing extra notes for public SDK only
987 ndk_notes: A string describing extra notes for public NDK only
988 parent: An edge to the parent, always an Enum instance.
989 hal_major_version: The major HIDL HAL version this value was first added in
990 hal_minor_version: The minor HIDL HAL version this value was first added in
992 def __init__(self, name, parent,
993 id=None, deprecated=False, optional=False, hidden=False, notes=None, sdk_notes=None, ndk_notes=None, ndk_hidden=False, hal_version='3.2'):
994 self._name = name # str, e.g. 'ON' or 'OFF'
995 self._id = id # int, e.g. '0'
996 self._deprecated = deprecated # bool
997 self._optional = optional # bool
998 self._hidden = hidden # bool
999 self._ndk_hidden = ndk_hidden # bool
1000 self._notes = notes # None or str
1001 self._sdk_notes = sdk_notes # None or str
1002 self._ndk_notes = ndk_notes # None or str
1003 self._parent = parent
1004 if hal_version is None:
1005 if parent is not None and parent.parent is not None:
1006 self._hal_major_version = parent.parent.hal_major_version
1007 self._hal_minor_version = parent.parent.hal_minor_version
1009 self._hal_major_version = 3
1010 self._hal_minor_version = 2
1012 self._hal_major_version = int(hal_version.partition('.')[0])
1013 self._hal_minor_version = int(hal_version.partition('.')[2])
1020 def deprecated(self):
1021 return self._deprecated
1025 return self._optional
1032 def ndk_hidden(self):
1033 return self._ndk_hidden
1040 def sdk_notes(self):
1041 return self._sdk_notes
1044 def ndk_notes(self):
1045 return self._ndk_notes
1048 def hal_major_version(self):
1049 return self._hal_major_version
1052 def hal_minor_version(self):
1053 return self._hal_minor_version
1055 def _get_children(self):
1060 A class corresponding to an <enum> element within an <entry>.
1062 Attributes (Read-Only):
1063 parent: An edge to the parent, always an Entry instance.
1064 values: A sequence of EnumValue children.
1065 has_values_with_id: A boolean representing if any of the children have a
1066 non-empty id property.
1068 def __init__(self, parent, values, ids={}, deprecateds=[],
1069 optionals=[], hiddens=[], notes={}, sdk_notes={}, ndk_notes={}, ndk_hiddens=[], hal_versions={}):
1070 self._parent = parent
1073 [ EnumValue(val, self, ids.get(val), val in deprecateds, val in optionals, val in hiddens, \
1074 notes.get(val), sdk_notes.get(val), ndk_notes.get(val), val in ndk_hiddens, hal_versions.get(val)) \
1079 return (i for i in self._values)
1082 def has_values_with_id(self):
1083 return bool(any(i for i in self.values if i.id))
1085 def has_new_values_added_in_hal_version(self, hal_major_version, hal_minor_version):
1086 return bool(any(i for i in self.values if i.hal_major_version == hal_major_version and i.hal_minor_version == hal_minor_version))
1088 def _get_children(self):
1089 return (i for i in self._values)
1093 A node corresponding to an <entry> element.
1095 Attributes (Read-Only):
1096 parent: An edge to the parent node, which is an InnerNamespace or Kind.
1097 name: The fully qualified name string, e.g. 'android.shading.mode'
1098 name_short: The name attribute from <entry name="mode">, e.g. mode
1099 type: The type attribute from <entry type="bar">
1100 kind: A string ('static', 'dynamic', 'controls') corresponding to the
1102 container: The container attribute from <entry container="array">, or None.
1103 container_sizes: A sequence of size strings or None if container is None.
1104 enum: An Enum instance if the enum attribute is true, None otherwise.
1105 visibility: The visibility of this entry ('system', 'hidden', 'public')
1106 across the system. System entries are only visible in native code
1107 headers. Hidden entries are marked @hide in managed code, while
1108 public entries are visible in the Android SDK.
1109 applied_visibility: As visibility, but always valid, defaulting to 'system'
1110 if no visibility is given for an entry.
1111 applied_ndk_visible: Always valid. Default is 'false'.
1112 Set to 'true' when the visibility implied entry is visible
1114 synthetic: The C-level visibility of this entry ('false', 'true').
1115 Synthetic entries will not be generated into the native metadata
1116 list of entries (in C code). In general a synthetic entry is
1117 glued together at the Java layer from multiple visibiltity=hidden
1119 hwlevel: The lowest hardware level at which the entry is guaranteed
1120 to be supported by the camera device. All devices with higher
1121 hwlevels will also include this entry. None means that the
1122 entry is optional on any hardware level.
1123 deprecated: Marks an entry as @Deprecated in the Java layer; if within an
1124 unreleased version this needs to be removed altogether. If applied
1125 to an entry from an older release, then this means the entry
1126 should be ignored by newer code.
1127 optional: a bool representing the optional attribute, which denotes the entry
1128 is required for hardware level full devices, but optional for other
1129 hardware levels. None if not present.
1130 applied_optional: As optional but always valid, defaulting to False if no
1131 optional attribute is present.
1132 tuple_values: A sequence of strings describing the tuple values,
1133 None if container is not 'tuple'.
1134 description: A string description, or None.
1135 deprecation_description: A string describing the reason for deprecation. Must be present
1136 if deprecated is true, otherwise may be None.
1137 range: A string range, or None.
1138 units: A string units, or None.
1139 tags: A sequence of Tag nodes associated with this Entry.
1140 type_notes: A string describing notes for the type, or None.
1141 typedef: A Typedef associated with this Entry, or None.
1144 Subclass Clone can be used interchangeable with an Entry,
1145 for when we don't care about the underlying type.
1147 parent and tags edges are invalid until after Metadata#construct_graph
1150 def __init__(self, **kwargs):
1152 Instantiate a new Entry node.
1155 name: A string with the fully qualified name, e.g. 'android.shading.mode'
1156 type: A string describing the type, e.g. 'int32'
1157 kind: A string describing the kind, e.g. 'static'
1158 hal_version: A string for the initial HIDL HAL metadata version this entry
1161 Args (if container):
1162 container: A string describing the container, e.g. 'array' or 'tuple'
1163 container_sizes: A list of string sizes if a container, or None otherwise
1165 Args (if container is 'tuple'):
1166 tuple_values: A list of tuple values, e.g. ['width', 'height']
1168 Args (if the 'enum' attribute is true):
1169 enum: A boolean, True if this is an enum, False otherwise
1170 enum_values: A list of value strings, e.g. ['ON', 'OFF']
1171 enum_optionals: A list of optional enum values, e.g. ['OFF']
1172 enum_notes: A dictionary of value->notes strings.
1173 enum_ids: A dictionary of value->id strings.
1174 enum_hal_versions: A dictionary of value->hal version strings
1176 Args (if the 'deprecated' attribute is true):
1177 deprecation_description: A string explaining the deprecation, to be added
1178 to the Java-layer @deprecated tag
1181 description: A string with a description of the entry.
1182 range: A string with the range of the values of the entry, e.g. '>= 0'
1183 units: A string with the units of the values, e.g. 'inches'
1184 details: A string with the detailed documentation for the entry
1185 hal_details: A string with the HAL implementation details for the entry
1186 ndk_details: A string with the extra NDK API documentation for the entry=
1187 tag_ids: A list of tag ID strings, e.g. ['BC', 'V1']
1188 type_notes: A string with the notes for the type
1189 visibility: A string describing the visibility, eg 'system', 'hidden',
1191 synthetic: A bool to mark whether this entry is visible only at the Java
1192 layer (True), or at both layers (False = default).
1193 hwlevel: A string of the HW level (one of 'legacy', 'limited', 'full')
1194 deprecated: A bool to mark whether this is @Deprecated at the Java layer
1196 optional: A bool to mark whether optional for non-full hardware devices
1197 typedef: A string corresponding to a typedef's name attribute.
1200 if kwargs.get('type') is None:
1201 print >> sys.stderr, "ERROR: Missing type for entry '%s' kind '%s'" \
1202 %(kwargs.get('name'), kwargs.get('kind'))
1204 # Attributes are Read-Only, but edges may be mutated by
1205 # Metadata, particularly during construct_graph
1207 self._name = kwargs['name']
1208 self._type = kwargs['type']
1209 self._kind = kwargs['kind'] # static, dynamic, or controls
1211 self._init_common(**kwargs)
1222 def hal_major_version(self):
1223 return self._hal_major_version
1226 def hal_minor_version(self):
1227 return self._hal_minor_version
1230 def visibility(self):
1231 return self._visibility
1234 def applied_visibility(self):
1235 return self._visibility or 'system'
1238 def applied_ndk_visible(self):
1239 if self._visibility in ("public", "ndk_public"):
1244 def synthetic(self):
1245 return self._synthetic
1249 return self._hwlevel
1252 def deprecated(self):
1253 return self._deprecated
1256 def deprecation_description(self):
1257 return self._deprecation_description
1259 # TODO: optional should just return hwlevel is None
1262 return self._optional
1265 def applied_optional(self):
1266 return self._optional or False
1269 def name_short(self):
1270 return self.get_name_minimal()
1273 def container(self):
1274 return self._container
1277 def container_sizes(self):
1278 if self._container_sizes is None:
1281 return (i for i in self._container_sizes)
1284 def tuple_values(self):
1285 if self._tuple_values is None:
1288 return (i for i in self._tuple_values)
1291 def description(self):
1292 return self._description
1304 return self._details
1307 def hal_details(self):
1308 return self._hal_details
1311 def ndk_details(self):
1312 return self._ndk_details
1315 def applied_ndk_details(self):
1316 return (self._details or "") + (self._ndk_details or "")
1320 if self._tags is None:
1323 return (i for i in self._tags)
1326 def type_notes(self):
1327 return self._type_notes
1331 return self._typedef
1337 def has_new_values_added_in_hal_version(self, hal_major_version, hal_minor_version):
1338 if self._enum is not None:
1339 return self._enum.has_new_values_added_in_hal_version(hal_major_version,hal_minor_version)
1343 def _get_children(self):
1347 def sort_children(self):
1352 Whether or not this is a Clone instance.
1359 def _init_common(self, **kwargs):
1361 self._parent = None # filled in by Metadata::_construct_entries
1363 self._container = kwargs.get('container')
1364 self._container_sizes = kwargs.get('container_sizes')
1366 hal_version = kwargs.get('hal_version')
1367 if hal_version is None:
1368 self._hal_major_version = 3
1369 self._hal_minor_version = 2
1371 self._hal_major_version = int(hal_version.partition('.')[0])
1372 self._hal_minor_version = int(hal_version.partition('.')[2])
1374 # access these via the 'enum' prop
1375 enum_values = kwargs.get('enum_values')
1376 enum_deprecateds = kwargs.get('enum_deprecateds')
1377 enum_optionals = kwargs.get('enum_optionals')
1378 enum_hiddens = kwargs.get('enum_hiddens')
1379 enum_ndk_hiddens = kwargs.get('enum_ndk_hiddens')
1380 enum_notes = kwargs.get('enum_notes') # { value => notes }
1381 enum_sdk_notes = kwargs.get('enum_sdk_notes') # { value => sdk_notes }
1382 enum_ndk_notes = kwargs.get('enum_ndk_notes') # { value => ndk_notes }
1383 enum_ids = kwargs.get('enum_ids') # { value => notes }
1384 enum_hal_versions = kwargs.get('enum_hal_versions') # { value => hal_versions }
1386 self._tuple_values = kwargs.get('tuple_values')
1388 self._description = kwargs.get('description')
1389 self._range = kwargs.get('range')
1390 self._units = kwargs.get('units')
1391 self._details = kwargs.get('details')
1392 self._hal_details = kwargs.get('hal_details')
1393 self._ndk_details = kwargs.get('ndk_details')
1395 self._tag_ids = kwargs.get('tag_ids', [])
1396 self._tags = None # Filled in by Metadata::_construct_tags
1398 self._type_notes = kwargs.get('type_notes')
1399 self._type_name = kwargs.get('type_name')
1400 self._typedef = None # Filled in by Metadata::_construct_types
1402 if kwargs.get('enum', False):
1403 self._enum = Enum(self, enum_values, enum_ids, enum_deprecateds, enum_optionals,
1404 enum_hiddens, enum_notes, enum_sdk_notes, enum_ndk_notes, enum_ndk_hiddens, enum_hal_versions)
1408 self._visibility = kwargs.get('visibility')
1409 self._synthetic = kwargs.get('synthetic', False)
1410 self._hwlevel = kwargs.get('hwlevel')
1411 self._deprecated = kwargs.get('deprecated', False)
1412 self._deprecation_description = kwargs.get('deprecation_description')
1414 self._optional = kwargs.get('optional')
1415 self._ndk_visible = kwargs.get('ndk_visible')
1417 self._property_keys = kwargs
1421 Copy the attributes into a new entry, merging it with the target entry
1424 return MergedEntry(self)
1426 # Helpers for accessing less than the fully qualified name
1428 def get_name_as_list(self):
1430 Returns the name as a list split by a period.
1433 entry.name is 'android.lens.info.shading'
1434 entry.get_name_as_list() == ['android', 'lens', 'info', 'shading']
1436 return self.name.split(".")
1438 def get_inner_namespace_list(self):
1440 Returns the inner namespace part of the name as a list
1443 entry.name is 'android.lens.info.shading'
1444 entry.get_inner_namespace_list() == ['info']
1446 return self.get_name_as_list()[2:-1]
1448 def get_outer_namespace(self):
1450 Returns the outer namespace as a string.
1453 entry.name is 'android.lens.info.shading'
1454 entry.get_outer_namespace() == 'android'
1457 Since outer namespaces are non-recursive,
1458 and each entry has one, this does not need to be a list.
1460 return self.get_name_as_list()[0]
1462 def get_section(self):
1464 Returns the section as a string.
1467 entry.name is 'android.lens.info.shading'
1468 entry.get_section() == ''
1471 Since outer namespaces are non-recursive,
1472 and each entry has one, this does not need to be a list.
1474 return self.get_name_as_list()[1]
1476 def get_name_minimal(self):
1478 Returns only the last component of the fully qualified name as a string.
1481 entry.name is 'android.lens.info.shading'
1482 entry.get_name_minimal() == 'shading'
1485 entry.name_short it an alias for this
1487 return self.get_name_as_list()[-1]
1489 def get_path_without_name(self):
1491 Returns a string path to the entry, with the name component excluded.
1494 entry.name is 'android.lens.info.shading'
1495 entry.get_path_without_name() == 'android.lens.info'
1497 return ".".join(self.get_name_as_list()[0:-1])
1502 A Node corresponding to a <clone> element. It has all the attributes of an
1503 <entry> element (Entry) plus the additions specified below.
1505 Attributes (Read-Only):
1506 entry: an edge to an Entry object that this targets
1507 target_kind: A string describing the kind of the target entry.
1508 name: a string of the name, same as entry.name
1509 kind: a string of the Kind ancestor, one of 'static', 'controls', 'dynamic'
1510 for the <clone> element.
1511 type: always None, since a clone cannot override the type.
1513 def __init__(self, entry=None, **kwargs):
1515 Instantiate a new Clone node.
1518 name: A string with the fully qualified name, e.g. 'android.shading.mode'
1519 type: A string describing the type, e.g. 'int32'
1520 kind: A string describing the kind, e.g. 'static'
1521 target_kind: A string for the kind of the target entry, e.g. 'dynamic'
1522 hal_version: A string for the initial HIDL HAL metadata version this entry
1525 Args (if container):
1526 container: A string describing the container, e.g. 'array' or 'tuple'
1527 container_sizes: A list of string sizes if a container, or None otherwise
1529 Args (if container is 'tuple'):
1530 tuple_values: A list of tuple values, e.g. ['width', 'height']
1532 Args (if the 'enum' attribute is true):
1533 enum: A boolean, True if this is an enum, False otherwise
1534 enum_values: A list of value strings, e.g. ['ON', 'OFF']
1535 enum_optionals: A list of optional enum values, e.g. ['OFF']
1536 enum_notes: A dictionary of value->notes strings.
1537 enum_ids: A dictionary of value->id strings.
1540 entry: An edge to the corresponding target Entry.
1541 description: A string with a description of the entry.
1542 range: A string with the range of the values of the entry, e.g. '>= 0'
1543 units: A string with the units of the values, e.g. 'inches'
1544 details: A string with the detailed documentation for the entry
1545 hal_details: A string with the HAL implementation details for the entry
1546 ndk_details: A string with the extra NDK documentation for the entry
1547 tag_ids: A list of tag ID strings, e.g. ['BC', 'V1']
1548 type_notes: A string with the notes for the type
1551 Note that type is not specified since it has to be the same as the
1554 self._entry = entry # Entry object
1555 self._target_kind = kwargs['target_kind']
1556 self._name = kwargs['name'] # same as entry.name
1557 self._kind = kwargs['kind']
1559 # illegal to override the type, it should be the same as the entry
1561 # the rest of the kwargs are optional
1562 # can be used to override the regular entry data
1563 self._init_common(**kwargs)
1570 def target_kind(self):
1571 return self._target_kind
1575 Whether or not this is a Clone instance.
1582 class MergedEntry(Entry):
1584 A MergedEntry has all the attributes of a Clone and its target Entry merged
1588 Useful when we want to 'unfold' a clone into a real entry by copying out
1589 the target entry data. In this case we don't care about distinguishing
1590 a clone vs an entry.
1592 def __init__(self, entry):
1594 Create a new instance of MergedEntry.
1597 entry: An Entry or Clone instance
1599 props_distinct = ['description', 'units', 'range', 'details',
1600 'hal_details', 'ndk_details', 'tags', 'kind',
1601 'deprecation_description']
1603 for p in props_distinct:
1605 if entry.is_clone():
1606 setattr(self, p, getattr(entry, p) or getattr(entry.entry, p))
1608 setattr(self, p, getattr(entry, p))
1610 props_common = ['parent', 'name', 'container',
1611 'container_sizes', 'enum',
1622 'hal_major_version',
1626 for p in props_common:
1628 if entry.is_clone():
1629 setattr(self, p, getattr(entry.entry, p))
1631 setattr(self, p, getattr(entry, p))