Skip to content

Commit

Permalink
Split SODA into language components
Browse files Browse the repository at this point in the history
This CL splits the SODA component into a single SODA binary component
and multiple language pack components.

Todo: Update the settings UI reflect the download progress of the
SODA binary and the language pack(s).

Todo: Verify that the SODA binary component and the language pack
component is installed before launching the Live caption feature.

Change-Id: Ia82ac3b46da2d37ce1e0fae9d6cd7fb541d67d60
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2340873
Reviewed-by: Joshua Pawlicki <waffles@chromium.org>
Reviewed-by: Scott Violet <sky@chromium.org>
Reviewed-by: Matthew Denton <mpdenton@chromium.org>
Reviewed-by: Dominic Mazzoni <dmazzoni@chromium.org>
Commit-Queue: Evan Liu <evliu@google.com>
Cr-Commit-Position: refs/heads/master@{#800723}
  • Loading branch information
evliu-google authored and Commit Bot committed Aug 21, 2020
1 parent 87071b6 commit 5826f33
Show file tree
Hide file tree
Showing 23 changed files with 739 additions and 13 deletions.
4 changes: 4 additions & 0 deletions chrome/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -3139,6 +3139,10 @@ static_library("browser") {
"component_updater/intervention_policy_database_component_installer.h",
"component_updater/soda_component_installer.cc",
"component_updater/soda_component_installer.h",
"component_updater/soda_en_us_component_installer.cc",
"component_updater/soda_en_us_component_installer.h",
"component_updater/soda_ja_jp_component_installer.cc",
"component_updater/soda_ja_jp_component_installer.h",
"content_settings/generated_cookie_prefs.cc",
"content_settings/generated_cookie_prefs.h",
"custom_handlers/register_protocol_handler_permission_request.cc",
Expand Down
1 change: 1 addition & 0 deletions chrome/browser/accessibility/DEPS
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
include_rules = [
"+components/soda",
"+services/image_annotation",
]
21 changes: 21 additions & 0 deletions chrome/browser/accessibility/caption_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "chrome/common/pref_names.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/soda/constants.h"
#include "components/sync_preferences/pref_service_syncable.h"
#include "content/public/browser/browser_accessibility_state.h"
#include "content/public/browser/web_contents.h"
Expand Down Expand Up @@ -52,6 +53,10 @@ void CaptionController::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
registry->RegisterFilePathPref(prefs::kSodaBinaryPath, base::FilePath());
registry->RegisterFilePathPref(prefs::kSodaEnUsConfigPath, base::FilePath());
registry->RegisterFilePathPref(prefs::kSodaJaJpConfigPath, base::FilePath());

// Initially default the language to en-US.
registry->RegisterStringPref(prefs::kLiveCaptionLanguageCode, "en-US");
}

void CaptionController::Init() {
Expand All @@ -65,6 +70,10 @@ void CaptionController::Init() {
prefs::kLiveCaptionEnabled,
base::BindRepeating(&CaptionController::OnLiveCaptionEnabledChanged,
base::Unretained(this)));
pref_change_registrar_->Add(
prefs::kLiveCaptionLanguageCode,
base::BindRepeating(&CaptionController::OnLiveCaptionLanguageChanged,
base::Unretained(this)));

enabled_ = IsLiveCaptionEnabled();
if (enabled_)
Expand All @@ -83,9 +92,14 @@ void CaptionController::OnLiveCaptionEnabledChanged() {
enabled_ = enabled;

UpdateSpeechRecognitionServiceEnabled();
UpdateSpeechRecognitionLanguage();
UpdateUIEnabled();
}

void CaptionController::OnLiveCaptionLanguageChanged() {
UpdateSpeechRecognitionLanguage();
}

bool CaptionController::IsLiveCaptionEnabled() {
PrefService* profile_prefs = profile_->GetPrefs();
return profile_prefs->GetBoolean(prefs::kLiveCaptionEnabled);
Expand All @@ -104,6 +118,13 @@ void CaptionController::UpdateSpeechRecognitionServiceEnabled() {
}
}

void CaptionController::UpdateSpeechRecognitionLanguage() {
if (enabled_) {
component_updater::RegisterSodaLanguageComponent(
g_browser_process->component_updater(), profile_->GetPrefs());
}
} // namespace captions

void CaptionController::UpdateUIEnabled() {
if (enabled_) {
// Create captions UI in each browser view.
Expand Down
2 changes: 2 additions & 0 deletions chrome/browser/accessibility/caption_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,10 @@ class CaptionController : public BrowserListObserver, public KeyedService {
void OnBrowserRemoved(Browser* browser) override;

void OnLiveCaptionEnabledChanged();
void OnLiveCaptionLanguageChanged();
bool IsLiveCaptionEnabled();
void UpdateSpeechRecognitionServiceEnabled();
void UpdateSpeechRecognitionLanguage();
void UpdateUIEnabled();
void UpdateCaptionStyle();

Expand Down
1 change: 1 addition & 0 deletions chrome/browser/component_updater/registration.cc
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ void RegisterComponentsForUpdate(bool is_off_the_record_profile,
#if !defined(OS_ANDROID)
component_updater::RegisterSODAComponent(cus, profile_prefs,
base::OnceClosure());
component_updater::RegisterSodaLanguageComponent(cus, profile_prefs);
#endif

#if defined(OS_CHROMEOS)
Expand Down
35 changes: 29 additions & 6 deletions chrome/browser/component_updater/soda_component_installer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include "base/files/file_util.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/component_updater/soda_en_us_component_installer.h"
#include "chrome/browser/component_updater/soda_ja_jp_component_installer.h"
#include "chrome/common/pref_names.h"
#include "chrome/services/speech/buildflags.h"
#include "components/component_updater/component_updater_service.h"
Expand Down Expand Up @@ -36,9 +38,6 @@ static_assert(base::size(kSODAPublicKeySHA256) == crypto::kSHA256Length,

const char kSODAManifestName[] = "SODA Library";

constexpr base::FilePath::CharType kSodaEnUsConfigFileRelativePath[] =
FILE_PATH_LITERAL("SODAFiles/en_us/dictation.ascii_proto");

} // namespace

SODAComponentInstallerPolicy::SODAComponentInstallerPolicy(
Expand Down Expand Up @@ -78,7 +77,7 @@ bool SODAComponentInstallerPolicy::SupportsGroupPolicyEnabledComponentUpdates()
}

bool SODAComponentInstallerPolicy::RequiresNetworkEncryption() const {
return false;
return true;
}

update_client::CrxInstaller::Result
Expand Down Expand Up @@ -127,8 +126,6 @@ void UpdateSODAInstallDirPref(PrefService* prefs,
#if !defined(OS_ANDROID)
prefs->SetFilePath(prefs::kSodaBinaryPath,
install_dir.Append(speech::kSodaBinaryRelativePath));
prefs->SetFilePath(prefs::kSodaEnUsConfigPath,
install_dir.Append(kSodaEnUsConfigFileRelativePath));
#endif
}

Expand Down Expand Up @@ -172,6 +169,32 @@ void RegisterSODAComponent(ComponentUpdateService* cus,
#endif
}

void RegisterSodaLanguageComponent(ComponentUpdateService* cus,
PrefService* prefs) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
#if BUILDFLAG(ENABLE_SODA)
speech::LanguageCode language = speech::GetLanguageCode(
prefs->GetString(prefs::kLiveCaptionLanguageCode));
switch (language) {
case speech::LanguageCode::kNone:
// Do nothing.
break;
case speech::LanguageCode::kEnUs:
RegisterSodaEnUsComponent(
cus, prefs,
base::BindOnce(&SodaEnUsComponentInstallerPolicy::
UpdateSodaEnUsComponentOnDemand));
break;
case speech::LanguageCode::kJaJp:
RegisterSodaJaJpComponent(
cus, prefs,
base::BindOnce(&SodaJaJpComponentInstallerPolicy::
UpdateSodaJaJpComponentOnDemand));
break;
}
#endif
}

bool UninstallSODAComponent(ComponentUpdateService* cus, PrefService* prefs) {
return cus->UnregisterComponent(
SODAComponentInstallerPolicy::GetExtensionId());
Expand Down
3 changes: 3 additions & 0 deletions chrome/browser/component_updater/soda_component_installer.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ void RegisterSODAComponent(ComponentUpdateService* cus,
PrefService* prefs,
base::OnceClosure callback);

void RegisterSodaLanguageComponent(ComponentUpdateService* cus,
PrefService* prefs);

bool UninstallSODAComponent(ComponentUpdateService* cus, PrefService* prefs);

} // namespace component_updater
Expand Down
165 changes: 165 additions & 0 deletions chrome/browser/component_updater/soda_en_us_component_installer.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
// 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 "chrome/browser/component_updater/soda_en_us_component_installer.h"

#include "base/bind.h"
#include "base/files/file_util.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/common/pref_names.h"
#include "chrome/services/speech/buildflags.h"
#include "components/component_updater/component_updater_service.h"
#include "components/crx_file/id_util.h"
#include "components/soda/constants.h"
#include "components/update_client/update_client_errors.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "crypto/sha2.h"

using content::BrowserThread;

namespace component_updater {

namespace {

// The SHA256 of the SubjectPublicKeyInfo used to sign the component.
// The component id is: oegebmmcimckjhkhbggblnkjloogjdfg
const uint8_t kSodaEnUsPublicKeySHA256[32] = {
0xe4, 0x64, 0x1c, 0xc2, 0x8c, 0x2a, 0x97, 0xa7, 0x16, 0x61, 0xbd,
0xa9, 0xbe, 0xe6, 0x93, 0x56, 0xf5, 0x05, 0x33, 0x9b, 0x8b, 0x0b,
0x02, 0xe2, 0x6b, 0x7e, 0x6c, 0x40, 0xa1, 0xd2, 0x7e, 0x18};

static_assert(base::size(kSodaEnUsPublicKeySHA256) == crypto::kSHA256Length,
"Wrong hash length");

const char kSodaEnUsManifestName[] = "SODA en-US Models";

constexpr base::FilePath::CharType kSodaEnUsConfigFileRelativePath[] =
FILE_PATH_LITERAL("SODAModels/dictation.ascii_proto");

} // namespace

SodaEnUsComponentInstallerPolicy::SodaEnUsComponentInstallerPolicy(
OnSodaEnUsComponentReadyCallback callback)
: on_component_ready_callback_(callback) {}

SodaEnUsComponentInstallerPolicy::~SodaEnUsComponentInstallerPolicy() = default;

const std::string SodaEnUsComponentInstallerPolicy::GetExtensionId() {
return crx_file::id_util::GenerateIdFromHash(
kSodaEnUsPublicKeySHA256, sizeof(kSodaEnUsPublicKeySHA256));
}

void SodaEnUsComponentInstallerPolicy::UpdateSodaEnUsComponentOnDemand() {
const std::string crx_id =
component_updater::SodaEnUsComponentInstallerPolicy::GetExtensionId();
g_browser_process->component_updater()->GetOnDemandUpdater().OnDemandUpdate(
crx_id, component_updater::OnDemandUpdater::Priority::FOREGROUND,
base::BindOnce([](update_client::Error error) {
if (error != update_client::Error::NONE &&
error != update_client::Error::UPDATE_IN_PROGRESS)
LOG(ERROR) << "On demand update of the SODA en-US component failed "
"with error: "
<< static_cast<int>(error);
}));
}

bool SodaEnUsComponentInstallerPolicy::VerifyInstallation(
const base::DictionaryValue& manifest,
const base::FilePath& install_dir) const {
return base::PathExists(install_dir.Append(kSodaEnUsConfigFileRelativePath));
}

bool SodaEnUsComponentInstallerPolicy::
SupportsGroupPolicyEnabledComponentUpdates() const {
return true;
}

bool SodaEnUsComponentInstallerPolicy::RequiresNetworkEncryption() const {
return true;
}

update_client::CrxInstaller::Result
SodaEnUsComponentInstallerPolicy::OnCustomInstall(
const base::DictionaryValue& manifest,
const base::FilePath& install_dir) {
return update_client::CrxInstaller::Result(0); // Nothing custom here.
}

void SodaEnUsComponentInstallerPolicy::OnCustomUninstall() {}

void SodaEnUsComponentInstallerPolicy::ComponentReady(
const base::Version& version,
const base::FilePath& install_dir,
std::unique_ptr<base::DictionaryValue> manifest) {
VLOG(1) << "Component ready, version " << version.GetString() << " in "
<< install_dir.value();

on_component_ready_callback_.Run(install_dir);
}

base::FilePath SodaEnUsComponentInstallerPolicy::GetRelativeInstallDir() const {
return base::FilePath(speech::kSodaEnUsInstallationRelativePath);
}

void SodaEnUsComponentInstallerPolicy::GetHash(
std::vector<uint8_t>* hash) const {
hash->assign(kSodaEnUsPublicKeySHA256,
kSodaEnUsPublicKeySHA256 + base::size(kSodaEnUsPublicKeySHA256));
}

std::string SodaEnUsComponentInstallerPolicy::GetName() const {
return kSodaEnUsManifestName;
}

update_client::InstallerAttributes
SodaEnUsComponentInstallerPolicy::GetInstallerAttributes() const {
return update_client::InstallerAttributes();
}

std::vector<std::string> SodaEnUsComponentInstallerPolicy::GetMimeTypes()
const {
return std::vector<std::string>();
}

void UpdateSodaEnUsInstallDirPref(PrefService* prefs,
const base::FilePath& install_dir) {
#if !defined(OS_ANDROID)
prefs->SetFilePath(prefs::kSodaEnUsConfigPath,
install_dir.Append(kSodaEnUsConfigFileRelativePath));
#endif
}

void RegisterSodaEnUsComponent(ComponentUpdateService* cus,
PrefService* prefs,
base::OnceClosure callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
#if BUILDFLAG(ENABLE_SODA)
if (!prefs->GetBoolean(prefs::kLiveCaptionEnabled))
return;

auto installer = base::MakeRefCounted<ComponentInstaller>(
std::make_unique<SodaEnUsComponentInstallerPolicy>(base::BindRepeating(
[](ComponentUpdateService* cus, PrefService* prefs,
const base::FilePath& install_dir) {
if (prefs->GetBoolean(prefs::kLiveCaptionEnabled)) {
content::GetUIThreadTaskRunner({base::TaskPriority::BEST_EFFORT})
->PostTask(FROM_HERE,
base::BindOnce(&UpdateSodaEnUsInstallDirPref,
prefs, install_dir));
}
},
cus, prefs)));

installer->Register(cus, std::move(callback));
#endif
}

bool UninstallSodaEnUsComponent(ComponentUpdateService* cus,
PrefService* prefs) {
return cus->UnregisterComponent(
SodaEnUsComponentInstallerPolicy::GetExtensionId());
}
} // namespace component_updater
Loading

0 comments on commit 5826f33

Please sign in to comment.