Permalink
Browse files

Introduce a workaround for sandboxed applications.

In short, Mozc cannot establish IPC connections from sandboxed
applications until mozc_server is launched from any other non-sandboxed
applications because:
  1. Mozc client cannot launch mozc_server from sandboxed applications.
  2. mozc::client::Client does give up further connection when it fails
     to launch mozc_server.
  3. Mozc client cannot directly read the config file from sandboxed
     applications.  Hence it asks mozc_server to send back the current
     config data.  If the client cannot establish connection to
     mozc_server, mozc client assumes that no short-cut key is assigned
     to enable IME.

To make matters worse, on Windows 10 the search box on Windows 10 is
implemented by SearchUI.exe, which is a sandboxed application but is
launched at an early starge of the log-in process.  Because of that,
Mozc client that was loaded into SearchUI.exe will end up with "give-up"
mode before mozc_server is launched from Mozc client running in other
non-sandboxed applications.  Unfortunately this is a kind of design
issue of Mozc IPC implementation.  In particular, fixing the 1st
limitation in the above list requires non-trivial redesign.

To mitigate the problem in SearchUI.exe, we slightly modify the 2nd
limitation in the above list.  With this CL, if Mozc client is running
in a sandboxed application, we call mozc::client::Client::Reset() every
time when the UI thread gains focus.  Hence there is still a chance that
user cannot use Mozc in SearchUI.exe just after logging in, but it is
supposed to not be persistent anymore.

Closes #351.

BUG=#351
TEST=manually done
REF_BUG=24793812
REF_CL=105726484
  • Loading branch information...
