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
419 if (p.hal_major_version == 0):
420 p._hal_major_version = target_entry._hal_major_version
421 p._hal_minor_version = target_entry._hal_minor_version
422 # should not throw if we pass validation
423 # but can happen when importing obsolete CSV entries
424 if target_entry is None:
425 print >> sys.stderr, ("WARNING: Clone entry '%s' target kind '%s'" + \
426 " has no corresponding entry") \
427 %(p.name, p.target_kind)
429 def _construct_outer_namespaces(self):
431 if self._outer_namespaces is None: #the first time this runs
432 self._outer_namespaces = []
434 root = self._dictionary_by_name(self._outer_namespaces)
435 for ons_name, ons in root.iteritems():
438 for p in self._entries_ordered:
439 ons_name = p.get_outer_namespace()
440 ons = root.get(ons_name, OuterNamespace(ons_name, self))
443 if p not in ons._leafs:
446 for ons_name, ons in root.iteritems():
450 self._construct_sections(ons)
452 if ons not in self._outer_namespaces:
453 self._outer_namespaces.append(ons)
457 def _construct_sections(self, outer_namespace):
459 sections_dict = self._dictionary_by_name(outer_namespace.sections)
460 for sec_name, sec in sections_dict.iteritems():
464 for p in outer_namespace._leafs:
465 does_exist = sections_dict.get(p.get_section())
467 sec = sections_dict.get(p.get_section(), \
468 Section(p.get_section(), outer_namespace))
469 sections_dict[p.get_section()] = sec
473 if p not in sec._leafs:
476 for sec_name, sec in sections_dict.iteritems():
478 if not sec.validate_tree():
479 print >> sys.stderr, ("ERROR: Failed to validate tree in " + \
480 "construct_sections (start), with section = '%s'")\
483 self._construct_kinds(sec)
485 if sec not in outer_namespace.sections:
486 outer_namespace._sections.append(sec)
488 if not sec.validate_tree():
489 print >> sys.stderr, ("ERROR: Failed to validate tree in " + \
490 "construct_sections (end), with section = '%s'") \
493 # 'controls', 'static' 'dynamic'. etc
494 def _construct_kinds(self, section):
495 for kind in section.kinds:
497 section.validate_tree()
499 group_entry_by_kind = itertools.groupby(section._leafs, lambda x: x.kind)
500 leaf_it = ((k, g) for k, g in group_entry_by_kind)
502 # allow multiple kinds with the same name. merge if adjacent
503 # e.g. dynamic,dynamic,static,static,dynamic -> dynamic,static,dynamic
504 # this helps maintain ABI compatibility when adding an entry in a new kind
505 for idx, (kind_name, entry_it) in enumerate(leaf_it):
506 if idx >= len(section._kinds):
507 kind = Kind(kind_name, section)
508 section._kinds.append(kind)
509 section.validate_tree()
511 kind = section._kinds[idx]
514 if p not in kind._leafs:
515 kind._leafs.append(p)
517 for kind in section._kinds:
519 self._construct_inner_namespaces(kind)
521 self._construct_entries(kind)
524 if not section.validate_tree():
525 print >> sys.stderr, ("ERROR: Failed to validate tree in " + \
526 "construct_kinds, with kind = '%s'") %(kind)
528 if not kind.validate_tree():
529 print >> sys.stderr, ("ERROR: Failed to validate tree in " + \
530 "construct_kinds, with kind = '%s'") %(kind)
532 def _construct_inner_namespaces(self, parent, depth=0):
533 #parent is InnerNamespace or Kind
534 ins_dict = self._dictionary_by_name(parent.namespaces)
535 for name, ins in ins_dict.iteritems():
538 for p in parent._leafs:
539 ins_list = p.get_inner_namespace_list()
541 if len(ins_list) > depth:
542 ins_str = ins_list[depth]
543 ins = ins_dict.get(ins_str, InnerNamespace(ins_str, parent))
544 ins_dict[ins_str] = ins
546 if p not in ins._leafs:
549 for name, ins in ins_dict.iteritems():
551 # construct children INS
552 self._construct_inner_namespaces(ins, depth + 1)
554 # construct children entries
555 self._construct_entries(ins, depth + 1)
557 if ins not in parent.namespaces:
558 parent._namespaces.append(ins)
560 if not ins.validate_tree():
561 print >> sys.stderr, ("ERROR: Failed to validate tree in " + \
562 "construct_inner_namespaces, with ins = '%s'") \
565 # doesnt construct the entries, so much as links them
566 def _construct_entries(self, parent, depth=0):
567 #parent is InnerNamespace or Kind
568 entry_dict = self._dictionary_by_name(parent.entries)
569 for p in parent._leafs:
570 ins_list = p.get_inner_namespace_list()
572 if len(ins_list) == depth:
573 entry = entry_dict.get(p.name, p)
574 entry_dict[p.name] = entry
576 for name, entry in entry_dict.iteritems():
578 old_parent = entry.parent
579 entry._parent = parent
581 if entry not in parent.entries:
582 parent._entries.append(entry)
584 if old_parent is not None and old_parent != parent:
585 print >> sys.stderr, ("ERROR: Parent changed from '%s' to '%s' for " + \
587 %(old_parent.name, parent.name, entry.name)
589 def _get_children(self):
590 if self.outer_namespaces is not None:
591 for i in self.outer_namespaces:
594 if self.tags is not None:
600 A tag Node corresponding to a top-level <tag> element.
602 Attributes (Read-Only):
604 id: The name of the tag, e.g. for <tag id="BC"/> id = 'BC'
605 description: The description of the tag, the contents of the <tag> element.
606 parent: An edge to the parent, which is always the Metadata root node.
607 entries: A sequence of edges to entries/clones that are using this Tag.
609 def __init__(self, name, parent, description=""):
610 self._name = name # 'id' attribute in XML
612 self._description = description
613 self._parent = parent
615 # all entries that have this tag, including clones
616 self._entries = [] # filled in by Metadata#construct_tags
623 def description(self):
624 return self._description
628 return (i for i in self._entries)
630 def _get_children(self):
635 A typedef Node corresponding to a <typedef> element under a top-level <types>.
637 Attributes (Read-Only):
638 name: The name of this typedef as a string.
639 languages: A dictionary of 'language name' -> 'fully qualified class'.
640 parent: An edge to the parent, which is always the Metadata root node.
641 entries: An iterable over all entries which reference this typedef.
643 def __init__(self, name, parent, languages=None):
645 self._parent = parent
647 # all entries that have this typedef
648 self._entries = [] # filled in by Metadata#construct_types
650 self._languages = languages or {}
654 return self._languages
658 return (i for i in self._entries)
660 def _get_children(self):
663 class OuterNamespace(Node):
665 A node corresponding to a <namespace> element under <metadata>
667 Attributes (Read-Only):
668 name: The name attribute of the <namespace name="foo"> element.
669 parent: An edge to the parent, which is always the Metadata root node.
670 sections: A sequence of Section children.
672 def __init__(self, name, parent, sections=[]):
674 self._parent = parent # MetadataSet
675 self._sections = sections[:]
678 self._children = self._sections
682 return (i for i in self._sections)
686 A node corresponding to a <section> element under <namespace>
688 Attributes (Read-Only):
689 name: The name attribute of the <section name="foo"> element.
690 parent: An edge to the parent, which is always an OuterNamespace instance.
691 description: A string description of the section, or None.
692 kinds: A sequence of Kind children.
693 merged_kinds: A sequence of virtual Kind children,
694 with each Kind's children merged by the kind.name
695 hal_versions: A set of tuples (major, minor) describing all the HAL versions entries in this section have
697 def __init__(self, name, parent, description=None, kinds=[]):
699 self._parent = parent
700 self._description = description
701 self._kinds = kinds[:]
706 def description(self):
707 return self._description
711 return (i for i in self._kinds)
714 def hal_versions(self):
716 for i in self._kinds:
717 for entry in i.entries:
718 hal_versions.add( (entry.hal_major_version, entry.hal_minor_version) )
719 for namespace in i.namespaces:
720 hal_versions.update(namespace.hal_versions)
723 def sort_children(self):
725 # order is always controls,static,dynamic
726 find_child = lambda x: [i for i in self._get_children() if i.name == x]
727 new_lst = find_child('controls') \
728 + find_child('static') \
729 + find_child('dynamic')
730 self._kinds = new_lst
733 def _get_children(self):
734 return (i for i in self.kinds)
737 def merged_kinds(self):
739 def aggregate_by_name(acc, el):
740 existing = [i for i in acc if i.name == el.name]
744 k = Kind(el.name, el.parent)
747 k._namespaces.extend(el._namespaces)
748 k._entries.extend(el._entries)
752 new_kinds_lst = reduce(aggregate_by_name, self.kinds, [])
754 for k in new_kinds_lst:
757 def combine_kinds_into_single_node(self):
759 Combines the section's Kinds into a single node.
761 Combines all the children (kinds) of this section into a single
765 A new Kind node that collapses all Kind siblings into one, combining
766 all their children together.
768 For example, given self.kinds == [ x, y ]
774 a new instance z is returned in this example.
777 The children of the kinds are the same references as before, that is
778 their parents will point to the old parents and not to the new parent.
780 combined = Kind(name="combined", parent=self)
782 for k in self._get_children():
783 combined._namespaces.extend(k.namespaces)
784 combined._entries.extend(k.entries)
790 A node corresponding to one of: <static>,<dynamic>,<controls> under a
793 Attributes (Read-Only):
794 name: A string which is one of 'static', 'dynamic, or 'controls'.
795 parent: An edge to the parent, which is always a Section instance.
796 namespaces: A sequence of InnerNamespace children.
797 entries: A sequence of Entry/Clone children.
798 merged_entries: A sequence of MergedEntry virtual nodes from entries
800 def __init__(self, name, parent):
802 self._parent = parent
803 self._namespaces = []
809 def namespaces(self):
810 return self._namespaces
817 def merged_entries(self):
818 for i in self.entries:
821 def sort_children(self):
822 self._namespaces.sort(key=self._get_name())
823 self._entries.sort(key=self._get_name())
825 def _get_children(self):
826 for i in self.namespaces:
828 for i in self.entries:
831 def combine_children_by_name(self):
833 Combine multiple children with the same name into a single node.
836 A new Kind where all of the children with the same name were combined.
852 The returned Kind will look like this:
861 This operation is not recursive. To combine the grandchildren and other
862 ancestors, call this method on the ancestor nodes.
864 return Kind._combine_children_by_name(self, new_type=type(self))
866 # new_type is either Kind or InnerNamespace
868 def _combine_children_by_name(self, new_type):
869 new_ins_dict = OrderedDict()
870 new_ent_dict = OrderedDict()
872 for ins in self.namespaces:
873 new_ins = new_ins_dict.setdefault(ins.name,
874 InnerNamespace(ins.name, parent=self))
875 new_ins._namespaces.extend(ins.namespaces)
876 new_ins._entries.extend(ins.entries)
878 for ent in self.entries:
879 new_ent = new_ent_dict.setdefault(ent.name,
882 kind = new_type(self.name, self.parent)
883 kind._namespaces = new_ins_dict.values()
884 kind._entries = new_ent_dict.values()
888 class InnerNamespace(Node):
890 A node corresponding to a <namespace> which is an ancestor of a Kind.
891 These namespaces may have other namespaces recursively, or entries as leafs.
893 Attributes (Read-Only):
894 name: Name attribute from the element, e.g. <namespace name="foo"> -> 'foo'
895 parent: An edge to the parent, which is an InnerNamespace or a Kind.
896 namespaces: A sequence of InnerNamespace children.
897 entries: A sequence of Entry/Clone children.
898 merged_entries: A sequence of MergedEntry virtual nodes from entries
899 hal_versions: A set of tuples (major, minor) describing all the HAL versions entries in this section have
901 def __init__(self, name, parent):
903 self._parent = parent
904 self._namespaces = []
909 def namespaces(self):
910 return self._namespaces
917 def hal_versions(self):
919 for entry in self.entries:
920 hal_versions.add( (entry.hal_major_version, entry.hal_minor_version) )
921 for namespace in self.namespaces:
922 hal_versions.update(namespace.hal_versions)
926 def merged_entries(self):
927 for i in self.entries:
930 def sort_children(self):
931 self._namespaces.sort(key=self._get_name())
932 self._entries.sort(key=self._get_name())
934 def _get_children(self):
935 for i in self.namespaces:
937 for i in self.entries:
940 def combine_children_by_name(self):
942 Combine multiple children with the same name into a single node.
945 A new InnerNamespace where all of the children with the same name were
950 Given an InnerNamespace i:
962 The returned InnerNamespace will look like this:
971 This operation is not recursive. To combine the grandchildren and other
972 ancestors, call this method on the ancestor nodes.
974 return Kind._combine_children_by_name(self, new_type=type(self))
976 class EnumValue(Node):
978 A class corresponding to a <value> element within an <enum> within an <entry>.
980 Attributes (Read-Only):
981 name: A string, e.g. 'ON' or 'OFF'
982 id: An optional numeric string, e.g. '0' or '0xFF'
983 deprecated: A boolean, True if the enum should be deprecated.
985 hidden: A boolean, True if the enum should be hidden.
986 ndk_hidden: A boolean, True if the enum should be hidden in NDK
987 notes: A string describing the notes, or None.
988 sdk_notes: A string describing extra notes for public SDK only
989 ndk_notes: A string describing extra notes for public NDK only
990 parent: An edge to the parent, always an Enum instance.
991 hal_major_version: The major HIDL HAL version this value was first added in
992 hal_minor_version: The minor HIDL HAL version this value was first added in
994 def __init__(self, name, parent,
995 id=None, deprecated=False, optional=False, hidden=False, notes=None, sdk_notes=None, ndk_notes=None, ndk_hidden=False, hal_version='3.2'):
996 self._name = name # str, e.g. 'ON' or 'OFF'
997 self._id = id # int, e.g. '0'
998 self._deprecated = deprecated # bool
999 self._optional = optional # bool
1000 self._hidden = hidden # bool
1001 self._ndk_hidden = ndk_hidden # bool
1002 self._notes = notes # None or str
1003 self._sdk_notes = sdk_notes # None or str
1004 self._ndk_notes = ndk_notes # None or str
1005 self._parent = parent
1006 if hal_version is None:
1007 if parent is not None and parent.parent is not None:
1008 self._hal_major_version = parent.parent.hal_major_version
1009 self._hal_minor_version = parent.parent.hal_minor_version
1011 self._hal_major_version = 3
1012 self._hal_minor_version = 2
1014 self._hal_major_version = int(hal_version.partition('.')[0])
1015 self._hal_minor_version = int(hal_version.partition('.')[2])
1022 def deprecated(self):
1023 return self._deprecated
1027 return self._optional
1034 def ndk_hidden(self):
1035 return self._ndk_hidden
1042 def sdk_notes(self):
1043 return self._sdk_notes
1046 def ndk_notes(self):
1047 return self._ndk_notes
1050 def hal_major_version(self):
1051 return self._hal_major_version
1054 def hal_minor_version(self):
1055 return self._hal_minor_version
1057 def _get_children(self):
1062 A class corresponding to an <enum> element within an <entry>.
1064 Attributes (Read-Only):
1065 parent: An edge to the parent, always an Entry instance.
1066 values: A sequence of EnumValue children.
1067 has_values_with_id: A boolean representing if any of the children have a
1068 non-empty id property.
1070 def __init__(self, parent, values, ids={}, deprecateds=[],
1071 optionals=[], hiddens=[], notes={}, sdk_notes={}, ndk_notes={}, ndk_hiddens=[], hal_versions={}):
1072 self._parent = parent
1075 [ EnumValue(val, self, ids.get(val), val in deprecateds, val in optionals, val in hiddens, \
1076 notes.get(val), sdk_notes.get(val), ndk_notes.get(val), val in ndk_hiddens, hal_versions.get(val)) \
1081 return (i for i in self._values)
1084 def has_values_with_id(self):
1085 return bool(any(i for i in self.values if i.id))
1087 def has_new_values_added_in_hal_version(self, hal_major_version, hal_minor_version):
1088 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))
1090 def _get_children(self):
1091 return (i for i in self._values)
1095 A node corresponding to an <entry> element.
1097 Attributes (Read-Only):
1098 parent: An edge to the parent node, which is an InnerNamespace or Kind.
1099 name: The fully qualified name string, e.g. 'android.shading.mode'
1100 name_short: The name attribute from <entry name="mode">, e.g. mode
1101 type: The type attribute from <entry type="bar">
1102 kind: A string ('static', 'dynamic', 'controls') corresponding to the
1104 container: The container attribute from <entry container="array">, or None.
1105 container_sizes: A sequence of size strings or None if container is None.
1106 enum: An Enum instance if the enum attribute is true, None otherwise.
1107 visibility: The visibility of this entry ('system', 'hidden', 'public')
1108 across the system. System entries are only visible in native code
1109 headers. Hidden entries are marked @hide in managed code, while
1110 public entries are visible in the Android SDK.
1111 applied_visibility: As visibility, but always valid, defaulting to 'system'
1112 if no visibility is given for an entry.
1113 applied_ndk_visible: Always valid. Default is 'false'.
1114 Set to 'true' when the visibility implied entry is visible
1116 synthetic: The C-level visibility of this entry ('false', 'true').
1117 Synthetic entries will not be generated into the native metadata
1118 list of entries (in C code). In general a synthetic entry is
1119 glued together at the Java layer from multiple visibiltity=hidden
1121 hwlevel: The lowest hardware level at which the entry is guaranteed
1122 to be supported by the camera device. All devices with higher
1123 hwlevels will also include this entry. None means that the
1124 entry is optional on any hardware level.
1125 deprecated: Marks an entry as @Deprecated in the Java layer; if within an
1126 unreleased version this needs to be removed altogether. If applied
1127 to an entry from an older release, then this means the entry
1128 should be ignored by newer code.
1129 optional: a bool representing the optional attribute, which denotes the entry
1130 is required for hardware level full devices, but optional for other
1131 hardware levels. None if not present.
1132 applied_optional: As optional but always valid, defaulting to False if no
1133 optional attribute is present.
1134 tuple_values: A sequence of strings describing the tuple values,
1135 None if container is not 'tuple'.
1136 description: A string description, or None.
1137 deprecation_description: A string describing the reason for deprecation. Must be present
1138 if deprecated is true, otherwise may be None.
1139 range: A string range, or None.
1140 units: A string units, or None.
1141 tags: A sequence of Tag nodes associated with this Entry.
1142 type_notes: A string describing notes for the type, or None.
1143 typedef: A Typedef associated with this Entry, or None.
1146 Subclass Clone can be used interchangeable with an Entry,
1147 for when we don't care about the underlying type.
1149 parent and tags edges are invalid until after Metadata#construct_graph
1152 def __init__(self, **kwargs):
1154 Instantiate a new Entry node.
1157 name: A string with the fully qualified name, e.g. 'android.shading.mode'
1158 type: A string describing the type, e.g. 'int32'
1159 kind: A string describing the kind, e.g. 'static'
1160 hal_version: A string for the initial HIDL HAL metadata version this entry
1163 Args (if container):
1164 container: A string describing the container, e.g. 'array' or 'tuple'
1165 container_sizes: A list of string sizes if a container, or None otherwise
1167 Args (if container is 'tuple'):
1168 tuple_values: A list of tuple values, e.g. ['width', 'height']
1170 Args (if the 'enum' attribute is true):
1171 enum: A boolean, True if this is an enum, False otherwise
1172 enum_values: A list of value strings, e.g. ['ON', 'OFF']
1173 enum_optionals: A list of optional enum values, e.g. ['OFF']
1174 enum_notes: A dictionary of value->notes strings.
1175 enum_ids: A dictionary of value->id strings.
1176 enum_hal_versions: A dictionary of value->hal version strings
1178 Args (if the 'deprecated' attribute is true):
1179 deprecation_description: A string explaining the deprecation, to be added
1180 to the Java-layer @deprecated tag
1183 description: A string with a description of the entry.
1184 range: A string with the range of the values of the entry, e.g. '>= 0'
1185 units: A string with the units of the values, e.g. 'inches'
1186 details: A string with the detailed documentation for the entry
1187 hal_details: A string with the HAL implementation details for the entry
1188 ndk_details: A string with the extra NDK API documentation for the entry=
1189 tag_ids: A list of tag ID strings, e.g. ['BC', 'V1']
1190 type_notes: A string with the notes for the type
1191 visibility: A string describing the visibility, eg 'system', 'hidden',
1193 synthetic: A bool to mark whether this entry is visible only at the Java
1194 layer (True), or at both layers (False = default).
1195 hwlevel: A string of the HW level (one of 'legacy', 'limited', 'full')
1196 deprecated: A bool to mark whether this is @Deprecated at the Java layer
1198 optional: A bool to mark whether optional for non-full hardware devices
1199 typedef: A string corresponding to a typedef's name attribute.
1202 if kwargs.get('type') is None:
1203 print >> sys.stderr, "ERROR: Missing type for entry '%s' kind '%s'" \
1204 %(kwargs.get('name'), kwargs.get('kind'))
1206 # Attributes are Read-Only, but edges may be mutated by
1207 # Metadata, particularly during construct_graph
1209 self._name = kwargs['name']
1210 self._type = kwargs['type']
1211 self._kind = kwargs['kind'] # static, dynamic, or controls
1213 self._init_common(**kwargs)
1224 def hal_major_version(self):
1225 return self._hal_major_version
1228 def hal_minor_version(self):
1229 return self._hal_minor_version
1232 def visibility(self):
1233 return self._visibility
1236 def applied_visibility(self):
1237 return self._visibility or 'system'
1240 def applied_ndk_visible(self):
1241 if self._visibility in ("public", "ndk_public"):
1246 def synthetic(self):
1247 return self._synthetic
1251 return self._hwlevel
1254 def deprecated(self):
1255 return self._deprecated
1258 def deprecation_description(self):
1259 return self._deprecation_description
1261 # TODO: optional should just return hwlevel is None
1264 return self._optional
1267 def applied_optional(self):
1268 return self._optional or False
1271 def name_short(self):
1272 return self.get_name_minimal()
1275 def container(self):
1276 return self._container
1279 def container_sizes(self):
1280 if self._container_sizes is None:
1283 return (i for i in self._container_sizes)
1286 def tuple_values(self):
1287 if self._tuple_values is None:
1290 return (i for i in self._tuple_values)
1293 def description(self):
1294 return self._description
1306 return self._details
1309 def hal_details(self):
1310 return self._hal_details
1313 def ndk_details(self):
1314 return self._ndk_details
1317 def applied_ndk_details(self):
1318 return (self._details or "") + (self._ndk_details or "")
1322 if self._tags is None:
1325 return (i for i in self._tags)
1328 def type_notes(self):
1329 return self._type_notes
1333 return self._typedef
1339 def has_new_values_added_in_hal_version(self, hal_major_version, hal_minor_version):
1340 if self._enum is not None:
1341 return self._enum.has_new_values_added_in_hal_version(hal_major_version,hal_minor_version)
1345 def _get_children(self):
1349 def sort_children(self):
1354 Whether or not this is a Clone instance.
1361 def _init_common(self, **kwargs):
1363 self._parent = None # filled in by Metadata::_construct_entries
1365 self._container = kwargs.get('container')
1366 self._container_sizes = kwargs.get('container_sizes')
1368 hal_version = kwargs.get('hal_version')
1369 if hal_version is None:
1371 self._hal_major_version = 0
1372 self._hal_minor_version = 0
1374 self._hal_major_version = 3
1375 self._hal_minor_version = 2
1377 self._hal_major_version = int(hal_version.partition('.')[0])
1378 self._hal_minor_version = int(hal_version.partition('.')[2])
1380 # access these via the 'enum' prop
1381 enum_values = kwargs.get('enum_values')
1382 enum_deprecateds = kwargs.get('enum_deprecateds')
1383 enum_optionals = kwargs.get('enum_optionals')
1384 enum_hiddens = kwargs.get('enum_hiddens')
1385 enum_ndk_hiddens = kwargs.get('enum_ndk_hiddens')
1386 enum_notes = kwargs.get('enum_notes') # { value => notes }
1387 enum_sdk_notes = kwargs.get('enum_sdk_notes') # { value => sdk_notes }
1388 enum_ndk_notes = kwargs.get('enum_ndk_notes') # { value => ndk_notes }
1389 enum_ids = kwargs.get('enum_ids') # { value => notes }
1390 enum_hal_versions = kwargs.get('enum_hal_versions') # { value => hal_versions }
1392 self._tuple_values = kwargs.get('tuple_values')
1394 self._description = kwargs.get('description')
1395 self._range = kwargs.get('range')
1396 self._units = kwargs.get('units')
1397 self._details = kwargs.get('details')
1398 self._hal_details = kwargs.get('hal_details')
1399 self._ndk_details = kwargs.get('ndk_details')
1401 self._tag_ids = kwargs.get('tag_ids', [])
1402 self._tags = None # Filled in by Metadata::_construct_tags
1404 self._type_notes = kwargs.get('type_notes')
1405 self._type_name = kwargs.get('type_name')
1406 self._typedef = None # Filled in by Metadata::_construct_types
1408 if kwargs.get('enum', False):
1409 self._enum = Enum(self, enum_values, enum_ids, enum_deprecateds, enum_optionals,
1410 enum_hiddens, enum_notes, enum_sdk_notes, enum_ndk_notes, enum_ndk_hiddens, enum_hal_versions)
1414 self._visibility = kwargs.get('visibility')
1415 self._synthetic = kwargs.get('synthetic', False)
1416 self._hwlevel = kwargs.get('hwlevel')
1417 self._deprecated = kwargs.get('deprecated', False)
1418 self._deprecation_description = kwargs.get('deprecation_description')
1420 self._optional = kwargs.get('optional')
1421 self._ndk_visible = kwargs.get('ndk_visible')
1423 self._property_keys = kwargs
1427 Copy the attributes into a new entry, merging it with the target entry
1430 return MergedEntry(self)
1432 # Helpers for accessing less than the fully qualified name
1434 def get_name_as_list(self):
1436 Returns the name as a list split by a period.
1439 entry.name is 'android.lens.info.shading'
1440 entry.get_name_as_list() == ['android', 'lens', 'info', 'shading']
1442 return self.name.split(".")
1444 def get_inner_namespace_list(self):
1446 Returns the inner namespace part of the name as a list
1449 entry.name is 'android.lens.info.shading'
1450 entry.get_inner_namespace_list() == ['info']
1452 return self.get_name_as_list()[2:-1]
1454 def get_outer_namespace(self):
1456 Returns the outer namespace as a string.
1459 entry.name is 'android.lens.info.shading'
1460 entry.get_outer_namespace() == 'android'
1463 Since outer namespaces are non-recursive,
1464 and each entry has one, this does not need to be a list.
1466 return self.get_name_as_list()[0]
1468 def get_section(self):
1470 Returns the section as a string.
1473 entry.name is 'android.lens.info.shading'
1474 entry.get_section() == ''
1477 Since outer namespaces are non-recursive,
1478 and each entry has one, this does not need to be a list.
1480 return self.get_name_as_list()[1]
1482 def get_name_minimal(self):
1484 Returns only the last component of the fully qualified name as a string.
1487 entry.name is 'android.lens.info.shading'
1488 entry.get_name_minimal() == 'shading'
1491 entry.name_short it an alias for this
1493 return self.get_name_as_list()[-1]
1495 def get_path_without_name(self):
1497 Returns a string path to the entry, with the name component excluded.
1500 entry.name is 'android.lens.info.shading'
1501 entry.get_path_without_name() == 'android.lens.info'
1503 return ".".join(self.get_name_as_list()[0:-1])
1508 A Node corresponding to a <clone> element. It has all the attributes of an
1509 <entry> element (Entry) plus the additions specified below.
1511 Attributes (Read-Only):
1512 entry: an edge to an Entry object that this targets
1513 target_kind: A string describing the kind of the target entry.
1514 name: a string of the name, same as entry.name
1515 kind: a string of the Kind ancestor, one of 'static', 'controls', 'dynamic'
1516 for the <clone> element.
1517 type: always None, since a clone cannot override the type.
1519 def __init__(self, entry=None, **kwargs):
1521 Instantiate a new Clone node.
1524 name: A string with the fully qualified name, e.g. 'android.shading.mode'
1525 type: A string describing the type, e.g. 'int32'
1526 kind: A string describing the kind, e.g. 'static'
1527 target_kind: A string for the kind of the target entry, e.g. 'dynamic'
1528 hal_version: A string for the initial HIDL HAL metadata version this entry
1531 Args (if container):
1532 container: A string describing the container, e.g. 'array' or 'tuple'
1533 container_sizes: A list of string sizes if a container, or None otherwise
1535 Args (if container is 'tuple'):
1536 tuple_values: A list of tuple values, e.g. ['width', 'height']
1538 Args (if the 'enum' attribute is true):
1539 enum: A boolean, True if this is an enum, False otherwise
1540 enum_values: A list of value strings, e.g. ['ON', 'OFF']
1541 enum_optionals: A list of optional enum values, e.g. ['OFF']
1542 enum_notes: A dictionary of value->notes strings.
1543 enum_ids: A dictionary of value->id strings.
1546 entry: An edge to the corresponding target Entry.
1547 description: A string with a description of the entry.
1548 range: A string with the range of the values of the entry, e.g. '>= 0'
1549 units: A string with the units of the values, e.g. 'inches'
1550 details: A string with the detailed documentation for the entry
1551 hal_details: A string with the HAL implementation details for the entry
1552 ndk_details: A string with the extra NDK documentation for the entry
1553 tag_ids: A list of tag ID strings, e.g. ['BC', 'V1']
1554 type_notes: A string with the notes for the type
1557 Note that type is not specified since it has to be the same as the
1560 self._entry = entry # Entry object
1561 self._target_kind = kwargs['target_kind']
1562 self._name = kwargs['name'] # same as entry.name
1563 self._kind = kwargs['kind']
1565 # illegal to override the type, it should be the same as the entry
1567 # the rest of the kwargs are optional
1568 # can be used to override the regular entry data
1569 self._init_common(**kwargs)
1576 def target_kind(self):
1577 return self._target_kind
1581 Whether or not this is a Clone instance.
1588 class MergedEntry(Entry):
1590 A MergedEntry has all the attributes of a Clone and its target Entry merged
1594 Useful when we want to 'unfold' a clone into a real entry by copying out
1595 the target entry data. In this case we don't care about distinguishing
1596 a clone vs an entry.
1598 def __init__(self, entry):
1600 Create a new instance of MergedEntry.
1603 entry: An Entry or Clone instance
1605 props_distinct = ['description', 'units', 'range', 'details',
1606 'hal_details', 'ndk_details', 'tags', 'kind',
1607 'deprecation_description']
1609 for p in props_distinct:
1611 if entry.is_clone():
1612 setattr(self, p, getattr(entry, p) or getattr(entry.entry, p))
1614 setattr(self, p, getattr(entry, p))
1616 props_common = ['parent', 'name', 'container',
1617 'container_sizes', 'enum',
1628 'hal_major_version',
1632 for p in props_common:
1634 if entry.is_clone():
1635 setattr(self, p, getattr(entry.entry, p))
1637 setattr(self, p, getattr(entry, p))