#!/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
}
Messung V0.5 in Prozent C=94 H=91 G=92
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-06-28)
¤
*© Formatika GbR, Deutschland