Loading scripts/hiddenapi/analyze_bcpf.py +227 −215 Original line number Diff line number Diff line Loading @@ -394,13 +394,17 @@ class BcpfAnalyzer: def reformat_report_test(text): return re.sub(r"(.)\n([^\s])", r"\1 \2", text) def report(self, text, **kwargs): def report(self, text="", **kwargs): # Concatenate lines that are not separated by a blank line together to # eliminate formatting applied to the supplied text to adhere to python # line length limitations. text = self.reformat_report_test(text) logging.info("%s", text, **kwargs) def report_dedent(self, text, **kwargs): text = textwrap.dedent(text) self.report(text, **kwargs) def run_command(self, cmd, *args, **kwargs): cmd_line = " ".join(cmd) logging.debug("Running %s", cmd_line) Loading Loading @@ -442,9 +446,7 @@ class BcpfAnalyzer: def load_module_info(self): module_info_file = os.path.join(self.product_out_dir, "module-info.json") self.report(f""" Making sure that {module_info_file} is up to date. """) self.report(f"\nMaking sure that {module_info_file} is up to date.\n") output = self.build_file_read_output(module_info_file) lines = output.lines() for line in lines: Loading Loading @@ -496,17 +498,17 @@ Making sure that {module_info_file} is up to date. optimizations that can be applied. """ self.report(f"Analyzing bootclasspath_fragment module {self.bcpf}") self.report(f""" Run this tool to help initialize a bootclasspath_fragment module. Before you start make sure that: self.report_dedent(f""" Run this tool to help initialize a bootclasspath_fragment module. Before you start make sure that: 1. The current checkout is up to date. 2. The environment has been initialized using lunch, e.g. lunch aosp_arm64-userdebug 3. You have added a bootclasspath_fragment module to the appropriate Android.bp file. Something like this: 3. You have added a bootclasspath_fragment module to the appropriate Android.bp file. Something like this: bootclasspath_fragment {{ name: "{self.bcpf}", Loading @@ -514,7 +516,8 @@ file. Something like this: "...", ], // The bootclasspath_fragments that provide APIs on which this depends. // The bootclasspath_fragments that provide APIs on which this // depends. fragments: [ {{ apex: "com.android.art", Loading Loading @@ -548,7 +551,7 @@ frameworks/base/boot/Android.bp. Something like this: # Make sure that the module-info.json file is up to date. self.load_module_info() self.report(""" self.report_dedent(""" Cleaning potentially stale files. """) # Remove the out/soong/hiddenapi files. Loading Loading @@ -605,26 +608,26 @@ merge these properties into it. if result.file_changes: if self.fix: file_change_message = """ The following files were modified by this script:""" file_change_message = textwrap.dedent(""" The following files were modified by this script: """) else: file_change_message = """ The following modifications need to be made:""" file_change_message = textwrap.dedent(""" The following modifications need to be made: """) self.report(f""" {file_change_message}""") self.report(file_change_message) result.file_changes.sort() for file_change in result.file_changes: self.report(f""" {file_change.path} {file_change.description} """.lstrip("\n")) self.report(f" {file_change.path}") self.report(f" {file_change.description}") self.report() if not self.fix: self.report(""" Run the command again with the --fix option to automatically make the above changes. """.lstrip()) self.report_dedent(""" Run the command again with the --fix option to automatically make the above changes. """.lstrip("\n")) def new_file_change(self, file, description): return FileChange( Loading @@ -635,11 +638,10 @@ changes. if not (module_line.startswith("< ") and monolithic_line.startswith("> ") and not separator_line): # Something went wrong. self.report(f"""Invalid build output detected: module_line: "{module_line}" monolithic_line: "{monolithic_line}" separator_line: "{separator_line}" """) self.report("Invalid build output detected:") self.report(f" module_line: '{module_line}'") self.report(f" monolithic_line: '{monolithic_line}'") self.report(f" separator_line: '{separator_line}'") sys.exit(1) if significant: Loading Loading @@ -698,10 +700,9 @@ changes. if module_signature != monolithic_signature: # Something went wrong. self.report(f"""Inconsistent signatures detected: module_signature: "{module_signature}" monolithic_signature: "{monolithic_signature}" """) self.report("Inconsistent signatures detected:") self.report(f" module_signature: '{module_signature}'") self.report(f" monolithic_signature: '{monolithic_signature}'") sys.exit(1) diffs[module_signature] = (module_flags, monolithic_flags) Loading Loading @@ -749,7 +750,7 @@ changes. return diffs def build_monolithic_stubs_flags(self): self.report(f""" self.report_dedent(f""" Attempting to build {_STUB_FLAGS_FILE} to verify that the bootclasspath_fragment has the correct API stubs available... """) Loading @@ -757,28 +758,32 @@ bootclasspath_fragment has the correct API stubs available... # Build the hiddenapi-stubs-flags.txt file. diffs = self.build_hiddenapi_flags(_STUB_FLAGS_FILE) if diffs: self.report(f""" There is a discrepancy between the stub API derived flags created by the bootclasspath_fragment and the platform_bootclasspath. See preceding error messages to see which flags are inconsistent. The inconsistencies can occur for self.report_dedent(f""" There is a discrepancy between the stub API derived flags created by the bootclasspath_fragment and the platform_bootclasspath. See preceding error messages to see which flags are inconsistent. The inconsistencies can occur for a couple of reasons: If you are building against prebuilts of the Android SDK, e.g. by using TARGET_BUILD_APPS then the prebuilt versions of the APIs this bootclasspath_fragment depends upon are out of date and need updating. See go/update-prebuilts for help. If you are building against prebuilts of the Android SDK, e.g. by using TARGET_BUILD_APPS then the prebuilt versions of the APIs this bootclasspath_fragment depends upon are out of date and need updating. See go/update-prebuilts for help. Otherwise, this is happening because there are some stub APIs that are either provided by or used by the contents of the bootclasspath_fragment but which are not available to it. There are 4 ways to handle this: Otherwise, this is happening because there are some stub APIs that are either provided by or used by the contents of the bootclasspath_fragment but which are not available to it. There are 4 ways to handle this: 1. A java_sdk_library in the contents property will automatically make its stub APIs available to the bootclasspath_fragment so nothing needs to be done. 1. A java_sdk_library in the contents property will automatically make its stub APIs available to the bootclasspath_fragment so nothing needs to be done. 2. If the API provided by the bootclasspath_fragment is created by an api_only java_sdk_library (or a java_library that compiles files generated by a separate droidstubs module then it cannot be added to the contents and instead must be added to the api.stubs property, e.g. 2. If the API provided by the bootclasspath_fragment is created by an api_only java_sdk_library (or a java_library that compiles files generated by a separate droidstubs module then it cannot be added to the contents and instead must be added to the api.stubs property, e.g. bootclasspath_fragment {{ name: "{self.bcpf}", Loading @@ -788,8 +793,9 @@ not available to it. There are 4 ways to handle this: }}, }} 3. If the contents use APIs provided by another bootclasspath_fragment then it needs to be added to the fragments property, e.g. 3. If the contents use APIs provided by another bootclasspath_fragment then it needs to be added to the fragments property, e.g. bootclasspath_fragment {{ name: "{self.bcpf}", Loading @@ -804,9 +810,9 @@ not available to it. There are 4 ways to handle this: ], }} 4. If the contents use APIs from a module that is not part of another bootclasspath_fragment then it must be added to the additional_stubs property, e.g. 4. If the contents use APIs from a module that is not part of another bootclasspath_fragment then it must be added to the additional_stubs property, e.g. bootclasspath_fragment {{ name: "{self.bcpf}", Loading @@ -814,17 +820,18 @@ not available to it. There are 4 ways to handle this: additional_stubs: ["android-non-updatable"], }} Like the api.stubs property these are typically java_sdk_library modules but can be java_library too. Like the api.stubs property these are typically java_sdk_library modules but can be java_library too. Note: The "android-non-updatable" is treated as if it was a java_sdk_library which it is not at the moment but will be in future. Note: The "android-non-updatable" is treated as if it was a java_sdk_library which it is not at the moment but will be in future. """) return diffs def build_monolithic_flags(self, result): self.report(f""" self.report_dedent(f""" Attempting to build {_FLAGS_FILE} to verify that the bootclasspath_fragment has the correct hidden API flags... """) Loading @@ -838,30 +845,32 @@ bootclasspath_fragment has the correct hidden API flags... self.load_all_flags() if result.diffs: self.report(f""" There is a discrepancy between the hidden API flags created by the bootclasspath_fragment and the platform_bootclasspath. See preceding error messages to see which flags are inconsistent. The inconsistencies can occur for a couple of reasons: If you are building against prebuilts of this bootclasspath_fragment then the prebuilt version of the sdk snapshot (specifically the hidden API flag files) are inconsistent with the prebuilt version of the apex {self.apex}. Please ensure that they are both updated from the same build. 1. There are custom hidden API flags specified in the one of the files in frameworks/base/boot/hiddenapi which apply to the bootclasspath_fragment but which are not supplied to the bootclasspath_fragment module. 2. The bootclasspath_fragment specifies invalid "package_prefixes" or "split_packages" properties that match packages and classes that it does not self.report_dedent(f""" There is a discrepancy between the hidden API flags created by the bootclasspath_fragment and the platform_bootclasspath. See preceding error messages to see which flags are inconsistent. The inconsistencies can occur for a couple of reasons: If you are building against prebuilts of this bootclasspath_fragment then the prebuilt version of the sdk snapshot (specifically the hidden API flag files) are inconsistent with the prebuilt version of the apex {self.apex}. Please ensure that they are both updated from the same build. 1. There are custom hidden API flags specified in the one of the files in frameworks/base/boot/hiddenapi which apply to the bootclasspath_fragment but which are not supplied to the bootclasspath_fragment module. 2. The bootclasspath_fragment specifies invalid "split_packages", "single_packages" and/of "package_prefixes" properties that match packages and classes that it does not provide. """) # Check to see if there are any hiddenapi related properties that # need to be added to the self.report(""" self.report_dedent(""" Checking custom hidden API flags.... """) self.check_frameworks_base_boot_hidden_api_files(result) Loading Loading @@ -1060,24 +1069,25 @@ Checking custom hidden API flags.... )) if split_packages: self.report(f""" bootclasspath_fragment {self.bcpf} contains classes in packages that also contain classes provided by other sources, those packages are called split packages. Split packages should be avoided where possible but are often self.report_dedent(f""" bootclasspath_fragment {self.bcpf} contains classes in packages that also contain classes provided by other bootclasspath modules. Those packages are called split packages. Split packages should be avoided where possible but are often unavoidable when modularizing existing code. The hidden api processing needs to know which packages are split (and conversely which are not) so that it can optimize the hidden API flags to remove unnecessary implementation details. """) self.report(""" By default (for backwards compatibility) the bootclasspath_fragment assumes that all packages are split unless one of the package_prefixes or split_packages properties are specified. While that is safe it is not optimal and can lead to unnecessary implementation details leaking into the hidden API flags. Adding an empty split_packages property allows the flags to be optimized and remove any unnecessary implementation details. The hidden api processing needs to know which packages are split (and conversely which are not) so that it can optimize the hidden API flags to remove unnecessary implementation details. By default (for backwards compatibility) the bootclasspath_fragment assumes that all packages are split unless one of the package_prefixes or split_packages properties are specified. While that is safe it is not optimal and can lead to unnecessary implementation details leaking into the hidden API flags. Adding an empty split_packages property allows the flags to be optimized and remove any unnecessary implementation details. """) if single_packages: Loading Loading @@ -1111,25 +1121,27 @@ unnecessary implementation details. signature_patterns_files = signature_patterns_files.removeprefix( self.top_dir) self.report(f""" The purpose of the hiddenapi split_packages and package_prefixes properties is to allow the removal of implementation details from the hidden API flags to reduce the coupling between sdk snapshots and the APEX runtime. It cannot eliminate that coupling completely though. Doing so may require changes to the self.report_dedent(f""" The purpose of the hiddenapi split_packages and package_prefixes properties is to allow the removal of implementation details from the hidden API flags to reduce the coupling between sdk snapshots and the APEX runtime. It cannot eliminate that coupling completely though. Doing so may require changes to the code. This tool provides support for managing those properties but it cannot decide whether the set of package prefixes suggested is appropriate that needs the input of the developer. This tool provides support for managing those properties but it cannot decide whether the set of package prefixes suggested is appropriate that needs the input of the developer. Please run the following command: m {signature_patterns_files} And then check the '{signature_patterns_files}' for any mention of implementation classes and packages (i.e. those classes/packages that do not contain any part of an API surface, including the hidden API). If they are found then the code should ideally be moved to a package unique to this module that is contained within a package that is part of an API surface. And then check the '{signature_patterns_files}' for any mention of implementation classes and packages (i.e. those classes/packages that do not contain any part of an API surface, including the hidden API). If they are found then the code should ideally be moved to a package unique to this module that is contained within a package that is part of an API surface. The format of the file is a list of patterns: Loading @@ -1137,9 +1149,9 @@ The format of the file is a list of patterns: * Patterns for package prefixes will end with .../**. * Patterns for packages which are not split but cannot use a package prefix because there are sub-packages which are provided by another module will end with .../*. * Patterns for packages which are not split but cannot use a package prefix because there are sub-packages which are provided by another module will end with .../*. """) def compute_hiddenapi_package_properties(self): Loading Loading
scripts/hiddenapi/analyze_bcpf.py +227 −215 Original line number Diff line number Diff line Loading @@ -394,13 +394,17 @@ class BcpfAnalyzer: def reformat_report_test(text): return re.sub(r"(.)\n([^\s])", r"\1 \2", text) def report(self, text, **kwargs): def report(self, text="", **kwargs): # Concatenate lines that are not separated by a blank line together to # eliminate formatting applied to the supplied text to adhere to python # line length limitations. text = self.reformat_report_test(text) logging.info("%s", text, **kwargs) def report_dedent(self, text, **kwargs): text = textwrap.dedent(text) self.report(text, **kwargs) def run_command(self, cmd, *args, **kwargs): cmd_line = " ".join(cmd) logging.debug("Running %s", cmd_line) Loading Loading @@ -442,9 +446,7 @@ class BcpfAnalyzer: def load_module_info(self): module_info_file = os.path.join(self.product_out_dir, "module-info.json") self.report(f""" Making sure that {module_info_file} is up to date. """) self.report(f"\nMaking sure that {module_info_file} is up to date.\n") output = self.build_file_read_output(module_info_file) lines = output.lines() for line in lines: Loading Loading @@ -496,17 +498,17 @@ Making sure that {module_info_file} is up to date. optimizations that can be applied. """ self.report(f"Analyzing bootclasspath_fragment module {self.bcpf}") self.report(f""" Run this tool to help initialize a bootclasspath_fragment module. Before you start make sure that: self.report_dedent(f""" Run this tool to help initialize a bootclasspath_fragment module. Before you start make sure that: 1. The current checkout is up to date. 2. The environment has been initialized using lunch, e.g. lunch aosp_arm64-userdebug 3. You have added a bootclasspath_fragment module to the appropriate Android.bp file. Something like this: 3. You have added a bootclasspath_fragment module to the appropriate Android.bp file. Something like this: bootclasspath_fragment {{ name: "{self.bcpf}", Loading @@ -514,7 +516,8 @@ file. Something like this: "...", ], // The bootclasspath_fragments that provide APIs on which this depends. // The bootclasspath_fragments that provide APIs on which this // depends. fragments: [ {{ apex: "com.android.art", Loading Loading @@ -548,7 +551,7 @@ frameworks/base/boot/Android.bp. Something like this: # Make sure that the module-info.json file is up to date. self.load_module_info() self.report(""" self.report_dedent(""" Cleaning potentially stale files. """) # Remove the out/soong/hiddenapi files. Loading Loading @@ -605,26 +608,26 @@ merge these properties into it. if result.file_changes: if self.fix: file_change_message = """ The following files were modified by this script:""" file_change_message = textwrap.dedent(""" The following files were modified by this script: """) else: file_change_message = """ The following modifications need to be made:""" file_change_message = textwrap.dedent(""" The following modifications need to be made: """) self.report(f""" {file_change_message}""") self.report(file_change_message) result.file_changes.sort() for file_change in result.file_changes: self.report(f""" {file_change.path} {file_change.description} """.lstrip("\n")) self.report(f" {file_change.path}") self.report(f" {file_change.description}") self.report() if not self.fix: self.report(""" Run the command again with the --fix option to automatically make the above changes. """.lstrip()) self.report_dedent(""" Run the command again with the --fix option to automatically make the above changes. """.lstrip("\n")) def new_file_change(self, file, description): return FileChange( Loading @@ -635,11 +638,10 @@ changes. if not (module_line.startswith("< ") and monolithic_line.startswith("> ") and not separator_line): # Something went wrong. self.report(f"""Invalid build output detected: module_line: "{module_line}" monolithic_line: "{monolithic_line}" separator_line: "{separator_line}" """) self.report("Invalid build output detected:") self.report(f" module_line: '{module_line}'") self.report(f" monolithic_line: '{monolithic_line}'") self.report(f" separator_line: '{separator_line}'") sys.exit(1) if significant: Loading Loading @@ -698,10 +700,9 @@ changes. if module_signature != monolithic_signature: # Something went wrong. self.report(f"""Inconsistent signatures detected: module_signature: "{module_signature}" monolithic_signature: "{monolithic_signature}" """) self.report("Inconsistent signatures detected:") self.report(f" module_signature: '{module_signature}'") self.report(f" monolithic_signature: '{monolithic_signature}'") sys.exit(1) diffs[module_signature] = (module_flags, monolithic_flags) Loading Loading @@ -749,7 +750,7 @@ changes. return diffs def build_monolithic_stubs_flags(self): self.report(f""" self.report_dedent(f""" Attempting to build {_STUB_FLAGS_FILE} to verify that the bootclasspath_fragment has the correct API stubs available... """) Loading @@ -757,28 +758,32 @@ bootclasspath_fragment has the correct API stubs available... # Build the hiddenapi-stubs-flags.txt file. diffs = self.build_hiddenapi_flags(_STUB_FLAGS_FILE) if diffs: self.report(f""" There is a discrepancy between the stub API derived flags created by the bootclasspath_fragment and the platform_bootclasspath. See preceding error messages to see which flags are inconsistent. The inconsistencies can occur for self.report_dedent(f""" There is a discrepancy between the stub API derived flags created by the bootclasspath_fragment and the platform_bootclasspath. See preceding error messages to see which flags are inconsistent. The inconsistencies can occur for a couple of reasons: If you are building against prebuilts of the Android SDK, e.g. by using TARGET_BUILD_APPS then the prebuilt versions of the APIs this bootclasspath_fragment depends upon are out of date and need updating. See go/update-prebuilts for help. If you are building against prebuilts of the Android SDK, e.g. by using TARGET_BUILD_APPS then the prebuilt versions of the APIs this bootclasspath_fragment depends upon are out of date and need updating. See go/update-prebuilts for help. Otherwise, this is happening because there are some stub APIs that are either provided by or used by the contents of the bootclasspath_fragment but which are not available to it. There are 4 ways to handle this: Otherwise, this is happening because there are some stub APIs that are either provided by or used by the contents of the bootclasspath_fragment but which are not available to it. There are 4 ways to handle this: 1. A java_sdk_library in the contents property will automatically make its stub APIs available to the bootclasspath_fragment so nothing needs to be done. 1. A java_sdk_library in the contents property will automatically make its stub APIs available to the bootclasspath_fragment so nothing needs to be done. 2. If the API provided by the bootclasspath_fragment is created by an api_only java_sdk_library (or a java_library that compiles files generated by a separate droidstubs module then it cannot be added to the contents and instead must be added to the api.stubs property, e.g. 2. If the API provided by the bootclasspath_fragment is created by an api_only java_sdk_library (or a java_library that compiles files generated by a separate droidstubs module then it cannot be added to the contents and instead must be added to the api.stubs property, e.g. bootclasspath_fragment {{ name: "{self.bcpf}", Loading @@ -788,8 +793,9 @@ not available to it. There are 4 ways to handle this: }}, }} 3. If the contents use APIs provided by another bootclasspath_fragment then it needs to be added to the fragments property, e.g. 3. If the contents use APIs provided by another bootclasspath_fragment then it needs to be added to the fragments property, e.g. bootclasspath_fragment {{ name: "{self.bcpf}", Loading @@ -804,9 +810,9 @@ not available to it. There are 4 ways to handle this: ], }} 4. If the contents use APIs from a module that is not part of another bootclasspath_fragment then it must be added to the additional_stubs property, e.g. 4. If the contents use APIs from a module that is not part of another bootclasspath_fragment then it must be added to the additional_stubs property, e.g. bootclasspath_fragment {{ name: "{self.bcpf}", Loading @@ -814,17 +820,18 @@ not available to it. There are 4 ways to handle this: additional_stubs: ["android-non-updatable"], }} Like the api.stubs property these are typically java_sdk_library modules but can be java_library too. Like the api.stubs property these are typically java_sdk_library modules but can be java_library too. Note: The "android-non-updatable" is treated as if it was a java_sdk_library which it is not at the moment but will be in future. Note: The "android-non-updatable" is treated as if it was a java_sdk_library which it is not at the moment but will be in future. """) return diffs def build_monolithic_flags(self, result): self.report(f""" self.report_dedent(f""" Attempting to build {_FLAGS_FILE} to verify that the bootclasspath_fragment has the correct hidden API flags... """) Loading @@ -838,30 +845,32 @@ bootclasspath_fragment has the correct hidden API flags... self.load_all_flags() if result.diffs: self.report(f""" There is a discrepancy between the hidden API flags created by the bootclasspath_fragment and the platform_bootclasspath. See preceding error messages to see which flags are inconsistent. The inconsistencies can occur for a couple of reasons: If you are building against prebuilts of this bootclasspath_fragment then the prebuilt version of the sdk snapshot (specifically the hidden API flag files) are inconsistent with the prebuilt version of the apex {self.apex}. Please ensure that they are both updated from the same build. 1. There are custom hidden API flags specified in the one of the files in frameworks/base/boot/hiddenapi which apply to the bootclasspath_fragment but which are not supplied to the bootclasspath_fragment module. 2. The bootclasspath_fragment specifies invalid "package_prefixes" or "split_packages" properties that match packages and classes that it does not self.report_dedent(f""" There is a discrepancy between the hidden API flags created by the bootclasspath_fragment and the platform_bootclasspath. See preceding error messages to see which flags are inconsistent. The inconsistencies can occur for a couple of reasons: If you are building against prebuilts of this bootclasspath_fragment then the prebuilt version of the sdk snapshot (specifically the hidden API flag files) are inconsistent with the prebuilt version of the apex {self.apex}. Please ensure that they are both updated from the same build. 1. There are custom hidden API flags specified in the one of the files in frameworks/base/boot/hiddenapi which apply to the bootclasspath_fragment but which are not supplied to the bootclasspath_fragment module. 2. The bootclasspath_fragment specifies invalid "split_packages", "single_packages" and/of "package_prefixes" properties that match packages and classes that it does not provide. """) # Check to see if there are any hiddenapi related properties that # need to be added to the self.report(""" self.report_dedent(""" Checking custom hidden API flags.... """) self.check_frameworks_base_boot_hidden_api_files(result) Loading Loading @@ -1060,24 +1069,25 @@ Checking custom hidden API flags.... )) if split_packages: self.report(f""" bootclasspath_fragment {self.bcpf} contains classes in packages that also contain classes provided by other sources, those packages are called split packages. Split packages should be avoided where possible but are often self.report_dedent(f""" bootclasspath_fragment {self.bcpf} contains classes in packages that also contain classes provided by other bootclasspath modules. Those packages are called split packages. Split packages should be avoided where possible but are often unavoidable when modularizing existing code. The hidden api processing needs to know which packages are split (and conversely which are not) so that it can optimize the hidden API flags to remove unnecessary implementation details. """) self.report(""" By default (for backwards compatibility) the bootclasspath_fragment assumes that all packages are split unless one of the package_prefixes or split_packages properties are specified. While that is safe it is not optimal and can lead to unnecessary implementation details leaking into the hidden API flags. Adding an empty split_packages property allows the flags to be optimized and remove any unnecessary implementation details. The hidden api processing needs to know which packages are split (and conversely which are not) so that it can optimize the hidden API flags to remove unnecessary implementation details. By default (for backwards compatibility) the bootclasspath_fragment assumes that all packages are split unless one of the package_prefixes or split_packages properties are specified. While that is safe it is not optimal and can lead to unnecessary implementation details leaking into the hidden API flags. Adding an empty split_packages property allows the flags to be optimized and remove any unnecessary implementation details. """) if single_packages: Loading Loading @@ -1111,25 +1121,27 @@ unnecessary implementation details. signature_patterns_files = signature_patterns_files.removeprefix( self.top_dir) self.report(f""" The purpose of the hiddenapi split_packages and package_prefixes properties is to allow the removal of implementation details from the hidden API flags to reduce the coupling between sdk snapshots and the APEX runtime. It cannot eliminate that coupling completely though. Doing so may require changes to the self.report_dedent(f""" The purpose of the hiddenapi split_packages and package_prefixes properties is to allow the removal of implementation details from the hidden API flags to reduce the coupling between sdk snapshots and the APEX runtime. It cannot eliminate that coupling completely though. Doing so may require changes to the code. This tool provides support for managing those properties but it cannot decide whether the set of package prefixes suggested is appropriate that needs the input of the developer. This tool provides support for managing those properties but it cannot decide whether the set of package prefixes suggested is appropriate that needs the input of the developer. Please run the following command: m {signature_patterns_files} And then check the '{signature_patterns_files}' for any mention of implementation classes and packages (i.e. those classes/packages that do not contain any part of an API surface, including the hidden API). If they are found then the code should ideally be moved to a package unique to this module that is contained within a package that is part of an API surface. And then check the '{signature_patterns_files}' for any mention of implementation classes and packages (i.e. those classes/packages that do not contain any part of an API surface, including the hidden API). If they are found then the code should ideally be moved to a package unique to this module that is contained within a package that is part of an API surface. The format of the file is a list of patterns: Loading @@ -1137,9 +1149,9 @@ The format of the file is a list of patterns: * Patterns for package prefixes will end with .../**. * Patterns for packages which are not split but cannot use a package prefix because there are sub-packages which are provided by another module will end with .../*. * Patterns for packages which are not split but cannot use a package prefix because there are sub-packages which are provided by another module will end with .../*. """) def compute_hiddenapi_package_properties(self): Loading