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:
commit
709684da65
1 changed files with 206 additions and 194 deletions
|
@ -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()
|
||||
|
|
Loading…
Reference in a new issue