| // 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 "chromeos/services/machine_learning/cpp/ash/handwriting_model_loader.h" |
| |
| #include <string> |
| #include <utility> |
| |
| #include "base/callback_helpers.h" |
| #include "base/command_line.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "chromeos/services/machine_learning/public/cpp/service_connection.h" |
| #include "third_party/cros_system_api/dbus/service_constants.h" |
| |
| namespace ash { |
| namespace machine_learning { |
| namespace { |
| |
| using ::chromeos::machine_learning::mojom::HandwritingRecognizerSpecPtr; |
| using ::chromeos::machine_learning::mojom::LoadHandwritingModelResult; |
| using HandwritingRecognizer = mojo::PendingReceiver< |
| ::chromeos::machine_learning::mojom::HandwritingRecognizer>; |
| using LoadHandwritingModelCallback = ::chromeos::machine_learning::mojom:: |
| MachineLearningService::LoadHandwritingModelCallback; |
| |
| // Records CrOSActionRecorder event. |
| void RecordLoadHandwritingModelResult(const LoadHandwritingModelResult val) { |
| UMA_HISTOGRAM_ENUMERATION( |
| "MachineLearningService.HandwritingModel.LoadModelResult.Event", val, |
| LoadHandwritingModelResult::LOAD_MODEL_FILES_ERROR); |
| } |
| |
| constexpr char kOndeviceHandwritingSwitch[] = "ondevice_handwriting"; |
| constexpr char kLibHandwritingDlcId[] = "libhandwriting"; |
| // A list of supported language code. |
| constexpr char kLanguageCodeEn[] = "en"; |
| constexpr char kLanguageCodeGesture[] = "gesture_in_context"; |
| |
| // Returns whether the `value` is set for command line switch |
| // kOndeviceHandwritingSwitch. |
| bool HandwritingSwitchHasValue(const std::string& value) { |
| base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
| return command_line->HasSwitch(kOndeviceHandwritingSwitch) && |
| command_line->GetSwitchValueASCII(kOndeviceHandwritingSwitch) == value; |
| } |
| |
| // Returns true if switch kOndeviceHandwritingSwitch is set to use_rootfs. |
| bool IsLibHandwritingRootfsEnabled() { |
| return HandwritingSwitchHasValue("use_rootfs"); |
| } |
| |
| // Returns true if switch kOndeviceHandwritingSwitch is set to use_dlc. |
| bool IsLibHandwritingDlcEnabled() { |
| return HandwritingSwitchHasValue("use_dlc"); |
| } |
| |
| // Called when InstallDlc completes. |
| // Returns an error if the `result.error` is not dlcservice::kErrorNone. |
| // Calls mlservice to LoadHandwritingModel otherwise. |
| void OnInstallDlcComplete( |
| HandwritingRecognizerSpecPtr spec, |
| HandwritingRecognizer receiver, |
| LoadHandwritingModelCallback callback, |
| const chromeos::DlcserviceClient::InstallResult& result) { |
| // Call LoadHandwritingModelWithSpec if no error was found. |
| if (result.error == dlcservice::kErrorNone) { |
| chromeos::machine_learning::ServiceConnection::GetInstance() |
| ->GetMachineLearningService() |
| .LoadHandwritingModel(std::move(spec), std::move(receiver), |
| std::move(callback)); |
| return; |
| } |
| |
| RecordLoadHandwritingModelResult( |
| LoadHandwritingModelResult::DLC_INSTALL_ERROR); |
| std::move(callback).Run(LoadHandwritingModelResult::DLC_INSTALL_ERROR); |
| } |
| |
| // Called when the existing-dlc-list is returned. |
| // Returns an error if libhandwriting is not in the existing-dlc-list. |
| // Calls InstallDlc otherwise. |
| void OnGetExistingDlcsComplete( |
| HandwritingRecognizerSpecPtr spec, |
| HandwritingRecognizer receiver, |
| LoadHandwritingModelCallback callback, |
| chromeos::DlcserviceClient* const dlc_client, |
| const std::string& err, |
| const dlcservice::DlcsWithContent& dlcs_with_content) { |
| // Loop over dlcs_with_content, and installs libhandwriting if already exists. |
| // Since we don't want to trigger downloading here, we only install(mount) |
| // the handwriting dlc if it is already on device. |
| for (const auto& dlc_info : dlcs_with_content.dlc_infos()) { |
| if (dlc_info.id() == kLibHandwritingDlcId) { |
| dlc_client->Install( |
| kLibHandwritingDlcId, |
| base::BindOnce(&OnInstallDlcComplete, std::move(spec), |
| std::move(receiver), std::move(callback)), |
| base::DoNothing()); |
| return; |
| } |
| } |
| |
| // Returns error if the handwriting dlc is not on the device. |
| RecordLoadHandwritingModelResult( |
| LoadHandwritingModelResult::DLC_DOES_NOT_EXIST); |
| std::move(callback).Run(LoadHandwritingModelResult::DLC_DOES_NOT_EXIST); |
| } |
| |
| } // namespace |
| |
| void LoadHandwritingModelFromRootfsOrDlc( |
| HandwritingRecognizerSpecPtr spec, |
| HandwritingRecognizer receiver, |
| LoadHandwritingModelCallback callback, |
| chromeos::DlcserviceClient* const dlc_client) { |
| // Returns FEATURE_NOT_SUPPORTED_ERROR if both rootfs and dlc are not enabled. |
| if (!IsLibHandwritingRootfsEnabled() && !IsLibHandwritingDlcEnabled()) { |
| RecordLoadHandwritingModelResult( |
| LoadHandwritingModelResult::FEATURE_NOT_SUPPORTED_ERROR); |
| std::move(callback).Run( |
| LoadHandwritingModelResult::FEATURE_NOT_SUPPORTED_ERROR); |
| return; |
| } |
| |
| // Returns LANGUAGE_NOT_SUPPORTED_ERROR if the language is not supported yet. |
| if (spec->language != kLanguageCodeEn && |
| spec->language != kLanguageCodeGesture) { |
| RecordLoadHandwritingModelResult( |
| LoadHandwritingModelResult::LANGUAGE_NOT_SUPPORTED_ERROR); |
| std::move(callback).Run( |
| LoadHandwritingModelResult::LANGUAGE_NOT_SUPPORTED_ERROR); |
| return; |
| } |
| |
| // Load from rootfs if enabled. |
| if (IsLibHandwritingRootfsEnabled()) { |
| chromeos::machine_learning::ServiceConnection::GetInstance() |
| ->GetMachineLearningService() |
| .LoadHandwritingModel(std::move(spec), std::move(receiver), |
| std::move(callback)); |
| return; |
| } |
| |
| // Gets existing dlc list and based on the presence of libhandwriting |
| // either returns an error or installs the libhandwriting dlc. |
| dlc_client->GetExistingDlcs( |
| base::BindOnce(&OnGetExistingDlcsComplete, std::move(spec), |
| std::move(receiver), std::move(callback), dlc_client)); |
| } |
| |
| } // namespace machine_learning |
| } // namespace ash |