Merge "analyze_bcpf: Indent multi-line text to improve formatting" am: b84f1d5bb8

Original change: https://android-review.googlesource.com/c/platform/build/soong/+/2054408

Change-Id: Ic6b2fadfe34bace2b85e36e317f74cad057cd01e
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Paul Duffin 2022-04-05 11:37:00 +00:00 committed by Automerger Merge Worker
commit 709684da65

View file

@ -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)
@ -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:
@ -496,61 +498,62 @@ 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.
1. The current checkout is up to date.
2. The environment has been initialized using lunch, e.g.
lunch aosp_arm64-userdebug
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}",
contents: [
"...",
],
bootclasspath_fragment {{
name: "{self.bcpf}",
contents: [
"...",
],
// The bootclasspath_fragments that provide APIs on which this
// depends.
fragments: [
{{
apex: "com.android.art",
module: "art-bootclasspath-fragment",
}},
],
}}
4. You have added it to the platform_bootclasspath module in
frameworks/base/boot/Android.bp. Something like this:
// The bootclasspath_fragments that provide APIs on which this depends.
fragments: [
{{
apex: "com.android.art",
module: "art-bootclasspath-fragment",
}},
],
}}
platform_bootclasspath {{
name: "platform-bootclasspath",
fragments: [
...
{{
apex: "{self.apex}",
module: "{self.bcpf}",
}},
],
}}
4. You have added it to the platform_bootclasspath module in
frameworks/base/boot/Android.bp. Something like this:
5. You have added an sdk module. Something like this:
platform_bootclasspath {{
name: "platform-bootclasspath",
fragments: [
...
{{
apex: "{self.apex}",
module: "{self.bcpf}",
}},
],
}}
5. You have added an sdk module. Something like this:
sdk {{
name: "{self.sdk}",
bootclasspath_fragments: ["{self.bcpf}"],
}}
""")
sdk {{
name: "{self.sdk}",
bootclasspath_fragments: ["{self.bcpf}"],
}}
""")
# Make sure that the module-info.json file is up to date.
self.load_module_info()
self.report("""
Cleaning potentially stale files.
""")
self.report_dedent("""
Cleaning potentially stale files.
""")
# Remove the out/soong/hiddenapi files.
shutil.rmtree(f"{self.out_dir}/soong/hiddenapi", ignore_errors=True)
@ -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(
@ -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:
@ -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)
@ -749,85 +750,91 @@ changes.
return diffs
def build_monolithic_stubs_flags(self):
self.report(f"""
Attempting to build {_STUB_FLAGS_FILE} to verify that the
bootclasspath_fragment has the correct API stubs available...
""")
self.report_dedent(f"""
Attempting to build {_STUB_FLAGS_FILE} to verify that the
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
a couple of reasons:
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}",
...
api: {{
stubs: ["$MODULE-api-only"],"
}},
}}
bootclasspath_fragment {{
name: "{self.bcpf}",
...
api: {{
stubs: ["$MODULE-api-only"],"
}},
}}
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}",
...
// The bootclasspath_fragments that provide APIs on which this depends.
fragments: [
...
{{
apex: "com.android.other",
module: "com.android.other-bootclasspath-fragment",
}},
],
}}
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}",
...
// The bootclasspath_fragments that provide APIs on which this depends.
fragments: [
...
{{
apex: "com.android.other",
module: "com.android.other-bootclasspath-fragment",
}},
],
}}
bootclasspath_fragment {{
name: "{self.bcpf}",
...
additional_stubs: ["android-non-updatable"],
}}
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.
Like the api.stubs property these are typically
java_sdk_library modules but can be java_library too.
bootclasspath_fragment {{
name: "{self.bcpf}",
...
additional_stubs: ["android-non-updatable"],
}}
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"""
Attempting to build {_FLAGS_FILE} to verify that the
bootclasspath_fragment has the correct hidden API flags...
""")
self.report_dedent(f"""
Attempting to build {_FLAGS_FILE} to verify that the
bootclasspath_fragment has the correct hidden API flags...
""")
# Build the hiddenapi-flags.csv file and extract any differences in
# the flags between this bootclasspath_fragment and the monolithic
@ -838,32 +845,34 @@ 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:
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.
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.
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
provide.
""")
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("""
Checking custom hidden API flags....
""")
self.report_dedent("""
Checking custom hidden API flags....
""")
self.check_frameworks_base_boot_hidden_api_files(result)
def report_hidden_api_flag_file_changes(self, result, property_name,
@ -1060,25 +1069,26 @@ 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
unavoidable when modularizing existing code.
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.
""")
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.
""")
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:
result.property_changes.append(
@ -1091,7 +1101,7 @@ unnecessary implementation details.
contain classes from other bootclasspath modules. Packages
should only be listed here when necessary for legacy
purposes, new packages should match a package prefix.
"""),
"""),
action=PropertyChangeAction.REPLACE,
))
@ -1111,36 +1121,38 @@ 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
code.
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}
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:
The format of the file is a list of patterns:
* Patterns for split packages will list every class in that package.
* Patterns for split packages will list every class in that package.
* Patterns for package prefixes will end with .../**.
* 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):
trie = signature_trie()