Commit aa056af6 authored by Leo Zhang's avatar Leo Zhang Committed by Commit Bot

Add shared library support

Implement platform support for loading shared library in decoder.

This feature will be disabled by default and only compiled when flag
enable_cros_ime_decoder in chromeos/services/ime/public/features.gni
is turned on.


Bug: 837156
Change-Id: Iaec701361f50061ded08a1998975a521701b0387
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1659553Reviewed-by: default avatarMarti Wong <martiw@chromium.org>
Reviewed-by: default avatarShu Chen <shuchen@chromium.org>
Commit-Queue: Leo Zhang <googleo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#669926}
parent 0ae05482
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "chromeos/services/ime/decoder/decoder_engine.h" #include "chromeos/services/ime/decoder/decoder_engine.h"
#include "base/bind_helpers.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "build/buildflag.h" #include "build/buildflag.h"
#include "chromeos/services/ime/public/cpp/buildflags.h" #include "chromeos/services/ime/public/cpp/buildflags.h"
...@@ -13,17 +14,52 @@ namespace ime { ...@@ -13,17 +14,52 @@ namespace ime {
namespace { namespace {
// TODO(https://crbug.com/837156): Use define instead.
#if BUILDFLAG(ENABLE_CROS_IME_EXAMPLE_SO) #if BUILDFLAG(ENABLE_CROS_IME_EXAMPLE_SO)
const char kDecoderLibName[] = "input_decoder_example"; const char kDecoderLibName[] = "input_decoder_example";
#else #else
const char kDecoderLibName[] = "input_decoder_engine"; const char kDecoderLibName[] = "input_decoder_engine";
#endif #endif
// A client delegate that makes calls on client side.
class ClientDelegate : public ImeClientDelegate {
public:
ClientDelegate(const std::string& ime_spec,
mojo::PendingRemote<mojom::InputChannel> remote)
: ime_spec_(ime_spec), client_remote_(std::move(remote)) {
client_remote_.set_disconnect_handler(base::BindOnce(
&ClientDelegate::OnDisconnected, base::Unretained(this)));
}
~ClientDelegate() override {}
const char* ImeSpec() override { return ime_spec_.c_str(); }
void Process(const uint8_t* data, size_t size) override {
if (client_remote_ && client_remote_.is_bound()) {
std::vector<uint8_t> msg(data, data + size);
client_remote_->ProcessMessage(msg, base::DoNothing());
}
}
void Destroy() override {}
private:
void OnDisconnected() {
client_remote_.reset();
LOG(ERROR) << "Client remote is disconnected." << ime_spec_;
}
// The ime specification which is unique in the scope of engine.
std::string ime_spec_;
// The InputChannel remote used to talk to the client.
mojo::Remote<mojom::InputChannel> client_remote_;
};
} // namespace } // namespace
DecoderEngine::DecoderEngine( DecoderEngine::DecoderEngine(ImeCrosPlatform* platform) : platform_(platform) {
service_manager::Connector* connector,
scoped_refptr<base::SequencedTaskRunner> task_runner) {
// TODO(https://crbug.com/837156): Connect utility services for InputEngine // TODO(https://crbug.com/837156): Connect utility services for InputEngine
// via connector(). Eg. take advantage of the file and network services to // via connector(). Eg. take advantage of the file and network services to
// download relevant language models required by the decocers to the device. // download relevant language models required by the decocers to the device.
...@@ -31,39 +67,52 @@ DecoderEngine::DecoderEngine( ...@@ -31,39 +67,52 @@ DecoderEngine::DecoderEngine(
// Load the decoder library. // Load the decoder library.
base::NativeLibraryLoadError load_error; base::NativeLibraryLoadError load_error;
base::FilePath lib_path(base::GetNativeLibraryName(kDecoderLibName)); base::FilePath lib_path(base::GetNativeLibraryName(kDecoderLibName));
library_.Reset(base::LoadNativeLibrary(lib_path, &load_error)); library_ = base::ScopedNativeLibrary(lib_path);
if (!library_.is_valid()) { if (!library_.is_valid()) {
LOG(ERROR) << "Failed to load a decoder shared library."; LOG(ERROR) << "Failed to load a decoder shared library, error: "
<< library_.GetError()->ToString();
return; return;
} }
// TODO(https://crbug.com/837156): Based on the defined function pointer types ImeMainEntryCreateFn createMainEntryFn =
// in DecoderAPILibrary, load all required function pointers. reinterpret_cast<ImeMainEntryCreateFn>(
library_.GetFunctionPointer(IME_MAIN_ENTRY_CREATE_FN_NAME));
engine_main_entry_ = createMainEntryFn(platform_);
LOG(ERROR) << "Loaded SO main_entry in DecoderEngine!";
} }
DecoderEngine::~DecoderEngine() {} DecoderEngine::~DecoderEngine() {}
bool DecoderEngine::BindRequest(const std::string& ime_spec, bool DecoderEngine::BindRequest(
mojom::InputChannelRequest request, const std::string& ime_spec,
mojom::InputChannelPtr client, mojo::PendingReceiver<mojom::InputChannel> receiver,
const std::vector<uint8_t>& extra) { mojo::PendingRemote<mojom::InputChannel> remote,
if (!IsImeSupported(ime_spec)) const std::vector<uint8_t>& extra) {
// If the shared library supports this ime_spec.
if (IsImeSupported(ime_spec)) {
// Activates an IME engine via the shared library. Passing a
// |ClientDelegate| for engine instance created by the shared library to
// make safe calls on the client.
if (engine_main_entry_->ActivateIme(
ime_spec.c_str(),
new ClientDelegate(ime_spec, std::move(remote)))) {
channel_receivers_.Add(this, std::move(receiver));
// TODO(https://crbug.com/837156): Registry connection error handler.
return true;
}
return false; return false;
// TODO(https://crbug.com/837156): Notify the input logic loaded from the }
// shared library about the change by forwarding the information received.
// Moreover, in order to make safe calls on the clientPtr inside the input // Otherwise, try the rule-based engine for this ime_spec.
// logic with multiple threads, we will send a wrapper of the clientPtr, return InputEngine::BindRequest(ime_spec, std::move(receiver),
// where we make sure it runs in the correct SequencedTaskRunner. std::move(remote), extra);
channel_bindings_.AddBinding(this, std::move(request));
// TODO(https://crbug.com/837156): Registry connection error handler.
return true;
} }
bool DecoderEngine::IsImeSupported(const std::string& ime_spec) { bool DecoderEngine::IsImeSupported(const std::string& ime_spec) {
// TODO(https://crbug.com/837156): Check the capability of the loaded shared return engine_main_entry_ &&
// library first. engine_main_entry_->IsImeSupported(ime_spec.c_str());
return InputEngine::IsImeSupported(ime_spec);
} }
void DecoderEngine::ProcessMessage(const std::vector<uint8_t>& message, void DecoderEngine::ProcessMessage(const std::vector<uint8_t>& message,
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/scoped_native_library.h" #include "base/scoped_native_library.h"
#include "chromeos/services/ime/input_engine.h" #include "chromeos/services/ime/input_engine.h"
#include "chromeos/services/ime/public/cpp/shared_lib/interfaces.h"
#include "chromeos/services/ime/public/mojom/input_engine.mojom.h" #include "chromeos/services/ime/public/mojom/input_engine.mojom.h"
#include "mojo/public/cpp/bindings/binding_set.h" #include "mojo/public/cpp/bindings/binding_set.h"
#include "services/service_manager/public/cpp/connector.h" #include "services/service_manager/public/cpp/connector.h"
...@@ -23,15 +24,16 @@ namespace ime { ...@@ -23,15 +24,16 @@ namespace ime {
// a premium typing experience. // a premium typing experience.
class DecoderEngine : public InputEngine { class DecoderEngine : public InputEngine {
public: public:
DecoderEngine(service_manager::Connector* connector, explicit DecoderEngine(ImeCrosPlatform* platform);
scoped_refptr<base::SequencedTaskRunner> task_runner);
~DecoderEngine() override; ~DecoderEngine() override;
// InputEngine overrides: // InputEngine overrides:
bool BindRequest(const std::string& ime_spec, bool BindRequest(const std::string& ime_spec,
mojom::InputChannelRequest request, mojo::PendingReceiver<mojom::InputChannel> receiver,
mojom::InputChannelPtr client, mojo::PendingRemote<mojom::InputChannel> remote,
const std::vector<uint8_t>& extra) override; const std::vector<uint8_t>& extra) override;
// Returns whether the loaded shared library supports this ime_spec.
bool IsImeSupported(const std::string& ime_spec) override; bool IsImeSupported(const std::string& ime_spec) override;
void ProcessMessage(const std::vector<uint8_t>& message, void ProcessMessage(const std::vector<uint8_t>& message,
ProcessMessageCallback callback) override; ProcessMessageCallback callback) override;
...@@ -40,7 +42,11 @@ class DecoderEngine : public InputEngine { ...@@ -40,7 +42,11 @@ class DecoderEngine : public InputEngine {
// Shared library handle of the implementation for input logic with decoders. // Shared library handle of the implementation for input logic with decoders.
base::ScopedNativeLibrary library_; base::ScopedNativeLibrary library_;
mojo::BindingSet<mojom::InputChannel> channel_bindings_; ImeEngineMainEntry* engine_main_entry_ = nullptr;
ImeCrosPlatform* platform_ = nullptr;
mojo::ReceiverSet<mojom::InputChannel> channel_receivers_;
DISALLOW_COPY_AND_ASSIGN(DecoderEngine); DISALLOW_COPY_AND_ASSIGN(DecoderEngine);
}; };
......
...@@ -18,7 +18,7 @@ DownloaderImpl::~DownloaderImpl() { ...@@ -18,7 +18,7 @@ DownloaderImpl::~DownloaderImpl() {
int DownloaderImpl::DownloadToFile(const char* url, int DownloaderImpl::DownloadToFile(const char* url,
const DownloadOptions& options, const DownloadOptions& options,
const char* file_path, const char* file_path,
DownloadCallback callback) { ImeCrosDownloadCallback callback) {
// TODO(crbug/946913): Implement this. // TODO(crbug/946913): Implement this.
return 0; return 0;
} }
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
namespace chromeos { namespace chromeos {
namespace ime { namespace ime {
class DownloaderImpl : public Downloader { class DownloaderImpl : public ImeCrosDownloader {
public: public:
explicit DownloaderImpl(); explicit DownloaderImpl();
~DownloaderImpl() override; ~DownloaderImpl() override;
...@@ -19,7 +19,7 @@ class DownloaderImpl : public Downloader { ...@@ -19,7 +19,7 @@ class DownloaderImpl : public Downloader {
int DownloadToFile(const char* url, int DownloadToFile(const char* url,
const DownloadOptions& options, const DownloadOptions& options,
const char* file_path, const char* file_path,
DownloadCallback callback) override; ImeCrosDownloadCallback callback) override;
void Cancel(int request_id) override; void Cancel(int request_id) override;
......
...@@ -29,8 +29,7 @@ void ImeService::OnStart() { ...@@ -29,8 +29,7 @@ void ImeService::OnStart() {
&ImeService::OnConnectionLost, base::Unretained(this))); &ImeService::OnConnectionLost, base::Unretained(this)));
#if BUILDFLAG(ENABLE_CROS_IME_DECODER) #if BUILDFLAG(ENABLE_CROS_IME_DECODER)
input_engine_ = std::make_unique<DecoderEngine>( input_engine_ = std::make_unique<DecoderEngine>(this);
service_binding_.GetConnector(), base::SequencedTaskRunnerHandle::Get());
#else #else
input_engine_ = std::make_unique<InputEngine>(); input_engine_ = std::make_unique<InputEngine>();
#endif #endif
...@@ -68,5 +67,31 @@ void ImeService::OnConnectionLost() { ...@@ -68,5 +67,31 @@ void ImeService::OnConnectionLost() {
} }
} }
const char* ImeService::GetImeBundleDir() {
return "";
}
const char* ImeService::GetImeGlobalDir() {
return "";
}
const char* ImeService::GetImeUserHomeDir() {
return "";
}
int ImeService::SimpleDownloadToFile(const char* url,
const char* file_path,
SimpleDownloadCallback callback) {
// TODO(https://crbug.com/837156): Create a download with PlatformAccess
// Mojo remote. Make sure the parent of |file_path| is ImeUserHomeDir.
return 0;
}
ImeCrosDownloader* ImeService::GetDownloader() {
// TODO(https://crbug.com/837156): Create a ImeCrosDownloader based on its
// specification in interfaces. The caller should free it after use.
return nullptr;
}
} // namespace ime } // namespace ime
} // namespace chromeos } // namespace chromeos
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define CHROMEOS_SERVICES_IME_IME_SERVICE_H_ #define CHROMEOS_SERVICES_IME_IME_SERVICE_H_
#include "chromeos/services/ime/input_engine.h" #include "chromeos/services/ime/input_engine.h"
#include "chromeos/services/ime/public/cpp/shared_lib/interfaces.h"
#include "chromeos/services/ime/public/mojom/input_engine.mojom.h" #include "chromeos/services/ime/public/mojom/input_engine.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/pending_remote.h"
...@@ -19,7 +20,8 @@ namespace chromeos { ...@@ -19,7 +20,8 @@ namespace chromeos {
namespace ime { namespace ime {
class ImeService : public service_manager::Service, class ImeService : public service_manager::Service,
public mojom::InputEngineManager { public mojom::InputEngineManager,
public ImeCrosPlatform {
public: public:
explicit ImeService( explicit ImeService(
mojo::PendingReceiver<service_manager::mojom::Service> receiver); mojo::PendingReceiver<service_manager::mojom::Service> receiver);
...@@ -40,6 +42,15 @@ class ImeService : public service_manager::Service, ...@@ -40,6 +42,15 @@ class ImeService : public service_manager::Service,
const std::vector<uint8_t>& extra, const std::vector<uint8_t>& extra,
ConnectToImeEngineCallback callback) override; ConnectToImeEngineCallback callback) override;
// ImeCrosPlatform overrides:
const char* GetImeBundleDir() override;
const char* GetImeGlobalDir() override;
const char* GetImeUserHomeDir() override;
int SimpleDownloadToFile(const char* url,
const char* file_path,
SimpleDownloadCallback callback) override;
ImeCrosDownloader* GetDownloader() override;
// Adds a mojom::InputEngineManager receiver to this object. // Adds a mojom::InputEngineManager receiver to this object.
void AddInputEngineManagerReceiver( void AddInputEngineManagerReceiver(
mojo::PendingReceiver<mojom::InputEngineManager> receiver); mojo::PendingReceiver<mojom::InputEngineManager> receiver);
......
...@@ -63,7 +63,10 @@ namespace ime { ...@@ -63,7 +63,10 @@ namespace ime {
// issued |request_id| (as returned by DownloadToFile()) and an |error_code| (as // issued |request_id| (as returned by DownloadToFile()) and an |error_code| (as
// defined at // defined at
// https://cs.chromium.org/chromium/src/net/base/net_error_list.h?rcl=f9c935b73381772d508eebba1e216c437139d475). // https://cs.chromium.org/chromium/src/net/base/net_error_list.h?rcl=f9c935b73381772d508eebba1e216c437139d475).
typedef void (*DownloadCallback)(int request_id, int status_code); typedef void (*ImeCrosDownloadCallback)(int request_id, int status_code);
// A simple downloading callback.
typedef void (*SimpleDownloadCallback)(int status_code, const char* file_path);
// Based on RequestPriority defined at // Based on RequestPriority defined at
// https://cs.chromium.org/chromium/src/net/base/request_priority.h?rcl=f9c935b73381772d508eebba1e216c437139d475 // https://cs.chromium.org/chromium/src/net/base/request_priority.h?rcl=f9c935b73381772d508eebba1e216c437139d475
...@@ -97,9 +100,9 @@ struct DownloadOptions { ...@@ -97,9 +100,9 @@ struct DownloadOptions {
}; };
// Provides CrOS network download service to the shared library. // Provides CrOS network download service to the shared library.
class Downloader { class ImeCrosDownloader {
protected: protected:
virtual ~Downloader() = default; virtual ~ImeCrosDownloader() = default;
public: public:
// Download data from the given |url| and store into a file located at the // Download data from the given |url| and store into a file located at the
...@@ -114,7 +117,7 @@ class Downloader { ...@@ -114,7 +117,7 @@ class Downloader {
virtual int DownloadToFile(const char* url, virtual int DownloadToFile(const char* url,
const DownloadOptions& options, const DownloadOptions& options,
const char* file_path, const char* file_path,
DownloadCallback callback) = 0; ImeCrosDownloadCallback callback) = 0;
// Cancel the download whose |request_id| is given (|request_id| is issued // Cancel the download whose |request_id| is given (|request_id| is issued
// in the return value of each DownloadToFile() call). The callback of a // in the return value of each DownloadToFile() call). The callback of a
...@@ -124,14 +127,14 @@ class Downloader { ...@@ -124,14 +127,14 @@ class Downloader {
virtual void Cancel(int request_id) = 0; virtual void Cancel(int request_id) = 0;
}; };
// This defines the `Platform` interface, which is used throughout the shared // This defines the `ImeCrosPlatform` interface, which is used throughout the
// library to manage platform-specific data/operations. // shared library to manage platform-specific data/operations.
// //
// This class should be provided by the IME service before creating an // This class should be provided by the IME service before creating an
// `ImeEngineMainEntry` and be always owned by the IME service. // `ImeEngineMainEntry` and be always owned by the IME service.
class Platform { class ImeCrosPlatform {
protected: protected:
virtual ~Platform() = default; virtual ~ImeCrosPlatform() = default;
public: public:
// The three methods below are Getters of the local data directories on the // The three methods below are Getters of the local data directories on the
...@@ -154,8 +157,15 @@ class Platform { ...@@ -154,8 +157,15 @@ class Platform {
// Get the Downloader that provides CrOS network download service. Ownership // Get the Downloader that provides CrOS network download service. Ownership
// of the returned Downloader instance is never transferred, i.e. it remains // of the returned Downloader instance is never transferred, i.e. it remains
// owned by the IME service / Platform at all times. // owned by the IME service / Platform at all times.
virtual Downloader* GetDownloader() = 0; virtual ImeCrosDownloader* GetDownloader() = 0;
// A shortcut for starting a downloading by the network |SimpleURLLoader|.
// Each SimpleDownloadToFile can only be used for a single request.
// Make a call after the previous task completes or cancels.
virtual int SimpleDownloadToFile(const char* url,
const char* file_path,
SimpleDownloadCallback callback) = 0;
// TODO(https://crbug.com/837156): Provide Logger for main entry. // TODO(https://crbug.com/837156): Provide Logger for main entry.
}; };
...@@ -224,7 +234,7 @@ class ImeEngineMainEntry { ...@@ -224,7 +234,7 @@ class ImeEngineMainEntry {
// name defined in IME_MAIN_ENTRY_CREATE_FN_NAME. // name defined in IME_MAIN_ENTRY_CREATE_FN_NAME.
// //
// Returns an instance of ImeEngineMainEntry from the IME shared library. // Returns an instance of ImeEngineMainEntry from the IME shared library.
typedef ImeEngineMainEntry* (*ImeMainEntryCreateFn)(Platform*); typedef ImeEngineMainEntry* (*ImeMainEntryCreateFn)(ImeCrosPlatform*);
// Defined name of ImeMainEntryCreateFn exported from shared library. // Defined name of ImeMainEntryCreateFn exported from shared library.
#define IME_MAIN_ENTRY_CREATE_FN_NAME "CreateImeMainEntry" #define IME_MAIN_ENTRY_CREATE_FN_NAME "CreateImeMainEntry"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment