Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(444)

Unified Diff: components/cronet/android/api/src/org/chromium/net/CronetEngine.java

Issue 2626523003: Cronet: a framework for providing alternative Cronet implementations (Closed)
Patch Set: Fixed JavaDoc links Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/cronet/android/api/src/org/chromium/net/CronetEngine.java
diff --git a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java
index cd7f42558d03a9e3bcae83a468e22f5c47f6e1ef..cb6fe0ad51d4872db1eebf89cb71ac2a23cb61b3 100644
--- a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java
+++ b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java
@@ -6,12 +6,17 @@ package org.chromium.net;
import android.content.Context;
import android.net.http.HttpResponseCache;
+import android.support.annotation.VisibleForTesting;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandlerFactory;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;
@@ -63,7 +68,20 @@ public abstract class CronetEngine {
* the lifetime of {@code context} unnecessarily.
*/
public Builder(Context context) {
- mBuilderDelegate = ImplLoader.load(context);
+ this(createBuilderDelegate(context));
+ }
+
+ /**
+ * Constructs {@link Builder} with a given delegate that provides the actual implementation
+ * of the {@code Builder} methods. This constructor is used only by the internal
+ * implementation.
+ *
+ * @param builderDelegate delegate that provides the actual implementation.
+ *
+ * {@hide}
+ */
+ public Builder(ICronetEngineBuilder builderDelegate) {
+ mBuilderDelegate = builderDelegate;
}
/**
@@ -282,6 +300,131 @@ public abstract class CronetEngine {
public CronetEngine build() {
return mBuilderDelegate.build();
}
+
+ /**
+ * Creates an implementation of {@link ICronetEngineBuilder} by going through
+ * all available {@link CronetProvider CronetProviders} and selecting one
+ * with the highest priority.
pauljensen 2017/01/20 17:13:35 Please explain "highest priority"
kapishnikov 2017/01/20 21:48:38 Since an enabled provider should never return null
+ *
+ * @param context Android Context to use.
+ * @return the created {@code ICronetEngineBuilder}.
+ */
+ private static ICronetEngineBuilder createBuilderDelegate(Context context) {
+ ICronetEngineBuilder mBuilderDelegate;
pauljensen 2017/01/20 17:13:35 local variables should not have "m" prefixes, remo
kapishnikov 2017/01/20 21:48:38 Deleted.
+ List<CronetProvider> providerList =
+ getEnabledCronetProviders(context, CronetProviders.getInstance());
+
+ // Try to load implementation using available providers. Assuming that
mef 2017/01/19 22:57:46 nit: Assuming -> Assume
kapishnikov 2017/01/20 16:21:53 Done.
+ // providers in the beginning of the list have higher priority.
+ ICronetEngineBuilder builderDelegate = null;
+ for (CronetProvider provider : providerList) {
+ Builder builder = provider.createBuilder();
+ if (builder != null) {
pauljensen 2017/01/20 17:13:35 We should use either isEnabled() or createBuilder(
kapishnikov 2017/01/20 21:48:38 Agree. createBuilder() now throws an exception tha
+ builderDelegate = builder.mBuilderDelegate;
+ break;
+ }
+ }
+
+ if (builderDelegate == null) {
+ throw new RuntimeException("Unable to load any Cronet implementation."
+ + " The list of enabled providers: " + providerList);
+ }
+
+ mBuilderDelegate = builderDelegate;
+ return mBuilderDelegate;
+ }
+
+ /**
+ * Returns the list of available and enabled {@link CronetProvider}. The returned list
+ * is sorted based on the provider versions and types.
+ *
+ * @param context Android Context to use.
+ * @return the sorted list of enabled providers.
+ * @throws RuntimeException is the list of providers is empty or all of the providers
+ * are disabled.
+ *
+ * {@hide}
pauljensen 2017/01/20 17:13:35 I don't think package private appears in javadocs,
kapishnikov 2017/01/20 21:48:38 Removed.
+ */
+ @VisibleForTesting
+ static List<CronetProvider> getEnabledCronetProviders(
mef 2017/01/19 22:57:46 Should this and below be moved into CronetProvider
kapishnikov 2017/01/20 16:21:53 I have a strong opinion that CronetProviders shoul
+ Context context, CronetProviders providers) {
+ // Check that there is at least one available provider.
+ List<CronetProvider> providerList = providers.getAvailableProviders(context);
+ if (providerList.size() == 0) {
+ throw new RuntimeException("Unable to find any Cronet provider."
+ + " Have you included all necessary jars?");
+ }
+
+ // Exclude disabled providers from the list.
+ for (Iterator<CronetProvider> i = providerList.iterator(); i.hasNext();) {
+ CronetProvider provider = i.next();
+ if (!provider.isEnabled()) {
+ i.remove();
+ }
+ }
+
+ // Check that there is at least one enabled provider.
+ if (providerList.size() == 0) {
+ throw new RuntimeException("All found Cronet providers are disabled."
mef 2017/01/19 22:57:46 nit: found -> available
kapishnikov 2017/01/20 16:21:53 Done.
+ + " A provider should be enabled before it can be used.");
+ }
+
+ // Sort providers based on version and type.
+ Collections.sort(providerList, new Comparator<CronetProvider>() {
+ @Override
+ public int compare(CronetProvider p1, CronetProvider p2) {
+ // The platform provider should always be at the end of the list.
mef 2017/01/19 22:57:46 Can PlatformProvider be just added to the end of t
kapishnikov 2017/01/20 16:21:53 We could extract PlatformProvider from the list, s
+ if (CronetProviders.PROVIDER_NAME_PLATFORM.equals(p1.getName())) {
+ return 1;
+ }
+ if (CronetProviders.PROVIDER_NAME_PLATFORM.equals(p2.getName())) {
+ return -1;
+ }
+ // A provider with higher version should go first.
+ return -compareVersions(p1.getVersion(), p2.getVersion());
mef 2017/01/19 22:57:46 Is it ok if compareVersions throws an exception?
kapishnikov 2017/01/20 16:21:53 It is a good question. Currently it will cause the
+ }
+ });
+ return providerList;
+ }
+
+ /**
+ * Compares two strings that contain versions. The string should only contain
+ * dot-separated segments that contain an arbitrary number of digits digits [0-9].
+ *
+ * @param s1 the first string.
+ * @param s2 the second string.
+ * @return -1 if s1<s2, +1 if s1>s2 and 0 if s1=s2. If two versions are equal, the
+ * version with the higher number of segments is considered to be higher.
+ *
+ * @throws IllegalArgumentException if any of the strings contains an illegal
+ * version number.
+ *
+ * {@hide}
pauljensen 2017/01/20 17:13:35 I don't think package private appears in javadocs,
kapishnikov 2017/01/20 21:48:38 Removed.
+ */
+ @VisibleForTesting
+ static int compareVersions(String s1, String s2) {
+ if (s1 == null || s2 == null) {
+ throw new IllegalArgumentException("The input values cannot be null");
+ }
+ String[] s1segments = s1.split("\\.");
+ String[] s2segments = s2.split("\\.");
+ int index = 0;
+ while (s1segments.length > index && s2segments.length > index) {
pauljensen 2017/01/20 17:13:35 how about: for (int i = 0; i < s1segments.length &
kapishnikov 2017/01/20 21:48:38 Neat. Done.
+ try {
+ int s1segment = Integer.parseInt(s1segments[index]);
+ int s2segment = Integer.parseInt(s2segments[index]);
+ if (s1segment != s2segment) {
+ return Integer.signum(s1segment - s2segment);
+ }
+ index += 1;
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Unable to convert version segments into"
+ + " integers: " + s1segments[index] + " & " + s2segments[index],
+ e);
+ }
+ }
+ return Integer.signum(s1segments.length - s2segments.length);
+ }
}
/**

Powered by Google App Engine
This is Rietveld 408576698