• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2#coding=utf-8
3
4#
5# Copyright (c) 2025 Huawei Device Co., Ltd.
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
9#
10#     http://www.apache.org/licenses/LICENSE-2.0
11#
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.
17#
18
19import os
20import json
21
22from .base_rule import BaseRule
23
24
25class PassthroughRule(BaseRule):
26    RULE_NAME = "Passthrough"
27
28    def __init__(self, mgr, args):
29        super().__init__(mgr, args)
30        self.__out_path = mgr.get_product_out_path()
31        self.__white_lists = self.load_passthrough_json("passthrough_info.json")
32        self.__ignored_tags = ["platformsdk", "sasdk", "platformsdk_indirect", "ndk"]
33        self.__valid_mod_tags = ["llndk", "chipsetsdk_sp", "passthrough", "passthrough_indirect"] + self.__ignored_tags
34
35    def get_white_lists(self):
36        return self.__white_lists
37
38    def get_out_path(self):
39        return self.__out_path
40
41    def load_passthrough_json(self, name):
42        rules_dir = []
43        rules_dir.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../rules"))
44        if self._args and self._args.rules:
45            self.log("****add more ChipsetSDK info in:{}****".format(self._args.rules))
46            rules_dir = rules_dir + self._args.rules
47
48        chipsetsdk_rules_path = self.get_out_path().replace("out", "out/products_ext")
49        if os.path.exists(chipsetsdk_rules_path):
50            self.log("****add more ChipsetSDK info in dir:{}****".format(chipsetsdk_rules_path))
51            rules_dir.append(chipsetsdk_rules_path)
52        else:
53            self.warn("****add chipsetsdk_rules_path path not exist: {}****".format(chipsetsdk_rules_path))
54        res = []
55        for d in rules_dir:
56            rules_file = os.path.join(d, self.__class__.RULE_NAME, name)
57            if os.path.isfile(rules_file):
58                res = self.__parser_rules_file(rules_file, res)
59            else:
60                self.warn("****rules path not exist: {}****".format(rules_file))
61
62        return res
63
64    def check(self):
65        self.__load_passthrough_indirects()
66        white_lists = self.get_white_lists()
67
68        # Check if all chipset modules depends on chipsetsdk modules only
69        passed = self.__check_depends_on_passthrough()
70        self.log(f"****check_depends_on_chipsetsdk result:{passed}****")
71        if not passed:
72            return passed
73
74        # Check if all ChipsetSDK modules are correctly tagged by innerapi_tags
75        passed = self.__check_if_passthrough_tagged_correctly()
76        self.log(f"****check_if_tagged_correctly result:{passed}****")
77        if not passed:
78            return passed
79
80        passed = self.check_if_deps_correctly(
81            self.__modules_with_passthrough_tag, self.__valid_mod_tags, self.__valid_mod_tags, white_lists)
82        self.log(f"****check_if_deps_correctly result:{passed}****")
83        if not passed:
84            return passed
85
86        passed = self.check_if_deps_correctly(
87            self.__modules_with_passthrough_tag, self.__valid_mod_tags, self.__valid_mod_tags, self.__indirects)
88        self.log(f"****check_if_deps_correctly indirect result:{passed}****")
89        if not passed:
90            return passed
91
92        self.__write_innerkits_header_files()
93
94        return True
95
96    def __parser_rules_file(self, rules_file, res):
97        try:
98            self.log("****Parsing rules file in {}****".format(rules_file))
99            with open(rules_file, "r") as f:
100                contents = f.read()
101            if not contents:
102                self.log("****rules file {} is null****".format(rules_file))
103                return res
104            json_data = json.loads(contents)
105            for so in json_data:
106                so_file_name = so.get("so_file_name")
107                if so_file_name and so_file_name not in res:
108                    res.append(so_file_name)
109        except (FileNotFoundError, IOError, UnicodeDecodeError) as file_open_or_decode_err:
110            self.error(file_open_or_decode_err)
111
112        return res
113
114    def __is_passthrough_tagged(self, mod):
115        if not "innerapi_tags" in mod:
116            return False
117        if "passthrough" in mod["innerapi_tags"]:
118            return True
119        return False
120
121    def __is_passthrough_indirect(self, mod):
122        if not "innerapi_tags" in mod:
123            return False
124        if "passthrough_indirect" in mod["innerapi_tags"]:
125            return True
126        return False
127
128    def __write_innerkits_header_files(self):
129        inner_kits_info = os.path.join(self.get_mgr().get_product_out_path(),
130                                       "build_configs/parts_info/inner_kits_info.json")
131        with open(inner_kits_info, "r") as f:
132            info = json.load(f)
133
134        headers = []
135        for sdk in self.__passthroughs:
136            path = sdk["labelPath"][:sdk["labelPath"].find(":")]
137            target_name = sdk["labelPath"][sdk["labelPath"].find(":") + 1:]
138            item = {"name": sdk["componentName"] + ":" + target_name, "so_file_name":
139                    sdk["name"], "path": sdk["labelPath"], "headers": []}
140            if sdk["componentName"] not in info:
141                headers.append(item)
142                continue
143
144            for name, innerapi in info[sdk["componentName"]].items():
145                if innerapi["label"] != sdk["labelPath"]:
146                    continue
147                got_headers = True
148                base = innerapi["header_base"]
149                for f in innerapi["header_files"]:
150                    item["headers"].append(os.path.join(base, f))
151            headers.append(item)
152
153        return headers
154
155    def __check_depends_on_passthrough(self):
156        lists = self.get_white_lists()
157
158        passed = True
159
160        self.__passthroughs = []
161        self.__modules_with_passthrough_tag = []
162        self.__modules_with_passthrough_indirect_tag = []
163
164        # Check if any napi modules has dependedBy
165        for mod in self.get_mgr().get_all():
166            # Collect all modules with passthrough tag
167            if self.__is_passthrough_tagged(mod):
168                self.__modules_with_passthrough_tag.append(mod)
169
170            # Collect all modules with passthrough_indirect tag
171            if self.__is_passthrough_indirect(mod):
172                self.__modules_with_passthrough_indirect_tag.append(mod)
173
174            # Check chipset modules only
175            if mod["path"].startswith("vendor"):
176                continue
177
178            # Check passthrough so only
179            if not mod["path"].endswith("so"):
180                continue
181
182            # Check chipset modules depends
183            for dep in mod["deps"]:
184                callee = dep["callee"]
185
186                # If callee is chipset module, it is OK
187                if not callee["path"].startswith("vendor"):
188                    continue
189
190                # Add to list
191                if callee not in self.__passthroughs:
192                    if "hdiType" not in callee or callee["hdiType"] != "hdi_proxy":
193                        self.__passthroughs.append(callee)
194
195                # If callee is in passthroughwhite list module, it is OK
196                if callee["name"] in lists:
197                    continue
198
199                # If callee is asan library, it is OK
200                if callee["name"].endswith(".asan.so"):
201                    continue
202
203                # If callee is hdi proxy module, it is OK
204                if "hdiType" in callee and callee["hdiType"] == "hdi_proxy":
205                    continue
206
207                # Not allowed
208                passed = True
209                self.error("NEED MODIFY: passthrough module %s in %s depends on non passthrough module %s in %s"
210                           % (mod["name"], mod["labelPath"], callee["name"], mod["labelPath"]))
211
212        return passed
213
214    def __check_if_passthrough_tagged_correctly(self):
215        passed = True
216        for mod in self.__passthroughs:
217            if not self.__is_passthrough_tagged(mod):
218                self.warn('passthrough module %s has no innerapi_tags with "passthrough", add it in %s'
219                          % (mod["name"], mod["labelPath"]))
220
221        for mod in self.__modules_with_passthrough_tag:
222            if mod["name"] not in self.get_white_lists():
223                passed = True
224                self.error('NEED MODIFY: non passthrough %s with innerapi_tags="passthrough", %s'
225                           % (mod["name"], mod["labelPath"]))
226
227        for mod in self.__modules_with_passthrough_indirect_tag:
228            if mod["name"] not in self.__indirects and mod["name"] not in self.get_white_lists():
229                self.warn('non passthrough_indirect module %s with innerapi_tags="passthrough_indirect", %s'
230                          % (mod["name"], mod["labelPath"]))
231
232        return passed
233
234    def __load_passthrough_indirects(self):
235        self.__indirects = self.load_passthrough_json("passthrough_indirect.json")
236