Update from the upstream. (BUILD=4219)
* Fixed some incompatibility issues of Bazel build.
* Fixed potential issues of the thread handling.
* Removed no longer used code around GenericStorageManager.
* Code refactoring.
Hiroyuki Komatsu
3 years ago
9 | 9 | build --objccopt "-fsigned-char" |
10 | 10 | |
11 | 11 | # Linux |
12 | build:linux --define TARGET=oss_linux | |
13 | build:oss_linux --define TARGET=oss_linux | |
12 | build:linux --define TARGET=oss_linux --copt "-fPIC" | |
13 | build:oss_linux --define TARGET=oss_linux --copt "-fPIC" | |
14 | 14 | |
15 | 15 | # Android |
16 | 16 | build:android --define TARGET=oss_android \ |
1108 | 1108 | "version_def_template.h", |
1109 | 1109 | ], |
1110 | 1110 | outs = ["version_def.h"], |
1111 | cmd = "$(location //build_tools:replace_version) --version_file=$(location mozc_version.txt) --input=$(location version_def_template.h) --output=$(OUTS) --branding=GoogleJapaneseInput", | |
1111 | cmd = ("$(location //build_tools:replace_version)" + | |
1112 | " --version_file=$(location mozc_version.txt) " + | |
1113 | " --input=$(location version_def_template.h) --output=$(OUTS)" + | |
1114 | " --branding=Mozc"), | |
1112 | 1115 | exec_tools = ["//build_tools:replace_version"], |
1113 | 1116 | visibility = ["//visibility:private"], |
1114 | 1117 | ) |
169 | 169 | return build_override |
170 | 170 | |
171 | 171 | if not build_changelist_file: |
172 | return '0' | |
172 | return None | |
173 | 173 | |
174 | 174 | with open(build_changelist_file, 'r') as cl_file: |
175 | 175 | for line in cl_file: |
176 | 176 | if line.startswith('BUILD_CHANGELIST'): |
177 | 177 | return line.rstrip().split(' ')[1] |
178 | 178 | |
179 | return '0' | |
179 | return None | |
180 | 180 | |
181 | 181 | |
182 | 182 | def GenerateVersionFileFromTemplate(template_path, |
109 | 109 | ":client_interface", |
110 | 110 | "//base", |
111 | 111 | "//base:logging", |
112 | "//base:mutex", | |
112 | 113 | "//protocol:commands_proto", |
113 | 114 | ], |
114 | 115 | ) |
37 | 37 | // boilerplates for those methods. |
38 | 38 | #define MockConstBoolImplementation(method_name, argument) \ |
39 | 39 | bool ClientMock::method_name(argument) const { \ |
40 | scoped_lock l(&mutex_); \ | |
40 | 41 | function_counter_[#method_name]++; \ |
41 | 42 | std::map<std::string, bool>::const_iterator it = \ |
42 | 43 | return_bool_values_.find(#method_name); \ |
47 | 48 | } |
48 | 49 | #define MockBoolImplementation(method_name, argument) \ |
49 | 50 | bool ClientMock::method_name(argument) { \ |
51 | scoped_lock l(&mutex_); \ | |
50 | 52 | function_counter_[#method_name]++; \ |
51 | 53 | std::map<std::string, bool>::const_iterator it = \ |
52 | 54 | return_bool_values_.find(#method_name); \ |
57 | 59 | } |
58 | 60 | #define MockVoidImplementation(method_name, argument) \ |
59 | 61 | void ClientMock::method_name(argument) { \ |
62 | scoped_lock l(&mutex_); \ | |
60 | 63 | function_counter_[#method_name]++; \ |
61 | 64 | return; \ |
62 | 65 | } |
99 | 102 | bool ClientMock::method_name(argtype argument, \ |
100 | 103 | const commands::Context &context, \ |
101 | 104 | commands::Output *output) { \ |
105 | scoped_lock l(&mutex_); \ | |
102 | 106 | function_counter_[#method_name]++; \ |
103 | 107 | called_##method_name##_.CopyFrom(argument); \ |
104 | 108 | std::map<std::string, commands::Output>::const_iterator it = \ |
126 | 130 | // Exceptional methods. |
127 | 131 | // GetConfig needs to obtain the "called_config_". |
128 | 132 | bool ClientMock::GetConfig(config::Config *config) { |
133 | scoped_lock l(&mutex_); | |
129 | 134 | function_counter_["GetConfig"]++; |
130 | 135 | config->CopyFrom(called_config_); |
131 | 136 | std::map<std::string, bool>::const_iterator it = |
138 | 143 | |
139 | 144 | // SetConfig needs to set the "called_config_". |
140 | 145 | bool ClientMock::SetConfig(const config::Config &config) { |
146 | scoped_lock l(&mutex_); | |
141 | 147 | function_counter_["SetConfig"]++; |
142 | 148 | called_config_.CopyFrom(config); |
143 | 149 | std::map<std::string, bool>::const_iterator it = |
151 | 157 | // LaunchTool arguments are quite different from other methods. |
152 | 158 | bool ClientMock::LaunchTool(const std::string &mode, |
153 | 159 | const std::string &extra_arg) { |
160 | scoped_lock l(&mutex_); | |
154 | 161 | function_counter_["LaunchTool"]++; |
155 | 162 | return return_bool_values_["LaunchTool"]; |
156 | 163 | } |
158 | 165 | // Other methods to deal with internal data such like operations over |
159 | 166 | // function counters or setting the expected return values. |
160 | 167 | void ClientMock::ClearFunctionCounter() { |
168 | scoped_lock l(&mutex_); | |
161 | 169 | for (std::map<std::string, int>::iterator it = function_counter_.begin(); |
162 | 170 | it != function_counter_.end(); it++) { |
163 | 171 | it->second = 0; |
165 | 173 | } |
166 | 174 | |
167 | 175 | void ClientMock::SetBoolFunctionReturn(std::string func_name, bool value) { |
176 | scoped_lock l(&mutex_); | |
168 | 177 | return_bool_values_[func_name] = value; |
169 | 178 | } |
170 | 179 | |
171 | 180 | int ClientMock::GetFunctionCallCount(std::string key) { |
181 | scoped_lock l(&mutex_); | |
172 | 182 | return function_counter_[key]; |
173 | 183 | } |
174 | 184 |
31 | 31 | |
32 | 32 | #include <map> |
33 | 33 | #include <string> |
34 | #include "base/mutex.h" | |
34 | 35 | #include "client/client_interface.h" |
35 | 36 | #include "protocol/commands.pb.h" |
36 | 37 | |
106 | 107 | std::map<std::string, commands::Output> outputs_; |
107 | 108 | |
108 | 109 | config::Config called_config_; |
110 | ||
111 | // ClientMock is called from a thread in SessionWatchDog, and | |
112 | // SessionWatchDogTest. So a mutex lock is required. | |
113 | mutable Mutex mutex_; | |
109 | 114 | }; |
110 | 115 | } // namespace client |
111 | 116 | } // namespace mozc |
317 | 317 | SendCommand_UndoOrRewind |
318 | 318 | SendCommand_StopKeyToggling |
319 | 319 | SendCommand_ExpandSuggestion |
320 | SendCommand_ObsoleteSendCaretLocation | |
321 | SendCommand_ObsoleteSendLanguageBarCommand | |
322 | SendCommand_ObsoleteGetAsyncResult | |
323 | 320 | SendCommand_CommitRawText |
324 | 321 | SendCommand_ConvertPrevPage |
325 | 322 | SendCommand_ConvertNextPage |
32 | 32 | MINOR = 26 |
33 | 33 | |
34 | 34 | # Number to be increased. This value may be replaced by other tools. |
35 | BUILD = 4213 | |
35 | BUILD = 4219 | |
36 | 36 | |
37 | 37 | # Represent the platform and release channel. |
38 | 38 | REVISION = 100 |
96 | 96 | '<(PRODUCT_DIR)/libengine_builder.a', |
97 | 97 | '<(PRODUCT_DIR)/libengine_builder_proto.a', |
98 | 98 | '<(PRODUCT_DIR)/libflags.a', |
99 | '<(PRODUCT_DIR)/libgeneric_storage_manager.a', | |
100 | 99 | '<(PRODUCT_DIR)/libgoogle_data_manager.a', |
101 | 100 | '<(PRODUCT_DIR)/libhash.a', |
102 | 101 | '<(PRODUCT_DIR)/libimmutable_converter.a', |
256 | 256 | ) |
257 | 257 | |
258 | 258 | ## Commented out on 2011-03-09, because no other rule depends on it. |
259 | ## cc_binary_mozc(name = "process_watch_dog_main", | |
260 | ## srcs = ["process_watch_dog_main.cc",], | |
261 | ## deps = [":process_watch_dog", | |
262 | ## "//base:base",]) | |
259 | # cc_binary_mozc( | |
260 | # name = "process_watch_dog_main", | |
261 | # srcs = ["process_watch_dog_main.cc"], | |
262 | # deps = [ | |
263 | # ":process_watch_dog", | |
264 | # "//base", | |
265 | # "//base:flags", | |
266 | # "//base:init_mozc", | |
267 | # "//base:logging", | |
268 | # "//base:number_util", | |
269 | # "//base:port", | |
270 | # "//base:util", | |
271 | # ], | |
272 | # ) | |
263 | 273 | |
264 | 274 | cc_test_mozc( |
265 | 275 | name = "process_watch_dog_test", |
55 | 55 | LOG(ERROR) << "::CreateEvent() failed."; |
56 | 56 | return; |
57 | 57 | } |
58 | Thread::Start("WatchDog"); // start | |
59 | 58 | } |
60 | 59 | |
61 | 60 | ProcessWatchDog::~ProcessWatchDog() { |
62 | is_finished_ = true; // set the flag to terminate the thread | |
61 | StopWatchDog(); | |
62 | } | |
63 | ||
64 | void ProcessWatchDog::StartWatchDog() { | |
65 | Thread::Start("WatchDog"); | |
66 | } | |
67 | ||
68 | void ProcessWatchDog::StopWatchDog() { | |
69 | { | |
70 | scoped_lock l(mutex_.get()); | |
71 | is_finished_ = true; // set the flag to terminate the thread | |
72 | } | |
63 | 73 | |
64 | 74 | if (event_.get() != nullptr) { |
65 | 75 | ::SetEvent(event_.get()); // wake up WaitForMultipleObjects |
66 | 76 | } |
67 | 77 | |
68 | Join(); // wait for the thread | |
78 | Join(); | |
69 | 79 | } |
70 | 80 | |
71 | 81 | bool ProcessWatchDog::SetID(ProcessID process_id, ThreadID thread_id, |
81 | 91 | return true; |
82 | 92 | } |
83 | 93 | |
84 | // rewrite the valeus | |
94 | // rewrite the values | |
85 | 95 | { |
86 | 96 | scoped_lock l(mutex_.get()); |
87 | 97 | process_id_ = process_id; |
96 | 106 | } |
97 | 107 | |
98 | 108 | void ProcessWatchDog::Run() { |
99 | while (!is_finished_) { | |
109 | while (true) { | |
110 | { | |
111 | scoped_lock l(mutex_.get()); | |
112 | if (is_finished_) { | |
113 | break; | |
114 | } | |
115 | } | |
116 | ||
100 | 117 | ScopedHandle process_handle; |
101 | 118 | ScopedHandle thread_handle; |
102 | 119 | int timeout = -1; |
218 | 235 | : process_id_(UnknownProcessID), |
219 | 236 | thread_id_(UnknownProcessID), |
220 | 237 | is_finished_(false), |
221 | mutex_(new Mutex) { | |
238 | mutex_(new Mutex) {} | |
239 | ||
240 | ProcessWatchDog::~ProcessWatchDog() { | |
241 | // StopWatchDog() should be called before the deconstructor. | |
242 | // This call is a fallback. | |
243 | StopWatchDog(); | |
244 | } | |
245 | ||
246 | void ProcessWatchDog::StartWatchDog() { | |
222 | 247 | Thread::Start("WatchDog"); |
223 | 248 | } |
224 | 249 | |
225 | ProcessWatchDog::~ProcessWatchDog() { | |
226 | is_finished_ = true; | |
250 | void ProcessWatchDog::StopWatchDog() { | |
251 | { | |
252 | scoped_lock l(mutex_.get()); | |
253 | is_finished_ = true; // set the flag to terminate the thread | |
254 | } | |
227 | 255 | Join(); |
228 | 256 | } |
229 | 257 | |
266 | 294 | // reuse same process id in 250ms or write to is_finished_ stays |
267 | 295 | // forever in another CPU's local cache. |
268 | 296 | // TODO(team): use kqueue with EVFILT_PROC/NOTE_EXIT for Mac. |
269 | while (!is_finished_) { | |
297 | while (true) { | |
298 | { | |
299 | scoped_lock l(mutex_.get()); | |
300 | if (is_finished_) { | |
301 | break; | |
302 | } | |
303 | } | |
304 | ||
270 | 305 | Util::Sleep(250); |
271 | if (process_id_ == UnknownProcessID) { | |
272 | continue; | |
306 | { | |
307 | scoped_lock l(mutex_.get()); | |
308 | if (process_id_ == UnknownProcessID) { | |
309 | continue; | |
310 | } | |
273 | 311 | } |
274 | 312 | if (::kill(process_id_, 0) != 0) { |
275 | 313 | if (errno == EPERM) { |
61 | 61 | PROCESS_SIGNALED = 1, // process is signaled, |
62 | 62 | PROCESS_NOT_FOUND_SIGNALED = 3, // process id was not found |
63 | 63 | PROCESS_ACCESS_DENIED_SIGNALED = 4, // operation was not allowed |
64 | PROCESS_ERROR_SIGNALED = 5, // unkown error in getting process info | |
64 | PROCESS_ERROR_SIGNALED = 5, // unknown error in getting process info | |
65 | 65 | THREAD_SIGNALED = 6, // thread is signaled |
66 | 66 | THREAD_NOT_FOUND_SIGNALED = 7, // thread id was not found |
67 | 67 | THREAD_ACCESS_DENIED_SIGNALED = 8, // operation was not allowed |
68 | THREAD_ERROR_SIGNALED = 9, // unkown error in getting thread info | |
68 | THREAD_ERROR_SIGNALED = 9, // unknown error in getting thread info | |
69 | 69 | TIMEOUT_SIGNALED = 10, // timeout is signaled |
70 | 70 | }; |
71 | 71 | |
102 | 102 | |
103 | 103 | ProcessWatchDog(); |
104 | 104 | virtual ~ProcessWatchDog(); |
105 | void StartWatchDog(); | |
106 | void StopWatchDog(); | |
105 | 107 | |
106 | 108 | private: |
107 | 109 | #ifdef OS_WIN |
33 | 33 | #include "base/flags.h" |
34 | 34 | #include "base/init_mozc.h" |
35 | 35 | #include "base/logging.h" |
36 | #include "base/number_util.h" | |
36 | 37 | #include "base/port.h" |
37 | 38 | #include "base/util.h" |
38 | 39 | #include "ipc/process_watch_dog.h" |
52 | 53 | mozc::InitMozc(argv[0], &argc, &argv); |
53 | 54 | |
54 | 55 | mozc::TestProcessWatchDog dog; |
56 | dog.StartWatchDog(); | |
55 | 57 | |
56 | 58 | string line; |
57 | 59 | std::vector<string> fields; |
58 | 60 | |
59 | while (getline(cin, line)) { | |
61 | while (std::getline(std::cin, line)) { | |
60 | 62 | fields.clear(); |
61 | 63 | mozc::Util::SplitStringUsing(line, "\t ", &fields); |
62 | 64 | if (line == "exit") { |
67 | 69 | continue; |
68 | 70 | } |
69 | 71 | |
70 | const int32 process_id = atoi32(fields[0].c_str()); | |
71 | const int32 thread_id = atoi32(fields[1].c_str()); | |
72 | const int32 process_id = mozc::NumberUtil::SimpleAtoi(fields[0]); | |
73 | const int32 thread_id = mozc::NumberUtil::SimpleAtoi(fields[1]); | |
72 | 74 | |
73 | 75 | if (!dog.SetID(static_cast<mozc::ProcessWatchDog::ProcessID>(process_id), |
74 | 76 | static_cast<mozc::ProcessWatchDog::ThreadID>(thread_id), |
60 | 60 | exit(0); |
61 | 61 | } else if (pid > 0) { |
62 | 62 | TestProcessWatchDog dog; |
63 | dog.StartWatchDog(); | |
63 | 64 | dog.SetID(static_cast<ProcessWatchDog::ProcessID>(pid), |
64 | 65 | ProcessWatchDog::UnknownThreadID, -1); |
65 | 66 | Util::Sleep(4000); |
67 | dog.StopWatchDog(); | |
66 | 68 | } else { |
67 | 69 | LOG(ERROR) << "cannot execute fork"; |
68 | 70 | } |
211 | 211 | } |
212 | 212 | optional Direction direction = 14 [default = VERTICAL]; |
213 | 213 | |
214 | reserved 15; // Deprecated composition_rectangle | |
215 | reserved 16; // Deprecated caret_rectangle | |
216 | reserved 17; // Deprecated window_location | |
214 | reserved 15; | |
215 | reserved "composition_rectangle"; | |
216 | reserved 16; | |
217 | reserved "caret_rectangle"; | |
218 | reserved 17; | |
219 | reserved "window_location"; | |
217 | 220 | |
218 | 221 | // The number of candidates per page. |
219 | 222 | optional uint32 page_size = 18 [default = 9]; |
409 | 409 | EXPAND_SUGGESTION = 15; |
410 | 410 | |
411 | 411 | // Obsolete command. Used only in old IBus client. |
412 | OBSOLETE_SEND_CARET_LOCATION = 16; | |
412 | reserved 16; | |
413 | reserved "SEND_CARET_LOCATION"; | |
413 | 414 | |
414 | 415 | // Obsolete command. Don't simply remove this command for NUM_OF_COMMANDS. |
415 | 416 | // TODO(team): Replace this command by useful one. |
416 | OBSOLETE_SEND_LANGUAGE_BAR_COMMAND = 17; | |
417 | reserved 17; | |
418 | reserved "SEND_LANGUAGE_BAR_COMMAND"; | |
417 | 419 | |
418 | 420 | // Obsolete command. Don't simply remove this command for NUM_OF_COMMANDS. |
419 | 421 | // TODO(team): Replace this command by useful one. |
420 | OBSOLETE_GET_ASYNC_RESULT = 18; | |
422 | reserved 18; | |
423 | reserved "GET_ASYNC_RESULT"; | |
421 | 424 | |
422 | 425 | // Commit the raw text of the composed string. |
423 | 426 | COMMIT_RAW_TEXT = 19; |
657 | 660 | NOTOUCH_TO_HALFWIDTHASCII = 41; |
658 | 661 | |
659 | 662 | // Obsolete items. |
660 | OBSOLETE_TWELVE_KEYS_TO_NUMBER = 12; | |
661 | OBSOLETE_FLICK_TO_NUMBER = 15; | |
662 | OBSOLETE_GODAN_TO_NUMBER = 32; | |
663 | OBSOLETE_QWERTY_MOBILE_TO_HIRAGANA_NUMBER = 21; | |
664 | OBSOLETE_TOGGLE_FLICK_TO_NUMBER = 18; | |
663 | reserved 12, 15, 32, 21, 18; | |
664 | reserved "TWELVE_KEYS_TO_NUMBER"; | |
665 | reserved "GODAN_TO_NUMBER"; | |
666 | reserved "QWERTY_MOBILE_TO_HIRAGANA_NUMBER"; | |
665 | 667 | } |
666 | 668 | |
667 | 669 | // Use special Romanji table. |
897 | 899 | NO_OPERATION = 14; |
898 | 900 | |
899 | 901 | // Sync feature is deprecated since 1.13 dev. |
900 | // TODO(mozc-team): Remove following variables. | |
901 | OBSOLETE_START_CLOUD_SYNC = 18; | |
902 | OBSOLETE_GET_CLOUD_SYNC_STATUS = 23; | |
903 | OBSOLETE_ADD_AUTH_CODE = 24; | |
904 | ||
905 | INSERT_TO_STORAGE = 20; | |
906 | READ_ALL_FROM_STORAGE = 21; | |
907 | CLEAR_STORAGE = 25; | |
902 | reserved 18, 23, 24; | |
903 | reserved "START_CLOUD_SYNC"; | |
904 | reserved "GET_CLOUD_SYNC_STATUS"; | |
905 | reserved "ADD_AUTH_CODE"; | |
906 | ||
907 | reserved 20, 21, 25; | |
908 | reserved "INSERT_TO_STORAGE"; | |
909 | reserved "READ_ALL_FROM_STORAGE"; | |
910 | reserved "CLEAR_STORAGE"; | |
908 | 911 | |
909 | 912 | // Send a command for user dictionary session. |
910 | 913 | SEND_USER_DICTIONARY_COMMAND = 26; |
76 | 76 | // set verbose level of logging library (FLAGS_v) |
77 | 77 | optional int32 verbose_level = 10 [default = 0]; |
78 | 78 | |
79 | reserved 11; // Deprecated log_all_commands | |
79 | reserved 11; | |
80 | reserved "log_all_commands"; | |
80 | 81 | |
81 | 82 | ////////////////////////////////////////////////////////////// |
82 | 83 | // |
87 | 88 | // Disable all mutable operation if incognito_mode is true |
88 | 89 | optional bool incognito_mode = 20 [default = false]; |
89 | 90 | |
90 | reserved 21; // Deprecated upload_usage_stats | |
91 | reserved 21; | |
92 | reserved "upload_usage_stats"; | |
91 | 93 | |
92 | 94 | // whether to show the set default dialog on startup |
93 | 95 | optional bool check_default = 22 [default = true]; |
300 | 302 | |
301 | 303 | message InformationListConfig { |
302 | 304 | optional bool use_local_usage_dictionary = 1 [default = true]; |
303 | reserved 2; // Deprecated use_web_usage_dictionary | |
304 | reserved 10; // Deprecated web_service_entries | |
305 | reserved 2; | |
306 | reserved "use_web_usage_dictionary"; | |
307 | reserved 10; | |
308 | reserved "web_service_entries"; | |
305 | 309 | } |
306 | 310 | optional InformationListConfig information_list_config = 90; |
307 | 311 | |
333 | 337 | // Cloud (300-319) |
334 | 338 | // |
335 | 339 | // Configuration for cloud sync feature. This field is obsolete. |
336 | reserved 300; // Deprecated sync_config | |
337 | reserved 301; // Deprecated allow_cloud_handwriting | |
338 | reserved 996; // Deprecated pinyin_config | |
339 | reserved 998; // Deprecated hangul_config | |
340 | reserved 999; // Deprecated chewing_config | |
340 | reserved 300; | |
341 | reserved "sync_config"; | |
342 | reserved 301; | |
343 | reserved "allow_cloud_handwriting"; | |
344 | reserved 996; | |
345 | reserved "pinyin_config"; | |
346 | reserved 998; | |
347 | reserved "hangul_config"; | |
348 | reserved 999; | |
349 | reserved "chewing_config"; | |
341 | 350 | } |
89 | 89 | // An equivalent to COMPOSITIONFORM in IMM32. (For Windows only) |
90 | 90 | // TODO(yukawa): make a common composition form format for all platforms. |
91 | 91 | message CompositionForm { |
92 | reserved 1; // Deprecated style | |
92 | reserved 1; | |
93 | reserved "style"; | |
93 | 94 | optional Point current_position = 2; |
94 | 95 | optional Rectangle area = 3; |
95 | 96 | // Used as bit flags in |style_bits|. |
106 | 107 | // An equivalent to CANDIDATEFORM in IMM32. (For Windows only) |
107 | 108 | // TODO(yukawa): make a common candidate form format for all platforms. |
108 | 109 | message CandidateForm { |
109 | reserved 1; // Deprecated style | |
110 | reserved 1; | |
111 | reserved "style"; | |
110 | 112 | optional Point current_position = 2; |
111 | 113 | optional Rectangle area = 3; |
112 | 114 | // Used as bit flags in |style_bits|. |
202 | 204 | // Represents caret information. |
203 | 205 | optional CaretInfo caret_info = 11; |
204 | 206 | |
205 | reserved 12; // Deprecated message_sender_type | |
207 | reserved 12; | |
208 | reserved "message_sender_type"; | |
206 | 209 | |
207 | 210 | // A string representation of PangoFontDescription |
208 | 211 | // http://developer.gnome.org/pango/stable/pango-Fonts.html#pango-font-description-from-string |
43 | 43 | // whether session is just after commitment |
44 | 44 | optional bool committed = 3 [default = false]; |
45 | 45 | |
46 | reserved 4; // Deprecated selected_indices | |
47 | ||
48 | reserved 5; // Deprecated mode | |
46 | reserved 4; | |
47 | reserved "selected_indices"; | |
48 | reserved 5; | |
49 | reserved "mode"; | |
49 | 50 | |
50 | 51 | optional uint64 start_preedit_time = 10 [jstype = JS_STRING]; |
51 | 52 | optional uint64 start_conversion_window_time = 11 [jstype = JS_STRING]; |
59 | 60 | // last candidates state |
60 | 61 | optional mozc.commands.Candidates candidates = 21; |
61 | 62 | |
62 | reserved 22; // Deprecated all_candidate_words | |
63 | reserved 22; | |
64 | reserved "all_candidate_words"; | |
63 | 65 | |
64 | 66 | // last candidates result |
65 | 67 | optional mozc.commands.Result result = 23; |
203 | 203 | GET_ENTRY_SIZE = 10; |
204 | 204 | |
205 | 205 | // Use GET_ENTRIES instead. |
206 | OBSOLETE_GET_ENTRY = 11; | |
206 | reserved 11; | |
207 | reserved "OBSOLETE_GET_ENTRY"; | |
207 | 208 | |
208 | 209 | // Returns if it is possible to add new dictionary or not. |
209 | 210 | // The result is returned by using status code. |
107 | 107 | "//ipc:process_watch_dog", |
108 | 108 | "//protocol:config_proto", |
109 | 109 | "//protocol:renderer_proto", |
110 | "@com_google_absl//absl/memory", | |
110 | 111 | ], |
111 | 112 | ) |
112 | 113 |
48 | 48 | #include "protocol/config.pb.h" |
49 | 49 | #include "protocol/renderer_command.pb.h" |
50 | 50 | #include "renderer/renderer_interface.h" |
51 | #include "absl/memory/memory.h" | |
51 | 52 | |
52 | 53 | // By default, mozc_renderer quits when user-input continues to be |
53 | 54 | // idle for 10min. |
168 | 169 | : IPCServer(GetServiceName(), kNumConnections, kIPCServerTimeOut), |
169 | 170 | timeout_(0), |
170 | 171 | renderer_interface_(nullptr), |
171 | ALLOW_THIS_IN_INITIALIZER_LIST( | |
172 | watch_dog_(new ParentApplicationWatchDog(this))), | |
173 | 172 | send_command_(new RendererServerSendCommand) { |
173 | watch_dog_ = absl::make_unique<ParentApplicationWatchDog>(this); | |
174 | watch_dog_->StartWatchDog(); | |
174 | 175 | if (FLAGS_restricted) { |
175 | 176 | FLAGS_timeout = |
176 | 177 | std::min(FLAGS_timeout, 60); // set 60sec with restricted mode |
186 | 187 | #endif // MOZC_NO_LOGGING |
187 | 188 | } |
188 | 189 | |
189 | RendererServer::~RendererServer() {} | |
190 | RendererServer::~RendererServer() { | |
191 | watch_dog_->StopWatchDog(); | |
192 | } | |
190 | 193 | |
191 | 194 | void RendererServer::SetRendererInterface( |
192 | 195 | RendererInterface *renderer_interface) { |
223 | 226 | // different threads, we have to use heap to share the serialized message. |
224 | 227 | // If we use stack, this program will be crashed. |
225 | 228 | // |
226 | // The reciver of command_str takes the ownership of this string. | |
229 | // The receiver of command_str takes the ownership of this string. | |
227 | 230 | std::string *command_str = new std::string(request, request_size); |
228 | 231 | |
229 | 232 | // no need to set the result code. |
50 | 50 | test_suite( |
51 | 51 | name = "android_test", |
52 | 52 | tests = [ |
53 | ":generic_storage_manager_test_android", | |
54 | 53 | ":ime_switch_util_test_android", |
55 | 54 | ":key_info_util_test_android", |
56 | 55 | ":output_util_test_android", |
316 | 315 | "//base:process", |
317 | 316 | ], |
318 | 317 | ) + [ |
319 | ":generic_storage_manager", | |
320 | 318 | ":session", |
321 | 319 | ":session_handler_interface", |
322 | 320 | ":session_observer_handler", |
394 | 392 | ], |
395 | 393 | requires_full_emulation = False, |
396 | 394 | deps = [ |
397 | ":generic_storage_manager", | |
398 | 395 | ":session_handler", |
399 | 396 | ":session_handler_test_util", |
400 | 397 | "//base", |
771 | 768 | ) |
772 | 769 | |
773 | 770 | cc_library_mozc( |
774 | name = "generic_storage_manager", | |
775 | srcs = ["generic_storage_manager.cc"], | |
776 | hdrs = ["generic_storage_manager.h"], | |
777 | deps = [ | |
778 | "//base", | |
779 | "//base:config_file_stream", | |
780 | "//base:logging", | |
781 | "//base:mutex", | |
782 | "//base:port", | |
783 | "//base:singleton", | |
784 | "//protocol:commands_proto", | |
785 | "//storage:lru_storage", | |
786 | ], | |
787 | ) | |
788 | ||
789 | cc_library_mozc( | |
790 | 771 | name = "session_handler_interface", |
791 | 772 | hdrs = ["session_handler_interface.h"], |
792 | 773 | visibility = [ |
817 | 798 | visibility = ["//visibility:private"], |
818 | 799 | deps = ["//base:port"], |
819 | 800 | ) |
820 | ||
821 | cc_test_mozc( | |
822 | name = "generic_storage_manager_test", | |
823 | size = "small", | |
824 | srcs = ["generic_storage_manager_test.cc"], | |
825 | requires_full_emulation = False, | |
826 | deps = [ | |
827 | ":generic_storage_manager", | |
828 | "//base:file_util", | |
829 | "//base:util", | |
830 | "//testing:gunit_main", | |
831 | ], | |
832 | ) |
0 | // Copyright 2010-2020, Google Inc. | |
1 | // All rights reserved. | |
2 | // | |
3 | // Redistribution and use in source and binary forms, with or without | |
4 | // modification, are permitted provided that the following conditions are | |
5 | // met: | |
6 | // | |
7 | // * Redistributions of source code must retain the above copyright | |
8 | // notice, this list of conditions and the following disclaimer. | |
9 | // * Redistributions in binary form must reproduce the above | |
10 | // copyright notice, this list of conditions and the following disclaimer | |
11 | // in the documentation and/or other materials provided with the | |
12 | // distribution. | |
13 | // * Neither the name of Google Inc. nor the names of its | |
14 | // contributors may be used to endorse or promote products derived from | |
15 | // this software without specific prior written permission. | |
16 | // | |
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
18 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
19 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
20 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
21 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
22 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
23 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
24 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
25 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
28 | ||
29 | #include "session/generic_storage_manager.h" | |
30 | ||
31 | #include <cstring> | |
32 | #include <memory> | |
33 | #include <string> | |
34 | #include <vector> | |
35 | ||
36 | #include "base/config_file_stream.h" | |
37 | #include "base/logging.h" | |
38 | #include "base/mutex.h" | |
39 | #include "base/port.h" | |
40 | #include "base/singleton.h" | |
41 | #include "storage/lru_storage.h" | |
42 | ||
43 | namespace { | |
44 | ||
45 | mozc::Mutex g_storage_ensure_mutex; | |
46 | ||
47 | mozc::GenericStorageManagerInterface *g_storage_manager = nullptr; | |
48 | ||
49 | const char kSymbolStorageFileName[] = "user://symbol_history.db"; | |
50 | // 32 characters * 3 bytes(typical byte size per character) | |
51 | const size_t kSymbolValueSize = 32 * 3; | |
52 | const size_t kSymbolSize = 100; | |
53 | const uint32 kSymbolSeed = 336843897; | |
54 | ||
55 | const char kEmoticonStorageFileName[] = "user://emoticon_history.db"; | |
56 | // 64 characters * 3 bytes(typical byte size per character) | |
57 | const size_t kEmoticonValueSize = 64 * 3; | |
58 | const size_t kEmoticonSize = 100; | |
59 | const uint32 kEmoticonSeed = 236843897; | |
60 | ||
61 | const char kEmojiStorageFileName[] = "user://emoji_history.db"; | |
62 | // 32 characters * 3 bytes(typical byte size per character) | |
63 | const size_t kEmojiValueSize = 32 * 3; | |
64 | const size_t kEmojiSize = 100; | |
65 | const uint32 kEmojiSeed = 136843897; | |
66 | ||
67 | } // namespace | |
68 | ||
69 | namespace mozc { | |
70 | ||
71 | using mozc::storage::LRUStorage; | |
72 | ||
73 | class GenericStorageManagerImpl : public GenericStorageManagerInterface { | |
74 | public: | |
75 | GenericStorageManagerImpl() | |
76 | : symbol_history_storage_(kSymbolStorageFileName, kSymbolValueSize, | |
77 | kSymbolSize, kSymbolSeed), | |
78 | emoticon_history_storage_(kEmoticonStorageFileName, kEmoticonValueSize, | |
79 | kEmoticonSize, kEmoticonSeed), | |
80 | emoji_history_storage_(kEmojiStorageFileName, kEmojiValueSize, | |
81 | kEmojiSize, kEmojiSeed) {} | |
82 | ||
83 | ~GenericStorageManagerImpl() override = default; | |
84 | ||
85 | GenericStorageInterface *GetStorage( | |
86 | commands::GenericStorageEntry::StorageType storage_type) override; | |
87 | ||
88 | bool SyncAll() override; | |
89 | ||
90 | private: | |
91 | GenericLruStorage symbol_history_storage_; | |
92 | GenericLruStorage emoticon_history_storage_; | |
93 | GenericLruStorage emoji_history_storage_; | |
94 | }; | |
95 | ||
96 | GenericStorageInterface *GenericStorageManagerImpl::GetStorage( | |
97 | commands::GenericStorageEntry::StorageType storage_type) { | |
98 | switch (storage_type) { | |
99 | case commands::GenericStorageEntry::SYMBOL_HISTORY: | |
100 | return &symbol_history_storage_; | |
101 | case commands::GenericStorageEntry::EMOTICON_HISTORY: | |
102 | return &emoticon_history_storage_; | |
103 | case commands::GenericStorageEntry::EMOJI_HISTORY: | |
104 | return &emoji_history_storage_; | |
105 | default: | |
106 | LOG(WARNING) << "Invalid storage type"; | |
107 | } | |
108 | return nullptr; | |
109 | } | |
110 | ||
111 | bool GenericStorageManagerImpl::SyncAll() { | |
112 | const bool symbol_ok = symbol_history_storage_.Sync(); | |
113 | const bool emoticon_ok = emoticon_history_storage_.Sync(); | |
114 | const bool emoji_ok = emoji_history_storage_.Sync(); | |
115 | return symbol_ok && emoticon_ok && emoji_ok; | |
116 | } | |
117 | ||
118 | // static | |
119 | void GenericStorageManagerFactory::SetGenericStorageManager( | |
120 | GenericStorageManagerInterface *manager) { | |
121 | g_storage_manager = manager; | |
122 | } | |
123 | ||
124 | // static | |
125 | GenericStorageInterface *GenericStorageManagerFactory::GetStorage( | |
126 | commands::GenericStorageEntry::StorageType storage_type) { | |
127 | GenericStorageManagerInterface *manager = | |
128 | g_storage_manager ? g_storage_manager | |
129 | : Singleton<GenericStorageManagerImpl>::get(); | |
130 | return manager->GetStorage(storage_type); | |
131 | } | |
132 | ||
133 | bool GenericStorageManagerFactory::SyncAll() { | |
134 | GenericStorageManagerInterface *manager = | |
135 | g_storage_manager ? g_storage_manager | |
136 | : Singleton<GenericStorageManagerImpl>::get(); | |
137 | return manager->SyncAll(); | |
138 | } | |
139 | ||
140 | GenericLruStorage::GenericLruStorage(const char *file_name, size_t value_size, | |
141 | size_t size, uint32 seed) | |
142 | : file_name_(file_name), | |
143 | value_size_(value_size), | |
144 | size_(size), | |
145 | seed_(seed), | |
146 | value_buffer_(new char[value_size + 1]) {} | |
147 | ||
148 | GenericLruStorage::~GenericLruStorage() {} | |
149 | ||
150 | bool GenericLruStorage::EnsureStorage() { | |
151 | scoped_lock lock(&g_storage_ensure_mutex); | |
152 | if (lru_storage_.get()) { | |
153 | // We already have prepared storage. | |
154 | return true; | |
155 | } | |
156 | std::unique_ptr<LRUStorage> new_storage; | |
157 | new_storage.reset(new LRUStorage()); | |
158 | const std::string &filename = ConfigFileStream::GetFileName(file_name_); | |
159 | if (!new_storage->OpenOrCreate(filename.data(), value_size_, size_, seed_)) { | |
160 | return false; | |
161 | } | |
162 | lru_storage_.swap(new_storage); | |
163 | return true; | |
164 | } | |
165 | ||
166 | bool GenericLruStorage::Insert(const std::string &key, const char *value) { | |
167 | if (!EnsureStorage()) { | |
168 | return false; | |
169 | } | |
170 | const size_t value_size = strnlen(value, value_size_ + 1); | |
171 | if (value_size > value_size_) { | |
172 | LOG(DFATAL) << "Too long value: [" << value << "] size: " << value_size; | |
173 | return false; | |
174 | } | |
175 | // LRUStorage only accepts fixed-length value, so we should allocate enough | |
176 | // memory to avoid illegal access. | |
177 | memcpy(value_buffer_.get(), value, value_size + 1); | |
178 | return lru_storage_->Insert(key, value_buffer_.get()); | |
179 | } | |
180 | ||
181 | const char *GenericLruStorage::Lookup(const std::string &key) { | |
182 | if (!EnsureStorage()) { | |
183 | return nullptr; | |
184 | } | |
185 | return lru_storage_->Lookup(key); | |
186 | } | |
187 | ||
188 | bool GenericLruStorage::GetAllValues(std::vector<std::string> *values) { | |
189 | if (!EnsureStorage()) { | |
190 | return false; | |
191 | } | |
192 | lru_storage_->GetAllValues(values); | |
193 | return true; | |
194 | } | |
195 | ||
196 | bool GenericLruStorage::Clear() { | |
197 | if (!EnsureStorage()) { | |
198 | return false; | |
199 | } | |
200 | return lru_storage_->Clear(); | |
201 | } | |
202 | ||
203 | bool GenericLruStorage::Sync() { | |
204 | if (!EnsureStorage()) { | |
205 | return false; | |
206 | } | |
207 | lru_storage_->DeleteElementsUntouchedFor62Days(); | |
208 | return true; | |
209 | } | |
210 | ||
211 | } // namespace mozc |
0 | // Copyright 2010-2020, Google Inc. | |
1 | // All rights reserved. | |
2 | // | |
3 | // Redistribution and use in source and binary forms, with or without | |
4 | // modification, are permitted provided that the following conditions are | |
5 | // met: | |
6 | // | |
7 | // * Redistributions of source code must retain the above copyright | |
8 | // notice, this list of conditions and the following disclaimer. | |
9 | // * Redistributions in binary form must reproduce the above | |
10 | // copyright notice, this list of conditions and the following disclaimer | |
11 | // in the documentation and/or other materials provided with the | |
12 | // distribution. | |
13 | // * Neither the name of Google Inc. nor the names of its | |
14 | // contributors may be used to endorse or promote products derived from | |
15 | // this software without specific prior written permission. | |
16 | // | |
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
18 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
19 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
20 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
21 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
22 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
23 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
24 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
25 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
28 | ||
29 | #ifndef MOZC_SESSION_GENERIC_STORAGE_MANAGER_H_ | |
30 | #define MOZC_SESSION_GENERIC_STORAGE_MANAGER_H_ | |
31 | ||
32 | #include <memory> | |
33 | ||
34 | #include "base/port.h" | |
35 | #include "protocol/commands.pb.h" | |
36 | ||
37 | namespace mozc { | |
38 | ||
39 | class GenericStorageInterface; | |
40 | ||
41 | // For unit test. | |
42 | class GenericLruStorageProxy; | |
43 | ||
44 | namespace storage { | |
45 | class LRUStorage; | |
46 | } // namespace storage | |
47 | ||
48 | // Override and set the subclass's instance to | |
49 | // GenericStorageManager for unit test. | |
50 | class GenericStorageManagerInterface { | |
51 | public: | |
52 | virtual ~GenericStorageManagerInterface() = default; | |
53 | ||
54 | virtual GenericStorageInterface *GetStorage( | |
55 | commands::GenericStorageEntry::StorageType storage_type) = 0; | |
56 | ||
57 | // Synchronizes all the managed storages. Returns true iff all the storages | |
58 | // are synchronized successfully (Note: even if one failed, it's guaranteed | |
59 | // that Sync() to all the storages are called.). | |
60 | virtual bool SyncAll() = 0; | |
61 | }; | |
62 | ||
63 | // Manages generic storages. | |
64 | class GenericStorageManagerFactory { | |
65 | public: | |
66 | // Returns corresponding storage's instance. | |
67 | // If no instance is available, NULL is returned. | |
68 | static GenericStorageInterface *GetStorage( | |
69 | commands::GenericStorageEntry::StorageType storage_type); | |
70 | ||
71 | // Synchronizes all the storages managed by this factory. Returns true iff | |
72 | // all the storages are synchronized successfully (Note: even if one failed, | |
73 | // it's guaranteed that Sync() to all the storages are called.). | |
74 | static bool SyncAll(); | |
75 | ||
76 | // For unit test. | |
77 | static void SetGenericStorageManager(GenericStorageManagerInterface *manager); | |
78 | ||
79 | GenericStorageManagerFactory() = delete; | |
80 | GenericStorageManagerFactory(const GenericStorageManagerFactory &) = delete; | |
81 | GenericStorageManagerFactory &operator=( | |
82 | const GenericStorageManagerFactory &) = delete; | |
83 | }; | |
84 | ||
85 | // Generic interface for storages. | |
86 | // This class defines only the interfaces. | |
87 | // Detailed behaviors depend on the subclass's | |
88 | // backend. | |
89 | class GenericStorageInterface { | |
90 | public: | |
91 | virtual ~GenericStorageInterface() = default; | |
92 | ||
93 | // Inserts new entry. | |
94 | // If something goes wrong, returns false. | |
95 | // value should be terminated by '\0'. | |
96 | virtual bool Insert(const std::string &key, const char *value) = 0; | |
97 | // Looks up the value. | |
98 | // If something goes wrong, returns NULL. | |
99 | virtual const char *Lookup(const std::string &key) = 0; | |
100 | // Lists all the values. | |
101 | // If something goes wrong, returns false. | |
102 | virtual bool GetAllValues(std::vector<std::string> *values) = 0; | |
103 | // Clears all the entries. | |
104 | virtual bool Clear() = 0; | |
105 | // Writes the data to file(s). | |
106 | virtual bool Sync() = 0; | |
107 | }; | |
108 | ||
109 | // Storage class of which backend is LRUStorage. | |
110 | class GenericLruStorage : public GenericStorageInterface { | |
111 | public: | |
112 | GenericLruStorage(const char *file_name, size_t value_size, size_t size, | |
113 | uint32 seed); | |
114 | ||
115 | GenericLruStorage(const GenericLruStorage &) = delete; | |
116 | GenericLruStorage &operator=(const GenericLruStorage &) = delete; | |
117 | ||
118 | ~GenericLruStorage() override; | |
119 | ||
120 | // If the storage has |key|, this method overwrites | |
121 | // the old value. | |
122 | // If the entiry's size is over GetSize(), | |
123 | // the oldest value is disposed. | |
124 | bool Insert(const std::string &key, const char *value) override; | |
125 | ||
126 | const char *Lookup(const std::string &key) override; | |
127 | ||
128 | // The order is new to old. | |
129 | bool GetAllValues(std::vector<std::string> *values) override; | |
130 | ||
131 | bool Clear() override; | |
132 | bool Sync() override; | |
133 | ||
134 | protected: | |
135 | // Opens the storage if not opened yet. | |
136 | // If something goes wrong, returns false. | |
137 | bool EnsureStorage(); | |
138 | ||
139 | private: | |
140 | friend class GenericLruStorageProxy; | |
141 | std::unique_ptr<mozc::storage::LRUStorage> lru_storage_; | |
142 | const std::string file_name_; | |
143 | const size_t value_size_; | |
144 | const size_t size_; | |
145 | const uint32 seed_; | |
146 | // Temporary buffer to insert a value into this storage. | |
147 | std::unique_ptr<char[]> value_buffer_; | |
148 | }; | |
149 | ||
150 | } // namespace mozc | |
151 | ||
152 | #endif // MOZC_SESSION_GENERIC_STORAGE_MANAGER_H_ |
0 | // Copyright 2010-2020, Google Inc. | |
1 | // All rights reserved. | |
2 | // | |
3 | // Redistribution and use in source and binary forms, with or without | |
4 | // modification, are permitted provided that the following conditions are | |
5 | // met: | |
6 | // | |
7 | // * Redistributions of source code must retain the above copyright | |
8 | // notice, this list of conditions and the following disclaimer. | |
9 | // * Redistributions in binary form must reproduce the above | |
10 | // copyright notice, this list of conditions and the following disclaimer | |
11 | // in the documentation and/or other materials provided with the | |
12 | // distribution. | |
13 | // * Neither the name of Google Inc. nor the names of its | |
14 | // contributors may be used to endorse or promote products derived from | |
15 | // this software without specific prior written permission. | |
16 | // | |
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
18 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
19 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
20 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
21 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
22 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
23 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
24 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
25 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
28 | ||
29 | #include "session/generic_storage_manager.h" | |
30 | ||
31 | #include "base/file_util.h" | |
32 | #include "base/util.h" | |
33 | #include "testing/base/public/googletest.h" | |
34 | #include "testing/base/public/gunit.h" | |
35 | ||
36 | namespace { | |
37 | ||
38 | static const std::string GetTemporaryFilePath() { | |
39 | return mozc::FileUtil::JoinPath(FLAGS_test_tmpdir, "generic_storage_test.db"); | |
40 | } | |
41 | ||
42 | } // namespace | |
43 | ||
44 | namespace mozc { | |
45 | ||
46 | TEST(GenericStorageManagerFactoryTest, GetStorage) { | |
47 | GenericStorageInterface *symbol = GenericStorageManagerFactory::GetStorage( | |
48 | commands::GenericStorageEntry::SYMBOL_HISTORY); | |
49 | GenericStorageInterface *emoticon = GenericStorageManagerFactory::GetStorage( | |
50 | commands::GenericStorageEntry::EMOTICON_HISTORY); | |
51 | GenericStorageInterface *invalid = GenericStorageManagerFactory::GetStorage( | |
52 | static_cast<commands::GenericStorageEntry::StorageType>(100)); | |
53 | ||
54 | EXPECT_NE(nullptr, symbol); | |
55 | EXPECT_NE(nullptr, emoticon); | |
56 | EXPECT_EQ(nullptr, invalid); | |
57 | EXPECT_NE(symbol, emoticon); | |
58 | } | |
59 | ||
60 | // Checks the basic operations of LRU. | |
61 | // Detailed test is omitted because storage/lru_storage_test.cc does. | |
62 | TEST(GenericLruStorageTest, BasicOperations) { | |
63 | const int kValueSize = 12; | |
64 | const int kSize = 10; | |
65 | constexpr const char *kPrintFormat = "%12zu"; // 12 = kValueSize | |
66 | ||
67 | GenericLruStorage storage(GetTemporaryFilePath().data(), kValueSize, kSize, | |
68 | 123); | |
69 | // Inserts (kSize + 1) entries. | |
70 | for (size_t i = 0; i < kSize + 1; ++i) { | |
71 | const std::string value = Util::StringPrintf(kPrintFormat, i); | |
72 | const std::string key = std::string("key") + value; | |
73 | storage.Insert(key, value.data()); | |
74 | // Check the existence. | |
75 | EXPECT_EQ(value, std::string(storage.Lookup(key), kValueSize)); | |
76 | } | |
77 | ||
78 | // First inserted entry is already pushed out. | |
79 | EXPECT_EQ(nullptr, storage.Lookup("0")); | |
80 | for (size_t i = 1; i < kSize + 1; ++i) { | |
81 | const std::string value = Util::StringPrintf(kPrintFormat, i); | |
82 | const std::string key = std::string("key") + value; | |
83 | EXPECT_EQ(value, std::string(storage.Lookup(key), kValueSize)); | |
84 | } | |
85 | ||
86 | // Check the list. | |
87 | std::vector<std::string> values; | |
88 | storage.GetAllValues(&values); | |
89 | EXPECT_EQ(kSize, values.size()); | |
90 | for (size_t i = 1; i < kSize + 1; ++i) { | |
91 | EXPECT_EQ(Util::StringPrintf(kPrintFormat, i), values.at(kSize - i)); | |
92 | } | |
93 | ||
94 | // Clean | |
95 | storage.Clear(); | |
96 | storage.GetAllValues(&values); | |
97 | EXPECT_TRUE(values.empty()); | |
98 | } | |
99 | ||
100 | } // namespace mozc |
104 | 104 | '../protocol/protocol.gyp:engine_builder_proto', |
105 | 105 | '../protocol/protocol.gyp:user_dictionary_storage_proto', |
106 | 106 | '../usage_stats/usage_stats_base.gyp:usage_stats', |
107 | 'session_base.gyp:generic_storage_manager', | |
108 | 107 | ':session_watch_dog', |
109 | 108 | ], |
110 | 109 | 'conditions': [ |
129 | 129 | '../usage_stats/usage_stats_base.gyp:usage_stats', |
130 | 130 | ], |
131 | 131 | }, |
132 | { | |
133 | 'target_name': 'generic_storage_manager', | |
134 | 'type': 'static_library', | |
135 | 'sources': [ | |
136 | 'generic_storage_manager.cc', | |
137 | ], | |
138 | 'dependencies': [ | |
139 | '../base/base.gyp:base', | |
140 | '../base/base.gyp:config_file_stream', | |
141 | '../protocol/protocol.gyp:commands_proto', | |
142 | '../storage/storage.gyp:storage', | |
143 | ] | |
144 | }, | |
145 | 132 | ], |
146 | 133 | } |
55 | 55 | #include "protocol/commands.pb.h" |
56 | 56 | #include "protocol/config.pb.h" |
57 | 57 | #include "protocol/user_dictionary_storage.pb.h" |
58 | #include "session/generic_storage_manager.h" | |
59 | 58 | #include "session/session.h" |
60 | 59 | #include "session/session_observer_handler.h" |
61 | 60 | #ifndef MOZC_DISABLE_SESSION_WATCHDOG |
123 | 122 | // android version supports base/process.cc |
124 | 123 | #endif // MOZC_DISABLE_SESSION_WATCHDOG |
125 | 124 | return true; |
126 | } | |
127 | ||
128 | bool IsCarrierEmoji(const std::string &utf8_str) { | |
129 | if (Util::CharsLen(utf8_str) != 1) { | |
130 | return false; | |
131 | } | |
132 | const char *utf8_begin = utf8_str.c_str(); | |
133 | size_t mblen = 0; | |
134 | const uint32 ucs4_val = static_cast<uint32>( | |
135 | Util::UTF8ToUCS4(utf8_begin, utf8_begin + utf8_str.size(), &mblen)); | |
136 | const uint32 kMinEmojiPuaCodePoint = 0xFE000; | |
137 | const uint32 kMaxEmojiPuaCodePoint = 0xFEEA0; | |
138 | return kMinEmojiPuaCodePoint <= ucs4_val && ucs4_val <= kMaxEmojiPuaCodePoint; | |
139 | 125 | } |
140 | 126 | } // namespace |
141 | 127 | |
262 | 248 | bool SessionHandler::SyncData(commands::Command *command) { |
263 | 249 | VLOG(1) << "Syncing user data"; |
264 | 250 | engine_->GetUserDataManager()->Sync(); |
265 | GenericStorageManagerFactory::SyncAll(); | |
266 | 251 | return true; |
267 | 252 | } |
268 | 253 | |
367 | 352 | return true; |
368 | 353 | } |
369 | 354 | |
370 | bool SessionHandler::InsertToStorage(commands::Command *command) { | |
371 | VLOG(1) << "Insert to generic storage"; | |
372 | if (!command->input().has_storage_entry()) { | |
373 | LOG(WARNING) << "No storage_entry"; | |
374 | return false; | |
375 | } | |
376 | const commands::GenericStorageEntry &storage_entry = | |
377 | command->input().storage_entry(); | |
378 | if (!storage_entry.has_type() || !storage_entry.has_key() || | |
379 | storage_entry.value().empty()) { | |
380 | LOG(WARNING) << "storage_entry lacks some fields."; | |
381 | return false; | |
382 | } | |
383 | ||
384 | GenericStorageInterface *storage = | |
385 | GenericStorageManagerFactory::GetStorage(storage_entry.type()); | |
386 | if (!storage) { | |
387 | LOG(WARNING) << "No storage found"; | |
388 | return false; | |
389 | } | |
390 | ||
391 | for (int i = 0; i < storage_entry.value_size(); ++i) { | |
392 | const std::string &value = storage_entry.value(i); | |
393 | storage->Insert(value, value.c_str()); | |
394 | } | |
395 | ||
396 | if (storage_entry.type() == commands::GenericStorageEntry::EMOJI_HISTORY) { | |
397 | for (int i = 0; i < storage_entry.value_size(); ++i) { | |
398 | if (IsCarrierEmoji(storage_entry.value(i))) { | |
399 | UsageStats::IncrementCount("CommitCarrierEmoji"); | |
400 | } else { | |
401 | UsageStats::IncrementCount("CommitUnicodeEmoji"); | |
402 | } | |
403 | } | |
404 | } | |
405 | ||
406 | return true; | |
407 | } | |
408 | ||
409 | bool SessionHandler::ReadAllFromStorage(commands::Command *command) { | |
410 | VLOG(1) << "Read all from storage"; | |
411 | commands::Output *output = command->mutable_output(); | |
412 | if (!command->input().has_storage_entry()) { | |
413 | LOG(WARNING) << "No storage_entry"; | |
414 | return false; | |
415 | } | |
416 | if (!command->input().storage_entry().has_type()) { | |
417 | LOG(WARNING) << "storage_entry lacks type fields."; | |
418 | return false; | |
419 | } | |
420 | ||
421 | commands::GenericStorageEntry::StorageType storage_type = | |
422 | command->input().storage_entry().type(); | |
423 | GenericStorageInterface *storage = | |
424 | GenericStorageManagerFactory::GetStorage(storage_type); | |
425 | if (!storage) { | |
426 | LOG(WARNING) << "No storage found"; | |
427 | return false; | |
428 | } | |
429 | ||
430 | std::vector<std::string> result; | |
431 | storage->GetAllValues(&result); | |
432 | output->mutable_storage_entry()->set_type(storage_type); | |
433 | for (size_t i = 0; i < result.size(); ++i) { | |
434 | output->mutable_storage_entry()->add_value(result[i]); | |
435 | } | |
436 | return true; | |
437 | } | |
438 | ||
439 | bool SessionHandler::ClearStorage(commands::Command *command) { | |
440 | VLOG(1) << "Clear storage"; | |
441 | commands::Output *output = command->mutable_output(); | |
442 | if (!command->input().has_storage_entry()) { | |
443 | LOG(WARNING) << "No storage_entry"; | |
444 | return false; | |
445 | } | |
446 | if (!command->input().storage_entry().has_type()) { | |
447 | LOG(WARNING) << "storage_entry lacks type fields."; | |
448 | return false; | |
449 | } | |
450 | ||
451 | commands::GenericStorageEntry::StorageType storage_type = | |
452 | command->input().storage_entry().type(); | |
453 | GenericStorageInterface *storage = | |
454 | GenericStorageManagerFactory::GetStorage(storage_type); | |
455 | if (!storage) { | |
456 | LOG(WARNING) << "No storage found"; | |
457 | return false; | |
458 | } | |
459 | output->mutable_storage_entry()->set_type(storage_type); | |
460 | return storage->Clear(); | |
461 | } | |
462 | ||
463 | 355 | bool SessionHandler::EvalCommand(commands::Command *command) { |
464 | 356 | if (!is_available_) { |
465 | 357 | LOG(ERROR) << "SessionHandler is not available."; |
518 | 410 | break; |
519 | 411 | case commands::Input::CLEANUP: |
520 | 412 | eval_succeeded = Cleanup(command); |
521 | break; | |
522 | case commands::Input::INSERT_TO_STORAGE: | |
523 | eval_succeeded = InsertToStorage(command); | |
524 | break; | |
525 | case commands::Input::READ_ALL_FROM_STORAGE: | |
526 | eval_succeeded = ReadAllFromStorage(command); | |
527 | break; | |
528 | case commands::Input::CLEAR_STORAGE: | |
529 | eval_succeeded = ClearStorage(command); | |
530 | 413 | break; |
531 | 414 | case commands::Input::SEND_USER_DICTIONARY_COMMAND: |
532 | 415 | eval_succeeded = SendUserDictionaryCommand(command); |
712 | 595 | if (engine_->GetUserDataManager()) { |
713 | 596 | engine_->GetUserDataManager()->Sync(); |
714 | 597 | } |
715 | GenericStorageManagerFactory::SyncAll(); | |
716 | 598 | return true; |
717 | 599 | } |
718 | 600 | |
781 | 663 | |
782 | 664 | // Sync all data. This is a regression bug fix http://b/3033708 |
783 | 665 | engine_->GetUserDataManager()->Sync(); |
784 | GenericStorageManagerFactory::SyncAll(); | |
785 | 666 | |
786 | 667 | // timeout is enabled. |
787 | 668 | if (FLAGS_timeout > 0 && last_session_empty_time_ != 0 && |
129 | 129 | bool SetImposedConfig(commands::Command *command); |
130 | 130 | bool SetRequest(commands::Command *command); |
131 | 131 | |
132 | bool InsertToStorage(commands::Command *command); | |
133 | bool ReadAllFromStorage(commands::Command *command); | |
134 | bool ClearStorage(commands::Command *command); | |
135 | 132 | bool Cleanup(commands::Command *command); |
136 | 133 | bool SendUserDictionaryCommand(commands::Command *command); |
137 | 134 | bool SendEngineReloadRequest(commands::Command *command); |
46 | 46 | #include "engine/user_data_manager_mock.h" |
47 | 47 | #include "protocol/commands.pb.h" |
48 | 48 | #include "protocol/config.pb.h" |
49 | #include "session/generic_storage_manager.h" | |
50 | 49 | #include "session/session_handler_test_util.h" |
51 | 50 | #include "testing/base/public/googletest.h" |
52 | 51 | #include "testing/base/public/gunit.h" |
148 | 147 | void SetUp() override { |
149 | 148 | SessionHandlerTestBase::SetUp(); |
150 | 149 | Clock::SetClockForUnitTest(nullptr); |
151 | GenericStorageManagerFactory::SetGenericStorageManager(nullptr); | |
152 | 150 | } |
153 | 151 | |
154 | 152 | void TearDown() override { |
155 | GenericStorageManagerFactory::SetGenericStorageManager(nullptr); | |
156 | 153 | Clock::SetClockForUnitTest(nullptr); |
157 | 154 | SessionHandlerTestBase::TearDown(); |
158 | 155 | } |
438 | 435 | } |
439 | 436 | } |
440 | 437 | |
441 | const char *kStorageTestData[] = { | |
442 | "angel", | |
443 | "bishop", | |
444 | "chariot", | |
445 | "dragon", | |
446 | }; | |
447 | ||
448 | class MockStorage : public GenericStorageInterface { | |
449 | public: | |
450 | int insert_count; | |
451 | int clear_count; | |
452 | const char **insert_expect; | |
453 | ||
454 | MockStorage() : insert_count(0), clear_count(0) {} | |
455 | ~MockStorage() override = default; | |
456 | ||
457 | bool Insert(const std::string &key, const char *value) override { | |
458 | EXPECT_EQ(std::string(insert_expect[insert_count]), key); | |
459 | EXPECT_EQ(std::string(insert_expect[insert_count]), std::string(value)); | |
460 | ++insert_count; | |
461 | return true; | |
462 | } | |
463 | ||
464 | const char *Lookup(const std::string &key) override { return nullptr; } | |
465 | ||
466 | bool GetAllValues(std::vector<std::string> *values) override { | |
467 | values->clear(); | |
468 | for (size_t i = 0; i < arraysize(kStorageTestData); ++i) { | |
469 | values->push_back(kStorageTestData[i]); | |
470 | } | |
471 | return true; | |
472 | } | |
473 | ||
474 | bool Clear() override { | |
475 | ++clear_count; | |
476 | return true; | |
477 | } | |
478 | ||
479 | bool Sync() override { return true; } | |
480 | ||
481 | void SetInsertExpect(const char **expect) { insert_expect = expect; } | |
482 | }; | |
483 | ||
484 | class MockStorageManager : public GenericStorageManagerInterface { | |
485 | public: | |
486 | GenericStorageInterface *GetStorage( | |
487 | commands::GenericStorageEntry::StorageType storage_type) override { | |
488 | return storage; | |
489 | } | |
490 | ||
491 | void SetStorage(MockStorage *newStorage) { storage = newStorage; } | |
492 | ||
493 | bool SyncAll() override { | |
494 | if (storage == nullptr) { | |
495 | return true; | |
496 | } | |
497 | return storage->Sync(); | |
498 | } | |
499 | ||
500 | private: | |
501 | MockStorage *storage; | |
502 | }; | |
503 | ||
504 | // Tests basic behavior of InsertToStorage and ReadAllFromStorage methods. | |
505 | TEST_F(SessionHandlerTest, StorageTest) { | |
506 | // Inject mock objects. | |
507 | MockStorageManager storageManager; | |
508 | GenericStorageManagerFactory::SetGenericStorageManager(&storageManager); | |
509 | SessionHandler handler(CreateMockDataEngine()); | |
510 | { | |
511 | // InsertToStorage | |
512 | MockStorage mock_storage; | |
513 | mock_storage.SetInsertExpect(kStorageTestData); | |
514 | storageManager.SetStorage(&mock_storage); | |
515 | commands::Command command; | |
516 | command.mutable_input()->set_type(commands::Input::INSERT_TO_STORAGE); | |
517 | commands::GenericStorageEntry *storage_entry = | |
518 | command.mutable_input()->mutable_storage_entry(); | |
519 | storage_entry->set_type(commands::GenericStorageEntry::SYMBOL_HISTORY); | |
520 | storage_entry->mutable_key()->assign("dummy key"); | |
521 | for (size_t i = 0; i < arraysize(kStorageTestData); ++i) { | |
522 | storage_entry->mutable_value()->Add()->assign(kStorageTestData[i]); | |
523 | } | |
524 | EXPECT_TRUE(handler.InsertToStorage(&command)); | |
525 | EXPECT_EQ(arraysize(kStorageTestData), mock_storage.insert_count); | |
526 | } | |
527 | { | |
528 | // ReadAllFromStorage | |
529 | MockStorage mock_storage; | |
530 | storageManager.SetStorage(&mock_storage); | |
531 | commands::Command command; | |
532 | command.mutable_input()->set_type(commands::Input::READ_ALL_FROM_STORAGE); | |
533 | commands::GenericStorageEntry *storage_entry = | |
534 | command.mutable_input()->mutable_storage_entry(); | |
535 | storage_entry->set_type(commands::GenericStorageEntry::EMOTICON_HISTORY); | |
536 | EXPECT_TRUE(handler.ReadAllFromStorage(&command)); | |
537 | EXPECT_EQ(commands::GenericStorageEntry::EMOTICON_HISTORY, | |
538 | command.output().storage_entry().type()); | |
539 | EXPECT_EQ(arraysize(kStorageTestData), | |
540 | command.output().storage_entry().value().size()); | |
541 | } | |
542 | { | |
543 | // Clear | |
544 | MockStorage mock_storage; | |
545 | storageManager.SetStorage(&mock_storage); | |
546 | commands::Command command; | |
547 | command.mutable_input()->set_type(commands::Input::CLEAR_STORAGE); | |
548 | commands::GenericStorageEntry *storage_entry = | |
549 | command.mutable_input()->mutable_storage_entry(); | |
550 | storage_entry->set_type(commands::GenericStorageEntry::EMOTICON_HISTORY); | |
551 | EXPECT_TRUE(handler.ClearStorage(&command)); | |
552 | EXPECT_EQ(commands::GenericStorageEntry::EMOTICON_HISTORY, | |
553 | command.output().storage_entry().type()); | |
554 | EXPECT_EQ(1, mock_storage.clear_count); | |
555 | } | |
556 | } | |
557 | ||
558 | TEST_F(SessionHandlerTest, EmojiUsageStatsTest) { | |
559 | SessionHandler handler(CreateMockDataEngine()); | |
560 | ||
561 | commands::Command command; | |
562 | command.mutable_input()->set_type(commands::Input::INSERT_TO_STORAGE); | |
563 | commands::GenericStorageEntry *storage_entry = | |
564 | command.mutable_input()->mutable_storage_entry(); | |
565 | storage_entry->set_type(commands::GenericStorageEntry::EMOJI_HISTORY); | |
566 | storage_entry->mutable_key()->assign("dummy key"); | |
567 | ||
568 | // Carrier emoji "BLACK SUN WITH RAYS" | |
569 | storage_entry->mutable_value()->Clear(); | |
570 | storage_entry->mutable_value()->Add()->assign("\xF3\xBE\x80\x80"); | |
571 | EXPECT_TRUE(handler.EvalCommand(&command)); | |
572 | EXPECT_COUNT_STATS("CommitCarrierEmoji", 1); | |
573 | EXPECT_COUNT_STATS("CommitUnicodeEmoji", 0); | |
574 | ||
575 | storage_entry->mutable_value()->Clear(); | |
576 | // Carrier emoji "BLACK SUN WITH RAYS" | |
577 | storage_entry->mutable_value()->Add()->assign("\xF3\xBE\x80\x80"); | |
578 | // Carrier emoji "GOOGLE" | |
579 | storage_entry->mutable_value()->Add()->assign("\xF3\xBE\xBA\xA0"); | |
580 | // Unicode emoji "BLACK SUN WITH RAYS" | |
581 | storage_entry->mutable_value()->Add()->assign("☀"); | |
582 | // Unicode emoji "RABBIT FACE" | |
583 | storage_entry->mutable_value()->Add()->assign("🐰"); | |
584 | EXPECT_TRUE(handler.EvalCommand(&command)); | |
585 | EXPECT_COUNT_STATS("CommitCarrierEmoji", 3); | |
586 | EXPECT_COUNT_STATS("CommitUnicodeEmoji", 2); | |
587 | } | |
588 | ||
589 | 438 | // Tests the interaction with EngineBuilderInterface for successful Engine |
590 | 439 | // reload event. |
591 | 440 | TEST_F(SessionHandlerTest, EngineReload_SuccessfulScenario) { |
282 | 282 | }, |
283 | 283 | }, |
284 | 284 | { |
285 | 'target_name': 'generic_storage_manager_test', | |
286 | 'type': 'executable', | |
287 | 'sources': [ | |
288 | 'generic_storage_manager_test.cc' | |
289 | ], | |
290 | 'dependencies': [ | |
291 | '../base/base.gyp:base', | |
292 | '../testing/testing.gyp:gtest_main', | |
293 | 'session_base.gyp:generic_storage_manager', | |
294 | ], | |
295 | 'variables': { | |
296 | 'test_size': 'small', | |
297 | }, | |
298 | }, | |
299 | { | |
300 | 285 | 'target_name': 'request_test_util_test', |
301 | 286 | 'type': 'executable', |
302 | 287 | 'sources': [ |
340 | 325 | 'target_name': 'session_all_test', |
341 | 326 | 'type': 'none', |
342 | 327 | 'dependencies': [ |
343 | 'generic_storage_manager_test', | |
344 | 328 | 'random_keyevents_generator_test', |
345 | 329 | 'request_test_util_test', |
346 | 330 | 'session_converter_stress_test', |
90 | 90 | case commands::Input::CLEAR_USER_HISTORY: |
91 | 91 | case commands::Input::CLEAR_USER_PREDICTION: |
92 | 92 | case commands::Input::CLEAR_UNUSED_USER_PREDICTION: |
93 | case commands::Input::CLEAR_STORAGE: | |
94 | case commands::Input::READ_ALL_FROM_STORAGE: | |
95 | 93 | case commands::Input::RELOAD: |
96 | 94 | case commands::Input::SEND_USER_DICTIONARY_COMMAND: |
97 | 95 | return true; |
163 | 163 | |
164 | 164 | // Smoke test to make sure it works without crash. |
165 | 165 | for (int i = 0; i < SessionCommand::CommandType_ARRAYSIZE; ++i) { |
166 | if (!SessionCommand::CommandType_IsValid(i)) { | |
167 | continue; | |
168 | } | |
166 | 169 | input.Clear(); |
167 | 170 | input.set_type(Input::SEND_COMMAND); |
168 | 171 | input.mutable_command()->set_type( |