blob: de8abb8a283ca5e1072b5070fd6b287a411161a5 [file] [log] [blame]
Andrew Moylanff6be512018-07-03 11:05:01 +10001// Copyright 2018 The Chromium OS 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 "ml/machine_learning_service_impl.h"
6
Michael Martisa74af932018-08-13 16:52:36 +10007#include <memory>
Andrew Moylanff6be512018-07-03 11:05:01 +10008#include <utility>
9
Honglin Yu7b6c1192020-09-16 10:07:17 +100010#include <unistd.h>
11
Michael Martisa74af932018-08-13 16:52:36 +100012#include <base/bind.h>
hscham4ce3c992021-02-19 16:37:23 +090013#include <base/callback_helpers.h>
Qijiang Fan713061e2021-03-08 15:45:12 +090014#include <base/check.h>
Honglin Yuf33dce32019-12-05 15:10:39 +110015#include <base/files/file.h>
16#include <base/files/file_util.h>
Honglin Yu20391cd2020-10-27 15:58:49 +110017#include <base/files/memory_mapped_file.h>
Honglin Yud88ebcd2021-05-07 11:04:25 +100018#include <base/notreached.h>
Michael Martis8783c8e2019-06-26 17:30:54 +100019#include <tensorflow/lite/model.h>
Honglin Yuf33dce32019-12-05 15:10:39 +110020#include <unicode/putil.h>
21#include <unicode/udata.h>
22#include <utils/memory/mmap.h>
Michael Martisa74af932018-08-13 16:52:36 +100023
Jing Wang961b8af2020-10-26 12:40:35 +110024#include "ml/grammar_checker_impl.h"
25#include "ml/grammar_library.h"
charleszhao17777f92020-04-23 12:53:11 +100026#include "ml/handwriting.h"
27#include "ml/handwriting_recognizer_impl.h"
Michael Martisa74af932018-08-13 16:52:36 +100028#include "ml/model_impl.h"
charleszhao17777f92020-04-23 12:53:11 +100029#include "ml/mojom/handwriting_recognizer.mojom.h"
Hidehiko Abeaa488c32018-08-31 23:49:41 +090030#include "ml/mojom/model.mojom.h"
Honglin Yud2204272020-08-26 14:21:37 +100031#include "ml/mojom/soda.mojom.h"
Honglin Yu0f5b21d2021-04-06 23:39:04 +100032#include "ml/mojom/web_platform_handwriting.mojom.h"
Honglin Yu7b6c1192020-09-16 10:07:17 +100033#include "ml/process.h"
Andrew Moylan44c352f2020-11-04 15:19:46 +110034#include "ml/request_metrics.h"
Honglin Yud2204272020-08-26 14:21:37 +100035#include "ml/soda_recognizer_impl.h"
Honglin Yuf33dce32019-12-05 15:10:39 +110036#include "ml/text_classifier_impl.h"
Curtis McMullanf11584f2021-01-13 12:21:36 +110037#include "ml/text_suggester_impl.h"
38#include "ml/text_suggestions.h"
Honglin Yu0f5b21d2021-04-06 23:39:04 +100039#include "ml/web_platform_handwriting_recognizer_impl.h"
Michael Martisa74af932018-08-13 16:52:36 +100040
Andrew Moylanff6be512018-07-03 11:05:01 +100041namespace ml {
42
Michael Martisa74af932018-08-13 16:52:36 +100043namespace {
44
Honglin Yu0ed72352019-08-27 17:42:01 +100045using ::chromeos::machine_learning::mojom::BuiltinModelId;
46using ::chromeos::machine_learning::mojom::BuiltinModelSpecPtr;
47using ::chromeos::machine_learning::mojom::FlatBufferModelSpecPtr;
Andrew Moylanb481af72020-07-09 15:22:00 +100048using ::chromeos::machine_learning::mojom::HandwritingRecognizer;
charleszhao05c5a4a2020-06-09 16:49:54 +100049using ::chromeos::machine_learning::mojom::HandwritingRecognizerSpec;
50using ::chromeos::machine_learning::mojom::HandwritingRecognizerSpecPtr;
Charles Zhao6d467e62020-08-31 10:02:03 +100051using ::chromeos::machine_learning::mojom::LoadHandwritingModelResult;
Michael Martisa74af932018-08-13 16:52:36 +100052using ::chromeos::machine_learning::mojom::LoadModelResult;
Andrew Moylanb481af72020-07-09 15:22:00 +100053using ::chromeos::machine_learning::mojom::MachineLearningService;
54using ::chromeos::machine_learning::mojom::Model;
Honglin Yud2204272020-08-26 14:21:37 +100055using ::chromeos::machine_learning::mojom::SodaClient;
56using ::chromeos::machine_learning::mojom::SodaConfigPtr;
57using ::chromeos::machine_learning::mojom::SodaRecognizer;
Andrew Moylanb481af72020-07-09 15:22:00 +100058using ::chromeos::machine_learning::mojom::TextClassifier;
Michael Martisa74af932018-08-13 16:52:36 +100059
60constexpr char kSystemModelDir[] = "/opt/google/chrome/ml_models/";
Andrew Moylan79b34a42020-07-08 11:13:11 +100061// Base name for UMA metrics related to model loading (`LoadBuiltinModel`,
62// `LoadFlatBufferModel`, `LoadTextClassifier` or LoadHandwritingModel).
Honglin Yu6adafcd2019-07-22 13:48:11 +100063constexpr char kMetricsRequestName[] = "LoadModelResult";
Michael Martisa74af932018-08-13 16:52:36 +100064
Honglin Yuf33dce32019-12-05 15:10:39 +110065constexpr char kIcuDataFilePath[] = "/opt/google/chrome/icudtl.dat";
66
Honglin Yu20391cd2020-10-27 15:58:49 +110067// Used to hold the mmap object of the icu data file. Each process should only
68// have one instance of it. Intentionally never close it.
69// We can not make it as a member of `MachineLearningServiceImpl` because it
70// will crash the unit test (because in that case, when the
71// `MachineLearningServiceImpl` object is destructed, the file will be
72// unmapped but the icu data can not be reset in the testing process).
73base::MemoryMappedFile* g_icu_data_mmap_file = nullptr;
74
75void InitIcuIfNeeded() {
76 if (!g_icu_data_mmap_file) {
77 g_icu_data_mmap_file = new base::MemoryMappedFile();
78 CHECK(g_icu_data_mmap_file->Initialize(
79 base::FilePath(kIcuDataFilePath),
80 base::MemoryMappedFile::Access::READ_ONLY));
81 // Init the Icu library.
82 UErrorCode err = U_ZERO_ERROR;
83 udata_setCommonData(const_cast<uint8_t*>(g_icu_data_mmap_file->data()),
84 &err);
85 DCHECK(err == U_ZERO_ERROR);
86 // Never try to load Icu data from files.
87 udata_setFileAccess(UDATA_ONLY_PACKAGES, &err);
88 DCHECK(err == U_ZERO_ERROR);
89 }
90}
91
Honglin Yu0f5b21d2021-04-06 23:39:04 +100092// Used to avoid duplicating code between two types of recognizers.
93// Currently used in function `LoadHandwritingModelFromDir`.
94template <class Recognizer>
95struct RecognizerTraits;
96
97template <>
98struct RecognizerTraits<HandwritingRecognizer> {
99 using SpecPtr = HandwritingRecognizerSpecPtr;
100 using Callback = MachineLearningServiceImpl::LoadHandwritingModelCallback;
101 using Impl = HandwritingRecognizerImpl;
Honglin Yu7b6c1192020-09-16 10:07:17 +1000102 static constexpr char kModelName[] = "HandwritingModel";
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000103};
104
105template <>
106struct RecognizerTraits<
107 chromeos::machine_learning::web_platform::mojom::HandwritingRecognizer> {
108 using SpecPtr = chromeos::machine_learning::web_platform::mojom::
109 HandwritingModelConstraintPtr;
110 using Callback =
111 MachineLearningServiceImpl::LoadWebPlatformHandwritingModelCallback;
112 using Impl = WebPlatformHandwritingRecognizerImpl;
Honglin Yu7b6c1192020-09-16 10:07:17 +1000113 static constexpr char kModelName[] = "WebPlatformHandwritingModel";
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000114};
115
Michael Martisa74af932018-08-13 16:52:36 +1000116} // namespace
117
Andrew Moylanff6be512018-07-03 11:05:01 +1000118MachineLearningServiceImpl::MachineLearningServiceImpl(
hschamd13deea2021-03-08 09:46:15 +0900119 mojo::PendingReceiver<
120 chromeos::machine_learning::mojom::MachineLearningService> receiver,
Andrew Moylanb481af72020-07-09 15:22:00 +1000121 base::Closure disconnect_handler,
Michael Martisa74af932018-08-13 16:52:36 +1000122 const std::string& model_dir)
Honglin Yu20391cd2020-10-27 15:58:49 +1100123 : builtin_model_metadata_(GetBuiltinModelMetadata()),
Michael Martisa74af932018-08-13 16:52:36 +1000124 model_dir_(model_dir),
hschamd13deea2021-03-08 09:46:15 +0900125 receiver_(this, std::move(receiver)) {
Andrew Moylanb481af72020-07-09 15:22:00 +1000126 receiver_.set_disconnect_handler(std::move(disconnect_handler));
Andrew Moylanff6be512018-07-03 11:05:01 +1000127}
128
Michael Martisa74af932018-08-13 16:52:36 +1000129MachineLearningServiceImpl::MachineLearningServiceImpl(
hschamd13deea2021-03-08 09:46:15 +0900130 mojo::PendingReceiver<
131 chromeos::machine_learning::mojom::MachineLearningService> receiver,
Charles Zhaod4fb7b62020-08-25 17:21:58 +1000132 base::Closure disconnect_handler,
133 dbus::Bus* bus)
Andrew Moylanb481af72020-07-09 15:22:00 +1000134 : MachineLearningServiceImpl(
hschamd13deea2021-03-08 09:46:15 +0900135 std::move(receiver), std::move(disconnect_handler), kSystemModelDir) {
Charles Zhaod4fb7b62020-08-25 17:21:58 +1000136 if (bus) {
137 dlcservice_client_ = std::make_unique<DlcserviceClient>(bus);
138 }
139}
Michael Martisa74af932018-08-13 16:52:36 +1000140
Andrew Moylanb481af72020-07-09 15:22:00 +1000141void MachineLearningServiceImpl::Clone(
142 mojo::PendingReceiver<MachineLearningService> receiver) {
143 clone_receivers_.Add(this, std::move(receiver));
Andrew Moylan2fb80af2020-07-08 10:52:08 +1000144}
145
Honglin Yu0ed72352019-08-27 17:42:01 +1000146void MachineLearningServiceImpl::LoadBuiltinModel(
147 BuiltinModelSpecPtr spec,
Andrew Moylanb481af72020-07-09 15:22:00 +1000148 mojo::PendingReceiver<Model> receiver,
Qijiang Fan5d381a02020-04-19 23:42:37 +0900149 LoadBuiltinModelCallback callback) {
Honglin Yu0ed72352019-08-27 17:42:01 +1000150 // Unsupported models do not have metadata entries.
151 const auto metadata_lookup = builtin_model_metadata_.find(spec->id);
152 if (metadata_lookup == builtin_model_metadata_.end()) {
Honglin Yua81145a2019-09-23 15:20:13 +1000153 LOG(WARNING) << "LoadBuiltinModel requested for unsupported model ID "
154 << spec->id << ".";
Qijiang Fan5d381a02020-04-19 23:42:37 +0900155 std::move(callback).Run(LoadModelResult::MODEL_SPEC_ERROR);
Honglin Yu0ed72352019-08-27 17:42:01 +1000156 RecordModelSpecificationErrorEvent();
157 return;
158 }
159
160 const BuiltinModelMetadata& metadata = metadata_lookup->second;
161
162 DCHECK(!metadata.metrics_model_name.empty());
163
charleszhao5a7050e2020-07-14 15:21:41 +1000164 RequestMetrics request_metrics(metadata.metrics_model_name,
165 kMetricsRequestName);
Honglin Yu0ed72352019-08-27 17:42:01 +1000166 request_metrics.StartRecordingPerformanceMetrics();
167
168 // Attempt to load model.
169 const std::string model_path = model_dir_ + metadata.model_file;
170 std::unique_ptr<tflite::FlatBufferModel> model =
171 tflite::FlatBufferModel::BuildFromFile(model_path.c_str());
172 if (model == nullptr) {
173 LOG(ERROR) << "Failed to load model file '" << model_path << "'.";
Qijiang Fan5d381a02020-04-19 23:42:37 +0900174 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
Honglin Yu0ed72352019-08-27 17:42:01 +1000175 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
176 return;
177 }
178
Honglin Yuc0cef102020-01-17 15:26:01 +1100179 ModelImpl::Create(metadata.required_inputs, metadata.required_outputs,
Andrew Moylanb481af72020-07-09 15:22:00 +1000180 std::move(model), std::move(receiver),
Honglin Yuc0cef102020-01-17 15:26:01 +1100181 metadata.metrics_model_name);
Honglin Yu0ed72352019-08-27 17:42:01 +1000182
Qijiang Fan5d381a02020-04-19 23:42:37 +0900183 std::move(callback).Run(LoadModelResult::OK);
Honglin Yu0ed72352019-08-27 17:42:01 +1000184
185 request_metrics.FinishRecordingPerformanceMetrics();
186 request_metrics.RecordRequestEvent(LoadModelResult::OK);
187}
188
189void MachineLearningServiceImpl::LoadFlatBufferModel(
190 FlatBufferModelSpecPtr spec,
Andrew Moylanb481af72020-07-09 15:22:00 +1000191 mojo::PendingReceiver<Model> receiver,
Qijiang Fan5d381a02020-04-19 23:42:37 +0900192 LoadFlatBufferModelCallback callback) {
Honglin Yu0ed72352019-08-27 17:42:01 +1000193 DCHECK(!spec->metrics_model_name.empty());
194
charleszhao5a7050e2020-07-14 15:21:41 +1000195 RequestMetrics request_metrics(spec->metrics_model_name, kMetricsRequestName);
Honglin Yu0ed72352019-08-27 17:42:01 +1000196 request_metrics.StartRecordingPerformanceMetrics();
197
Andrew Moylan79b34a42020-07-08 11:13:11 +1000198 // Take the ownership of the content of `model_string` because `ModelImpl` has
Honglin Yu0ed72352019-08-27 17:42:01 +1000199 // to hold the memory.
Andrew Moylan44c352f2020-11-04 15:19:46 +1100200 auto model_data =
201 std::make_unique<AlignedModelData>(std::move(spec->model_string));
Honglin Yu0ed72352019-08-27 17:42:01 +1000202
203 std::unique_ptr<tflite::FlatBufferModel> model =
Andrew Moylan44c352f2020-11-04 15:19:46 +1100204 tflite::FlatBufferModel::VerifyAndBuildFromBuffer(model_data->data(),
205 model_data->size());
Honglin Yu0ed72352019-08-27 17:42:01 +1000206 if (model == nullptr) {
207 LOG(ERROR) << "Failed to load model string of metric name: "
208 << spec->metrics_model_name << "'.";
Qijiang Fan5d381a02020-04-19 23:42:37 +0900209 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
Honglin Yu0ed72352019-08-27 17:42:01 +1000210 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
211 return;
212 }
213
Honglin Yuc0cef102020-01-17 15:26:01 +1100214 ModelImpl::Create(
Honglin Yu0ed72352019-08-27 17:42:01 +1000215 std::map<std::string, int>(spec->inputs.begin(), spec->inputs.end()),
216 std::map<std::string, int>(spec->outputs.begin(), spec->outputs.end()),
Andrew Moylan44c352f2020-11-04 15:19:46 +1100217 std::move(model), std::move(model_data), std::move(receiver),
Honglin Yu0ed72352019-08-27 17:42:01 +1000218 spec->metrics_model_name);
219
Qijiang Fan5d381a02020-04-19 23:42:37 +0900220 std::move(callback).Run(LoadModelResult::OK);
Honglin Yu0ed72352019-08-27 17:42:01 +1000221
222 request_metrics.FinishRecordingPerformanceMetrics();
223 request_metrics.RecordRequestEvent(LoadModelResult::OK);
224}
225
Honglin Yuf33dce32019-12-05 15:10:39 +1100226void MachineLearningServiceImpl::LoadTextClassifier(
Andrew Moylanb481af72020-07-09 15:22:00 +1000227 mojo::PendingReceiver<TextClassifier> receiver,
Honglin Yuf33dce32019-12-05 15:10:39 +1100228 LoadTextClassifierCallback callback) {
charleszhao5a7050e2020-07-14 15:21:41 +1000229 RequestMetrics request_metrics("TextClassifier", kMetricsRequestName);
Honglin Yuf33dce32019-12-05 15:10:39 +1100230 request_metrics.StartRecordingPerformanceMetrics();
231
Honglin Yuf33dce32019-12-05 15:10:39 +1100232 // Create the TextClassifier.
Honglin Yu3f99ff12020-10-15 00:40:11 +1100233 if (!TextClassifierImpl::Create(std::move(receiver))) {
Honglin Yuf33dce32019-12-05 15:10:39 +1100234 LOG(ERROR) << "Failed to create TextClassifierImpl object.";
235 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
236 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
237 return;
238 }
239
240 // initialize the icu library.
241 InitIcuIfNeeded();
242
243 std::move(callback).Run(LoadModelResult::OK);
244
245 request_metrics.FinishRecordingPerformanceMetrics();
246 request_metrics.RecordRequestEvent(LoadModelResult::OK);
247}
248
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000249template <class Recognizer>
Charles Zhao6d467e62020-08-31 10:02:03 +1000250void LoadHandwritingModelFromDir(
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000251 typename RecognizerTraits<Recognizer>::SpecPtr spec,
252 mojo::PendingReceiver<Recognizer> receiver,
253 typename RecognizerTraits<Recognizer>::Callback callback,
Charles Zhao6d467e62020-08-31 10:02:03 +1000254 const std::string& root_path) {
Honglin Yu7b6c1192020-09-16 10:07:17 +1000255 RequestMetrics request_metrics(RecognizerTraits<Recognizer>::kModelName,
256 kMetricsRequestName);
Charles Zhao6d467e62020-08-31 10:02:03 +1000257 request_metrics.StartRecordingPerformanceMetrics();
258
259 // Returns error if root_path is empty.
260 if (root_path.empty()) {
261 std::move(callback).Run(LoadHandwritingModelResult::DLC_GET_PATH_ERROR);
262 request_metrics.RecordRequestEvent(
263 LoadHandwritingModelResult::DLC_GET_PATH_ERROR);
264 return;
265 }
266
267 // Load HandwritingLibrary.
268 auto* const hwr_library = ml::HandwritingLibrary::GetInstance(root_path);
269
270 if (hwr_library->GetStatus() != ml::HandwritingLibrary::Status::kOk) {
271 LOG(ERROR) << "Initialize ml::HandwritingLibrary with error "
272 << static_cast<int>(hwr_library->GetStatus());
273
274 switch (hwr_library->GetStatus()) {
275 case ml::HandwritingLibrary::Status::kLoadLibraryFailed: {
276 std::move(callback).Run(
277 LoadHandwritingModelResult::LOAD_NATIVE_LIB_ERROR);
278 request_metrics.RecordRequestEvent(
279 LoadHandwritingModelResult::LOAD_NATIVE_LIB_ERROR);
280 return;
281 }
282 case ml::HandwritingLibrary::Status::kFunctionLookupFailed: {
283 std::move(callback).Run(
284 LoadHandwritingModelResult::LOAD_FUNC_PTR_ERROR);
285 request_metrics.RecordRequestEvent(
286 LoadHandwritingModelResult::LOAD_FUNC_PTR_ERROR);
287 return;
288 }
289 default: {
290 std::move(callback).Run(LoadHandwritingModelResult::LOAD_MODEL_ERROR);
291 request_metrics.RecordRequestEvent(
292 LoadHandwritingModelResult::LOAD_MODEL_ERROR);
293 return;
294 }
295 }
296 }
297
298 // Create HandwritingRecognizer.
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000299 if (!RecognizerTraits<Recognizer>::Impl::Create(std::move(spec),
300 std::move(receiver))) {
Charles Zhao6d467e62020-08-31 10:02:03 +1000301 LOG(ERROR) << "LoadHandwritingRecognizer returned false.";
302 std::move(callback).Run(LoadHandwritingModelResult::LOAD_MODEL_FILES_ERROR);
303 request_metrics.RecordRequestEvent(
304 LoadHandwritingModelResult::LOAD_MODEL_FILES_ERROR);
305 return;
306 }
307
308 std::move(callback).Run(LoadHandwritingModelResult::OK);
309 request_metrics.FinishRecordingPerformanceMetrics();
310 request_metrics.RecordRequestEvent(LoadHandwritingModelResult::OK);
311}
312
313void MachineLearningServiceImpl::LoadHandwritingModel(
314 chromeos::machine_learning::mojom::HandwritingRecognizerSpecPtr spec,
315 mojo::PendingReceiver<
316 chromeos::machine_learning::mojom::HandwritingRecognizer> receiver,
317 LoadHandwritingModelCallback callback) {
318 // If handwriting is installed on rootfs, load it from there.
319 if (ml::HandwritingLibrary::IsUseLibHandwritingEnabled()) {
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000320 LoadHandwritingModelFromDir<HandwritingRecognizer>(
Charles Zhao6d467e62020-08-31 10:02:03 +1000321 std::move(spec), std::move(receiver), std::move(callback),
322 ml::HandwritingLibrary::kHandwritingDefaultModelDir);
323 return;
324 }
325
326 // If handwriting is installed as DLC, get the dir and subsequently load it
327 // from there.
328 if (ml::HandwritingLibrary::IsUseLibHandwritingDlcEnabled()) {
329 dlcservice_client_->GetDlcRootPath(
330 "libhandwriting",
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000331 base::BindOnce(&LoadHandwritingModelFromDir<HandwritingRecognizer>,
332 std::move(spec), std::move(receiver),
333 std::move(callback)));
Charles Zhao6d467e62020-08-31 10:02:03 +1000334 return;
335 }
336
337 // If handwriting is not on rootfs and not in DLC, this function should not
338 // be called.
339 LOG(ERROR) << "Calling LoadHandwritingModel without Handwriting enabled "
340 "should never happen.";
341 std::move(callback).Run(LoadHandwritingModelResult::LOAD_MODEL_ERROR);
charleszhao05c5a4a2020-06-09 16:49:54 +1000342}
343
344void MachineLearningServiceImpl::LoadHandwritingModelWithSpec(
345 HandwritingRecognizerSpecPtr spec,
Andrew Moylanb481af72020-07-09 15:22:00 +1000346 mojo::PendingReceiver<HandwritingRecognizer> receiver,
Charles Zhaoc882eb02020-07-27 10:02:35 +1000347 LoadHandwritingModelWithSpecCallback callback) {
charleszhao5a7050e2020-07-14 15:21:41 +1000348 RequestMetrics request_metrics("HandwritingModel", kMetricsRequestName);
charleszhao17777f92020-04-23 12:53:11 +1000349 request_metrics.StartRecordingPerformanceMetrics();
350
351 // Load HandwritingLibrary.
352 auto* const hwr_library = ml::HandwritingLibrary::GetInstance();
353
354 if (hwr_library->GetStatus() ==
355 ml::HandwritingLibrary::Status::kNotSupported) {
356 LOG(ERROR) << "Initialize ml::HandwritingLibrary with error "
357 << static_cast<int>(hwr_library->GetStatus());
358
359 std::move(callback).Run(LoadModelResult::FEATURE_NOT_SUPPORTED_ERROR);
360 request_metrics.RecordRequestEvent(
361 LoadModelResult::FEATURE_NOT_SUPPORTED_ERROR);
362 return;
363 }
364
365 if (hwr_library->GetStatus() != ml::HandwritingLibrary::Status::kOk) {
366 LOG(ERROR) << "Initialize ml::HandwritingLibrary with error "
367 << static_cast<int>(hwr_library->GetStatus());
368
369 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
370 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
371 return;
372 }
373
374 // Create HandwritingRecognizer.
Andrew Moylanb481af72020-07-09 15:22:00 +1000375 if (!HandwritingRecognizerImpl::Create(std::move(spec),
376 std::move(receiver))) {
charleszhao17777f92020-04-23 12:53:11 +1000377 LOG(ERROR) << "LoadHandwritingRecognizer returned false.";
378 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
379 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
380 return;
381 }
382
383 std::move(callback).Run(LoadModelResult::OK);
384 request_metrics.FinishRecordingPerformanceMetrics();
385 request_metrics.RecordRequestEvent(LoadModelResult::OK);
386}
387
Honglin Yud2204272020-08-26 14:21:37 +1000388void MachineLearningServiceImpl::LoadSpeechRecognizer(
389 SodaConfigPtr config,
390 mojo::PendingRemote<SodaClient> soda_client,
391 mojo::PendingReceiver<SodaRecognizer> soda_recognizer,
392 LoadSpeechRecognizerCallback callback) {
393 RequestMetrics request_metrics("Soda", kMetricsRequestName);
394 request_metrics.StartRecordingPerformanceMetrics();
395
396 // Create the SodaRecognizer.
397 if (!SodaRecognizerImpl::Create(std::move(config), std::move(soda_client),
398 std::move(soda_recognizer))) {
399 LOG(ERROR) << "Failed to create SodaRecognizerImpl object.";
400 // TODO(robsc): it may be better that SODA has its specific enum values to
401 // return, similar to handwriting. So before we finalize the impl of SODA
402 // Mojo API, we may revisit this return value.
403 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
404 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
405 return;
406 }
407
408 std::move(callback).Run(LoadModelResult::OK);
409
410 request_metrics.FinishRecordingPerformanceMetrics();
411 request_metrics.RecordRequestEvent(LoadModelResult::OK);
412}
413
Jing Wang961b8af2020-10-26 12:40:35 +1100414void MachineLearningServiceImpl::LoadGrammarChecker(
415 mojo::PendingReceiver<chromeos::machine_learning::mojom::GrammarChecker>
416 receiver,
417 LoadGrammarCheckerCallback callback) {
418 RequestMetrics request_metrics("GrammarChecker", kMetricsRequestName);
419 request_metrics.StartRecordingPerformanceMetrics();
420
421 // Load GrammarLibrary.
422 auto* const grammar_library = ml::GrammarLibrary::GetInstance();
423
424 if (grammar_library->GetStatus() ==
425 ml::GrammarLibrary::Status::kNotSupported) {
426 LOG(ERROR) << "Initialize ml::GrammarLibrary with error "
427 << static_cast<int>(grammar_library->GetStatus());
428
429 std::move(callback).Run(LoadModelResult::FEATURE_NOT_SUPPORTED_ERROR);
430 request_metrics.RecordRequestEvent(
431 LoadModelResult::FEATURE_NOT_SUPPORTED_ERROR);
432 return;
433 }
434
435 if (grammar_library->GetStatus() != ml::GrammarLibrary::Status::kOk) {
436 LOG(ERROR) << "Initialize ml::GrammarLibrary with error "
437 << static_cast<int>(grammar_library->GetStatus());
438
439 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
440 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
441 return;
442 }
443
444 // Create GrammarChecker.
445 if (!GrammarCheckerImpl::Create(std::move(receiver))) {
446 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
447 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
448 return;
449 }
450
451 std::move(callback).Run(LoadModelResult::OK);
452
453 request_metrics.FinishRecordingPerformanceMetrics();
454 request_metrics.RecordRequestEvent(LoadModelResult::OK);
455}
456
Curtis McMullanf11584f2021-01-13 12:21:36 +1100457void MachineLearningServiceImpl::LoadTextSuggester(
458 mojo::PendingReceiver<chromeos::machine_learning::mojom::TextSuggester>
459 receiver,
460 LoadTextSuggesterCallback callback) {
461 RequestMetrics request_metrics("TextSuggester", kMetricsRequestName);
462 request_metrics.StartRecordingPerformanceMetrics();
463
464 // Load TextSuggestions library.
465 auto* const text_suggestions = ml::TextSuggestions::GetInstance();
466
467 if (text_suggestions->GetStatus() ==
468 ml::TextSuggestions::Status::kNotSupported) {
469 LOG(ERROR) << "Initialize ml::TextSuggestions with error "
470 << static_cast<int>(text_suggestions->GetStatus());
471
472 std::move(callback).Run(LoadModelResult::FEATURE_NOT_SUPPORTED_ERROR);
473 request_metrics.RecordRequestEvent(
474 LoadModelResult::FEATURE_NOT_SUPPORTED_ERROR);
475 return;
476 }
477
478 if (text_suggestions->GetStatus() != ml::TextSuggestions::Status::kOk) {
479 LOG(ERROR) << "Initialize ml::TextSuggestions with error "
480 << static_cast<int>(text_suggestions->GetStatus());
481
482 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
483 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
484 return;
485 }
486
487 // Create TextSuggester.
488 if (!TextSuggesterImpl::Create(std::move(receiver))) {
489 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
490 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
491 return;
492 }
493
494 std::move(callback).Run(LoadModelResult::OK);
495
496 request_metrics.FinishRecordingPerformanceMetrics();
497 request_metrics.RecordRequestEvent(LoadModelResult::OK);
498}
499
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000500void MachineLearningServiceImpl::LoadWebPlatformHandwritingModel(
501 chromeos::machine_learning::web_platform::mojom::
502 HandwritingModelConstraintPtr constraint,
503 mojo::PendingReceiver<
504 chromeos::machine_learning::web_platform::mojom::HandwritingRecognizer>
505 receiver,
506 LoadWebPlatformHandwritingModelCallback callback) {
Honglin Yud88ebcd2021-05-07 11:04:25 +1000507 constexpr bool is_rootfs_enabled =
508 ml::HandwritingLibrary::IsUseLibHandwritingEnabled();
509 constexpr bool is_dlc_enabled =
510 ml::HandwritingLibrary::IsUseLibHandwritingDlcEnabled();
511
512 if (!is_rootfs_enabled && !is_dlc_enabled) {
513 // If handwriting is not on rootfs and not in DLC, this function should not
514 // be called because the client side should also be guarded by the same
515 // flags.
516 LOG(ERROR) << "Calling LoadWebPlatformHandwritingModel without Handwriting "
517 "enabled should never happen.";
518 std::move(callback).Run(LoadHandwritingModelResult::LOAD_MODEL_ERROR);
Honglin Yu4533e7b2021-05-12 08:28:20 +1000519 return;
Honglin Yud88ebcd2021-05-07 11:04:25 +1000520 }
521
Honglin Yu7b6c1192020-09-16 10:07:17 +1000522 // If it is run in the control process, spawn a worker process and forward the
523 // request to it.
Honglin Yuf3c47b32021-05-06 18:38:37 +1000524 if (Process::GetInstance()->IsControlProcess()) {
Honglin Yu7b6c1192020-09-16 10:07:17 +1000525 pid_t worker_pid;
526 mojo::PlatformChannel channel;
527 constexpr char kModelName[] = "WebPlatformHandwritingModel";
528 if (!Process::GetInstance()->SpawnWorkerProcessAndGetPid(
529 channel, kModelName, &worker_pid)) {
530 // TODO(https://crbug.com/1202545): may need a better error code here.
531 std::move(callback).Run(LoadHandwritingModelResult::LOAD_MODEL_ERROR);
532 return;
533 }
534 Process::GetInstance()
535 ->SendMojoInvitationAndGetRemote(worker_pid, std::move(channel),
536 kModelName)
537 ->LoadWebPlatformHandwritingModel(
538 std::move(constraint), std::move(receiver), std::move(callback));
539 return;
540 }
541
542 // From here below is in the worker process.
Honglin Yuf3c47b32021-05-06 18:38:37 +1000543 DCHECK(Process::GetInstance()->IsWorkerProcess());
Honglin Yu7b6c1192020-09-16 10:07:17 +1000544
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000545 // If handwriting is installed on rootfs, load it from there.
Honglin Yud88ebcd2021-05-07 11:04:25 +1000546 if (is_rootfs_enabled) {
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000547 LoadHandwritingModelFromDir<
548 chromeos::machine_learning::web_platform::mojom::HandwritingRecognizer>(
549 std::move(constraint), std::move(receiver), std::move(callback),
550 ml::HandwritingLibrary::kHandwritingDefaultModelDir);
551 return;
552 }
553
554 // If handwriting is installed as DLC, get the dir and subsequently load it
555 // from there.
Honglin Yud88ebcd2021-05-07 11:04:25 +1000556 if (is_dlc_enabled) {
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000557 dlcservice_client_->GetDlcRootPath(
558 "libhandwriting",
559 base::BindOnce(&LoadHandwritingModelFromDir<
560 chromeos::machine_learning::web_platform::mojom::
561 HandwritingRecognizer>,
562 std::move(constraint), std::move(receiver),
563 std::move(callback)));
564 return;
565 }
566
Honglin Yud88ebcd2021-05-07 11:04:25 +1000567 NOTREACHED();
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000568}
569
Andrew Moylanff6be512018-07-03 11:05:01 +1000570} // namespace ml