blob: 1727c24b7ba54ce88fdc410238262e1487fe0f86 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <jni.h>
#include <string>
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/net/dns_probe_runner.h"
#include "chrome/browser/net/secure_dns_config.h"
#include "chrome/browser/net/secure_dns_util.h"
#include "chrome/browser/net/stub_resolver_config_reader.h"
#include "chrome/browser/net/system_network_context_manager.h"
#include "chrome/browser/privacy/jni_headers/SecureDnsBridge_jni.h"
#include "chrome/common/pref_names.h"
#include "components/country_codes/country_codes.h"
#include "components/prefs/pref_service.h"
#include "net/dns/public/doh_provider_entry.h"
#include "net/dns/public/secure_dns_mode.h"
#include "net/dns/public/util.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/callback_helpers.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/network_service_instance.h"
using base::android::JavaParamRef;
using base::android::ScopedJavaLocalRef;
using chrome_browser_net::DnsProbeRunner;
namespace secure_dns = chrome_browser_net::secure_dns;
namespace {
net::DohProviderEntry::List GetFilteredProviders() {
const auto local_providers = secure_dns::ProvidersForCountry(
net::DohProviderEntry::GetList(), country_codes::GetCurrentCountryID());
return secure_dns::RemoveDisabledProviders(
local_providers, secure_dns::GetDisabledProviders());
}
// Runs a DNS probe according to the configuration in |overrides|,
// asynchronously sets |success| to indicate the result, and signals
// |waiter| when the probe has completed. Must run on the UI thread.
void RunProbe(base::WaitableEvent* waiter,
bool* success,
net::DnsConfigOverrides overrides) {
auto* manager = g_browser_process->system_network_context_manager();
auto runner = std::make_unique<DnsProbeRunner>(
std::move(overrides),
base::BindRepeating(&SystemNetworkContextManager::GetContext,
base::Unretained(manager)));
auto* const runner_ptr = runner.get();
runner_ptr->RunProbe(base::BindOnce(
[](base::WaitableEvent* waiter, bool* success,
std::unique_ptr<DnsProbeRunner> runner) {
*success = runner->result() == DnsProbeRunner::CORRECT;
waiter->Signal();
},
waiter, success, std::move(runner)));
}
} // namespace
static jint JNI_SecureDnsBridge_GetMode(JNIEnv* env) {
return static_cast<int>(
SystemNetworkContextManager::GetStubResolverConfigReader()
->GetSecureDnsConfiguration(
true /* force_check_parental_controls_for_automatic_mode */)
.mode());
}
static void JNI_SecureDnsBridge_SetMode(JNIEnv* env, jint mode) {
PrefService* local_state = g_browser_process->local_state();
local_state->SetString(
prefs::kDnsOverHttpsMode,
SecureDnsConfig::ModeToString(static_cast<net::SecureDnsMode>(mode)));
}
static jboolean JNI_SecureDnsBridge_IsModeManaged(JNIEnv* env) {
PrefService* local_state = g_browser_process->local_state();
return local_state->IsManagedPreference(prefs::kDnsOverHttpsMode);
}
static ScopedJavaLocalRef<jobjectArray> JNI_SecureDnsBridge_GetProviders(
JNIEnv* env) {
net::DohProviderEntry::List providers = GetFilteredProviders();
std::vector<std::vector<std::u16string>> ret;
ret.reserve(providers.size());
std::transform(providers.begin(), providers.end(), std::back_inserter(ret),
[](const auto* entry) {
return std::vector<std::u16string>{
{base::UTF8ToUTF16(entry->ui_name),
base::UTF8ToUTF16(entry->dns_over_https_template),
base::UTF8ToUTF16(entry->privacy_policy)}};
});
return base::android::ToJavaArrayOfStringArray(env, ret);
}
static ScopedJavaLocalRef<jstring> JNI_SecureDnsBridge_GetTemplates(
JNIEnv* env) {
PrefService* local_state = g_browser_process->local_state();
return base::android::ConvertUTF8ToJavaString(
env, local_state->GetString(prefs::kDnsOverHttpsTemplates));
}
static jboolean JNI_SecureDnsBridge_SetTemplates(
JNIEnv* env,
const JavaParamRef<jstring>& jtemplates) {
PrefService* local_state = g_browser_process->local_state();
std::string templates = base::android::ConvertJavaStringToUTF8(jtemplates);
if (templates.empty()) {
local_state->ClearPref(prefs::kDnsOverHttpsTemplates);
return true;
}
if (secure_dns::IsValidGroup(templates)) {
local_state->SetString(prefs::kDnsOverHttpsTemplates, templates);
return true;
}
return false;
}
static jint JNI_SecureDnsBridge_GetManagementMode(JNIEnv* env) {
return static_cast<int>(
SystemNetworkContextManager::GetStubResolverConfigReader()
->GetSecureDnsConfiguration(
true /* force_check_parental_controls_for_automatic_mode */)
.management_mode());
}
static void JNI_SecureDnsBridge_UpdateDropdownHistograms(
JNIEnv* env,
const JavaParamRef<jstring>& old_template,
const JavaParamRef<jstring>& new_template) {
secure_dns::UpdateDropdownHistograms(
GetFilteredProviders(),
base::android::ConvertJavaStringToUTF8(old_template),
base::android::ConvertJavaStringToUTF8(new_template));
}
static void JNI_SecureDnsBridge_UpdateValidationHistogram(JNIEnv* env,
jboolean valid) {
secure_dns::UpdateValidationHistogram(valid);
}
static ScopedJavaLocalRef<jobjectArray> JNI_SecureDnsBridge_SplitTemplateGroup(
JNIEnv* env,
const JavaParamRef<jstring>& jgroup) {
std::string group = base::android::ConvertJavaStringToUTF8(jgroup);
std::vector<base::StringPiece> templates = secure_dns::SplitGroup(group);
std::vector<std::string> templates_copy(templates.begin(), templates.end());
return base::android::ToJavaArrayOfStrings(env, templates_copy);
}
static jboolean JNI_SecureDnsBridge_ProbeServer(
JNIEnv* env,
const JavaParamRef<jstring>& jtemplate) {
net::DnsConfigOverrides overrides;
overrides.search = std::vector<std::string>();
overrides.attempts = 1;
overrides.secure_dns_mode = net::SecureDnsMode::kSecure;
secure_dns::ApplyTemplate(&overrides,
base::android::ConvertJavaStringToUTF8(jtemplate));
// Android recommends converting async functions to blocking when using JNI:
// https://developer.android.com/training/articles/perf-jni.
// This function converts the DnsProbeRunner, which can only be created and
// used on the UI thread, into a blocking function that can be called from an
// auxiliary Java thread.
// TODO: Use std::future if allowed in the future.
base::WaitableEvent waiter;
bool success;
bool posted = content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(RunProbe, &waiter, &success, std::move(overrides)));
DCHECK(posted);
waiter.Wait();
secure_dns::UpdateProbeHistogram(success);
return success;
}