// 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 #include #include "ash/constants/ash_switches.h" #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 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(ash::switches::kOndeviceHandwritingSwitch) && command_line->GetSwitchValueASCII( ash::switches::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