| #!/bin/bash -eu |
| |
| set -o pipefail |
| |
| function extend_mock_top_for_java_or_kotlin_partial_compile_test { |
| # Required for building java_library type modules. |
| symlink_directory prebuilts/jdk |
| symlink_directory prebuilts/gcc |
| symlink_directory external/turbine |
| symlink_directory external/gson |
| symlink_directory external/ow2-asm |
| symlink_directory external/auto |
| symlink_directory external/icu |
| symlink_directory external/zlib |
| symlink_directory external/guava |
| symlink_directory external/jspecify |
| symlink_directory external/error_prone |
| symlink_directory external/jsr305 |
| symlink_directory external/javapoet |
| symlink_directory external/escapevelocity |
| symlink_directory external/kotlinx.metadata |
| symlink_directory external/kotlinc |
| symlink_directory system/logging/liblog |
| symlink_directory external/abseil-cpp |
| |
| mkdir -p "$MOCK_TOP"/tools/lint_checks |
| cat > "$MOCK_TOP"/tools/lint_checks/Android.bp <<EOF |
| java_library_host { |
| name: "AndroidGlobalLintChecker", |
| } |
| EOF |
| |
| write_soong_vars soong.test_arm64.variables |
| } |
| |
| function extend_mock_top_for_java_partial_compile_test { |
| extend_mock_top_for_java_or_kotlin_partial_compile_test |
| # Pre-compile impl-library using partial compile. |
| partial_compile_setup ${impl_library_jar} |
| run_soong |
| run_ninja ${impl_library_jar} |
| } |
| |
| function extend_mock_top_for_kotlin_partial_compile_test { |
| extend_mock_top_for_java_or_kotlin_partial_compile_test |
| |
| symlink_directory prebuilts/tools/common/m2 |
| symlink_directory external/kotlinx.coroutines |
| symlink_directory external/kotlinx.atomicfu |
| symlink_directory sdk/annotations |
| |
| partial_compile_setup ${impl_library_jar} |
| create_kotlin_files |
| run_soong |
| run_ninja ${impl_library_jar} |
| } |
| |
| # This file is generated by soong during make, here we have copy pasted the |
| # exact same file, with VendorApiLevel added as an extra. |
| # shellcheck disable=SC2120 |
| function write_soong_vars { |
| local soong_out=$MOCK_TOP/out/soong |
| local variables_file_name="$1" |
| local tmp_variables_file="$soong_out"/"$variables_file_name".tmp |
| local variables_file="$soong_out"/"$variables_file_name" |
| mkdir -p "$soong_out" |
| cat > "$tmp_variables_file" << EOF |
| { |
| "BuildNumberFile": "build_number.txt", |
| "Platform_version_name": "S", |
| "Platform_sdk_version": 30, |
| "Platform_sdk_codename": "S", |
| "Platform_sdk_final": false, |
| "Platform_base_sdk_extension_version": 30, |
| "Platform_version_active_codenames": [ |
| "S" |
| ], |
| "Platform_version_all_preview_codenames": [ |
| "S" |
| ], |
| "DeviceName": "test_arm64", |
| "DeviceProduct": "test_arm64", |
| "DeviceArch": "arm64", |
| "DeviceArchVariant": "armv8-a", |
| "DeviceCpuVariant": "generic", |
| "DeviceAbi": [ |
| "arm64-v8a" |
| ], |
| "DeviceMaxPageSizeSupported": "4096", |
| "DeviceNoBionicPageSizeMacro": false, |
| "DeviceSecondaryArch": "arm", |
| "DeviceSecondaryArchVariant": "armv8-a", |
| "DeviceSecondaryCpuVariant": "generic", |
| "DeviceSecondaryAbi": [ |
| "armeabi-v7a", |
| "armeabi" |
| ], |
| "HostArch": "x86_64", |
| "HostSecondaryArch": "x86", |
| "CrossHost": "windows", |
| "CrossHostArch": "x86", |
| "CrossHostSecondaryArch": "x86_64", |
| "AAPTCharacteristics": "nosdcard", |
| "AAPTConfig": [ |
| "normal", |
| "large", |
| "xlarge", |
| "hdpi", |
| "xhdpi", |
| "xxhdpi" |
| ], |
| "AAPTPreferredConfig": "xhdpi", |
| "AAPTPrebuiltDPI": [ |
| "xhdpi", |
| "xxhdpi" |
| ], |
| "Malloc_low_memory": false, |
| "Malloc_zero_contents": true, |
| "Malloc_pattern_fill_contents": false, |
| "Safestack": false, |
| "Build_from_text_stub": false, |
| "BootJars": [], |
| "ApexBootJars": [], |
| "PartitionVarsForSoongMigrationOnlyDoNotUse": { |
| "PartitionQualifiedVariables": null |
| }, |
| "CompatibilityTestcases": null, |
| "VendorApiLevel": "202604", |
| "Eng": true |
| } |
| EOF |
| if cmp -s "$tmp_variables_file" "$variables_file"; then |
| rm "$tmp_variables_file" |
| else |
| mv -f "$tmp_variables_file" "$variables_file" |
| fi |
| } |
| |
| function create_base_files { |
| mkdir -p soong-test/java/integration/impllib |
| cat > soong-test/java/integration/Android.bp <<'EOF' |
| java_library { |
| name: "impl-library", |
| srcs: [ |
| "impllib/**/*.java", |
| ], |
| libs: ["provider-library"], |
| sdk_version: "35", |
| } |
| |
| java_library { |
| name: "provider-library", |
| srcs: ["provider/**/*.java"], |
| sdk_version: "35", |
| } |
| EOF |
| |
| cat > soong-test/java/integration/impllib/ExampleImpl1.java <<'EOF' |
| package soong.java.integration.impllib; |
| |
| import soong.java.integration.provider.Provider; |
| |
| class ExampleImpl1 { |
| public static final int EXAMPLE_1_CONST_1 = 100; |
| |
| private Provider mProvider; |
| |
| public ExampleImpl1() { |
| mProvider = new Provider(); |
| } |
| |
| public String getClassName() { |
| return "ExampleInt1"; |
| } |
| |
| public int getProviderConstant() { |
| return mProvider.nextProviderConst(); |
| } |
| } |
| EOF |
| |
| mkdir -p soong-test/java/integration/provider |
| |
| cat > soong-test/java/integration/provider/Provider.java <<'EOF' |
| package soong.java.integration.provider; |
| |
| public class Provider { |
| public static final int PROVIDER_CONST = -1; |
| |
| private String className; |
| |
| public Provider() { |
| this.className = "Provider"; |
| } |
| |
| public int nextProviderConst() { |
| return PROVIDER_CONST + 1; |
| } |
| |
| private String getProviderName() { |
| return className; |
| } |
| } |
| EOF |
| } |
| |
| function create_ap_files { |
| mkdir -p soong-test/java/integration/impllib |
| cat > soong-test/java/integration/Android.bp <<'EOF' |
| java_library { |
| name: "impl-library", |
| srcs: [ |
| "impllib/**/*.java", |
| ":wrapper-annotations-source", |
| ], |
| libs: ["provider-library"], |
| plugins: ["wrapper-annotation-processor"], |
| sdk_version: "35", |
| } |
| |
| java_library { |
| name: "provider-library", |
| srcs: ["provider/**/*.java"], |
| sdk_version: "35", |
| } |
| |
| java_library_host { |
| name: "annotation-processor-lib", |
| srcs: ["annotation/**/*.java"], |
| } |
| |
| java_plugin { |
| name: "wrapper-annotation-processor", |
| processor_class: "soong.java.integration.annotation.WrapperProcessor", |
| static_libs: ["annotation-processor-lib"], |
| installable: false, |
| generates_api: true, |
| } |
| |
| filegroup { |
| name: "wrapper-annotations-source", |
| srcs: ["annotation/GenerateWrapper.java"], |
| } |
| EOF |
| |
| mkdir -p soong-test/java/integration/annotation |
| cat > soong-test/java/integration/annotation/WrapperProcessor.java <<'EOF' |
| package soong.java.integration.annotation; |
| import soong.java.integration.annotation.GenerateWrapper; |
| import java.io.IOException; |
| import java.io.Writer; |
| import java.util.Set; |
| import javax.annotation.processing.AbstractProcessor; |
| import javax.annotation.processing.Filer; |
| import javax.annotation.processing.Messager; |
| import javax.annotation.processing.ProcessingEnvironment; |
| import javax.annotation.processing.Processor; |
| import javax.annotation.processing.RoundEnvironment; |
| import javax.annotation.processing.SupportedAnnotationTypes; |
| import javax.annotation.processing.SupportedSourceVersion; |
| import javax.lang.model.SourceVersion; |
| import javax.lang.model.element.Element; |
| import javax.lang.model.element.ElementKind; |
| import javax.lang.model.element.ExecutableElement; |
| import javax.lang.model.element.TypeElement; |
| import javax.lang.model.util.Elements; |
| import javax.tools.Diagnostic; |
| import javax.tools.JavaFileObject; |
| @SupportedAnnotationTypes("soong.java.integration.annotation.GenerateWrapper") |
| @SupportedSourceVersion(SourceVersion.RELEASE_17) |
| public class WrapperProcessor extends AbstractProcessor { |
| private Filer filer; |
| private Messager messager; |
| private Elements elementUtils; |
| @Override |
| public synchronized void init(ProcessingEnvironment processingEnv) { |
| super.init(processingEnv); |
| filer = processingEnv.getFiler(); |
| messager = processingEnv.getMessager(); |
| elementUtils = processingEnv.getElementUtils(); |
| } |
| @Override |
| public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { |
| for (Element annotatedElement : roundEnv.getElementsAnnotatedWith(GenerateWrapper.class)) { |
| ExecutableElement originalMethod = (ExecutableElement) annotatedElement; |
| GenerateWrapper annotation = originalMethod.getAnnotation(GenerateWrapper.class); |
| int methodCount = annotation.methodCount(); |
| TypeElement enclosingClass = (TypeElement) originalMethod.getEnclosingElement(); |
| String packageName = elementUtils.getPackageOf(enclosingClass).getQualifiedName().toString(); |
| String originalClassNameForNaming = enclosingClass.getSimpleName().toString(); |
| String wrapperClassName = originalClassNameForNaming + "Wrapper"; |
| String wrapperMethodName = originalMethod.getSimpleName().toString() + "Wrapper"; |
| try { |
| generateAlwaysVoidNoParamWrapper(packageName, wrapperClassName, wrapperMethodName, methodCount); |
| } catch (IOException e) { |
| throw new RuntimeException("Unable to generate class using annotation"); |
| } |
| } |
| return true; |
| } |
| private void generateAlwaysVoidNoParamWrapper(String packageName, String wrapperClassName, String originalMethodNameForNaming, int methodCount) throws IOException { |
| StringBuilder sb = new StringBuilder(); |
| sb.append("package ").append(packageName).append(";\n\n"); |
| sb.append("public final class ").append(wrapperClassName).append(" {\n\n"); |
| for (int i=0; i < methodCount; i++) { |
| sb.append(" public String ").append(originalMethodNameForNaming + String.valueOf(i)).append("() {\n"); |
| sb.append(" return ").append("\"").append(wrapperClassName).append("\"").append(";\n"); |
| sb.append(" }\n"); |
| } |
| sb.append("}\n"); |
| JavaFileObject jfo = filer.createSourceFile(packageName + "." + wrapperClassName); |
| try (Writer writer = jfo.openWriter()) { |
| writer.write(sb.toString()); |
| } |
| } |
| } |
| EOF |
| |
| cat > soong-test/java/integration/annotation/GenerateWrapper.java <<'EOF' |
| package soong.java.integration.annotation; |
| import java.lang.annotation.ElementType; |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| import java.lang.annotation.Target; |
| @Retention(RetentionPolicy.SOURCE) |
| @Target(ElementType.METHOD) |
| public @interface GenerateWrapper { |
| int methodCount() default 1; |
| } |
| EOF |
| |
| cat > soong-test/java/integration/impllib/AnnotationUsage.java <<'EOF' |
| package soong.java.integration.impllib; |
| import soong.java.integration.annotation.GenerateWrapper; |
| public class AnnotationUsage { |
| @GenerateWrapper(methodCount = 2) |
| public String getClassName() { |
| return "AnnotationUsage"; |
| } |
| } |
| EOF |
| |
| cat > soong-test/java/integration/impllib/ExampleImpl4.java <<'EOF' |
| package soong.java.integration.impllib; |
| import soong.java.integration.impllib.AnnotationUsageWrapper; |
| public class ExampleImpl4 { |
| private AnnotationUsageWrapper mAnnotationUsageWrapper; |
| public ExampleImpl4() { |
| this.mAnnotationUsageWrapper = new AnnotationUsageWrapper(); |
| } |
| public String readGenApi() { |
| return mAnnotationUsageWrapper.getClassNameWrapper1(); |
| } |
| } |
| EOF |
| } |
| |
| create_example_impl3_file() { |
| mkdir -p soong-test/java/integration/impllib |
| |
| cat > soong-test/java/integration/impllib/ExampleImpl3.java <<'EOF' |
| package soong.java.integration.impllib; |
| |
| import soong.java.integration.impllib.ExampleImpl1; |
| |
| public class ExampleImpl3 { |
| |
| public ExampleImpl3() { |
| } |
| |
| public String getClassName() { |
| return "ExampleImpl3"; |
| } |
| |
| private int getConstant() { |
| return ExampleImpl1.EXAMPLE_1_CONST_1; |
| } |
| } |
| EOF |
| } |
| |
| modify_example_impl1_file() { |
| mkdir -p soong-test/java/integration/impllib |
| |
| cat > soong-test/java/integration/impllib/ExampleImpl1.java <<'EOF' |
| package soong.java.integration.impllib; |
| |
| import soong.java.integration.provider.Provider; |
| |
| class ExampleImpl1 { |
| public static final int EXAMPLE_1_CONST_1_CHANGED = 10000; |
| |
| private Provider mProvider; |
| |
| public ExampleImpl1() { |
| mProvider = new Provider(); |
| } |
| |
| public String getClassName() { |
| return "ExampleInt1"; |
| } |
| |
| public int getProviderConstant() { |
| return mProvider.nextProviderConst(); |
| } |
| } |
| EOF |
| } |
| |
| modify_provider_file() { |
| mkdir -p soong-test/java/integration/provider |
| |
| cat > soong-test/java/integration/provider/Provider.java <<'EOF' |
| package soong.java.integration.provider; |
| |
| public class Provider { |
| public static final int PROVIDER_CONST = -1; |
| |
| private String className; |
| |
| public Provider() { |
| this.className = "Provider"; |
| } |
| |
| public int previousProviderConst() { |
| return PROVIDER_CONST - 1; |
| } |
| |
| private String getProviderName() { |
| return className; |
| } |
| } |
| EOF |
| } |
| |
| function modify_annotation_api { |
| mkdir -p soong-test/java/integration/impllib |
| |
| cat > soong-test/java/integration/impllib/AnnotationUsage.java <<'EOF' |
| package soong.java.integration.impllib; |
| import soong.java.integration.annotation.GenerateWrapper; |
| public class AnnotationUsage { |
| @GenerateWrapper(methodCount = 1) |
| public String getClassName() { |
| return "AnnotationUsage"; |
| } |
| } |
| EOF |
| } |
| |
| function remove_base_dir { |
| rm -rf soong-test |
| } |
| |
| # shellcheck disable=SC2120 |
| function partial_compile_setup { |
| remove_base_dir |
| create_base_files |
| set_partial_compile_flags |
| |
| local target_to_remove="${1:-}" |
| if [ -n "$target_to_remove" ]; then # Check if it's non-empty after default |
| echo "Removing target: $target_to_remove" |
| rm -rf "$target_to_remove" |
| fi |
| |
| local all_files="${2:-}" |
| local all_files_create=false |
| if [[ "$all_files" == "true" ]]; then |
| all_files_create=true |
| fi |
| if [[ "$all_files_create" == true ]]; then |
| echo "Adding All Files:" |
| create_example_impl3_file |
| fi |
| } |
| |
| function partial_compile_setup_with_ap { |
| remove_base_dir |
| create_base_files |
| create_ap_files |
| set_partial_compile_flags |
| } |
| |
| # shellcheck disable=SC2120 |
| function full_compile_setup { |
| remove_base_dir |
| create_base_files |
| unset_partial_compile_flags |
| |
| local target_to_remove="${1:-}" |
| if [ -n "$target_to_remove" ]; then # Check if it's non-empty after default |
| echo "Removing target: $target_to_remove" |
| rm -rf "$target_to_remove" |
| fi |
| |
| local all_files="${2:-}" |
| local all_files_create=false |
| if [[ "$all_files" == "true" ]]; then |
| all_files_create=true |
| fi |
| if [[ "$all_files_create" == true ]]; then |
| echo "Adding All Files:" |
| create_example_impl3_file |
| fi |
| } |
| |
| function set_partial_compile_flags { |
| export SOONG_PARTIAL_COMPILE=true |
| export SOONG_USE_PARTIAL_COMPILE=true |
| } |
| |
| function unset_partial_compile_flags { |
| export SOONG_PARTIAL_COMPILE=false |
| } |
| |
| function create_kotlin_files { |
| cat > soong-test/java/integration/Android.bp <<'EOF' |
| java_library { |
| name: "impl-library", |
| srcs: [ |
| "impllib/**/*.java", |
| "impllib/**/*.kt", |
| ], |
| libs: ["provider-library"], |
| sdk_version: "35", |
| } |
| |
| java_library { |
| name: "provider-library", |
| srcs: ["provider/**/*.java"], |
| sdk_version: "35", |
| } |
| EOF |
| |
| cat > soong-test/java/integration/impllib/UsesKt.java <<'EOF' |
| package soong.java.integration.impllib; |
| |
| class UsesKt { |
| private KtClass mKtClass; |
| |
| public UsesKt() { |
| mKtClass = new KtClass(); |
| } |
| |
| public void CallKt() { |
| mKtClass.foo(); |
| } |
| } |
| EOF |
| |
| cat > soong-test/java/integration/impllib/KtClass.kt <<'EOF' |
| package soong.java.integration.impllib; |
| |
| class KtClass() { |
| fun foo() { System.out.println("foo") } |
| } |
| EOF |
| } |