Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 420d7d58 authored by Wei Li's avatar Wei Li Committed by Gerrit Code Review
Browse files

Merge "Initial implementation of layoutlib SBOM generation." into main

parents ef5a9ea7 c134b763
Loading
Loading
Loading
Loading
+81 −0
Original line number Diff line number Diff line
@@ -33,3 +33,84 @@ FONT_TEMP :=
font_config :=
fonts_device :=
FONT_FILES :=

# The following build process of build.prop, layoutlib-res.zip is moved here from release_layoutlib.sh
# so the SBOM of all platform neutral artifacts and Linux/Windows artifacts of layoutlib can be built in Make/Soong.
# See go/layoutlib-sbom.

# build.prop shipped with layoutlib
LAYOUTLIB_BUILD_PROP := $(call intermediates-dir-for,PACKAGING,layoutlib-build-prop,HOST,COMMON)
$(LAYOUTLIB_BUILD_PROP)/layoutlib-build.prop: $(INSTALLED_SDK_BUILD_PROP_TARGET)
	rm -rf $@
	cp $< $@
	# Remove all the uncommon build properties
	sed -i '/^ro\.\(build\|product\|config\|system\)/!d' $@
	# Mark the build as layoutlib. This can be read at runtime by apps
	sed -i 's|ro.product.brand=generic|ro.product.brand=studio|' $@
	sed -i 's|ro.product.device=generic|ro.product.device=layoutlib|' $@

$(call dist-for-goals,layoutlib,$(LAYOUTLIB_BUILD_PROP)/layoutlib-build.prop:layoutlib_native/build.prop)

# Resource files from frameworks/base/core/res/res
LAYOUTLIB_RES := $(call intermediates-dir-for,PACKAGING,layoutlib-res,HOST,COMMON)
LAYOUTLIB_RES_FILES := $(shell find frameworks/base/core/res/res -type f -not -path 'frameworks/base/core/res/res/values-m[nc]c*' | sort)
$(LAYOUTLIB_RES)/layoutlib-res.zip: $(SOONG_ZIP) $(HOST_OUT_EXECUTABLES)/aapt2 $(LAYOUTLIB_RES_FILES)
	rm -rf $@
	echo $(LAYOUTLIB_RES_FILES) > $(LAYOUTLIB_RES)/filelist.txt
	$(SOONG_ZIP) -C frameworks/base/core/res -l $(LAYOUTLIB_RES)/filelist.txt -o $(LAYOUTLIB_RES)/temp.zip
	rm -rf $(LAYOUTLIB_RES)/data && unzip -q -d $(LAYOUTLIB_RES)/data $(LAYOUTLIB_RES)/temp.zip
	rm -rf $(LAYOUTLIB_RES)/compiled && mkdir $(LAYOUTLIB_RES)/compiled && $(HOST_OUT_EXECUTABLES)/aapt2 compile $(LAYOUTLIB_RES)/data/res/**/*.9.png -o $(LAYOUTLIB_RES)/compiled
	printf '<?xml version="1.0" encoding="utf-8"?>\n<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.google.android.layoutlib" />' > $(LAYOUTLIB_RES)/AndroidManifest.xml
	$(HOST_OUT_EXECUTABLES)/aapt2 link -R $(LAYOUTLIB_RES)/compiled/* -o $(LAYOUTLIB_RES)/compiled.apk --manifest $(LAYOUTLIB_RES)/AndroidManifest.xml
	rm -rf $(LAYOUTLIB_RES)/compiled_apk && unzip -q -d $(LAYOUTLIB_RES)/compiled_apk $(LAYOUTLIB_RES)/compiled.apk
	for f in $(LAYOUTLIB_RES)/compiled_apk/res/*; do mv "$$f" "$${f/-v4/}";done
	for f in $(LAYOUTLIB_RES)/compiled_apk/res/**/*.9.png; do mv "$$f" "$${f/.9.png/.compiled.9.png}";done
	cp -r $(LAYOUTLIB_RES)/compiled_apk/res $(LAYOUTLIB_RES)/data
	$(SOONG_ZIP) -C $(LAYOUTLIB_RES)/data -D $(LAYOUTLIB_RES)/data/res -o $@

$(call dist-for-goals,layoutlib,$(LAYOUTLIB_RES)/layoutlib-res.zip:layoutlib_native/res.zip)