1 parent 0989ef2 commit a2c1d40e5244e10c5afe808b92daf205cec76fdf @yukawa yukawa committed Jan 10, 2016
View
@@ -65,6 +65,24 @@ bool EqualLuid(const LUID &L1, const LUID &L2) {
return (L1.LowPart == L2.LowPart && L1.HighPart == L2.HighPart);
}
+bool IsProcessSandboxedImpl() {
+ bool is_restricted = false;
+ if (!WinUtil::IsProcessRestricted(::GetCurrentProcess(), &is_restricted)) {
+ return true;
+ }
+ if (is_restricted) {
+ return true;
+ }
+
+ bool in_appcontainer = false;
+ if (!WinUtil::IsProcessInAppContainer(::GetCurrentProcess(),
+ &in_appcontainer)) {
+ return true;
+ }
+
+ return in_appcontainer;
+}
+
} // namespace
HMODULE WinUtil::LoadSystemLibrary(const wstring &base_filename) {
@@ -603,6 +621,12 @@ bool WinUtil::IsPerUserInputSettingsEnabled() {
return !is_thread_local;
}
+bool WinUtil::IsProcessSandboxed() {
+ // Thread safety is not required.
+ static bool sandboxed = IsProcessSandboxedImpl();
+ return sandboxed;
+}
+
ScopedCOMInitializer::ScopedCOMInitializer()
: hr_(::CoInitialize(nullptr)) {
}
View
@@ -150,6 +150,9 @@ class WinUtil {
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms724947.aspx
static bool IsPerUserInputSettingsEnabled();
+ // Returns true if the current process is restricted or in AppContainer.
+ static bool IsProcessSandboxed();
+
private:
// Compares |lhs| with |rhs| by CompareStringOrdinal and returns the result
// in |are_equal|. If |ignore_case| is true, this function uses system
@@ -1,6 +1,6 @@
MAJOR=2
MINOR=17
-BUILD=2309
+BUILD=2310
REVISION=102
# NACL_DICTIONARY_VERSION is the target version of the system dictionary to be
# downloaded by NaCl Mozc.
@@ -53,50 +53,30 @@ struct StaticConfigSnapshot {
KeyInformation direct_mode_keys[kMaxDirectModeKeys];
};
-bool IsProcessSandboxedImpl() {
- bool is_restricted = false;
- if (!WinUtil::IsProcessRestricted(::GetCurrentProcess(), &is_restricted)) {
- return true;
+bool GetConfigSnapshotForSandboxedProcess(ClientInterface *client,
+ Config *config) {
+ if (client == nullptr) {
+ return false;
}
- if (is_restricted) {
- return true;
+ // config1.db is likely to be inaccessible from sandboxed processes.
+ // So retrieve the config data from the server process.
+ // CAVEATS: ConfigHandler::GetConfig always returns true even when it fails
+ // to load the config file due to the sandbox. b/10449414
+ if (!client->CheckVersionOrRestartServer()) {
+ return false;
}
-
- bool in_appcontainer = false;
- if (!WinUtil::IsProcessInAppContainer(::GetCurrentProcess(),
- &in_appcontainer)) {
- return true;
+ if (!client->GetConfig(config)) {
+ return false;
}
-
- return in_appcontainer;
-}
-
-bool IsProcessSandboxed() {
- // Thread safety is not required.
- static bool sandboxed = IsProcessSandboxedImpl();
- return sandboxed;
+ return true;
}
-StaticConfigSnapshot GetConfigSnapshotImpl(ClientInterface *client) {
- StaticConfigSnapshot snapshot = {};
-
+StaticConfigSnapshot GetConfigSnapshotForNonSandboxedProcess() {
Config config;
- if (IsProcessSandboxed()) {
- // config1.db is likely to be inaccessible from sandboxed processes.
- // So retrieve the config data from the server process.
- // CAVEATS: ConfigHandler::GetConfig always returns true even when it fails
- // to load the config file due to the sandbox. b/10449414
- if (!client->CheckVersionOrRestartServer()) {
- return snapshot;
- }
- if (!client->GetConfig(&config)) {
- return snapshot;
- }
- } else {
- // config1.db should be readable in this case.
- config.CopyFrom(config::ConfigHandler::GetConfig());
- }
+ // config1.db should be readable in this case.
+ config.CopyFrom(config::ConfigHandler::GetConfig());
+ StaticConfigSnapshot snapshot = {};
snapshot.use_kana_input = (config.preedit_method() == Config::KANA);
snapshot.use_keyboard_to_change_preedit_method =
config.use_keyboard_to_change_preedit_method();
@@ -122,24 +102,35 @@ ConfigSnapshot::Info::Info()
use_mode_indicator(false) {}
// static
-ConfigSnapshot::Info ConfigSnapshot::Get(client::ClientInterface *client) {
- if (client == nullptr) {
- return ConfigSnapshot::Info();
+bool ConfigSnapshot::Get(client::ClientInterface *client, Info *info) {
+ // A temporary workaround for b/24793812. Always reload config if the
+ // process is sandboxed.
+ // TODO(yukawa): Cache the result once it succeeds.
+ if (WinUtil::IsProcessSandboxed()) {
+ Config config;
+ if (!GetConfigSnapshotForSandboxedProcess(client, &config)) {
+ return false;
+ }
+ info->use_kana_input = (config.preedit_method() == Config::KANA);
+ info->use_keyboard_to_change_preedit_method =
+ config.use_keyboard_to_change_preedit_method();
+ info->use_mode_indicator = config.use_mode_indicator();
+ info->direct_mode_keys = KeyInfoUtil::ExtractSortedDirectModeKeys(config);
+ return true;
}
// Note: Thread-safety is not required.
- static auto static_snapshot = GetConfigSnapshotImpl(client);
-
- ConfigSnapshot::Info snapshot;
- snapshot.use_kana_input = static_snapshot.use_kana_input;
- snapshot.use_keyboard_to_change_preedit_method =
- static_snapshot.use_keyboard_to_change_preedit_method;
- snapshot.use_mode_indicator = static_snapshot.use_mode_indicator;
- snapshot.direct_mode_keys.resize(static_snapshot.num_direct_mode_keys);
- for (size_t i = 0; i < static_snapshot.num_direct_mode_keys; ++i) {
- snapshot.direct_mode_keys[i] = static_snapshot.direct_mode_keys[i];
+ const static StaticConfigSnapshot cached_snapshot =
+ GetConfigSnapshotForNonSandboxedProcess();
+ info->use_kana_input = cached_snapshot.use_kana_input;
+ info->use_keyboard_to_change_preedit_method =
+ cached_snapshot.use_keyboard_to_change_preedit_method;
+ info->use_mode_indicator = cached_snapshot.use_mode_indicator;
+ info->direct_mode_keys.resize(cached_snapshot.num_direct_mode_keys);
+ for (size_t i = 0; i < cached_snapshot.num_direct_mode_keys; ++i) {
+ info->direct_mode_keys[i] = cached_snapshot.direct_mode_keys[i];
}
- return snapshot;
+ return true;
}
} // namespace win32
@@ -52,7 +52,7 @@ class ConfigSnapshot {
Info();
};
- static Info Get(client::ClientInterface *client);
+ static bool Get(client::ClientInterface *client, Info *info);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ConfigSnapshot);
@@ -39,7 +39,8 @@ InputState::InputState()
}
InputBehavior::InputBehavior()
- : disabled(false),
+ : initialized(false),
+ disabled(false),
prefer_kana_input(false),
use_mode_indicator(false),
use_romaji_key_to_toggle_input_style(false) {}
@@ -55,6 +55,7 @@ struct InputState {
};
struct InputBehavior {
+ bool initialized;
bool disabled;
bool prefer_kana_input;
bool use_mode_indicator;
@@ -165,14 +165,16 @@ bool PrivateContextUtil::EnsurePrivateContextIsInitialized(
}
// Try to reflect the current config to the IME behavior.
- const auto &snapshot =
- ConfigSnapshot::Get(private_context_allocator->client);
- auto *behavior = private_context_allocator->ime_behavior;
- behavior->prefer_kana_input = snapshot.use_kana_input;
- behavior->use_romaji_key_to_toggle_input_style =
- snapshot.use_keyboard_to_change_preedit_method;
- behavior->use_mode_indicator = snapshot.use_mode_indicator;
- behavior->direct_mode_keys = snapshot.direct_mode_keys;
+ ConfigSnapshot::Info snapshot;
+ if (ConfigSnapshot::Get(private_context_allocator->client, &snapshot)) {
+ auto *behavior = private_context_allocator->ime_behavior;
+ behavior->prefer_kana_input = snapshot.use_kana_input;
+ behavior->use_romaji_key_to_toggle_input_style =
+ snapshot.use_keyboard_to_change_preedit_method;
+ behavior->use_mode_indicator = snapshot.use_mode_indicator;
+ behavior->direct_mode_keys = snapshot.direct_mode_keys;
+ behavior->initialized = true;
+ }
return true;
}
@@ -79,18 +79,7 @@ TipPrivateContext::TipPrivateContext(DWORD text_edit_sink_cookie,
DWORD text_layout_sink_cookie)
: state_(new InternalState(text_edit_sink_cookie,
text_layout_sink_cookie)) {
- Capability capability;
- capability.set_text_deletion(Capability::DELETE_PRECEDING_TEXT);
- state_->client_->set_client_capability(capability);
-
- // Try to reflect the current config to the IME behavior.
- const auto &snapshot = ConfigSnapshot::Get(state_->client_.get());
- auto *behavior = &state_->input_behavior_;
- behavior->prefer_kana_input = snapshot.use_kana_input;
- behavior->use_romaji_key_to_toggle_input_style =
- snapshot.use_keyboard_to_change_preedit_method;
- behavior->use_mode_indicator = snapshot.use_mode_indicator;
- behavior->direct_mode_keys = snapshot.direct_mode_keys;
+ EnsureInitialized();
}
TipPrivateContext::~TipPrivateContext() {}
@@ -99,6 +88,28 @@ ClientInterface *TipPrivateContext::GetClient() {
return state_->client_.get();
}
+void TipPrivateContext::EnsureInitialized() {
+ if (!state_->input_behavior_.initialized) {
+ state_->client_->Reset();
+
+ Capability capability;
+ capability.set_text_deletion(Capability::DELETE_PRECEDING_TEXT);
+ state_->client_->set_client_capability(capability);
+ }
+
+ // Try to reflect the current config to the IME behavior.
+ ConfigSnapshot::Info snapshot;
+ if (ConfigSnapshot::Get(state_->client_.get(), &snapshot)) {
+ auto *behavior = &state_->input_behavior_;
+ behavior->prefer_kana_input = snapshot.use_kana_input;
+ behavior->use_romaji_key_to_toggle_input_style =
+ snapshot.use_keyboard_to_change_preedit_method;
+ behavior->use_mode_indicator = snapshot.use_mode_indicator;
+ behavior->direct_mode_keys = snapshot.direct_mode_keys;
+ behavior->initialized = true;
+ }
+}
+
SurrogatePairObserver *TipPrivateContext::GetSurrogatePairObserver() {
return &state_->surrogate_pair_observer_;
}
@@ -63,6 +63,7 @@ class TipPrivateContext {
DWORD text_layout_sink_cookie);
~TipPrivateContext();
+ void EnsureInitialized();
client::ClientInterface *GetClient();
SurrogatePairObserver *GetSurrogatePairObserver();
TipUiElementManager *GetUiElementManager();
@@ -887,6 +887,17 @@ class TipTextServiceImpl
// ITfThreadFocusSink
virtual HRESULT STDMETHODCALLTYPE OnSetThreadFocus() {
EnsureKanaLockUnlocked();
+
+ // A temporary workaround for b/24793812. When previous atempt to
+ // establish conection failed, retry again as if this was the first attempt.
+ // TODO(yukawa): We should give up if this fails a number of times.
+ if (WinUtil::IsProcessSandboxed()) {
+ auto *private_context = GetFocusedPrivateContext();
+ if (private_context != nullptr) {
+ private_context->EnsureInitialized();
+ }
+ }
+
// While ITfThreadMgrEventSink::OnSetFocus notifies the logical focus inside
// the application, ITfThreadFocusSink notifies the OS-level keyboard focus
// events. In both cases, Mozc's UI visibility should be updated.

0 comments on commit a2c1d40

Please sign in to comment.