aboutsummaryrefslogtreecommitdiff
path: root/android
diff options
context:
space:
mode:
authorLouis Ryan <lryan@google.com>2015-08-31 09:45:03 -0700
committerLouis Ryan <lryan@google.com>2015-09-03 13:58:23 -0700
commitd6dc790f05c90ffba2c7a4356121ae4d586e467e (patch)
tree301e03df32dce3bebd3eaaebdbf6353a427c4cd3 /android
parentaefefb50c4fd5cb15828470694c73d7ba42a79e0 (diff)
downloadgrpc-grpc-java-d6dc790f05c90ffba2c7a4356121ae4d586e467e.tar.gz
Draft of Android specific Channe builder
Diffstat (limited to 'android')
-rw-r--r--android/build.gradle27
-rw-r--r--android/delegate.gradle151
-rw-r--r--android/src/androidTest/java/io/grpc/android/AndroidChannelBuilderTest.java56
-rw-r--r--android/src/main/AndroidManifest.xml34
-rw-r--r--android/src/main/java/io/grpc/android/AndroidChannelBuilder.java139
5 files changed, 407 insertions, 0 deletions
diff --git a/android/build.gradle b/android/build.gradle
new file mode 100644
index 000000000..ecc5f6bd6
--- /dev/null
+++ b/android/build.gradle
@@ -0,0 +1,27 @@
+// We fork the android build to avoid classpath conflicts from buildscript.
+task prereqs(dependsOn: [':grpc-okhttp:install', ':grpc-core:install']) {}
+
+task assemble(type: GradleBuild, dependsOn: 'prereqs') {
+ buildFile = 'delegate.gradle'
+ tasks = ['assemble']
+}
+
+task build(type: GradleBuild, dependsOn: 'prereqs') {
+ buildFile = 'delegate.gradle'
+ tasks = ['build']
+}
+
+task install(type: GradleBuild, dependsOn: 'prereqs') {
+ buildFile = 'delegate.gradle'
+ tasks = ['install']
+}
+
+task uploadArchives(type: GradleBuild, dependsOn: 'prereqs') {
+ buildFile = 'delegate.gradle'
+ tasks = ['uploadArchives']
+}
+
+task clean(type: GradleBuild) {
+ buildFile = 'delegate.gradle'
+ tasks = ['clean']
+}
diff --git a/android/delegate.gradle b/android/delegate.gradle
new file mode 100644
index 000000000..d653e8a03
--- /dev/null
+++ b/android/delegate.gradle
@@ -0,0 +1,151 @@
+buildscript {
+ repositories {
+ mavenCentral()
+ mavenLocal()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:1.3.+'
+ classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.12.+'
+ classpath 'com.github.dcendents:android-maven-plugin:1.2'
+ }
+}
+apply plugin: 'android-sdk-manager'
+apply plugin: 'com.android.library'
+apply plugin: 'com.github.dcendents.android-maven'
+apply plugin: 'signing'
+
+def properties = new Properties()
+properties.load(new FileInputStream(file('../version.properties')))
+
+description = 'gRPC: Android'
+group = "io.grpc"
+version = "${properties.version}"
+
+repositories {
+ mavenCentral()
+ mavenLocal()
+}
+
+// Need to override to ensure maven artifact is generated with correct name
+// Must match uploadTask.repositories.mavenDeployer.pom.artifactId
+project.archivesBaseName = "grpc-android"
+
+android {
+ // Matches preinstalled on travis to keep CI build times down
+ compileSdkVersion 21
+ buildToolsVersion '21.1.1'
+
+ defaultConfig {
+ minSdkVersion 9
+ targetSdkVersion 21
+ versionCode 1
+ versionName "1.0"
+ }
+ lintOptions {
+ disable 'InvalidPackage', 'HardcodedText'
+ }
+}
+
+// Disable JavaDoc doclint on Java 8. It's annoying.
+if (JavaVersion.current().isJava8Compatible()) {
+ allprojects {
+ tasks.withType(Javadoc) {
+ options.addStringOption('Xdoclint:none', '-quiet')
+ }
+ }
+}
+
+configurations {
+ javadocDeps
+}
+
+dependencies {
+ compile "io.grpc:grpc-okhttp:${properties.version}"
+ javadocDeps "io.grpc:grpc-okhttp:${properties.version}"
+
+ testCompile 'junit:junit:4.12'
+ testCompile 'org.mockito:mockito-core:1.9.5'
+}
+
+signing {
+ required false
+ sign configurations.archives
+}
+
+uploadArchives.repositories.mavenDeployer {
+ beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
+ String stagingUrl
+ if (rootProject.hasProperty('repositoryId')) {
+ stagingUrl = 'https://oss.sonatype.org/service/local/staging/deployByRepositoryId/' +
+ rootProject.repositoryId
+ } else {
+ stagingUrl = 'https://oss.sonatype.org/service/local/staging/deploy/maven2/'
+ }
+ def configureAuth = {
+ if (rootProject.hasProperty('ossrhUsername') && rootProject.hasProperty('ossrhPassword')) {
+ authentication(userName: rootProject.ossrhUsername, password: rootProject.ossrhPassword)
+ }
+ }
+ repository(url: stagingUrl, configureAuth)
+ snapshotRepository(url: 'https://oss.sonatype.org/content/repositories/snapshots/', configureAuth)
+ pom.artifactId = 'grpc-android'
+}
+
+[
+ install.repositories.mavenInstaller,
+ uploadArchives.repositories.mavenDeployer,
+]*.pom*.whenConfigured { pom ->
+ pom.project {
+ name "$project.group:grpc-android"
+ description project.description
+ packaging 'aar'
+ url 'https://github.com/grpc/grpc-java'
+
+ scm {
+ connection 'scm:svn:https://github.com/grpc/grpc-java.git'
+ developerConnection 'scm:svn:git@github.com:grpc/grpc-java.git'
+ url 'https://github.com/grpc/grpc-java'
+ }
+
+ licenses {
+ license {
+ name 'BSD 3-Clause'
+ url 'http://opensource.org/licenses/BSD-3-Clause'
+ }
+ }
+
+ developers {
+ developer {
+ id "grpc.io"
+ name "gRPC Contributors"
+ email "grpc-io@googlegroups.com"
+ url "http://grpc.io/"
+ // https://issues.gradle.org/browse/GRADLE-2719
+ organization = "Google, Inc."
+ organizationUrl "https://www.google.com"
+ }
+ }
+ }
+}
+
+task sourcesJar(type: Jar) {
+ from android.sourceSets.main.java.srcDirs
+ classifier = 'sources'
+}
+
+task javadoc(type: Javadoc) {
+ source = android.sourceSets.main.java.srcDirs
+ classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
+ classpath += configurations.javadocDeps
+ destinationDir = file("../javadoc/")
+}
+
+task javadocJar(type: Jar, dependsOn: javadoc) {
+ classifier = 'javadoc'
+ from javadoc.destinationDir
+}
+
+artifacts {
+ archives javadocJar
+ archives sourcesJar
+}
diff --git a/android/src/androidTest/java/io/grpc/android/AndroidChannelBuilderTest.java b/android/src/androidTest/java/io/grpc/android/AndroidChannelBuilderTest.java
new file mode 100644
index 000000000..fa49e91bd
--- /dev/null
+++ b/android/src/androidTest/java/io/grpc/android/AndroidChannelBuilderTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2014, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package io.grpc.android;
+
+import static org.junit.Assert.assertNotNull;
+
+import io.grpc.ManagedChannel;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for {@link io.grpc.android.AndroidChannelBuilder}.
+ */
+@RunWith(JUnit4.class)
+public class AndroidChannelBuilderTest {
+
+ @Test
+ public void testDefaultProducesChannel() {
+ AndroidChannelBuilder channelBuilder = AndroidChannelBuilder.forAddress("localhost", 1234);
+ channelBuilder.userAgent("test");
+ ManagedChannel channel = channelBuilder.build();
+ assertNotNull(channel);
+ channel.shutdownNow();
+ }
+}
diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..e41a7da94
--- /dev/null
+++ b/android/src/main/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014, Google Inc. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Google Inc. nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="io.grpc.android">
+</manifest>
diff --git a/android/src/main/java/io/grpc/android/AndroidChannelBuilder.java b/android/src/main/java/io/grpc/android/AndroidChannelBuilder.java
new file mode 100644
index 000000000..0b549164f
--- /dev/null
+++ b/android/src/main/java/io/grpc/android/AndroidChannelBuilder.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2014, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package io.grpc.android;
+
+import io.grpc.ClientInterceptor;
+import io.grpc.ExperimentalApi;
+import io.grpc.ManagedChannelBuilder;
+import io.grpc.internal.ManagedChannelImpl;
+import io.grpc.okhttp.NegotiationType;
+import io.grpc.okhttp.OkHttpChannelBuilder;
+
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+
+/**
+ * A {@link io.grpc.ManagedChannelBuilder} that provides a stable interface for producing
+ * {@link io.grpc.Channel} instances on Android. This allows applications to be resilient
+ * to changes such as defaulting to a new channel implementation or breaking API changes
+ * in existing ones. Configuration options will be added here only if they provide value
+ * to a broad set of users and are likely to be resilient to changes in the underlying channel
+ * implementation.
+ *
+ * <p>Developers needing advanced configuration are free to use the underlying channel
+ * implementations directly while assuming the risks associated with using an
+ * {@link io.grpc.ExperimentalApi}.
+ */
+
+// TODO(lryan):
+// - Document the various dangers of scheduling work onto Android Main/UI/whatever
+// threads. Is any enforcement practical? Conversely is there a sensible default. I assume
+// its also a bad idea to use huge numbers of threads too.
+// - Provide SSL installation and detect ALPN/NPN support?
+// - Allow for an alternate TrustManager ? for self-signed, pinning etc. Is there a good default
+// impl for these variations blessed by security team?
+// - Augment with user-agent with app id?
+// - Specify a smaller flow-control window by default? Fewer concurrent streams?
+public class AndroidChannelBuilder extends ManagedChannelBuilder<AndroidChannelBuilder> {
+ // Currently we only support OkHttp on Android. This will become dynamic as more transport
+ // implementations become available.
+ private final OkHttpChannelBuilder baseBuilder;
+
+ public static AndroidChannelBuilder forAddress(String host, int port) {
+ return new AndroidChannelBuilder(OkHttpChannelBuilder.forAddress(host, port));
+ }
+
+ private AndroidChannelBuilder(OkHttpChannelBuilder builder) {
+ this.baseBuilder = builder;
+ }
+
+ @Override
+ public AndroidChannelBuilder executor(ExecutorService executor) {
+ baseBuilder.executor(executor);
+ return this;
+ }
+
+ @Override
+ public AndroidChannelBuilder intercept(List<ClientInterceptor> list) {
+ baseBuilder.intercept(list);
+ return this;
+ }
+
+ @Override
+ public AndroidChannelBuilder intercept(ClientInterceptor... interceptors) {
+ baseBuilder.intercept(interceptors);
+ return this;
+ }
+
+ @Override
+ public AndroidChannelBuilder userAgent(String userAgent) {
+ baseBuilder.userAgent(userAgent);
+ return this;
+ }
+
+ /**
+ * Use of a plaintext connection to the server. By default a secure connection mechanism
+ * such as TLS will be used.
+ *
+ * <p>Should only be used for testing or for APIs where the use of such API or the data
+ * exchanged is not sensitive.
+ *
+ * @param skipNegotiation @{code true} if there is a priori knowledge that the endpoint supports
+ * plaintext, {@code false} if plaintext use must be negotiated.
+ */
+ @ExperimentalApi("primarily for testing")
+ public AndroidChannelBuilder usePlaintext(boolean skipNegotiation) {
+ if (skipNegotiation) {
+ baseBuilder.negotiationType(NegotiationType.PLAINTEXT);
+ return this;
+ } else {
+ throw new IllegalArgumentException("Not currently supported");
+ }
+ }
+
+ /**
+ * Overrides the host used with TLS and HTTP virtual hosting. It does not change what host is
+ * actually connected to.
+ *
+ * <p>Should only be used for testing.
+ */
+ @ExperimentalApi("primarily for testing")
+ public AndroidChannelBuilder overrideHostForAuthority(String host) {
+ baseBuilder.overrideHostForAuthority(host);
+ return this;
+ }
+
+ @Override
+ public ManagedChannelImpl build() {
+ return baseBuilder.build();
+ }
+}