# SBOM of layoutlib artifacts
LAYOUTLIB_SBOM := $(call intermediates-dir-for,PACKAGING,layoutlib-sbom,HOST)
_layoutlib_font_config_files := $(sort $(wildcard frameworks/base/data/fonts/*.xml))
_layoutlib_fonts_files := $(filter $(TARGET_OUT)/fonts/%.ttf $(TARGET_OUT)/fonts/%.ttc $(TARGET_OUT)/fonts/%.otf, $(INTERNAL_SYSTEMIMAGE_FILES))
$(LAYOUTLIB_SBOM)/sbom-metadata.csv:
	rm -rf $@
	echo installed_file,module_path,soong_module_type,is_prebuilt_make_module,product_copy_files,kernel_module_copy_files,is_platform_generated,build_output_path,static_libraries,whole_static_libraries,is_static_lib >> $@
	echo build.prop,,,,,,Y,$(LAYOUTLIB_BUILD_PROP)/layoutlib-build.prop,,, >> $@

	$(foreach f,$(_layoutlib_font_config_files),\
	  echo data/fonts/$(notdir $f),frameworks/base/data/fonts,prebuilt_etc,,,,,$f,,, >> $@; \
	)

	$(foreach f,$(_layoutlib_fonts_files), \
	  $(eval _module_name := $(ALL_INSTALLED_FILES.$f)) \
	  $(eval _module_path := $(strip $(sort $(ALL_MODULES.$(_module_name).PATH)))) \
	  $(eval _soong_module_type := $(strip $(sort $(ALL_MODULES.$(_module_name).SOONG_MODULE_TYPE)))) \
	  echo data/fonts/$(notdir $f),$(_module_path),$(_soong_module_type),,,,,$f,,, >> $@; \
	)

	$(foreach f,$(LAYOUTLIB_RES_FILES), \
	  $(eval _path := $(subst frameworks/base/core/res,data,$f)) \
	  echo $(_path),,,,,,Y,$f,,, >> $@; \
	)

.PHONY: layoutlib-sbom
layoutlib-sbom: $(LAYOUTLIB_SBOM)/layoutlib.spdx.json
$(LAYOUTLIB_SBOM)/layoutlib.spdx.json: $(PRODUCT_OUT)/always_dirty_file.txt $(LAYOUTLIB_SBOM)/sbom-metadata.csv $(_layoutlib_font_config_files) $(_layoutlib_fonts_files) $(LAYOUTLIB_BUILD_PROP)/layoutlib-build.prop $(LAYOUTLIB_RES_FILES)
	rm -rf $@
	$(GEN_SBOM) --output_file $@ --metadata $(LAYOUTLIB_SBOM)/sbom-metadata.csv --build_version $(BUILD_FINGERPRINT_FROM_FILE) --product_mfr "$(PRODUCT_MANUFACTURER)" --json

$(call dist-for-goals,layoutlib,$(LAYOUTLIB_SBOM)/layoutlib.spdx.json:layoutlib_native/sbom/layoutlib.spdx.json)

# Generate SBOM of framework_res.jar that is created in release_layoutlib.sh.
# The generated SBOM contains placeholders for release_layotlib.sh to substitute, and the placeholders include:
# document name, document namespace, document creation info, organization and SHA1 value of framework_res.jar.
GEN_SBOM_FRAMEWORK_RES := $(HOST_OUT_EXECUTABLES)/generate-sbom-framework_res
.PHONY: layoutlib-framework_res-sbom
layoutlib-framework_res-sbom: $(LAYOUTLIB_SBOM)/framework_res.jar.spdx.json
$(LAYOUTLIB_SBOM)/framework_res.jar.spdx.json: $(LAYOUTLIB_SBOM)/layoutlib.spdx.json $(GEN_SBOM_FRAMEWORK_RES)
	rm -rf $@
	$(GEN_SBOM_FRAMEWORK_RES) --output_file $(LAYOUTLIB_SBOM)/framework_res.jar.spdx.json --layoutlib_sbom $(LAYOUTLIB_SBOM)/layoutlib.spdx.json

$(call dist-for-goals,layoutlib,$(LAYOUTLIB_SBOM)/framework_res.jar.spdx.json:layoutlib_native/sbom/framework_res.jar.spdx.json)
 No newline at end of file
+15 −0
Original line number Diff line number Diff line
@@ -77,3 +77,18 @@ python_test_host {
    },
    test_suites: ["general-tests"],
}

python_binary_host {
    name: "generate-sbom-framework_res",
        srcs: [
            "generate-sbom-framework_res.py",
        ],
        version: {
            py3: {
                embedded_launcher: true,
            },
        },
        libs: [
            "sbom_lib",
        ],
}
 No newline at end of file
+80 −0
Original line number Diff line number Diff line
#!/usr/bin/env python3
#
# Copyright (C) 2023 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import argparse
import hashlib
import json
import sbom_data
import sbom_writers


def get_args():
  parser = argparse.ArgumentParser()
  parser.add_argument('-v', '--verbose', action='store_true', default=False,
                      help='Print more information.')
  parser.add_argument('--output_file', required=True,
                      help='The generated SBOM file in SPDX format.')
  parser.add_argument('--layoutlib_sbom', required=True,
                      help='The file path of the SBOM of layoutlib.')

  return parser.parse_args()


def main():
  global args
  args = get_args()

  doc = sbom_data.Document(name='<name>',
                           namespace='<namespace>',
                           creators=['Organization: <organization>'],
                           created='<created>')

  filename = 'data/framework_res.jar'
  file_id = f'SPDXRef-{sbom_data.encode_for_spdxid(filename)}'
  file = sbom_data.File(id=file_id, name=filename, checksum='SHA1: <checksum>')
  doc.files.append(file)
  doc.describes = file_id

  with open(args.layoutlib_sbom, 'r', encoding='utf-8') as f:
    layoutlib_sbom = json.load(f)

  with open(args.layoutlib_sbom, 'rb') as f:
    sha1 = hashlib.file_digest(f, 'sha1')

  layoutlib_sbom_namespace = layoutlib_sbom[sbom_writers.PropNames.DOCUMENT_NAMESPACE]
  external_doc_ref = 'DocumentRef-layoutlib'
  doc.external_refs = [
    sbom_data.DocumentExternalReference(external_doc_ref, layoutlib_sbom_namespace,
                                        f'SHA1: {sha1.hexdigest()}')]

  resource_file_spdxids = []
  for file in layoutlib_sbom[sbom_writers.PropNames.FILES]:
    if file[sbom_writers.PropNames.FILE_NAME].startswith('data/res/'):
      resource_file_spdxids.append(file[sbom_writers.PropNames.SPDXID])

  doc.relationships = []
  for spdxid in resource_file_spdxids:
    doc.relationships.append(
      sbom_data.Relationship(file_id, sbom_data.RelationshipType.GENERATED_FROM,
                             f'{external_doc_ref}:{spdxid}'))

  # write sbom file
  with open(args.output_file, 'w', encoding='utf-8') as f:
    sbom_writers.JSONWriter.write(doc, f)


if __name__ == '__main__':
  main()
+2 −16
Original line number Diff line number Diff line
@@ -143,26 +143,12 @@ def log(*info):
      print(i)


def encode_for_spdxid(s):
  """Simple encode for string values used in SPDXID which uses the charset of A-Za-Z0-9.-"""
  result = ''
  for c in s:
    if c.isalnum() or c in '.-':
      result += c
    elif c in '_@/':
      result += '-'
    else:
      result += '0x' + c.encode('utf-8').hex()

  return result.lstrip('-')


def new_package_id(package_name, type):
  return f'SPDXRef-{type}-{encode_for_spdxid(package_name)}'
  return f'SPDXRef-{type}-{sbom_data.encode_for_spdxid(package_name)}'


def new_file_id(file_path):
  return f'SPDXRef-{encode_for_spdxid(file_path)}'
  return f'SPDXRef-{sbom_data.encode_for_spdxid(file_path)}'


def checksum(file_path):
+13 −0
Original line number Diff line number Diff line
@@ -138,3 +138,16 @@ class Document:
      h = hashlib.sha1()
      h.update(''.join(checksums).encode(encoding='utf-8'))
      package.verification_code = h.hexdigest()

def encode_for_spdxid(s):
  """Simple encode for string values used in SPDXID which uses the charset of A-Za-Z0-9.-"""
  result = ''
  for c in s:
    if c.isalnum() or c in '.-':
      result += c
    elif c in '_@/':
      result += '-'
    else:
      result += '0x' + c.encode('utf-8').hex()

  return result.lstrip('-')
 No newline at end of file