15f9996aaSopenharmony_ci#!/usr/bin/env python3
25f9996aaSopenharmony_ci# -*- coding: utf-8 -*-
35f9996aaSopenharmony_ci
45f9996aaSopenharmony_ci#
55f9996aaSopenharmony_ci# Copyright (c) 2023 Huawei Device Co., Ltd.
65f9996aaSopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License");
75f9996aaSopenharmony_ci# you may not use this file except in compliance with the License.
85f9996aaSopenharmony_ci# You may obtain a copy of the License at
95f9996aaSopenharmony_ci#
105f9996aaSopenharmony_ci#     http://www.apache.org/licenses/LICENSE-2.0
115f9996aaSopenharmony_ci#
125f9996aaSopenharmony_ci# Unless required by applicable law or agreed to in writing, software
135f9996aaSopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS,
145f9996aaSopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
155f9996aaSopenharmony_ci# See the License for the specific language governing permissions and
165f9996aaSopenharmony_ci# limitations under the License.
175f9996aaSopenharmony_ci
185f9996aaSopenharmony_ciimport os
195f9996aaSopenharmony_ciimport stat
205f9996aaSopenharmony_ci
215f9996aaSopenharmony_cifrom services.interface.preload_interface import PreloadInterface
225f9996aaSopenharmony_cifrom util.io_util import IoUtil
235f9996aaSopenharmony_cifrom util.preloader.preloader_process_data import Dirs, Outputs, Product
245f9996aaSopenharmony_cifrom util.preloader.parse_lite_subsystems_config import parse_lite_subsystem_config
255f9996aaSopenharmony_cifrom util.log_util import LogUtil
265f9996aaSopenharmony_ci
275f9996aaSopenharmony_ci
285f9996aaSopenharmony_ciclass OHOSPreloader(PreloadInterface):
295f9996aaSopenharmony_ci
305f9996aaSopenharmony_ci    def __init__(self):
315f9996aaSopenharmony_ci        super().__init__()
325f9996aaSopenharmony_ci        self._dirs = ""
335f9996aaSopenharmony_ci        self._outputs = ""
345f9996aaSopenharmony_ci        self._product = ""
355f9996aaSopenharmony_ci        self._os_level = ""
365f9996aaSopenharmony_ci        self._target_cpu = ""
375f9996aaSopenharmony_ci        self._target_os = ""
385f9996aaSopenharmony_ci        self._toolchain_label = ""
395f9996aaSopenharmony_ci        self._subsystem_info = {}
405f9996aaSopenharmony_ci        self._all_parts = {}
415f9996aaSopenharmony_ci        self._build_vars = {}
425f9996aaSopenharmony_ci        self._compile_standard_whitelist_info = {}
435f9996aaSopenharmony_ci        self._compile_env_allowlist_info = {}
445f9996aaSopenharmony_ci
455f9996aaSopenharmony_ci    def __post_init__(self):
465f9996aaSopenharmony_ci        self._dirs = Dirs(self._config)
475f9996aaSopenharmony_ci        self._outputs = Outputs(self._dirs.preloader_output_dir)
485f9996aaSopenharmony_ci        self._product = Product(self._dirs, self._config)
495f9996aaSopenharmony_ci        self._all_parts = self._product._parts
505f9996aaSopenharmony_ci        self._build_vars = self._product._build_vars
515f9996aaSopenharmony_ci        self._os_level = self._build_vars.get('os_level')
525f9996aaSopenharmony_ci        self._target_os = self._build_vars.get('target_os')
535f9996aaSopenharmony_ci        self._target_cpu = self._build_vars.get('target_cpu')
545f9996aaSopenharmony_ci        self._toolchain_label = self._build_vars.get('product_toolchain_label')
555f9996aaSopenharmony_ci        self._subsystem_info = self._get_org_subsystem_info()
565f9996aaSopenharmony_ci        self._compile_standard_whitelist_info = self._get_compile_standard_whitelist_info()
575f9996aaSopenharmony_ci        self._compile_env_allowlist_info = self._get_compile_env_allowlist_info()
585f9996aaSopenharmony_ci
595f9996aaSopenharmony_ci# generate method
605f9996aaSopenharmony_ci
615f9996aaSopenharmony_ci    '''Description: generate platforms build info to "out/preloader/{product_name}/platforms.build"
625f9996aaSopenharmony_ci    @parameter:none
635f9996aaSopenharmony_ci    @return :none
645f9996aaSopenharmony_ci    '''
655f9996aaSopenharmony_ci
665f9996aaSopenharmony_ci    def _generate_platforms_build(self):
675f9996aaSopenharmony_ci        config = {
685f9996aaSopenharmony_ci            'target_os': self._target_os,
695f9996aaSopenharmony_ci            "target_cpu": self._target_cpu,
705f9996aaSopenharmony_ci            "toolchain": self._toolchain_label,
715f9996aaSopenharmony_ci            "parts_config": os.path.relpath(self._outputs.parts_json,
725f9996aaSopenharmony_ci                                            self._dirs.preloader_output_dir)
735f9996aaSopenharmony_ci        }
745f9996aaSopenharmony_ci        platform_config = {'version': 2, 'platforms': {'phone': config}}
755f9996aaSopenharmony_ci        IoUtil.dump_json_file(self._outputs.platforms_build, platform_config)
765f9996aaSopenharmony_ci        LogUtil.hb_info(
775f9996aaSopenharmony_ci            'generated platforms build info to {}/platforms.build'.format(
785f9996aaSopenharmony_ci                self._dirs.preloader_output_dir), mode=self.config.log_mode)
795f9996aaSopenharmony_ci
805f9996aaSopenharmony_ci    '''Description: generate build gnargs prop info to "out/preloader/{product_name}/build_gnargs.prop"
815f9996aaSopenharmony_ci    @parameter:none
825f9996aaSopenharmony_ci    @return :none
835f9996aaSopenharmony_ci    '''
845f9996aaSopenharmony_ci
855f9996aaSopenharmony_ci    def _generate_build_gnargs_prop(self):
865f9996aaSopenharmony_ci        all_features = {}
875f9996aaSopenharmony_ci        for _part_name, vals in self._all_parts.items():
885f9996aaSopenharmony_ci            _features = vals.get('features')
895f9996aaSopenharmony_ci            if _features:
905f9996aaSopenharmony_ci                all_features.update(_features)
915f9996aaSopenharmony_ci        attr_list = []
925f9996aaSopenharmony_ci        for key, val in all_features.items():
935f9996aaSopenharmony_ci            _item = ''
945f9996aaSopenharmony_ci            if isinstance(val, bool):
955f9996aaSopenharmony_ci                _item = f'{key}={str(val).lower()}'
965f9996aaSopenharmony_ci            elif isinstance(val, int):
975f9996aaSopenharmony_ci                _item = f'{key}={val}'
985f9996aaSopenharmony_ci            elif isinstance(val, str):
995f9996aaSopenharmony_ci                _item = f'{key}="{val}"'
1005f9996aaSopenharmony_ci            else:
1015f9996aaSopenharmony_ci                raise Exception("part feature '{key}:{val}' type not support.")
1025f9996aaSopenharmony_ci            attr_list.append(_item)
1035f9996aaSopenharmony_ci        with os.fdopen(os.open(self._outputs.build_gnargs_prop,
1045f9996aaSopenharmony_ci                               os.O_RDWR | os.O_CREAT, stat.S_IWUSR | stat.S_IRUSR), 'w') as fobj:
1055f9996aaSopenharmony_ci            fobj.write('\n'.join(attr_list))
1065f9996aaSopenharmony_ci        LogUtil.hb_info(
1075f9996aaSopenharmony_ci            'generated build gnargs prop info to {}/build_gnargs.prop'.format(
1085f9996aaSopenharmony_ci                self._dirs.preloader_output_dir), mode=self.config.log_mode)
1095f9996aaSopenharmony_ci
1105f9996aaSopenharmony_ci    '''Description: generate features to "out/preloader/{product_name}/features.json"
1115f9996aaSopenharmony_ci    @parameter:none
1125f9996aaSopenharmony_ci    @return :none
1135f9996aaSopenharmony_ci    '''
1145f9996aaSopenharmony_ci
1155f9996aaSopenharmony_ci    def _generate_features_json(self):
1165f9996aaSopenharmony_ci        all_features = {}
1175f9996aaSopenharmony_ci        part_feature_map = {}
1185f9996aaSopenharmony_ci        for _part_name, vals in self._all_parts.items():
1195f9996aaSopenharmony_ci            _features = vals.get('features')
1205f9996aaSopenharmony_ci            if _features:
1215f9996aaSopenharmony_ci                all_features.update(_features)
1225f9996aaSopenharmony_ci            if _features:
1235f9996aaSopenharmony_ci                part_feature_map[_part_name.split(
1245f9996aaSopenharmony_ci                    ':')[1]] = list(_features.keys())
1255f9996aaSopenharmony_ci        parts_feature_info = {
1265f9996aaSopenharmony_ci            "features": all_features,
1275f9996aaSopenharmony_ci            "part_to_feature": part_feature_map
1285f9996aaSopenharmony_ci        }
1295f9996aaSopenharmony_ci        IoUtil.dump_json_file(self._outputs.features_json, parts_feature_info)
1305f9996aaSopenharmony_ci        LogUtil.hb_info(
1315f9996aaSopenharmony_ci            'generated features info to {}/features.json'.format(
1325f9996aaSopenharmony_ci                self._dirs.preloader_output_dir), mode=self.config.log_mode)
1335f9996aaSopenharmony_ci
1345f9996aaSopenharmony_ci    '''Description: generate syscap to "out/preloader/product_name/syscap.json"
1355f9996aaSopenharmony_ci    @parameter:none
1365f9996aaSopenharmony_ci    @return :none
1375f9996aaSopenharmony_ci    '''
1385f9996aaSopenharmony_ci
1395f9996aaSopenharmony_ci    def _generate_syscap_json(self):
1405f9996aaSopenharmony_ci        all_syscap = {}
1415f9996aaSopenharmony_ci        part_syscap_map = {}
1425f9996aaSopenharmony_ci        for _part_name, vals in self._all_parts.items():
1435f9996aaSopenharmony_ci            _syscap = vals.get('syscap')
1445f9996aaSopenharmony_ci            if _syscap:
1455f9996aaSopenharmony_ci                all_syscap.update(_syscap)
1465f9996aaSopenharmony_ci                part_syscap_map[_part_name.split(':')[1]] = _syscap
1475f9996aaSopenharmony_ci        parts_syscap_info = {
1485f9996aaSopenharmony_ci            "syscap": all_syscap,
1495f9996aaSopenharmony_ci            "part_to_syscap": part_syscap_map
1505f9996aaSopenharmony_ci        }
1515f9996aaSopenharmony_ci        IoUtil.dump_json_file(self._outputs.syscap_json, parts_syscap_info)
1525f9996aaSopenharmony_ci        LogUtil.hb_info(
1535f9996aaSopenharmony_ci            'generated syscap info to {}/syscap.json'.format(
1545f9996aaSopenharmony_ci                self._dirs.preloader_output_dir), mode=self.config.log_mode)
1555f9996aaSopenharmony_ci
1565f9996aaSopenharmony_ci    '''Description: generate exclusion modules info to "out/preloader/product_name/exclusion_modules.json"
1575f9996aaSopenharmony_ci    @parameter:none
1585f9996aaSopenharmony_ci    @return :none
1595f9996aaSopenharmony_ci    '''
1605f9996aaSopenharmony_ci
1615f9996aaSopenharmony_ci    def _generate_exclusion_modules_json(self):
1625f9996aaSopenharmony_ci        exclusions = {}
1635f9996aaSopenharmony_ci        for _part_name, vals in self._all_parts.items():
1645f9996aaSopenharmony_ci            _exclusions = vals.get('exclusions')
1655f9996aaSopenharmony_ci            if _exclusions:
1665f9996aaSopenharmony_ci                pair = dict()
1675f9996aaSopenharmony_ci                pair[_part_name] = _exclusions
1685f9996aaSopenharmony_ci                exclusions.update(pair)
1695f9996aaSopenharmony_ci        IoUtil.dump_json_file(self._outputs.exclusion_modules_json, exclusions)
1705f9996aaSopenharmony_ci        LogUtil.hb_info(
1715f9996aaSopenharmony_ci            'generated exclusion modules info to {}/exclusion_modules.json'.format(
1725f9996aaSopenharmony_ci                self._dirs.preloader_output_dir), mode=self.config.log_mode)
1735f9996aaSopenharmony_ci
1745f9996aaSopenharmony_ci    '''Description: generate build config info to "out/preloader/product_name/build_config.json"
1755f9996aaSopenharmony_ci    @parameter:none
1765f9996aaSopenharmony_ci    @return :none
1775f9996aaSopenharmony_ci    '''
1785f9996aaSopenharmony_ci
1795f9996aaSopenharmony_ci    def _generate_build_config_json(self):
1805f9996aaSopenharmony_ci        IoUtil.dump_json_file(
1815f9996aaSopenharmony_ci            self._outputs.build_config_json, self._build_vars)
1825f9996aaSopenharmony_ci        LogUtil.hb_info(
1835f9996aaSopenharmony_ci            'generated build config info to {}/build_config.json'.format(
1845f9996aaSopenharmony_ci                self._dirs.preloader_output_dir), mode=self.config.log_mode)
1855f9996aaSopenharmony_ci
1865f9996aaSopenharmony_ci    '''Description: generate build prop info to "out/preloader/product_name/build.prop"
1875f9996aaSopenharmony_ci    @parameter:none
1885f9996aaSopenharmony_ci    @return :none
1895f9996aaSopenharmony_ci    '''
1905f9996aaSopenharmony_ci
1915f9996aaSopenharmony_ci    def _generate_build_prop(self):
1925f9996aaSopenharmony_ci        build_vars_list = []
1935f9996aaSopenharmony_ci        for key, value in self._build_vars.items():
1945f9996aaSopenharmony_ci            build_vars_list.append('{}={}'.format(key, value))
1955f9996aaSopenharmony_ci        with os.fdopen(os.open(self._outputs.build_prop,
1965f9996aaSopenharmony_ci                               os.O_RDWR | os.O_CREAT, stat.S_IWUSR | stat.S_IRUSR), 'w') as fobj:
1975f9996aaSopenharmony_ci            fobj.write('\n'.join(build_vars_list))
1985f9996aaSopenharmony_ci        LogUtil.hb_info(
1995f9996aaSopenharmony_ci            'generated build prop info to {}/build.prop'.format(
2005f9996aaSopenharmony_ci                self._dirs.preloader_output_dir), mode=self.config.log_mode)
2015f9996aaSopenharmony_ci
2025f9996aaSopenharmony_ci    '''Description: generate parts to "out/preloader/product_name/parts.json"
2035f9996aaSopenharmony_ci    @parameter:none
2045f9996aaSopenharmony_ci    @return :none
2055f9996aaSopenharmony_ci    '''
2065f9996aaSopenharmony_ci
2075f9996aaSopenharmony_ci    def _generate_parts_json(self):
2085f9996aaSopenharmony_ci        parts_info = {"parts": sorted(list(self._all_parts.keys()))}
2095f9996aaSopenharmony_ci        IoUtil.dump_json_file(self._outputs.parts_json, parts_info)
2105f9996aaSopenharmony_ci        LogUtil.hb_info(
2115f9996aaSopenharmony_ci            'generated product parts info to {}/parts.json'.format(
2125f9996aaSopenharmony_ci                self._dirs.preloader_output_dir), mode=self.config.log_mode)
2135f9996aaSopenharmony_ci
2145f9996aaSopenharmony_ci    '''Description: generate parts config to "out/preloader/product_name/parts_config.json"
2155f9996aaSopenharmony_ci    @parameter:none
2165f9996aaSopenharmony_ci    @return :none
2175f9996aaSopenharmony_ci    '''
2185f9996aaSopenharmony_ci
2195f9996aaSopenharmony_ci    def _generate_parts_config_json(self):
2205f9996aaSopenharmony_ci        parts_config = {}
2215f9996aaSopenharmony_ci        for part in self._all_parts:
2225f9996aaSopenharmony_ci            part = part.replace(":", "_")
2235f9996aaSopenharmony_ci            part = part.replace("-", "_")
2245f9996aaSopenharmony_ci            part = part.replace(".", "_")
2255f9996aaSopenharmony_ci            part = part.replace("/", "_")
2265f9996aaSopenharmony_ci            parts_config[part] = True
2275f9996aaSopenharmony_ci        IoUtil.dump_json_file(self._outputs.parts_config_json, parts_config)
2285f9996aaSopenharmony_ci        LogUtil.hb_info(
2295f9996aaSopenharmony_ci            'generated parts config info to {}/parts_config.json'.format(
2305f9996aaSopenharmony_ci                self._dirs.preloader_output_dir), mode=self.config.log_mode)
2315f9996aaSopenharmony_ci
2325f9996aaSopenharmony_ci    '''Description: generate subsystem config info to "out/preloader/product_name/subsystem_config.json"
2335f9996aaSopenharmony_ci    @parameter:none
2345f9996aaSopenharmony_ci    @return :none
2355f9996aaSopenharmony_ci    '''
2365f9996aaSopenharmony_ci
2375f9996aaSopenharmony_ci    def _generate_subsystem_config_json(self):
2385f9996aaSopenharmony_ci        if self._subsystem_info:
2395f9996aaSopenharmony_ci            self._subsystem_info.update(
2405f9996aaSopenharmony_ci                self._product._get_product_specific_subsystem())
2415f9996aaSopenharmony_ci            self._subsystem_info.update(
2425f9996aaSopenharmony_ci                self._product._get_device_specific_subsystem())
2435f9996aaSopenharmony_ci        IoUtil.dump_json_file(
2445f9996aaSopenharmony_ci            self._outputs.subsystem_config_json, self._subsystem_info)
2455f9996aaSopenharmony_ci        LogUtil.hb_info(
2465f9996aaSopenharmony_ci            'generated subsystem config info to {}/subsystem_config.json'.format(
2475f9996aaSopenharmony_ci                self._dirs.preloader_output_dir), mode=self.config.log_mode)
2485f9996aaSopenharmony_ci
2495f9996aaSopenharmony_ci    '''Description: generate systemcapability_json to "out/preloader/product_name/systemcapability.json"
2505f9996aaSopenharmony_ci    @parameter:none
2515f9996aaSopenharmony_ci    @return :none
2525f9996aaSopenharmony_ci    '''
2535f9996aaSopenharmony_ci
2545f9996aaSopenharmony_ci    def _generate_systemcapability_json(self):
2555f9996aaSopenharmony_ci        IoUtil.dump_json_file(
2565f9996aaSopenharmony_ci            self._outputs.systemcapability_json, self._product._syscap_info)
2575f9996aaSopenharmony_ci        LogUtil.hb_info(
2585f9996aaSopenharmony_ci            'generated system capability info to {}/systemcapability.json'.format(
2595f9996aaSopenharmony_ci                self._dirs.preloader_output_dir), mode=self.config.log_mode)
2605f9996aaSopenharmony_ci
2615f9996aaSopenharmony_ci    '''Description: generate compile_standard_whitelist info  to "out/preloader/product_name/compile_standard_whitelist.json"
2625f9996aaSopenharmony_ci    @parameter:none
2635f9996aaSopenharmony_ci    @return :none
2645f9996aaSopenharmony_ci    '''
2655f9996aaSopenharmony_ci
2665f9996aaSopenharmony_ci    def _generate_compile_standard_whitelist_json(self):
2675f9996aaSopenharmony_ci        IoUtil.dump_json_file(
2685f9996aaSopenharmony_ci            self._outputs.compile_standard_whitelist_json, self._compile_standard_whitelist_info)
2695f9996aaSopenharmony_ci        LogUtil.hb_info(
2705f9996aaSopenharmony_ci            'generated compile_standard_whitelist info to {}/compile_standard_whitelist.json'
2715f9996aaSopenharmony_ci            .format(self._dirs.preloader_output_dir), mode=self.config.log_mode)
2725f9996aaSopenharmony_ci
2735f9996aaSopenharmony_ci    def _generate_compile_env_allowlist_json(self):
2745f9996aaSopenharmony_ci        IoUtil.dump_json_file(
2755f9996aaSopenharmony_ci            self._outputs.compile_env_allowlist_json, self._compile_env_allowlist_info
2765f9996aaSopenharmony_ci        )
2775f9996aaSopenharmony_ci        LogUtil.hb_info(
2785f9996aaSopenharmony_ci            "generated compile_env_allowlist info to {}/compile_env_allowlist.json".format(
2795f9996aaSopenharmony_ci                self._dirs.preloader_output_dir
2805f9996aaSopenharmony_ci            )
2815f9996aaSopenharmony_ci        )
2825f9996aaSopenharmony_ci
2835f9996aaSopenharmony_ci# get method
2845f9996aaSopenharmony_ci
2855f9996aaSopenharmony_ci    def _get_org_subsystem_info(self) -> dict:
2865f9996aaSopenharmony_ci        subsystem_info = {}
2875f9996aaSopenharmony_ci        if self._os_level == "standard":
2885f9996aaSopenharmony_ci            subsystem_info = IoUtil.read_json_file(
2895f9996aaSopenharmony_ci                self._dirs.subsystem_config_json)
2905f9996aaSopenharmony_ci        elif self._os_level == "mini" or self._os_level == "small":
2915f9996aaSopenharmony_ci            ohos_build_output_dir = os.path.join(self._dirs.preloader_output_dir,
2925f9996aaSopenharmony_ci                                                 '{}_system'.format(self._os_level))
2935f9996aaSopenharmony_ci            subsystem_info = parse_lite_subsystem_config(
2945f9996aaSopenharmony_ci                self._dirs.lite_components_dir, ohos_build_output_dir,
2955f9996aaSopenharmony_ci                self._dirs.source_root_dir, self._dirs.subsystem_config_json)
2965f9996aaSopenharmony_ci        return subsystem_info
2975f9996aaSopenharmony_ci
2985f9996aaSopenharmony_ci    def _get_compile_standard_whitelist_info(self) -> dict:
2995f9996aaSopenharmony_ci        allow_info_file = "out/products_ext/{}/compile_standard_whitelist.json".format(self.config.product)
3005f9996aaSopenharmony_ci        allow_info_file = os.path.join(self._dirs.source_root_dir, allow_info_file)
3015f9996aaSopenharmony_ci        if not os.path.exists(allow_info_file):
3025f9996aaSopenharmony_ci            allow_info_file = os.path.join(self._dirs.source_root_dir, "build/compile_standard_whitelist.json")
3035f9996aaSopenharmony_ci
3045f9996aaSopenharmony_ci        allow_info = IoUtil.read_json_file(allow_info_file)
3055f9996aaSopenharmony_ci        return allow_info
3065f9996aaSopenharmony_ci
3075f9996aaSopenharmony_ci    def _get_compile_env_allowlist_info(self) -> dict:
3085f9996aaSopenharmony_ci        allow_env_file = os.path.join(
3095f9996aaSopenharmony_ci            self._dirs.source_root_dir,
3105f9996aaSopenharmony_ci            "out/products_ext/{}/compile_env_allowlist.json".format(
3115f9996aaSopenharmony_ci                self.config.product
3125f9996aaSopenharmony_ci            ),
3135f9996aaSopenharmony_ci        )
3145f9996aaSopenharmony_ci        if not os.path.exists(allow_env_file):
3155f9996aaSopenharmony_ci            allow_env_file = os.path.join(
3165f9996aaSopenharmony_ci                self._dirs.source_root_dir, "build/compile_env_allowlist.json"
3175f9996aaSopenharmony_ci            )
3185f9996aaSopenharmony_ci
3195f9996aaSopenharmony_ci        if not os.path.exists(allow_env_file):
3205f9996aaSopenharmony_ci            return {}
3215f9996aaSopenharmony_ci
3225f9996aaSopenharmony_ci        allow_env = IoUtil.read_json_file(allow_env_file)
3235f9996aaSopenharmony_ci        return allow_env
324