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