diff --git a/.bazelrc b/.bazelrc index 53485cb9743..e1d02eaf3de 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1 +1,7 @@ build --cxxopt=-std=c++17 --host_cxxopt=-std=c++17 + +# Enforce stable JDK 17 compilation globally (aligns with rules_android defaults) +common --java_language_version=17 +common --java_runtime_version=17 +common --tool_java_language_version=17 +common --tool_java_runtime_version=17 diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index ccabd9be79f..8793cfb82fe 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -81,7 +81,7 @@ jobs: matrix: bzlmod: [true, false] env: - USE_BAZEL_VERSION: 7.7.1 + USE_BAZEL_VERSION: 8.7.0 steps: - uses: actions/checkout@v4 @@ -100,11 +100,11 @@ jobs: key: ${{ runner.os }}-bazel-${{ env.USE_BAZEL_VERSION }}-${{ hashFiles('WORKSPACE', 'repositories.bzl') }} - name: Run bazel build - run: bazelisk build //... --enable_bzlmod=${{ matrix.bzlmod }} + run: bazelisk build //... --enable_bzlmod=${{ matrix.bzlmod }} --enable_workspace=${{ !matrix.bzlmod }} - name: Run bazel test - run: bazelisk test //... --enable_bzlmod=${{ matrix.bzlmod }} + run: bazelisk test //... --enable_bzlmod=${{ matrix.bzlmod }} --enable_workspace=${{ !matrix.bzlmod }} - name: Run example bazel build - run: bazelisk build //... --enable_bzlmod=${{ matrix.bzlmod }} + run: bazelisk build //... --enable_bzlmod=${{ matrix.bzlmod }} --enable_workspace=${{ !matrix.bzlmod }} working-directory: ./examples diff --git a/MODULE.bazel b/MODULE.bazel index 42c3ed23e03..4f4b0d46893 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,7 +1,6 @@ module( name = "grpc-java", version = "1.82.0-SNAPSHOT", # CURRENT_GRPC_VERSION - compatibility_level = 0, repo_name = "io_grpc_grpc_java", ) @@ -53,6 +52,7 @@ bazel_dep(name = "bazel_skylib", version = "1.7.1") bazel_dep(name = "googleapis", version = "0.0.0-20240326-1c8d509c5", repo_name = "com_google_googleapis") bazel_dep(name = "grpc-proto", version = "0.0.0-20240627-ec30f58.bcr.1", repo_name = "io_grpc_grpc_proto") bazel_dep(name = "protobuf", version = "33.4", repo_name = "com_google_protobuf") +bazel_dep(name = "rules_android", version = "0.6.0") bazel_dep(name = "rules_cc", version = "0.0.9") bazel_dep(name = "rules_java", version = "9.1.0") bazel_dep(name = "rules_jvm_external", version = "6.0") diff --git a/WORKSPACE b/WORKSPACE index 1efdf2793a8..c2df64bb814 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -17,6 +17,7 @@ load("@com_google_protobuf//:protobuf_deps.bzl", "PROTOBUF_MAVEN_ARTIFACTS", "pr protobuf_deps() +# Register remote JDK toolchains to safely compile Java targets under Bazel 8. load("@rules_java//java:rules_java_deps.bzl", "rules_java_dependencies") rules_java_dependencies() @@ -25,6 +26,11 @@ load("@bazel_features//:deps.bzl", "bazel_features_deps") bazel_features_deps() +# Must be loaded after bazel_features_deps() to avoid circular deps. +load("@rules_java//java:repositories.bzl", "rules_java_toolchains") + +rules_java_toolchains() + load("@bazel_jar_jar//:jar_jar.bzl", "jar_jar_repositories") jar_jar_repositories() @@ -49,10 +55,119 @@ http_archive( load("@rules_jvm_external//:defs.bzl", "maven_install") maven_install( - artifacts = IO_GRPC_GRPC_JAVA_ARTIFACTS + PROTOBUF_MAVEN_ARTIFACTS, + artifacts = IO_GRPC_GRPC_JAVA_ARTIFACTS + PROTOBUF_MAVEN_ARTIFACTS + [ + # Hack: Android compile-time worker ResourceProcessorBusyBox uses protos internally. + # This ensures rules_jvm_external generates its namespace target alias, + # enabling the IO_GRPC_GRPC_JAVA_OVERRIDE_TARGETS to override it correctly. + "com.google.protobuf:protobuf-java-util:3.25.5", + ], override_targets = IO_GRPC_GRPC_JAVA_OVERRIDE_TARGETS, repositories = [ "https://repo.maven.apache.org/maven2/", + # For androidx deps (e.g. core) not published to Maven Central. + "https://maven.google.com", ], strict_visibility = True, ) + +# Define a custom rules_android_maven repository to override its com.google.protobuf +# runtime dependency to point directly to our workspace compiled C++ target. +# This resolves severe runtime-vs-gencode validation crashes inside the precompiled +# ResourceProcessorBusyBox tool when executing under legacy workspace mode. +maven_install( + name = "rules_android_maven", + artifacts = [ + "androidx.privacysandbox.tools:tools:1.0.0-alpha06", + "androidx.privacysandbox.tools:tools-apigenerator:1.0.0-alpha06", + "androidx.privacysandbox.tools:tools-apipackager:1.0.0-alpha06", + "androidx.test:core:1.6.0-alpha01", + "androidx.test.ext:junit:1.2.0-alpha01", + "com.android.tools.apkdeployer:apkdeployer:8.8.0-alpha05", + "org.gradle:gradle-core:4.2.1", + "com.android.tools.build:bundletool:1.15.5", + "com.android.tools:desugar_jdk_libs_minimal:2.0.4", + "com.android.tools:desugar_jdk_libs_configuration_minimal:2.0.4", + "com.android.tools:desugar_jdk_libs_nio:2.0.4", + "com.android.tools:desugar_jdk_libs_configuration_nio:2.0.4", + "com.android.tools.build:gradle:8.7.0", + "com.android.tools:r8:8.5.35", + "org.bouncycastle:bcprov-jdk18on:1.77", + "org.hamcrest:hamcrest-core:2.2", + "org.robolectric:robolectric:4.14.1", + "com.google.flogger:flogger:0.8", + "com.google.guava:guava:32.1.2-jre", + "com.google.truth:truth:1.1.5", + "info.picocli:picocli:4.7.4", + "jakarta.inject:jakarta.inject-api:2.0.1", + "junit:junit:4.13.2", + "com.beust:jcommander:1.82", + "com.google.protobuf:protobuf-java:3.25.5", + "com.google.protobuf:protobuf-java-util:3.25.5", + "com.google.code.findbugs:jsr305:3.0.2", + "androidx.databinding:databinding-compiler:8.7.0", + "org.ow2.asm:asm:9.6", + "org.ow2.asm:asm-commons:9.6", + "org.ow2.asm:asm-tree:9.6", + "org.ow2.asm:asm-util:9.6", + "com.android.tools.layoutlib:layoutlib-api:30.1.3", + "com.android:zipflinger:8.7.0", + "com.android.tools.build:manifest-merger:30.1.3", + "com.android:signflinger:8.7.0", + "com.android.tools.build:aapt2-proto:8.6.1-11315950", + "com.android.tools.analytics-library:protos:30.1.3", + "com.android.tools.analytics-library:shared:30.1.3", + "com.android.tools.analytics-library:tracker:30.1.3", + "com.android.tools:annotations:30.1.3", + "com.android.tools.build:apksig:8.7.0", + "com.android.tools.build:apkzlib:8.7.0", + "com.android.tools.build:builder:8.7.0", + "com.android.tools.build:builder-model:8.7.0", + "com.google.auto.value:auto-value:1.11.0", + "com.google.auto.value:auto-value-annotations:1.11.0", + "com.google.auto:auto-common:1.2.2", + "com.google.auto.service:auto-service:1.1.1", + "com.google.auto.service:auto-service-annotations:1.1.1", + "com.google.errorprone:error_prone_annotations:2.33.0", + "com.google.errorprone:error_prone_type_annotations:2.33.0", + "com.google.errorprone:error_prone_check_api:2.33.0", + "com.google.errorprone:error_prone_core:2.33.0", + ], + override_targets = { + "com.google.protobuf:protobuf-java": "@com_google_protobuf//:protobuf_java", + "com.google.protobuf:protobuf-java-util": "@com_google_protobuf//:protobuf_java_util", + }, + repositories = [ + "https://repo1.maven.org/maven2", + "https://maven.google.com", + "https://repo.gradle.org/gradle/libs-releases", + ], + use_starlark_android_rules = True, + aar_import_bzl_label = "@rules_android//rules:rules.bzl", +) + +# Download rules_android prerequisite repositories (such as @robolectric, +# @io_bazel_rules_go, and @bazel_gazelle). This MUST be executed before loading +# @rules_android//:defs.bzl to resolve top-level circular Starlark load statements. +load("@rules_android//:prereqs.bzl", "rules_android_prereqs") + +rules_android_prereqs() + +load("@rules_android//:defs.bzl", "rules_android_workspace") + +rules_android_workspace() + +load("@rules_android//rules/android_sdk_repository:rule.bzl", "android_sdk_repository") + +android_sdk_repository( + name = "androidsdk", +) + +# Register Android and SDK toolchains. +# Note: @rules_android//toolchains/android_sdk:android_sdk_tools is required +# to bridge legacy generated `@androidsdk` toolchains to modern standalone +# rules_android toolchain type expectations under legacy workspace mode. +register_toolchains( + "@androidsdk//:all", + "@rules_android//toolchains/android:all", + "@rules_android//toolchains/android_sdk:android_sdk_tools", +) diff --git a/android/BUILD.bazel b/android/BUILD.bazel new file mode 100644 index 00000000000..287a91da01b --- /dev/null +++ b/android/BUILD.bazel @@ -0,0 +1,19 @@ +load("@rules_android//rules:rules.bzl", "android_library") +load("@rules_jvm_external//:defs.bzl", "artifact") + +android_library( + name = "android", + srcs = glob([ + "src/main/java/**/*.java", + ]), + custom_package = "io.grpc.android", + manifest = "src/main/AndroidManifest.xml", + visibility = ["//visibility:public"], + deps = [ + "//api", + "//core:internal", + artifact("com.google.code.findbugs:jsr305"), + artifact("com.google.errorprone:error_prone_annotations"), + artifact("com.google.guava:guava"), + ], +) diff --git a/examples/MODULE.bazel b/examples/MODULE.bazel index 105fcecaafe..10b541067cc 100644 --- a/examples/MODULE.bazel +++ b/examples/MODULE.bazel @@ -2,6 +2,8 @@ bazel_dep(name = "grpc-java", version = "1.82.0-SNAPSHOT", repo_name = "io_grpc_ bazel_dep(name = "rules_java", version = "9.3.0") bazel_dep(name = "grpc-proto", version = "0.0.0-20240627-ec30f58", repo_name = "io_grpc_grpc_proto") bazel_dep(name = "protobuf", version = "33.1", repo_name = "com_google_protobuf") +bazel_dep(name = "rules_android", version = "0.6.0") +bazel_dep(name = "rules_proto", version = "7.1.0") bazel_dep(name = "rules_jvm_external", version = "6.0") # Do not use this override in your own MODULE.bazel. It is unnecessary when @@ -26,7 +28,11 @@ maven.install( artifacts = [ "com.google.api.grpc:grpc-google-cloud-pubsub-v1:0.1.24", "com.google.api.grpc:proto-google-cloud-pubsub-v1:0.1.24", + "androidx.appcompat:appcompat:1.0.0", + ], + repositories = [ + "https://repo.maven.apache.org/maven2/", + "https://maven.google.com", ], - repositories = ["https://repo.maven.apache.org/maven2/"], strict_visibility = True, ) diff --git a/examples/android/helloworld/app/BUILD.bazel b/examples/android/helloworld/app/BUILD.bazel new file mode 100644 index 00000000000..8dac01c6a8c --- /dev/null +++ b/examples/android/helloworld/app/BUILD.bazel @@ -0,0 +1,42 @@ +load("@rules_android//rules:rules.bzl", "android_binary") +load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library") +load("@rules_proto//proto:defs.bzl", "proto_library") +load("@rules_java//java:defs.bzl", "java_lite_proto_library") + +proto_library( + name = "helloworld_proto", + srcs = ["src/main/proto/helloworld.proto"], +) + +java_lite_proto_library( + name = "helloworld_java_proto_lite", + deps = [":helloworld_proto"], +) + +java_grpc_library( + name = "helloworld_java_grpc_lite", + srcs = [":helloworld_proto"], + flavor = "lite", + deps = [":helloworld_java_proto_lite"], +) + +android_binary( + name = "app", + srcs = glob([ + "src/main/java/**/*.java", + ]), + custom_package = "io.grpc.helloworldexample", + manifest = "src/main/AndroidManifest.xml", + resource_files = glob(["src/main/res/**"]), + visibility = ["//visibility:public"], + deps = [ + ":helloworld_java_grpc_lite", + ":helloworld_java_proto_lite", + "@io_grpc_grpc_java//api", + "@io_grpc_grpc_java//android", + "@io_grpc_grpc_java//okhttp", + "@io_grpc_grpc_java//protobuf-lite", + "@io_grpc_grpc_java//stub", + "@maven//:androidx_appcompat_appcompat", + ], +) diff --git a/examples/android/helloworld/app/build.gradle b/examples/android/helloworld/app/build.gradle index 1e81415e483..caf20d95e1b 100644 --- a/examples/android/helloworld/app/build.gradle +++ b/examples/android/helloworld/app/build.gradle @@ -55,4 +55,5 @@ dependencies { implementation 'io.grpc:grpc-okhttp:1.82.0-SNAPSHOT' // CURRENT_GRPC_VERSION implementation 'io.grpc:grpc-protobuf-lite:1.82.0-SNAPSHOT' // CURRENT_GRPC_VERSION implementation 'io.grpc:grpc-stub:1.82.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-android:1.82.0-SNAPSHOT' // CURRENT_GRPC_VERSION } diff --git a/examples/android/helloworld/app/src/main/java/io/grpc/helloworldexample/HelloworldActivity.java b/examples/android/helloworld/app/src/main/java/io/grpc/helloworldexample/HelloworldActivity.java index 201c385a7aa..684d79a2993 100644 --- a/examples/android/helloworld/app/src/main/java/io/grpc/helloworldexample/HelloworldActivity.java +++ b/examples/android/helloworld/app/src/main/java/io/grpc/helloworldexample/HelloworldActivity.java @@ -29,7 +29,7 @@ import android.widget.EditText; import android.widget.TextView; import io.grpc.ManagedChannel; -import io.grpc.ManagedChannelBuilder; +import io.grpc.android.AndroidChannelBuilder; import io.grpc.examples.helloworld.GreeterGrpc; import io.grpc.examples.helloworld.HelloReply; import io.grpc.examples.helloworld.HelloRequest; @@ -91,7 +91,12 @@ protected String doInBackground(String... params) { String portStr = params[2]; int port = TextUtils.isEmpty(portStr) ? 0 : Integer.valueOf(portStr); try { - channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext().build(); + Activity activity = activityReference.get(); + AndroidChannelBuilder channelBuilder = AndroidChannelBuilder.forAddress(host, port); + if (activity != null) { + channelBuilder.context(activity.getApplicationContext()); + } + channel = channelBuilder.usePlaintext().build(); GreeterGrpc.GreeterBlockingStub stub = GreeterGrpc.newBlockingStub(channel); HelloRequest request = HelloRequest.newBuilder().setName(message).build(); HelloReply reply = stub.sayHello(request); diff --git a/repositories.bzl b/repositories.bzl index 0a09cece070..436021b091a 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -110,6 +110,13 @@ def grpc_java_repositories(): strip_prefix = "bazel_jar_jar-0.1.6", url = "https://github.com/bazeltools/bazel_jar_jar/releases/download/v0.1.6/bazel_jar_jar-v0.1.6.tar.gz", ) + if not native.existing_rule("rules_android"): + http_archive( + name = "rules_android", + sha256 = "af84b69ab3d16dd1a41056286e6511f147a94ccea995603e13e934c915c1631c", + strip_prefix = "rules_android-0.6.0", + urls = ["https://github.com/bazelbuild/rules_android/releases/download/v0.6.0/rules_android-v0.6.0.tar.gz"], + ) def com_google_protobuf(): # proto_library rules implicitly depend on @com_google_protobuf//:protoc,