1 // Copyright 2020 The Chromium Authors. All rights reserved.
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 "chromeos/services/machine_learning/public/cpp/handwriting_model_loader.h"
6
7 #include <string>
8 #include <utility>
9
10 #include "base/callback_helpers.h"
11 #include "base/command_line.h"
12 #include "base/metrics/histogram_macros.h"
13 #include "chromeos/services/machine_learning/public/cpp/service_connection.h"
14 #include "third_party/cros_system_api/dbus/service_constants.h"
15
16 namespace chromeos {
17 namespace machine_learning {
18 namespace {
19
20 using ::chromeos::machine_learning::mojom::HandwritingRecognizerSpecPtr;
21 using ::chromeos::machine_learning::mojom::LoadHandwritingModelResult;
22 using HandwritingRecognizer =
23 mojo::PendingReceiver<mojom::HandwritingRecognizer>;
24 using LoadHandwritingModelCallback = ::chromeos::machine_learning::mojom::
25 MachineLearningService::LoadHandwritingModelCallback;
26
27 // Records CrOSActionRecorder event.
RecordLoadHandwritingModelResult(const LoadHandwritingModelResult val)28 void RecordLoadHandwritingModelResult(const LoadHandwritingModelResult val) {
29 UMA_HISTOGRAM_ENUMERATION(
30 "MachineLearningService.HandwritingModel.LoadModelResult.Event", val,
31 LoadHandwritingModelResult::LOAD_MODEL_FILES_ERROR);
32 }
33
34 constexpr char kOndeviceHandwritingSwitch[] = "ondevice_handwriting";
35 constexpr char kLibHandwritingDlcId[] = "libhandwriting";
36 // A list of supported language code.
37 constexpr char kLanguageCodeEn[] = "en";
38 constexpr char kLanguageCodeGesture[] = "gesture_in_context";
39
40 // Returns whether the `value` is set for command line switch
41 // kOndeviceHandwritingSwitch.
HandwritingSwitchHasValue(const std::string & value)42 bool HandwritingSwitchHasValue(const std::string& value) {
43 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
44 return command_line->HasSwitch(kOndeviceHandwritingSwitch) &&
45 command_line->GetSwitchValueASCII(kOndeviceHandwritingSwitch) == value;
46 }
47
48 // Returns true if switch kOndeviceHandwritingSwitch is set to use_rootfs.
IsLibHandwritingRootfsEnabled()49 bool IsLibHandwritingRootfsEnabled() {
50 return HandwritingSwitchHasValue("use_rootfs");
51 }
52
53 // Returns true if switch kOndeviceHandwritingSwitch is set to use_dlc.
IsLibHandwritingDlcEnabled()54 bool IsLibHandwritingDlcEnabled() {
55 return HandwritingSwitchHasValue("use_dlc");
56 }
57
58 // Called when InstallDlc completes.
59 // Returns an error if the `result.error` is not dlcservice::kErrorNone.
60 // Calls mlservice to LoadHandwritingModel otherwise.
OnInstallDlcComplete(HandwritingRecognizerSpecPtr spec,HandwritingRecognizer receiver,LoadHandwritingModelCallback callback,const chromeos::DlcserviceClient::InstallResult & result)61 void OnInstallDlcComplete(
62 HandwritingRecognizerSpecPtr spec,
63 HandwritingRecognizer receiver,
64 LoadHandwritingModelCallback callback,
65 const chromeos::DlcserviceClient::InstallResult& result) {
66 // Call LoadHandwritingModelWithSpec if no error was found.
67 if (result.error == dlcservice::kErrorNone) {
68 ServiceConnection::GetInstance()->LoadHandwritingModel(
69 std::move(spec), std::move(receiver), std::move(callback));
70 return;
71 }
72
73 RecordLoadHandwritingModelResult(
74 LoadHandwritingModelResult::DLC_INSTALL_ERROR);
75 std::move(callback).Run(LoadHandwritingModelResult::DLC_INSTALL_ERROR);
76 }
77
78 // Called when the existing-dlc-list is returned.
79 // Returns an error if libhandwriting is not in the existing-dlc-list.
80 // Calls InstallDlc otherwise.
OnGetExistingDlcsComplete(HandwritingRecognizerSpecPtr spec,HandwritingRecognizer receiver,LoadHandwritingModelCallback callback,DlcserviceClient * const dlc_client,const std::string & err,const dlcservice::DlcsWithContent & dlcs_with_content)81 void OnGetExistingDlcsComplete(
82 HandwritingRecognizerSpecPtr spec,
83 HandwritingRecognizer receiver,
84 LoadHandwritingModelCallback callback,
85 DlcserviceClient* const dlc_client,
86 const std::string& err,
87 const dlcservice::DlcsWithContent& dlcs_with_content) {
88 // Loop over dlcs_with_content, and installs libhandwriting if already exists.
89 // Since we don't want to trigger downloading here, we only install(mount)
90 // the handwriting dlc if it is already on device.
91 for (const auto& dlc_info : dlcs_with_content.dlc_infos()) {
92 if (dlc_info.id() == kLibHandwritingDlcId) {
93 dlc_client->Install(
94 kLibHandwritingDlcId,
95 base::BindOnce(&OnInstallDlcComplete, std::move(spec),
96 std::move(receiver), std::move(callback)),
97 base::DoNothing());
98 return;
99 }
100 }
101
102 // Returns error if the handwriting dlc is not on the device.
103 RecordLoadHandwritingModelResult(
104 LoadHandwritingModelResult::DLC_DOES_NOT_EXIST);
105 std::move(callback).Run(LoadHandwritingModelResult::DLC_DOES_NOT_EXIST);
106 }
107
108 } // namespace
109
LoadHandwritingModelFromRootfsOrDlc(HandwritingRecognizerSpecPtr spec,HandwritingRecognizer receiver,LoadHandwritingModelCallback callback,DlcserviceClient * const dlc_client)110 void LoadHandwritingModelFromRootfsOrDlc(HandwritingRecognizerSpecPtr spec,
111 HandwritingRecognizer receiver,
112 LoadHandwritingModelCallback callback,
113 DlcserviceClient* const dlc_client) {
114 // Returns FEATURE_NOT_SUPPORTED_ERROR if both rootfs and dlc are not enabled.
115 if (!IsLibHandwritingRootfsEnabled() && !IsLibHandwritingDlcEnabled()) {
116 RecordLoadHandwritingModelResult(
117 LoadHandwritingModelResult::FEATURE_NOT_SUPPORTED_ERROR);
118 std::move(callback).Run(
119 LoadHandwritingModelResult::FEATURE_NOT_SUPPORTED_ERROR);
120 return;
121 }
122
123 // Returns LANGUAGE_NOT_SUPPORTED_ERROR if the language is not supported yet.
124 if (spec->language != kLanguageCodeEn &&
125 spec->language != kLanguageCodeGesture) {
126 RecordLoadHandwritingModelResult(
127 LoadHandwritingModelResult::LANGUAGE_NOT_SUPPORTED_ERROR);
128 std::move(callback).Run(
129 LoadHandwritingModelResult::LANGUAGE_NOT_SUPPORTED_ERROR);
130 return;
131 }
132
133 // Load from rootfs if enabled.
134 if (IsLibHandwritingRootfsEnabled()) {
135 ServiceConnection::GetInstance()->LoadHandwritingModel(
136 std::move(spec), std::move(receiver), std::move(callback));
137 return;
138 }
139
140 // Gets existing dlc list and based on the presence of libhandwriting
141 // either returns an error or installs the libhandwriting dlc.
142 dlc_client->GetExistingDlcs(
143 base::BindOnce(&OnGetExistingDlcsComplete, std::move(spec),
144 std::move(receiver), std::move(callback), dlc_client));
145 }
146
147 } // namespace machine_learning
148 } // namespace chromeos
149