xref: /aosp_15_r20/external/cronet/components/cronet/android/cronet_context_adapter.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/cronet/android/cronet_context_adapter.h"
6 #include "components/cronet/android/proto/request_context_config.pb.h"
7 
8 #include <limits.h>
9 #include <stddef.h>
10 #include <stdint.h>
11 
12 #include <limits>
13 #include <map>
14 #include <set>
15 #include <utility>
16 #include <vector>
17 
18 #include "base/android/jni_android.h"
19 #include "base/android/jni_array.h"
20 #include "base/android/jni_string.h"
21 #include "base/base64.h"
22 #include "base/files/file_path.h"
23 #include "base/files/file_util.h"
24 #include "base/files/scoped_file.h"
25 #include "base/functional/bind.h"
26 #include "base/functional/callback.h"
27 #include "base/lazy_instance.h"
28 #include "base/logging.h"
29 #include "base/memory/ptr_util.h"
30 #include "base/metrics/histogram_macros.h"
31 #include "base/task/single_thread_task_runner.h"
32 #include "base/threading/thread_restrictions.h"
33 #include "base/time/time.h"
34 #include "base/values.h"
35 #include "components/cronet/android/cronet_jni_headers/CronetUrlRequestContext_jni.h"
36 #include "components/cronet/android/cronet_library_loader.h"
37 #include "components/cronet/cronet_prefs_manager.h"
38 #include "components/cronet/host_cache_persistence_manager.h"
39 #include "components/cronet/url_request_context_config.h"
40 #include "components/metrics/library_support/histogram_manager.h"
41 #include "net/base/load_flags.h"
42 #include "net/base/logging_network_change_observer.h"
43 #include "net/base/net_errors.h"
44 #include "net/base/network_delegate_impl.h"
45 #include "net/base/url_util.h"
46 #include "net/cert/caching_cert_verifier.h"
47 #include "net/cert/cert_verifier.h"
48 #include "net/cookies/cookie_monster.h"
49 #include "net/http/http_auth_handler_factory.h"
50 #include "net/log/file_net_log_observer.h"
51 #include "net/log/net_log_util.h"
52 #include "net/nqe/network_quality_estimator_params.h"
53 #include "net/proxy_resolution/proxy_config_service_android.h"
54 #include "net/proxy_resolution/proxy_resolution_service.h"
55 #include "net/third_party/quiche/src/quiche/quic/core/quic_versions.h"
56 #include "net/url_request/url_request_context.h"
57 #include "net/url_request/url_request_context_builder.h"
58 #include "net/url_request/url_request_interceptor.h"
59 
60 using base::android::JavaParamRef;
61 using base::android::ScopedJavaLocalRef;
62 
63 namespace cronet {
64 
CronetContextAdapter(std::unique_ptr<URLRequestContextConfig> context_config)65 CronetContextAdapter::CronetContextAdapter(
66     std::unique_ptr<URLRequestContextConfig> context_config) {
67   // Create context and pass ownership of |this| (self) to the context.
68   context_ = new CronetContext(std::move(context_config),
69                                base::WrapUnique<CronetContextAdapter>(this));
70 }
71 
72 CronetContextAdapter::~CronetContextAdapter() = default;
73 
InitRequestContextOnInitThread(JNIEnv * env,const JavaParamRef<jobject> & jcaller)74 void CronetContextAdapter::InitRequestContextOnInitThread(
75     JNIEnv* env,
76     const JavaParamRef<jobject>& jcaller) {
77   jcronet_url_request_context_.Reset(env, jcaller);
78   context_->InitRequestContextOnInitThread();
79 }
80 
ConfigureNetworkQualityEstimatorForTesting(JNIEnv * env,const JavaParamRef<jobject> & jcaller,jboolean use_local_host_requests,jboolean use_smaller_responses,jboolean disable_offline_check)81 void CronetContextAdapter::ConfigureNetworkQualityEstimatorForTesting(
82     JNIEnv* env,
83     const JavaParamRef<jobject>& jcaller,
84     jboolean use_local_host_requests,
85     jboolean use_smaller_responses,
86     jboolean disable_offline_check) {
87   context_->ConfigureNetworkQualityEstimatorForTesting(
88       use_local_host_requests == JNI_TRUE, use_smaller_responses == JNI_TRUE,
89       disable_offline_check == JNI_TRUE);
90 }
91 
URLRequestContextExistsForTesting(net::handles::NetworkHandle network)92 bool CronetContextAdapter::URLRequestContextExistsForTesting(
93     net::handles::NetworkHandle network) {
94   return context_->URLRequestContextExistsForTesting(network);  // IN-TEST
95 }
96 
ProvideRTTObservations(JNIEnv * env,const JavaParamRef<jobject> & jcaller,bool should)97 void CronetContextAdapter::ProvideRTTObservations(
98     JNIEnv* env,
99     const JavaParamRef<jobject>& jcaller,
100     bool should) {
101   context_->ProvideRTTObservations(should == JNI_TRUE);
102 }
103 
ProvideThroughputObservations(JNIEnv * env,const JavaParamRef<jobject> & jcaller,bool should)104 void CronetContextAdapter::ProvideThroughputObservations(
105     JNIEnv* env,
106     const JavaParamRef<jobject>& jcaller,
107     bool should) {
108   context_->ProvideThroughputObservations(should == JNI_TRUE);
109 }
110 
OnInitNetworkThread()111 void CronetContextAdapter::OnInitNetworkThread() {
112   JNIEnv* env = base::android::AttachCurrentThread();
113   Java_CronetUrlRequestContext_initNetworkThread(env,
114                                                  jcronet_url_request_context_);
115 }
116 
OnDestroyNetworkThread()117 void CronetContextAdapter::OnDestroyNetworkThread() {
118   // The |context_| is destroyed.
119   context_ = nullptr;
120 }
121 
OnEffectiveConnectionTypeChanged(net::EffectiveConnectionType effective_connection_type)122 void CronetContextAdapter::OnEffectiveConnectionTypeChanged(
123     net::EffectiveConnectionType effective_connection_type) {
124   Java_CronetUrlRequestContext_onEffectiveConnectionTypeChanged(
125       base::android::AttachCurrentThread(), jcronet_url_request_context_,
126       effective_connection_type);
127 }
128 
OnRTTOrThroughputEstimatesComputed(int32_t http_rtt_ms,int32_t transport_rtt_ms,int32_t downstream_throughput_kbps)129 void CronetContextAdapter::OnRTTOrThroughputEstimatesComputed(
130     int32_t http_rtt_ms,
131     int32_t transport_rtt_ms,
132     int32_t downstream_throughput_kbps) {
133   Java_CronetUrlRequestContext_onRTTOrThroughputEstimatesComputed(
134       base::android::AttachCurrentThread(), jcronet_url_request_context_,
135       http_rtt_ms, transport_rtt_ms, downstream_throughput_kbps);
136 }
137 
OnRTTObservation(int32_t rtt_ms,int32_t timestamp_ms,net::NetworkQualityObservationSource source)138 void CronetContextAdapter::OnRTTObservation(
139     int32_t rtt_ms,
140     int32_t timestamp_ms,
141     net::NetworkQualityObservationSource source) {
142   Java_CronetUrlRequestContext_onRttObservation(
143       base::android::AttachCurrentThread(), jcronet_url_request_context_,
144       rtt_ms, timestamp_ms, source);
145 }
146 
OnThroughputObservation(int32_t throughput_kbps,int32_t timestamp_ms,net::NetworkQualityObservationSource source)147 void CronetContextAdapter::OnThroughputObservation(
148     int32_t throughput_kbps,
149     int32_t timestamp_ms,
150     net::NetworkQualityObservationSource source) {
151   Java_CronetUrlRequestContext_onThroughputObservation(
152       base::android::AttachCurrentThread(), jcronet_url_request_context_,
153       throughput_kbps, timestamp_ms, source);
154 }
155 
OnStopNetLogCompleted()156 void CronetContextAdapter::OnStopNetLogCompleted() {
157   Java_CronetUrlRequestContext_stopNetLogCompleted(
158       base::android::AttachCurrentThread(), jcronet_url_request_context_);
159 }
160 
Destroy(JNIEnv * env,const JavaParamRef<jobject> & jcaller)161 void CronetContextAdapter::Destroy(JNIEnv* env,
162                                    const JavaParamRef<jobject>& jcaller) {
163   // Deleting |context_| on client thread will post cleanup onto network thread,
164   // which will in turn delete |this| on network thread.
165   delete context_;
166 }
167 
GetURLRequestContext(net::handles::NetworkHandle network)168 net::URLRequestContext* CronetContextAdapter::GetURLRequestContext(
169     net::handles::NetworkHandle network) {
170   return context_->GetURLRequestContext(network);
171 }
172 
PostTaskToNetworkThread(const base::Location & posted_from,base::OnceClosure callback)173 void CronetContextAdapter::PostTaskToNetworkThread(
174     const base::Location& posted_from,
175     base::OnceClosure callback) {
176   context_->PostTaskToNetworkThread(posted_from, std::move(callback));
177 }
178 
IsOnNetworkThread() const179 bool CronetContextAdapter::IsOnNetworkThread() const {
180   return context_->IsOnNetworkThread();
181 }
182 
StartNetLogToFile(JNIEnv * env,const JavaParamRef<jobject> & jcaller,const JavaParamRef<jstring> & jfile_name,jboolean jlog_all)183 bool CronetContextAdapter::StartNetLogToFile(
184     JNIEnv* env,
185     const JavaParamRef<jobject>& jcaller,
186     const JavaParamRef<jstring>& jfile_name,
187     jboolean jlog_all) {
188   std::string file_name(
189       base::android::ConvertJavaStringToUTF8(env, jfile_name));
190   return context_->StartNetLogToFile(file_name, jlog_all == JNI_TRUE);
191 }
192 
StartNetLogToDisk(JNIEnv * env,const JavaParamRef<jobject> & jcaller,const JavaParamRef<jstring> & jdir_name,jboolean jlog_all,jint jmax_size)193 void CronetContextAdapter::StartNetLogToDisk(
194     JNIEnv* env,
195     const JavaParamRef<jobject>& jcaller,
196     const JavaParamRef<jstring>& jdir_name,
197     jboolean jlog_all,
198     jint jmax_size) {
199   std::string dir_name(base::android::ConvertJavaStringToUTF8(env, jdir_name));
200   context_->StartNetLogToDisk(dir_name, jlog_all == JNI_TRUE, jmax_size);
201 }
202 
StopNetLog(JNIEnv * env,const JavaParamRef<jobject> & jcaller)203 void CronetContextAdapter::StopNetLog(JNIEnv* env,
204                                       const JavaParamRef<jobject>& jcaller) {
205   context_->StopNetLog();
206 }
207 
FlushWritePropertiesForTesting(JNIEnv * env,const base::android::JavaParamRef<jobject> & jcaller)208 void CronetContextAdapter::FlushWritePropertiesForTesting(
209     JNIEnv* env,
210     const base::android::JavaParamRef<jobject>& jcaller) {
211   context_->FlushWritePropertiesForTesting();  // IN-TEST
212 }
213 
default_load_flags() const214 int CronetContextAdapter::default_load_flags() const {
215   return context_->default_load_flags();
216 }
217 
218 // Create a URLRequestContextConfig from the given parameters.
JNI_CronetUrlRequestContext_CreateRequestContextConfig(JNIEnv * env,const JavaParamRef<jbyteArray> & javaSerializedProto)219 static jlong JNI_CronetUrlRequestContext_CreateRequestContextConfig(
220     JNIEnv* env,
221     const JavaParamRef<jbyteArray>& javaSerializedProto) {
222   const int serializedProtoLength = env->GetArrayLength(javaSerializedProto);
223   org::chromium::net::RequestContextConfigOptions configOptions;
224 
225   std::vector<uint8_t> serializedProto;
226 
227   base::android::JavaByteArrayToByteVector(env, javaSerializedProto,
228                                            &serializedProto);
229 
230   if (!configOptions.ParseFromArray(serializedProto.data(),
231                                     serializedProtoLength)) {
232     return 0;
233   }
234 
235   std::unique_ptr<URLRequestContextConfig> url_request_context_config =
236       URLRequestContextConfig::CreateURLRequestContextConfig(
237           configOptions.quic_enabled(), configOptions.http2_enabled(),
238           configOptions.brotli_enabled(),
239           static_cast<URLRequestContextConfig::HttpCacheType>(
240               configOptions.http_cache_mode()),
241           configOptions.http_cache_max_size(), configOptions.disable_cache(),
242           configOptions.storage_path(),
243           /* accept_languages */ std::string(), configOptions.user_agent(),
244           configOptions.experimental_options(),
245           base::WrapUnique(reinterpret_cast<net::CertVerifier*>(
246               configOptions.mock_cert_verifier())),
247           configOptions.enable_network_quality_estimator(),
248           configOptions.bypass_public_key_pinning_for_local_trust_anchors(),
249           configOptions.network_thread_priority() >= -20 &&
250                   configOptions.network_thread_priority() <= 19
251               ? std::optional<double>(configOptions.network_thread_priority())
252               : std::optional<double>());
253   return reinterpret_cast<jlong>(url_request_context_config.release());
254 }
255 
256 // Add a QUIC hint to a URLRequestContextConfig.
JNI_CronetUrlRequestContext_AddQuicHint(JNIEnv * env,jlong jurl_request_context_config,const JavaParamRef<jstring> & jhost,jint jport,jint jalternate_port)257 static void JNI_CronetUrlRequestContext_AddQuicHint(
258     JNIEnv* env,
259     jlong jurl_request_context_config,
260     const JavaParamRef<jstring>& jhost,
261     jint jport,
262     jint jalternate_port) {
263   URLRequestContextConfig* config =
264       reinterpret_cast<URLRequestContextConfig*>(jurl_request_context_config);
265   config->quic_hints.push_back(
266       std::make_unique<URLRequestContextConfig::QuicHint>(
267           base::android::ConvertJavaStringToUTF8(env, jhost), jport,
268           jalternate_port));
269 }
270 
271 // Add a public key pin to URLRequestContextConfig.
272 // |jhost| is the host to apply the pin to.
273 // |jhashes| is an array of jbyte[32] representing SHA256 key hashes.
274 // |jinclude_subdomains| indicates if pin should be applied to subdomains.
275 // |jexpiration_time| is the time that the pin expires, in milliseconds since
276 // Jan. 1, 1970, midnight GMT.
JNI_CronetUrlRequestContext_AddPkp(JNIEnv * env,jlong jurl_request_context_config,const JavaParamRef<jstring> & jhost,const JavaParamRef<jobjectArray> & jhashes,jboolean jinclude_subdomains,jlong jexpiration_time)277 static void JNI_CronetUrlRequestContext_AddPkp(
278     JNIEnv* env,
279     jlong jurl_request_context_config,
280     const JavaParamRef<jstring>& jhost,
281     const JavaParamRef<jobjectArray>& jhashes,
282     jboolean jinclude_subdomains,
283     jlong jexpiration_time) {
284   URLRequestContextConfig* config =
285       reinterpret_cast<URLRequestContextConfig*>(jurl_request_context_config);
286   std::unique_ptr<URLRequestContextConfig::Pkp> pkp(
287       new URLRequestContextConfig::Pkp(
288           base::android::ConvertJavaStringToUTF8(env, jhost),
289           jinclude_subdomains,
290           base::Time::UnixEpoch() + base::Milliseconds(jexpiration_time)));
291   for (auto bytes_array : jhashes.ReadElements<jbyteArray>()) {
292     static_assert(std::is_pod<net::SHA256HashValue>::value,
293                   "net::SHA256HashValue is not POD");
294     static_assert(sizeof(net::SHA256HashValue) * CHAR_BIT == 256,
295                   "net::SHA256HashValue contains overhead");
296     if (env->GetArrayLength(bytes_array.obj()) !=
297         sizeof(net::SHA256HashValue)) {
298       LOG(ERROR) << "Unable to add public key hash value.";
299       continue;
300     }
301     jbyte* bytes = env->GetByteArrayElements(bytes_array.obj(), nullptr);
302     net::HashValue hash(*reinterpret_cast<net::SHA256HashValue*>(bytes));
303     pkp->pin_hashes.push_back(hash);
304     env->ReleaseByteArrayElements(bytes_array.obj(), bytes, JNI_ABORT);
305   }
306   config->pkp_list.push_back(std::move(pkp));
307 }
308 
309 // Creates RequestContextAdater if config is valid URLRequestContextConfig,
310 // returns 0 otherwise.
JNI_CronetUrlRequestContext_CreateRequestContextAdapter(JNIEnv * env,jlong jconfig)311 static jlong JNI_CronetUrlRequestContext_CreateRequestContextAdapter(
312     JNIEnv* env,
313     jlong jconfig) {
314   std::unique_ptr<URLRequestContextConfig> context_config(
315       reinterpret_cast<URLRequestContextConfig*>(jconfig));
316 
317   CronetContextAdapter* context_adapter =
318       new CronetContextAdapter(std::move(context_config));
319   return reinterpret_cast<jlong>(context_adapter);
320 }
321 
322 static ScopedJavaLocalRef<jbyteArray>
JNI_CronetUrlRequestContext_GetHistogramDeltas(JNIEnv * env)323 JNI_CronetUrlRequestContext_GetHistogramDeltas(JNIEnv* env) {
324   std::vector<uint8_t> data;
325   if (!metrics::HistogramManager::GetInstance()->GetDeltas(&data))
326     return ScopedJavaLocalRef<jbyteArray>();
327   return base::android::ToJavaByteArray(env, data);
328 }
329 
330 }  // namespace cronet
331