| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 package org.chromium.net; |
| 6 |
| 7 import android.content.Context; |
| 8 import android.util.Log; |
| 9 |
| 10 import java.lang.reflect.Constructor; |
| 11 import java.lang.reflect.InvocationTargetException; |
| 12 import java.util.ArrayList; |
| 13 import java.util.List; |
| 14 |
| 15 /** |
| 16 * Provides a factory method to create {@link CronetEngine.Builder} instances. |
| 17 * A {@code CronetEngine.Builder} instance can be used to create a specific {@li
nk CronetEngine} |
| 18 * implementation. To get the list of available {@link CronetProvider}s call |
| 19 * {@link #getAllProviders(Context)}. |
| 20 * <p/> |
| 21 * <b>NOTE:</b> This class is for advanced users that want to select a particula
r |
| 22 * Cronet implementation. Most users should simply use {@code new} {@link |
| 23 * CronetEngine.Builder#CronetEngine.Builder(android.content.Context)}. |
| 24 * |
| 25 * {@hide} |
| 26 */ |
| 27 public abstract class CronetProvider { |
| 28 /** |
| 29 * String returned by {@link CronetProvider#getName} for {@link CronetProvid
er} |
| 30 * that provides native Cronet implementation packaged inside an application
. |
| 31 * This implementation offers significantly higher performance relative to t
he |
| 32 * fallback Cronet implementations (see {@link #PROVIDER_NAME_FALLBACK}). |
| 33 */ |
| 34 public static final String PROVIDER_NAME_APP_PACKAGED = "App-Packaged-Cronet
-Provider"; |
| 35 |
| 36 /** |
| 37 * String returned by {@link CronetProvider#getName} for {@link CronetProvid
er} |
| 38 * that provides Cronet implementation based on the system's |
| 39 * {@link java.net.HttpURLConnection} implementation. This implementation |
| 40 * offers significantly degraded performance relative to native Cronet |
| 41 * implementations (see {@link #PROVIDER_NAME_APP_PACKAGED}). |
| 42 */ |
| 43 public static final String PROVIDER_NAME_FALLBACK = "Fallback-Cronet-Provide
r"; |
| 44 |
| 45 /** |
| 46 * The name of an optional key in the app string resource file that contains
the class name of |
| 47 * an alternative {@code CronetProvider} implementation. |
| 48 */ |
| 49 private static final String RES_KEY_CRONET_IMPL_CLASS = "CronetProviderClass
Name"; |
| 50 |
| 51 private static final String TAG = CronetProvider.class.getSimpleName(); |
| 52 |
| 53 protected final Context mContext; |
| 54 |
| 55 protected CronetProvider(Context context) { |
| 56 mContext = context; |
| 57 } |
| 58 |
| 59 /** |
| 60 * Creates and returns an instance of {@link CronetEngine.Builder}. |
| 61 * <p/> |
| 62 * <b>NOTE:</b> This class is for advanced users that want to select a parti
cular |
| 63 * Cronet implementation. Most users should simply use {@code new} {@link |
| 64 * CronetEngine.Builder#CronetEngine.Builder(android.content.Context)}. |
| 65 * |
| 66 * @return {@code CronetEngine.Builder}. |
| 67 * @throws IllegalStateException if the provider is not enabled (see {@link
#isEnabled}. |
| 68 */ |
| 69 public abstract CronetEngine.Builder createBuilder(); |
| 70 |
| 71 /** |
| 72 * Returns the provider name. The well-know provider names include: |
| 73 * <ul> |
| 74 * <li>{@link #PROVIDER_NAME_APP_PACKAGED}</li> |
| 75 * <li>{@link #PROVIDER_NAME_FALLBACK}</li> |
| 76 * </ul> |
| 77 * |
| 78 * @return provider name. |
| 79 */ |
| 80 public abstract String getName(); |
| 81 |
| 82 /** |
| 83 * Returns the provider version. The version can be used to select the newes
t |
| 84 * available provider if multiple providers are available. |
| 85 * |
| 86 * @return provider version. |
| 87 */ |
| 88 public abstract String getVersion(); |
| 89 |
| 90 /** |
| 91 * Returns whether the provider is enabled and can be used to instantiate th
e Cronet engine. |
| 92 * A provider being out-of-date (older than the API) and needing updating is
one potential |
| 93 * reason it could be disabled. Please read the provider documentation for |
| 94 * enablement procedure. |
| 95 * |
| 96 * @return {@code true} if the provider is enabled. |
| 97 */ |
| 98 public abstract boolean isEnabled(); |
| 99 |
| 100 @Override |
| 101 public String toString() { |
| 102 return "[" |
| 103 + "class=" + getClass().getName() + ", " |
| 104 + "name=" + getName() + ", " |
| 105 + "version=" + getVersion() + ", " |
| 106 + "enabled=" + isEnabled() + "]"; |
| 107 } |
| 108 |
| 109 /** |
| 110 * Name of the Java {@link CronetProvider} class. |
| 111 */ |
| 112 private static final String JAVA_CRONET_PROVIDER_CLASS = |
| 113 "org.chromium.net.impl.JavaCronetProvider"; |
| 114 |
| 115 /** |
| 116 * Name of the native {@link CronetProvider} class. |
| 117 */ |
| 118 private static final String NATIVE_CRONET_PROVIDER_CLASS = |
| 119 "org.chromium.net.impl.NativeCronetProvider"; |
| 120 |
| 121 /** |
| 122 * Returns an unmodifiable list of all available {@link CronetProvider}s. |
| 123 * The providers are returned in no particular order. Some of the returned |
| 124 * providers may be in a disabled state and should be enabled by the invoker
. |
| 125 * See {@link CronetProvider#isEnabled()}. |
| 126 * |
| 127 * @return the list of available providers. |
| 128 */ |
| 129 public static List<CronetProvider> getAllProviders(Context context) { |
| 130 List<CronetProvider> providers = new ArrayList<>(); |
| 131 addCronetProviderFromResourceFile(context, providers); |
| 132 addCronetProviderImplByClassName(context, NATIVE_CRONET_PROVIDER_CLASS,
providers, false); |
| 133 addCronetProviderImplByClassName(context, JAVA_CRONET_PROVIDER_CLASS, pr
oviders, false); |
| 134 return providers; |
| 135 } |
| 136 |
| 137 /** |
| 138 * Attempts to add a new provider referenced by the class name to the end of
the list. |
| 139 * |
| 140 * @param className the class name of the provider that should be instantiat
ed. |
| 141 * @param providers the list of providers to add the new provider to. |
| 142 * @return {@code true} if the provider was added to the list; {@code false} |
| 143 * if the provider couldn't be instantiated. |
| 144 */ |
| 145 private static boolean addCronetProviderImplByClassName( |
| 146 Context context, String className, List<CronetProvider> providers, b
oolean logError) { |
| 147 ClassLoader loader = context.getClassLoader(); |
| 148 try { |
| 149 Class<? extends CronetProvider> providerClass = |
| 150 loader.loadClass(className).asSubclass(CronetProvider.class)
; |
| 151 Constructor<? extends CronetProvider> ctor = |
| 152 providerClass.getConstructor(Context.class); |
| 153 providers.add(ctor.newInstance(context)); |
| 154 return true; |
| 155 } catch (InstantiationException e) { |
| 156 logReflectiveOperationException(className, logError, e); |
| 157 } catch (InvocationTargetException e) { |
| 158 logReflectiveOperationException(className, logError, e); |
| 159 } catch (NoSuchMethodException e) { |
| 160 logReflectiveOperationException(className, logError, e); |
| 161 } catch (IllegalAccessException e) { |
| 162 logReflectiveOperationException(className, logError, e); |
| 163 } catch (ClassNotFoundException e) { |
| 164 logReflectiveOperationException(className, logError, e); |
| 165 } |
| 166 return false; |
| 167 } |
| 168 |
| 169 /** |
| 170 * De-duplicates exception handling logic in {@link #addCronetProviderImplBy
ClassName}. |
| 171 * It should be removed when support of API Levels lower than 19 is deprecat
ed. |
| 172 */ |
| 173 private static void logReflectiveOperationException( |
| 174 String className, boolean logError, Exception e) { |
| 175 if (logError) { |
| 176 Log.e(TAG, "Unable to load provider class: " + className, e); |
| 177 } else { |
| 178 Log.d(TAG, "Tried to load " + className + " provider class but it wa
sn't" |
| 179 + " included in the app classpath"); |
| 180 } |
| 181 } |
| 182 |
| 183 /** |
| 184 * Attempts to add a provider specified in the app resource file to the end |
| 185 * of the provider list. |
| 186 * |
| 187 * @param providers the list of providers to add the new provider to. |
| 188 * @return {@code true} if the provider was added to the list; {@code false} |
| 189 * if the app resources do not include the string with |
| 190 * {@link #RES_KEY_CRONET_IMPL_CLASS} key. |
| 191 * @throws RuntimeException if the provider cannot be found or instantiated. |
| 192 */ |
| 193 private static boolean addCronetProviderFromResourceFile( |
| 194 Context context, List<CronetProvider> providers) { |
| 195 int resId = context.getResources().getIdentifier( |
| 196 RES_KEY_CRONET_IMPL_CLASS, "string", context.getPackageName()); |
| 197 // Resource not found |
| 198 if (resId == 0) { |
| 199 // The resource wasn't included in the app; therefore, there is noth
ing to add. |
| 200 return false; |
| 201 } |
| 202 String className = context.getResources().getString(resId); |
| 203 |
| 204 if (!addCronetProviderImplByClassName(context, className, providers, tru
e)) { |
| 205 throw new RuntimeException("Unable to instantiate Cronet implementat
ion class " |
| 206 + className + " that is listed as in the app string resource
file under " |
| 207 + RES_KEY_CRONET_IMPL_CLASS + " key"); |
| 208 } |
| 209 return true; |
| 210 } |
| 211 } |
| OLD | NEW |